summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/target/firmware/include/layer1/prim.h4
-rw-r--r--src/target/firmware/layer1/Makefile2
-rw-r--r--src/target/firmware/layer1/prim_sniff.c279
3 files changed, 284 insertions, 1 deletions
diff --git a/src/target/firmware/include/layer1/prim.h b/src/target/firmware/include/layer1/prim.h
index 30c51ae6..73f7c681 100644
--- a/src/target/firmware/include/layer1/prim.h
+++ b/src/target/firmware/include/layer1/prim.h
@@ -31,4 +31,8 @@ extern const struct tdma_sched_item tch_a_sched_set[];
extern const struct tdma_sched_item tch_d_sched_set[];
extern const struct tdma_sched_item neigh_pm_sched_set[];
+extern const struct tdma_sched_item sniff_xcch_dl_sched_set[];
+extern const struct tdma_sched_item sniff_xcch_ul_sched_set[];
+extern const struct tdma_sched_item sniff_tch_sched_set[];
+
#endif /* _L1_PRIM_H */
diff --git a/src/target/firmware/layer1/Makefile b/src/target/firmware/layer1/Makefile
index 0c710a5d..ac40efb4 100644
--- a/src/target/firmware/layer1/Makefile
+++ b/src/target/firmware/layer1/Makefile
@@ -5,5 +5,5 @@ LIB_layer1_SRCS=avg.c agc.c afc.c toa.c sync.c tdma_sched.c tpu_window.c init.c
l23_api.c mframe_sched.c sched_gsmtime.c async.c rfch.c apc.c
LIB_layer1_SRCS += prim_pm.c prim_rach.c prim_tx_nb.c prim_rx_nb.c prim_fbsb.c \
- prim_freq.c prim_utils.c prim_tch.c
+ prim_freq.c prim_utils.c prim_tch.c prim_sniff.c
diff --git a/src/target/firmware/layer1/prim_sniff.c b/src/target/firmware/layer1/prim_sniff.c
new file mode 100644
index 00000000..37dcd32a
--- /dev/null
+++ b/src/target/firmware/layer1/prim_sniff.c
@@ -0,0 +1,279 @@
+/* Layer 1 - Sniffing Bursts */
+
+/* (C) 2010 by Sylvain Munaut <tnt@246tNt.com>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+// #define DEBUG
+#undef DEBUG /* Very bw hungry */
+
+#include <stdint.h>
+#include <string.h>
+
+#include <defines.h>
+#include <byteorder.h>
+
+#include <debug.h>
+
+#include <osmocom/gsm/gsm_utils.h>
+
+#include <calypso/dsp.h>
+#include <layer1/agc.h>
+#include <layer1/l23_api.h>
+#include <layer1/rfch.h>
+#include <layer1/sync.h>
+#include <layer1/tdma_sched.h>
+#include <layer1/tpu_window.h>
+
+
+/* ------------------------------------------------------------------------ */
+/* Sniff TASK API */
+/* ------------------------------------------------------------------------ */
+
+#define SNIFF_DSP_TASK 23
+
+#define BASE_API_RAM 0xffd00000
+#define BASE_SNIFF_API_RAM (BASE_API_RAM + (0x2000 - 0x800) * sizeof(uint16_t))
+
+struct sniff_burst {
+ uint16_t toa;
+ uint16_t pm;
+ uint16_t angle;
+ uint16_t snr;
+ uint16_t dummy_ind;
+ uint16_t bits[29];
+};
+
+struct sniff_db {
+ uint16_t w_nb;
+ uint16_t r_nb;
+ struct sniff_burst bursts[4];
+};
+
+struct sniff_api {
+ struct sniff_db db[2];
+ uint16_t db_ptr;
+ uint16_t burst_ptr;
+};
+
+static inline struct sniff_db *
+sniff_get_page(int r_wn /* 0=W, 1=R */)
+{
+ struct sniff_api *sapi = (void*)BASE_SNIFF_API_RAM;
+ int idx = r_wn ? dsp_api.r_page : dsp_api.w_page;
+ return &sapi->db[idx];
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Local state */
+/* ------------------------------------------------------------------------ */
+
+struct sniff_local_db {
+ uint32_t fn;
+ uint8_t w_nb;
+ uint8_t r_nb;
+};
+
+static struct sniff_local_db _ldbs[2];
+
+static inline struct sniff_local_db *
+sniff_get_local_page(int r_wn /* 0=W, 1=R */)
+{
+ struct sniff_local_db *ldb;
+ int idx = r_wn ? dsp_api.r_page : dsp_api.w_page;
+
+ /* Get page */
+ ldb = &_ldbs[idx];
+
+ /* Clear page if it's not properly in sync */
+ if (!r_wn) {
+ if (ldb->fn != l1s.next_time.fn) {
+ memset(ldb, 0x00, sizeof(struct sniff_local_db));
+ ldb->fn = l1s.next_time.fn;
+ }
+ }
+
+ return ldb;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Sniff command & response */
+/* ------------------------------------------------------------------------ */
+
+static int
+l1s_sniff_resp(uint8_t ul, uint8_t burst_id, uint16_t p3)
+{
+ struct sniff_db *sp = sniff_get_page(1);
+ struct sniff_local_db *lsp = sniff_get_local_page(1);
+ struct sniff_api *sapi = (void*)BASE_SNIFF_API_RAM;
+
+ struct msgb *msg;
+ struct l1ctl_burst_ind *bi;
+
+ struct gsm_time rx_time;
+ uint16_t rf_arfcn;
+ uint8_t mf_task_id = p3 & 0xff;
+ uint8_t mf_task_flags = p3 >> 8;
+ uint8_t tn;
+
+ int bidx, i;
+
+ /* Debug */
+ printd("Fn: %d - %d - lsp->w_nb: %d - lsp->r_nb: %d - sp->w_nb: %d - sp->r_nb: %d\n",
+ l1s.current_time.fn-1, ul,
+ sp->w_nb, lsp->r_nb,
+ sp->w_nb, sp->r_nb
+ );
+ printd(" -> %d %04hx %04hx | %04hx %04hx %04hx %04hx %04hx\n",
+ dsp_api.r_page,
+ sapi->db_ptr,
+ sapi->burst_ptr,
+ sp->bursts[bidx].toa,
+ sp->bursts[bidx].pm,
+ sp->bursts[bidx].angle,
+ sp->bursts[bidx].snr,
+ sp->bursts[bidx].dummy_ind
+ );
+
+ for (i=0; i<29; i++)
+ printd("%04hx%c", sp->bursts[bidx].bits[i], i==28?'\n':' ');
+
+ /* Burst index in DSP response */
+ bidx = lsp->r_nb++;
+
+ /* The radio parameters for _this_ burst */
+ gsm_fn2gsmtime(&rx_time, l1s.current_time.fn - 1);
+ rfch_get_params(&rx_time, &rf_arfcn, NULL, &tn);
+
+ /* Create message */
+ msg = l1ctl_msgb_alloc(L1CTL_BURST_IND);
+ if (!msg)
+ goto exit;
+
+ bi = (struct l1ctl_burst_ind *) msgb_put(msg, sizeof(*bi));
+
+ /* Meta data */
+ /* Time */
+ bi->frame_nr = htonl(rx_time.fn);
+
+ /* ARFCN */
+ if (ul)
+ rf_arfcn |= ARFCN_UPLINK;
+ bi->band_arfcn = htons(rf_arfcn);
+
+ /* Set Channel Number depending on MFrame Task ID */
+ bi->chan_nr = mframe_task2chan_nr(mf_task_id, tn);
+
+ /* Set burst id */
+ bi->flags = burst_id;
+
+ /* Set SACCH indication */
+ if (mf_task_flags & MF_F_SACCH)
+ bi->flags |= BI_FLG_SACCH;
+
+ /* Set dummy indication */
+ if (sp->bursts[bidx].dummy_ind)
+ bi->flags |= BI_FLG_DUMMY;
+
+ /* DSP measurements */
+ bi->rx_level = dbm2rxlev(agc_inp_dbm8_by_pm(sp->bursts[bidx].pm >> 3)>>3);
+ bi->snr = (sp->bursts[bidx].snr - 1) >> 6;
+
+ /* Pack bits */
+ memset(bi->bits, 0x00, sizeof(bi->bits));
+
+ for (i=0; i<116; i++)
+ {
+ int sbit = 0x0008 << ((3 - (i & 3)) << 2);
+ int sword = i >> 2;
+ int dbit = 1 << (7 - (i & 7));
+ int dbyte = i >> 3;
+
+ if (sp->bursts[bidx].bits[sword] & sbit)
+ bi->bits[dbyte] |= dbit;
+ }
+
+ /* Send it ! */
+ l1_queue_for_l2(msg);
+
+exit:
+ /* mark READ page as being used */
+ dsp_api.r_page_used = 1;
+
+ return 0;
+}
+
+static int
+l1s_sniff_cmd(uint8_t ul, __unused uint8_t burst_id, __unused uint16_t p3)
+{
+ struct sniff_db *sp = sniff_get_page(0);
+ struct sniff_local_db *lsp = sniff_get_local_page(0);
+ uint16_t arfcn;
+ uint8_t tsc, tn;
+
+ printd("CMD: %d %d %d\n", lsp->w_nb);
+
+ sp->w_nb = ++lsp->w_nb;
+ sp->r_nb = 0;
+
+ rfch_get_params(&l1s.next_time, &arfcn, &tsc, &tn);
+
+ dsp_load_rx_task(SNIFF_DSP_TASK, 0, tsc);
+
+ /* enable dummy bursts detection */
+ dsp_api.db_w->d_ctrl_system |= (1 << B_BCCH_FREQ_IND);
+
+ if (ul) {
+ l1s_rx_win_ctrl(arfcn | ARFCN_UPLINK, L1_RXWIN_NB, 3);
+ } else {
+ l1s_rx_win_ctrl(arfcn, L1_RXWIN_NB, 0);
+ }
+
+ return 0;
+}
+
+const struct tdma_sched_item sniff_xcch_dl_sched_set[] = {
+ SCHED_ITEM_DT(l1s_sniff_cmd, 0, 0, 0), SCHED_END_FRAME(),
+ SCHED_ITEM_DT(l1s_sniff_cmd, 0, 0, 1), SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_sniff_resp, -5, 0, 0), SCHED_ITEM_DT(l1s_sniff_cmd, 0, 0, 2), SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_sniff_resp, -5, 0, 1), SCHED_ITEM_DT(l1s_sniff_cmd, 0, 0, 3), SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_sniff_resp, -5, 0, 2), SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_sniff_resp, -5, 0, 3), SCHED_END_FRAME(),
+ SCHED_END_SET()
+};
+
+const struct tdma_sched_item sniff_xcch_ul_sched_set[] = {
+ SCHED_ITEM_DT(l1s_sniff_cmd, 3, 1, 0), SCHED_END_FRAME(),
+ SCHED_ITEM_DT(l1s_sniff_cmd, 3, 1, 1), SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_sniff_resp, -4, 1, 0), SCHED_ITEM_DT(l1s_sniff_cmd, 3, 1, 2), SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_sniff_resp, -4, 1, 1), SCHED_ITEM_DT(l1s_sniff_cmd, 3, 1, 3), SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_sniff_resp, -4, 1, 2), SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_sniff_resp, -4, 1, 3), SCHED_END_FRAME(),
+ SCHED_END_SET()
+};
+
+const struct tdma_sched_item sniff_tch_sched_set[] = {
+ SCHED_ITEM_DT(l1s_sniff_cmd, 0, 0, 0), SCHED_ITEM_DT(l1s_sniff_cmd, 3, 1, 0), SCHED_END_FRAME(),
+ SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_sniff_resp, -5, 0, 0), SCHED_ITEM(l1s_sniff_resp, -4, 1, 0), SCHED_END_FRAME(),
+ SCHED_END_SET()
+};
+