diff options
author | Andreas Eversberg <jolly@eversberg.eu> | 2013-12-09 11:44:40 +0100 |
---|---|---|
committer | Harald Welte <laforge@gnumonks.org> | 2019-05-23 13:03:39 +0200 |
commit | 88db07994147f681f34f70f7810c96fe112b1dc5 (patch) | |
tree | 3e526ad17bcd3267f5c0c01df205ae32e0d9b2ba /src/target/firmware/layer1 | |
parent | e225f231860789dae22226cb4df04fe1b65a371c (diff) |
[WIP] HO: Add SCH read of neighbor cells to TCH channels
The task will try to sync to neighbor cell during search (idle) frame.
Change-Id: I7f2c6b5438676a816c546cb9dce404762ee5d5b5
Diffstat (limited to 'src/target/firmware/layer1')
-rw-r--r-- | src/target/firmware/layer1/l23_api.c | 2 | ||||
-rw-r--r-- | src/target/firmware/layer1/mframe_sched.c | 3 | ||||
-rw-r--r-- | src/target/firmware/layer1/prim_fbsb.c | 159 | ||||
-rw-r--r-- | src/target/firmware/layer1/prim_pm.c | 5 | ||||
-rw-r--r-- | src/target/firmware/layer1/tpu_window.c | 2 |
5 files changed, 171 insertions, 0 deletions
diff --git a/src/target/firmware/layer1/l23_api.c b/src/target/firmware/layer1/l23_api.c index e487864e..7d126cf1 100644 --- a/src/target/firmware/layer1/l23_api.c +++ b/src/target/firmware/layer1/l23_api.c @@ -564,7 +564,9 @@ static void l1ctl_rx_neigh_pm_req(struct msgb *msg) l1s.neigh_pm.band_arfcn[i] = ntohs(pm_req->band_arfcn[i]); l1s.neigh_pm.tn[i] = pm_req->tn[i]; l1s.neigh_pm.level[i] = 0; + l1s.neigh_sb.flags_bsic[i] = 0; } + l1s.neigh_sb.count = 0; printf("L1CTL_NEIGH_PM_REQ new list with %u entries\n", pm_req->n); l1s.neigh_pm.n = pm_req->n; /* atomic */ diff --git a/src/target/firmware/layer1/mframe_sched.c b/src/target/firmware/layer1/mframe_sched.c index b242f990..a83da812 100644 --- a/src/target/firmware/layer1/mframe_sched.c +++ b/src/target/firmware/layer1/mframe_sched.c @@ -52,6 +52,7 @@ struct mframe_sched_item { #define NB_QUAD_FH_UL NB_QUAD_UL #define NEIGH_PM_IDLE neigh_pm_idle_sched_set #define NEIGH_PM_TCH neigh_pm_tch_sched_set +#define NEIGH_SYNC neigh_sync_sched_set /* BCCH Normal */ static const struct mframe_sched_item mf_bcch_norm[] = { @@ -314,6 +315,7 @@ static const struct mframe_sched_item mf_neigh_pm26_even[] = { { .sched_set = NEIGH_PM_TCH, .modulo = 13, .frame_nr = 6 }, { .sched_set = NEIGH_PM_TCH, .modulo = 13, .frame_nr = 8 }, { .sched_set = NEIGH_PM_TCH, .modulo = 13, .frame_nr = 10 }, + { .sched_set = NEIGH_SYNC, .modulo = 26, .frame_nr = 24 }, { .sched_set = NULL } }; static const struct mframe_sched_item mf_neigh_pm26_odd[] = { @@ -323,6 +325,7 @@ static const struct mframe_sched_item mf_neigh_pm26_odd[] = { { .sched_set = NEIGH_PM_TCH, .modulo = 13, .frame_nr = 6 }, { .sched_set = NEIGH_PM_TCH, .modulo = 13, .frame_nr = 8 }, { .sched_set = NEIGH_PM_TCH, .modulo = 13, .frame_nr = 10 }, + { .sched_set = NEIGH_SYNC, .modulo = 26, .frame_nr = 11 }, { .sched_set = NULL } }; diff --git a/src/target/firmware/layer1/prim_fbsb.c b/src/target/firmware/layer1/prim_fbsb.c index 50acefcc..1682c509 100644 --- a/src/target/firmware/layer1/prim_fbsb.c +++ b/src/target/firmware/layer1/prim_fbsb.c @@ -571,6 +571,165 @@ void l1s_fbsb_req(uint8_t base_fn, struct l1ctl_fbsb_req *req) } + +/* SB for Neighbours in dedicated mode + * + * Only when number of neighbor cells is > 0, perform synchronization. + * + * For each synchronization, l1s.neigh_pm.running is set. In case of an update + * of neighbor cell list, this state is cleared, so a pending sync result would + * be ignored. + * + * After a (new) list of neighbor cells are received, the measurements are not + * yet valid. A valid state flag is used to indicate valid measurements. Until + * there are no valid measurements, the synchronization is not performed. + * + * The task is to scan the 6 strongest neighbor cells by trying to synchronize + * to it. This is done by selecting the strongest unscanned neighbor cell. + * If 6 cells have been scanned or all cells (if less than 6) have been + * scanned, the process clears all 'scanned' flags and starts over with the + * strongest (now the strongest unscanned) cell. + * + * Each synchronization attempt is performed during the "search frame" (IDLE + * frame). The process attempts to sync 11 times to ensure that it hits the + * SCH of the neighbor's BCCH. (The alignment of BCCH shifts after every two + * 26-multiframe in a way that the "search frame" is aligned with the SCH, at + * least once for 11 successive "search frames".) + * + * If the synchronization attempt is successful, the BSIC and neighbor cell + * offset is stored. These are indicated to layer23 with the measurement + * results. + * + * When performing handover to a neighbor cell, the stored offset is used to + * calculate new GSM time and tpu_offset. + */ + +static void select_neigh_cell(void) +{ + uint8_t strongest = 0, strongest_unscanned = 0; + int strongest_i = 0, strongest_unscanned_i = -1; + int num_scanned = 0; + int i; + + /* find strongest cell and strongest unscanned cell and count */ + for (i = 0; i < l1s.neigh_pm.n; i++) { + if (l1s.neigh_pm.level[i] > strongest) { + strongest = l1s.neigh_pm.level[i]; + strongest_i = i; + } + if (!(l1s.neigh_sb.flags_bsic[i] & NEIGH_PM_FLAG_SCANNED)) { + if (l1s.neigh_pm.level[i] > strongest_unscanned) { + strongest_unscanned = l1s.neigh_pm.level[i]; + strongest_unscanned_i = i; + } + } else + num_scanned++; + } + + /* no unscanned cell or we have scanned enough */ + if (strongest_unscanned_i < 0 || num_scanned >= 6) { + /* flag all cells unscanned */ + for (i = 0; i < l1s.neigh_pm.n; i++) + l1s.neigh_sb.flags_bsic[i] &= ~NEIGH_PM_FLAG_SCANNED; + /* use strongest cell to begin scanning with */ + l1s.neigh_sb.index = strongest_i; + } else { + /* use strongest unscanned cell to begin scanning with */ + l1s.neigh_sb.index = strongest_unscanned_i; + } +} + +static int l1s_neigh_sb_cmd(__unused uint8_t p1, __unused uint8_t p2, + __unused uint16_t p3) +{ + int index = l1s.neigh_sb.index; + uint8_t last_gain; + + if (l1s.neigh_pm.n == 0) + return 0; + + /* if measurements are not yet valid, wait */ + if (!l1s.neigh_pm.valid) + return 0; + + /* check for cell to sync to */ + if (l1s.neigh_sb.count == 0) { + /* there is no cell selected, search for cell */ + select_neigh_cell(); + } + + printf("detect SB arfcn %d (#%d) %d dbm\n", l1s.neigh_pm.band_arfcn[index], l1s.neigh_sb.count, rxlev2dbm(l1s.neigh_pm.level[index])); + + last_gain = rffe_get_gain(); + + /* Tell the RF frontend to set the gain appropriately */ + rffe_compute_gain(rxlev2dbm(l1s.neigh_pm.level[index]), CAL_DSP_TGT_BB_LVL); + + /* Program DSP */ + dsp_api.db_w->d_task_md = TCH_SB_DSP_TASK; /* maybe with I/Q swap? */ +// dsp_api.db_w->d_task_md = dsp_task_iq_swap(TCH_SB_DSP_TASK, l1s.neigh_pm.band_arfcn[index], 0); + dsp_api.ndb->d_fb_mode = 0; + + /* Program TPU */ + l1s_rx_win_ctrl(l1s.neigh_pm.band_arfcn[index], L1_RXWIN_SB26, 5); + + /* restore last gain */ + rffe_set_gain(last_gain); + + l1s.neigh_sb.running = 1; + + return 0; +} + +static int l1s_neigh_sb_resp(__unused uint8_t p1, __unused uint8_t p2, + __unused uint16_t p3) +{ + int index = l1s.neigh_sb.index; + uint32_t sb; + + if (l1s.neigh_pm.n == 0 || !l1s.neigh_sb.running) + goto out; + + /* check if sync was successful */ + if (dsp_api.db_r->a_sch[0] & (1<<B_SCH_CRC)) { + printf("SB error arfcn %d\n", l1s.neigh_pm.band_arfcn[index]); + + /* next sync */ + if (++l1s.neigh_sb.count == 11) { + l1s.neigh_sb.count = 0; + l1s.neigh_sb.flags_bsic[index] |= NEIGH_PM_FLAG_SCANNED; + } + } else { + l1s.neigh_sb.count = 0; + + read_sb_result(last_fb, 1); + sb = dsp_api.db_r->a_sch[3] | dsp_api.db_r->a_sch[4] << 16; + l1s.neigh_sb.flags_bsic[index] = + l1s_decode_sb(&fbs.mon.time, sb) + | NEIGH_PM_FLAG_BSIC | NEIGH_PM_FLAG_SCANNED; + printf("SB OK!!!!!! arfcn %d\n", l1s.neigh_pm.band_arfcn[index]); + + /* store time offset */ + } + +out: + l1s.neigh_sb.running = 0; + + dsp_api.r_page_used = 1; + + return 0; + +} + +/* NOTE: Prio 1 is below TCH's RX+TX prio 0 */ +const struct tdma_sched_item neigh_sync_sched_set[] = { + SCHED_ITEM_DT(l1s_neigh_sb_cmd, 1, 0, 1), SCHED_END_FRAME(), + SCHED_END_FRAME(), + SCHED_ITEM(l1s_neigh_sb_resp, -4, 0, 1), SCHED_END_FRAME(), + SCHED_END_SET() +}; + + static __attribute__ ((constructor)) void l1s_prim_fbsb_init(void) { l1s.completion[L1_COMPL_FB] = &l1a_fb_compl; diff --git a/src/target/firmware/layer1/prim_pm.c b/src/target/firmware/layer1/prim_pm.c index a4b8e638..416dff39 100644 --- a/src/target/firmware/layer1/prim_pm.c +++ b/src/target/firmware/layer1/prim_pm.c @@ -183,6 +183,11 @@ static void neigh_pm_ind(void) / l1s.neigh_pm.rounds; mi->pm[0] = l1s.neigh_pm.level[i]; l1s.neigh_pm.level_sum[i] = 0; + if ((l1s.neigh_sb.flags_bsic[i] & NEIGH_PM_FLAG_BSIC)) { + mi->bsic = l1s.neigh_sb.flags_bsic[i] & 0x3f; + mi->toa = l1s.neigh_sb.toa[i]; + } else + mi->bsic = L1CTL_BSIC_INVAL; } l1_queue_for_l2(msg); } diff --git a/src/target/firmware/layer1/tpu_window.c b/src/target/firmware/layer1/tpu_window.c index abdad956..dbe64eee 100644 --- a/src/target/firmware/layer1/tpu_window.c +++ b/src/target/firmware/layer1/tpu_window.c @@ -48,6 +48,7 @@ #define L1_SB_DURATION_Q (L1_BURST_LENGTH_Q + 2 * L1_SB_MARGIN_Q - L1_TAIL_DURATION_Q) #define L1_FB_DURATION_Q (11 * L1_TDMA_LENGTH_Q + 2057) /* more than 11 full slots */ #define L1_FB26_DURATION_Q (L1_TDMA_LENGTH_Q + 798) +#define L1_SB26_DURATION_Q (L1_TDMA_LENGTH_Q + 984) // 984 #define L1_PW_DURATION_Q 289 #define DSP_SETUP_TIME 66 @@ -57,6 +58,7 @@ static const uint16_t rx_burst_duration[_NUM_L1_RXWIN] = { [L1_RXWIN_FB] = L1_FB_DURATION_Q, [L1_RXWIN_SB] = L1_SB_DURATION_Q, [L1_RXWIN_NB] = L1_NB_DURATION_Q, + [L1_RXWIN_SB26] = L1_SB26_DURATION_Q, }; #define L1_TX_NB_DURATION_Q 626 |