summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Eversberg <jolly@eversberg.eu>2013-02-27 08:31:48 +0100
committerAndreas Eversberg <jolly@eversberg.eu>2013-02-27 08:31:48 +0100
commitf183f43f447f4e92ab6a12d4947e80b666a19274 (patch)
tree143f0e13d2530b73b4f10a99b5bdf72a2d114e97
parent49ef59bc62495eae904a11a017f747e839fdf886 (diff)
New sync task for calypso BTS, using a single frame per multiframe
By using single frame only, loss of packets is reduced. For normal data frames (and for TCH/H speech), one out of four parts of data gets lost. For TCH/F speech, only one out of eight parts of data gets lost. The error correction can compensate the missing parts. The sync code can use the extended DSP task, but it is currently disabled, because the current DSP code does not allow scheduling TSC for each individual task, but we need to use TSC of sync cell here.
-rw-r--r--src/target/firmware/include/layer1/mframe_sched.h1
-rw-r--r--src/target/firmware/include/layer1/prim.h1
-rw-r--r--src/target/firmware/layer1/Makefile2
-rw-r--r--src/target/firmware/layer1/l23_api.c4
-rw-r--r--src/target/firmware/layer1/mframe_sched.c7
-rw-r--r--src/target/firmware/layer1/prim_bts.c2
-rw-r--r--src/target/firmware/layer1/prim_bts_sync.c324
7 files changed, 338 insertions, 3 deletions
diff --git a/src/target/firmware/include/layer1/mframe_sched.h b/src/target/firmware/include/layer1/mframe_sched.h
index 7494eebc..7e9f91af 100644
--- a/src/target/firmware/include/layer1/mframe_sched.h
+++ b/src/target/firmware/include/layer1/mframe_sched.h
@@ -37,6 +37,7 @@ enum mframe_task {
MF_TASK_NEIGH_PM26O,
MF_TASK_BTS,
+ MF_TASK_BTS_SYNC,
/* Test task: send Normal Burst in all timeslots */
MF_TASK_UL_ALL_NB,
diff --git a/src/target/firmware/include/layer1/prim.h b/src/target/firmware/include/layer1/prim.h
index 654daa2f..f973ca4a 100644
--- a/src/target/firmware/include/layer1/prim.h
+++ b/src/target/firmware/include/layer1/prim.h
@@ -32,5 +32,6 @@ 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 bts_sched_set[];
+extern const struct tdma_sched_item bts_sync_sched_set[];
#endif /* _L1_PRIM_H */
diff --git a/src/target/firmware/layer1/Makefile b/src/target/firmware/layer1/Makefile
index 8e655b67..157a5c55 100644
--- a/src/target/firmware/layer1/Makefile
+++ b/src/target/firmware/layer1/Makefile
@@ -6,5 +6,5 @@ LIB_layer1_SRCS=avg.c agc.c afc.c toa.c sync.c tdma_sched.c tpu_window.c init.c
trx_dummy.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_bts.c
+ prim_freq.c prim_utils.c prim_tch.c prim_bts.c prim_bts_sync.c
diff --git a/src/target/firmware/layer1/l23_api.c b/src/target/firmware/layer1/l23_api.c
index 40bbdbae..39062201 100644
--- a/src/target/firmware/layer1/l23_api.c
+++ b/src/target/firmware/layer1/l23_api.c
@@ -605,11 +605,13 @@ static int l1ctl_bts_mode(struct msgb *msg)
printf("BTS MODE: %u %u\n", l1s.bts.bsic, l1s.bts.arfcn);
+ l1a_mftask_set(0);
if (bm->enabled) {
+ mframe_enable(MF_TASK_BTS_SYNC);
mframe_enable(MF_TASK_BTS);
l1s.bts.gain = bm->gain;
} else {
- mframe_disable(MF_TASK_BTS);
+ mframe_enable(MF_TASK_BCCH_NORM);
}
return 0;
diff --git a/src/target/firmware/layer1/mframe_sched.c b/src/target/firmware/layer1/mframe_sched.c
index c55b809b..f126e589 100644
--- a/src/target/firmware/layer1/mframe_sched.c
+++ b/src/target/firmware/layer1/mframe_sched.c
@@ -316,6 +316,12 @@ static const struct mframe_sched_item mf_bts[] = {
{ .sched_set = NULL }
};
+/* BTS Sync */
+static const struct mframe_sched_item mf_bts_sync[] = {
+ { .sched_set = bts_sync_sched_set, .modulo = 51, .frame_nr = 2 },
+ { .sched_set = NULL }
+};
+
/* Test TX */
static const struct mframe_sched_item mf_tx_all_nb[] = {
{ .sched_set = NB_QUAD_FH_UL, .modulo = 4, .frame_nr = 0 },
@@ -356,6 +362,7 @@ static const struct mframe_sched_item *sched_set_for_task[32] = {
[MF_TASK_NEIGH_PM26O] = mf_neigh_pm26_odd,
[MF_TASK_BTS] = mf_bts,
+ [MF_TASK_BTS_SYNC] = mf_bts_sync,
[MF_TASK_UL_ALL_NB] = mf_tx_all_nb,
};
diff --git a/src/target/firmware/layer1/prim_bts.c b/src/target/firmware/layer1/prim_bts.c
index ca64118e..92f455b0 100644
--- a/src/target/firmware/layer1/prim_bts.c
+++ b/src/target/firmware/layer1/prim_bts.c
@@ -245,7 +245,7 @@ l1s_bts_cmd(uint8_t p1, uint8_t p2, uint16_t p3)
t3 = l1s.next_time.t3;
- if ((t3 < 2) || (t3 > 5))
+ if (t3 != 2)
{
/* We're really a frame in advance since we RX in the next frame ! */
t3 = t3 - 1;
diff --git a/src/target/firmware/layer1/prim_bts_sync.c b/src/target/firmware/layer1/prim_bts_sync.c
new file mode 100644
index 00000000..60cb1576
--- /dev/null
+++ b/src/target/firmware/layer1/prim_bts_sync.c
@@ -0,0 +1,324 @@
+/* Layer 1 - Receiving Normal Bursts */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * 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.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <defines.h>
+#include <debug.h>
+#include <memory.h>
+#include <byteorder.h>
+#include <rffe.h>
+#include <osmocom/gsm/gsm_utils.h>
+#include <osmocom/core/msgb.h>
+#include <calypso/dsp_api.h>
+#include <calypso/irq.h>
+#include <calypso/tpu.h>
+#include <calypso/tsp.h>
+#include <calypso/dsp.h>
+#include <calypso/timer.h>
+#include <comm/sercomm.h>
+
+#include <layer1/sync.h>
+#include <layer1/afc.h>
+#include <layer1/toa.h>
+#include <layer1/tdma_sched.h>
+#include <layer1/mframe_sched.h>
+#include <layer1/tpu_window.h>
+#include <layer1/l23_api.h>
+#include <layer1/rfch.h>
+#include <layer1/prim.h>
+#include <layer1/agc.h>
+
+#include <l1ctl_proto.h>
+
+/* ------------------------------------------------------------------------ */
+/* DSP extensions API */
+/* ------------------------------------------------------------------------ */
+
+#define BASE_API 0xFFD00000
+
+#define API_DSP2ARM(x) (BASE_API + ((x) - 0x0800) * sizeof(uint16_t))
+
+#define BASE_API_EXT_DB0 API_DSP2ARM(0x2000)
+#define BASE_API_EXT_DB1 API_DSP2ARM(0x2200)
+#define BASE_API_EXT_NDB API_DSP2ARM(0x2400)
+
+struct dsp_ext_ndb {
+ uint16_t active;
+ uint16_t tsc;
+} __attribute__((packed));
+
+struct dsp_ext_db {
+ /* TX command and data ptr */
+ struct {
+#define DSP_EXT_TX_CMD_NONE 0
+#define DSP_EXT_TX_CMD_FB 1
+#define DSP_EXT_TX_CMD_SB 2
+#define DSP_EXT_TX_CMD_DUMMY 3
+#define DSP_EXT_TX_CMD_AB 4
+#define DSP_EXT_TX_CMD_NB 5
+ uint16_t cmd;
+ uint16_t data;
+ } tx[8];
+
+ /* RX command and data ptr */
+ struct {
+#define DSP_EXT_RX_CMD_NONE 0
+#define DSP_EXT_RX_CMD_AB 1
+#define DSP_EXT_RX_CMD_NB 2
+ uint16_t cmd;
+ uint16_t data;
+ } rx[8];
+
+ /* SCH data */
+ uint16_t sch[2];
+
+ /* Generic data array */
+ uint16_t data[0];
+} __attribute__((packed));
+
+struct dsp_ext_api {
+ struct dsp_ext_ndb *ndb;
+ struct dsp_ext_db *db[2];
+};
+
+static struct dsp_ext_api dsp_ext_api = {
+ .ndb = (struct dsp_ext_ndb *) BASE_API_EXT_NDB,
+ .db = {
+ (struct dsp_ext_db *) BASE_API_EXT_DB0,
+ (struct dsp_ext_db *) BASE_API_EXT_DB1,
+ },
+};
+
+static inline struct dsp_ext_db *
+dsp_ext_get_db(int r_wn /* 0=W, 1=R */)
+{
+ int idx = r_wn ? dsp_api.r_page : dsp_api.w_page;
+ return dsp_ext_api.db[idx];
+}
+
+
+
+struct l1s_rxnb_state {
+ struct l1s_meas_hdr meas[4];
+
+ struct msgb *msg;
+ struct l1ctl_info_dl *dl;
+ struct l1ctl_data_ind *di;
+};
+
+static struct l1s_rxnb_state rxnb;
+
+static int l1s_nb_resp(__unused uint8_t p1, __unused uint8_t p2, uint16_t p3)
+{
+ struct gsm_time rx_time;
+ uint16_t rf_arfcn;
+ uint8_t tsc, tn;
+ int i;
+
+#if 1
+ putchart('n');
+
+ /* just for debugging, d_task_d should not be 0 */
+ if (dsp_api.db_r->d_task_d == 0) {
+ puts("EMPTY\n");
+ return 0;
+ }
+
+ /* DSP burst ID needs to correspond with what we expect */
+ if (dsp_api.db_r->d_burst_d != 0) {
+ printf("BURST ID %u!=0\n", dsp_api.db_r->d_burst_d);
+ return 0;
+ }
+
+ /* get radio parameters for _this_ burst */
+ gsm_fn2gsmtime(&rx_time, l1s.current_time.fn - 1);
+ rfch_get_params(&rx_time, &rf_arfcn, &tsc, &tn);
+
+ /* collect measurements */
+ rxnb.meas[0].toa_qbit = dsp_api.db_r->a_serv_demod[D_TOA];
+ rxnb.meas[0].pm_dbm8 =
+ agc_inp_dbm8_by_pm(dsp_api.db_r->a_serv_demod[D_PM] >> 3);
+ rxnb.meas[0].freq_err =
+ ANGLE_TO_FREQ(dsp_api.db_r->a_serv_demod[D_ANGLE]);
+ rxnb.meas[0].snr = dsp_api.db_r->a_serv_demod[D_SNR];
+
+ /* feed computed frequency error into AFC loop */
+ if (rxnb.meas[0].snr > AFC_SNR_THRESHOLD)
+ afc_input(rxnb.meas[0].freq_err, rf_arfcn, 1);
+ else
+ afc_input(rxnb.meas[0].freq_err, rf_arfcn, 0);
+
+ /* feed computed TOA into TA loop */
+ printf("TOA=%d snr=%d (thres %d) freq_err=%d pm=%d\n",
+ rxnb.meas[0].toa_qbit, rxnb.meas[0].snr, 2560,
+ rxnb.meas[0].freq_err, rxnb.meas[0].pm_dbm8 / 8);
+ for (i = 0; i < 10; i++)
+ toa_input(rxnb.meas[0].toa_qbit << 2, rxnb.meas[0].snr);
+
+ /* Tell the RF frontend to set the gain appropriately */
+ rffe_compute_gain(rxnb.meas[0].pm_dbm8/8, CAL_DSP_TGT_BB_LVL);
+
+ {
+ /* Get radio parameters for the first burst */
+ gsm_fn2gsmtime(&rx_time, l1s.current_time.fn - 4);
+ rfch_get_params(&rx_time, &rf_arfcn, &tsc, &tn);
+
+ rxnb.dl->chan_nr = 0x80;
+ rxnb.dl->link_id = 0x00;
+
+ rxnb.dl->band_arfcn = htons(rf_arfcn);
+
+ rxnb.dl->frame_nr = htonl(rx_time.fn);
+
+ rxnb.dl->snr = rxnb.meas[0].snr;
+ rxnb.dl->rx_level = dbm2rxlev(rxnb.meas[0].pm_dbm8 / 8);
+
+ /* update rx level for pm report */
+ pu_update_rx_level(rxnb.dl->rx_level);
+
+ l1_queue_for_l2(rxnb.msg);
+ rxnb.msg = NULL; rxnb.dl = NULL; rxnb.di = NULL;
+
+ /* clear downlink task */
+ dsp_api.db_w->d_task_d = 0;
+ }
+
+ /* mark READ page as being used */
+ dsp_api.r_page_used = 1;
+#else
+ struct dsp_ext_db *db = dsp_ext_get_db(1);
+ uint16_t *d = &db->data[32];
+
+ /* get radio parameters for _this_ burst */
+ gsm_fn2gsmtime(&rx_time, l1s.current_time.fn - 1);
+ rfch_get_params(&rx_time, &rf_arfcn, &tsc, &tn);
+
+ /* collect measurements */
+ rxnb.meas[0].toa_qbit = d[D_TOA];
+ rxnb.meas[0].pm_dbm8 =
+ agc_inp_dbm8_by_pm(d[D_PM] >> 3);
+ rxnb.meas[0].freq_err =
+ ANGLE_TO_FREQ(d[D_ANGLE]);
+ rxnb.meas[0].snr = d[D_SNR];
+
+ /* feed computed frequency error into AFC loop */
+ if (rxnb.meas[0].snr > AFC_SNR_THRESHOLD)
+ afc_input(rxnb.meas[0].freq_err, rf_arfcn, 1);
+ else
+ afc_input(rxnb.meas[0].freq_err, rf_arfcn, 0);
+
+ /* feed computed TOA into TA loop */
+ printf("arfcn=%d tn=%d TOA=%d snr=%d (thres %d) freq_err=%d pm=%d\n",
+ rf_arfcn, tn,
+ rxnb.meas[0].toa_qbit, rxnb.meas[0].snr, 2560,
+ rxnb.meas[0].freq_err, rxnb.meas[0].pm_dbm8 / 8);
+ for (i = 0; i < 10; i++)
+ toa_input(rxnb.meas[0].toa_qbit << 2, rxnb.meas[0].snr);
+
+ /* Tell the RF frontend to set the gain appropriately */
+ rffe_compute_gain(rxnb.meas[0].pm_dbm8/8, CAL_DSP_TGT_BB_LVL);
+
+ {
+ rxnb.dl->chan_nr = 0x80;
+ rxnb.dl->link_id = 0x00;
+
+ rxnb.dl->band_arfcn = htons(rf_arfcn);
+
+ rxnb.dl->frame_nr = htonl(rx_time.fn);
+
+ rxnb.dl->snr = rxnb.meas[0].snr;
+ rxnb.dl->rx_level = dbm2rxlev(rxnb.meas[0].pm_dbm8 / 8);
+
+ /* update rx level for pm report */
+ pu_update_rx_level(rxnb.dl->rx_level);
+
+ l1_queue_for_l2(rxnb.msg);
+ rxnb.msg = NULL; rxnb.dl = NULL; rxnb.di = NULL;
+ }
+
+ /* We're done with this */
+ dsp_api.r_page_used = 1;
+#endif
+
+ return 0;
+}
+
+static int l1s_nb_cmd(__unused uint8_t p1, __unused uint8_t p2,
+ __unused uint16_t p3)
+{
+ uint16_t arfcn;
+ uint8_t tsc, tn;
+
+ putchart('N');
+
+ if (rxnb.msg) {
+ /* Can happen when resetting ... */
+ printf("nb_cmd(0) and rxnb.msg != NULL\n");
+ msgb_free(rxnb.msg);
+ }
+ /* allocate msgb as needed. FIXME: from L1A ?? */
+ rxnb.msg = l1ctl_msgb_alloc(L1CTL_DATA_IND);
+ if (!rxnb.msg)
+ printf("nb_cmd(0): unable to allocate msgb\n");
+ rxnb.dl = (struct l1ctl_info_dl *) msgb_put(rxnb.msg, sizeof(*rxnb.dl));
+ rxnb.di = (struct l1ctl_data_ind *) msgb_put(rxnb.msg, sizeof(*rxnb.di));
+
+ rfch_get_params(&l1s.next_time, &arfcn, &tsc, &tn);
+
+ dsp_ext_api.ndb->tsc = tsc;
+#if 1
+ /* DDL_DSP_TASK, four normal bursts */
+ dsp_load_tch_param(&l1s.next_time,
+ SIG_ONLY_MODE, SDCCH_4, 0, 0, 0, tn);
+
+ dsp_load_rx_task( dsp_task_iq_swap(ALLC_DSP_TASK, arfcn, 0), 0, tsc);
+#else
+ struct dsp_ext_db *db = dsp_ext_get_db(0);
+
+ /* Enable extensions */
+ dsp_ext_api.ndb->active = 1;
+
+ db->rx[0].data = 0x000;
+ db->rx[0].cmd = DSP_EXT_RX_CMD_NB;
+
+ /* Enable dummy bursts detection */
+ dsp_api.db_w->d_ctrl_system |= (1 << B_BCCH_FREQ_IND);
+
+ /* Enable task */
+ dsp_api.db_w->d_task_d = 23;
+#endif
+
+ l1s_rx_win_ctrl(arfcn, L1_RXWIN_NB, 0);
+
+ return 0;
+}
+
+const struct tdma_sched_item bts_sync_sched_set[] = {
+ SCHED_ITEM_DT(l1s_nb_cmd, 2, 0, 0), SCHED_END_FRAME(),
+ SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_nb_resp, -5, 0, 0), SCHED_END_FRAME(),
+ SCHED_END_SET()
+};