diff options
author | Harald Welte <laforge@gnumonks.org> | 2010-05-19 21:41:24 +0200 |
---|---|---|
committer | Harald Welte <laforge@gnumonks.org> | 2010-05-19 21:41:24 +0200 |
commit | 8978ec571efd7221098e5f6aa7cfbc3fa42fe1c3 (patch) | |
tree | aa145ed9b5a5e197e1824f2d95f3587d65639160 | |
parent | bcf3badc5b057c5651d15d11262afa757775cf47 (diff) |
layer1/l1ctl: Split L1CTL_NEW_CCCH_REQ in FBSB_REQ nad SYNC_REQ
We really want to have those two as distinct operations - and we
want proper state machines in L1 to quickly return if they've
managed to acquire a FB or SB or not. Otherwise scanning will
take ages...
This code now introduces a new l1ctl_fbsb_req that is sent via
L1CTL to ask for a bitmask of FB0/FB1/SB operations. The actual
FB0/FB1 detection now no longer runs for 500 TDMA interrupts
but completes as soon as we either know there is no FCCH,
or that our frequency error is smaller than a caller-specified
threshold.
FB0/FB1 are already working, SB is not yet, sorry.
-rw-r--r-- | include/l1a_l23_interface.h | 26 | ||||
-rw-r--r-- | src/host/layer23/include/osmocom/l1ctl.h | 5 | ||||
-rw-r--r-- | src/host/layer23/include/osmocom/osmocom_data.h | 3 | ||||
-rw-r--r-- | src/host/layer23/src/app_phone.c | 2 | ||||
-rw-r--r-- | src/host/layer23/src/bcch_scan.c | 2 | ||||
-rw-r--r--[-rwxr-xr-x] | src/host/layer23/src/gsm322.c | 2 | ||||
-rw-r--r-- | src/host/layer23/src/gsm48_rr.c | 2 | ||||
-rw-r--r-- | src/host/layer23/src/l1ctl.c | 46 | ||||
-rw-r--r-- | src/target/firmware/apps/layer1/main.c | 1 | ||||
-rw-r--r-- | src/target/firmware/layer1/afc.c | 1 | ||||
-rw-r--r-- | src/target/firmware/layer1/l23_api.c | 18 | ||||
-rw-r--r-- | src/target/firmware/layer1/prim_fbsb.c | 467 |
12 files changed, 338 insertions, 237 deletions
diff --git a/include/l1a_l23_interface.h b/include/l1a_l23_interface.h index 690a6baa..e1e7ccd5 100644 --- a/include/l1a_l23_interface.h +++ b/include/l1a_l23_interface.h @@ -24,8 +24,8 @@ #ifndef l1a_l23_interface_h #define l1a_l23_interface_h -#define L1CTL_NEW_CCCH_REQ 1 -#define L1CTL_NEW_CCCH_RESP 2 +#define L1CTL_FBSB_REQ 1 +#define L1CTL_FBSB_RESP 2 #define L1CTL_DATA_IND 3 #define L1CTL_RACH_REQ 4 #define L1CTL_DM_EST_REQ 5 @@ -70,9 +70,13 @@ struct l1ctl_info_dl { } __attribute__((packed)); /* new CCCH was found. This is following the header */ -struct l1ctl_sync_new_ccch_resp { +struct l1ctl_fbsb_resp { + uint16_t band_arfcn; + int16_t initial_freq_err; + uint8_t result; uint8_t bsic; - uint8_t padding[3]; + uint8_t padding[2]; + /* FIXME: contents of cell_info ? */ } __attribute__((packed)); /* data on the CCCH was found. This is following the header */ @@ -96,13 +100,23 @@ struct l1ctl_info_ul { } __attribute__((packed)); /* - * msg for SYNC_NEW_CCCH_REQ + * msg for FBSB_REQ * the l1_info_ul header is in front */ -struct l1ctl_sync_new_ccch_req { +struct l1ctl_fbsb_req { uint16_t band_arfcn; + uint16_t timeout; /* in TDMA frames */ + uint16_t freq_err_thresh1; + uint16_t freq_err_thresh2; + uint8_t num_freqerr_avg; + uint8_t flags; /* L1CTL_FBSB_F_* */ + uint8_t sync_info_idx; + uint8_t reserved; } __attribute__((packed)); +#define L1CTL_FBSB_F_FB0 (1 << 0) +#define L1CTL_FBSB_F_FB1 (1 << 1) +#define L1CTL_FBSB_F_SB (1 << 2) /* the l1_info_ul header is in front */ struct l1ctl_rach_req { diff --git a/src/host/layer23/include/osmocom/l1ctl.h b/src/host/layer23/include/osmocom/l1ctl.h index fa0e9c1f..c267fa75 100644 --- a/src/host/layer23/include/osmocom/l1ctl.h +++ b/src/host/layer23/include/osmocom/l1ctl.h @@ -18,8 +18,9 @@ int tx_ph_rach_req(struct osmocom_ms *ms); /* Transmit L1CTL_DM_EST_REQ */ int tx_ph_dm_est_req(struct osmocom_ms *ms, uint16_t band_arfcn, uint8_t chan_nr); -/* Transmit NEW_CCCH_REQ */ -int l1ctl_tx_ccch_req(struct osmocom_ms *ms, uint16_t arfcn); +/* Transmit FBSB_REQ */ +int l1ctl_tx_fbsb_req(struct osmocom_ms *ms, uint16_t arfcn, + uint8_t flags, uint16_t timeout, uint8_t sync_info_idx); int l1ctl_tx_echo_req(struct osmocom_ms *ms, unsigned int len); diff --git a/src/host/layer23/include/osmocom/osmocom_data.h b/src/host/layer23/include/osmocom/osmocom_data.h index f56ba288..bb18fed7 100644 --- a/src/host/layer23/include/osmocom/osmocom_data.h +++ b/src/host/layer23/include/osmocom/osmocom_data.h @@ -49,7 +49,8 @@ enum osmobb_sig_subsys { }; enum osmobb_meas_sig { - S_L1CTL_CCCH_RESP, + S_L1CTL_FBSB_ERR, + S_L1CTL_FBSB_RESP, S_L1CTL_RESET, S_L1CTL_PM_RES, S_L1CTL_PM_DONE, diff --git a/src/host/layer23/src/app_phone.c b/src/host/layer23/src/app_phone.c index 6b0df509..1c4f16a3 100644 --- a/src/host/layer23/src/app_phone.c +++ b/src/host/layer23/src/app_phone.c @@ -44,7 +44,7 @@ static int signal_cb(unsigned int subsys, unsigned int signal, switch (signal) { case S_L1CTL_RESET: ms = signal_data; - return l1ctl_tx_ccch_req(ms, ms->test_arfcn); + return l1ctl_tx_fbsb_req(ms, ms->test_arfcn, 0x07, 100, 0); break; } return 0; diff --git a/src/host/layer23/src/bcch_scan.c b/src/host/layer23/src/bcch_scan.c index 69fa5e6b..e6238237 100644 --- a/src/host/layer23/src/bcch_scan.c +++ b/src/host/layer23/src/bcch_scan.c @@ -154,7 +154,7 @@ static int _cinfo_start_arfcn(unsigned int band_arfcn) /* ask L1 to try to tune to new ARFCN */ /* FIXME: decode band */ - rc = l1ctl_tx_ccch_req(fps.ms, band_arfcn); + rc = l1ctl_tx_fbsb_req(fps.ms, band_arfcn, 0x01, 100, 0); if (rc < 0) return rc; diff --git a/src/host/layer23/src/gsm322.c b/src/host/layer23/src/gsm322.c index 0fc82e14..0480037f 100755..100644 --- a/src/host/layer23/src/gsm322.c +++ b/src/host/layer23/src/gsm322.c @@ -2280,7 +2280,7 @@ static int gsm322_l1_signal(unsigned int subsys, unsigned int signal, return -EINVAL; gsm322_cs_powerscan(ms); break; - case S_L1CTL_CCCH_RESP: + case S_L1CTL_FBSB_RESP: ms = signal_data; cs = &ms->cellsel; if (cs->ccch_state == GSM322_CCCH_ST_INIT) { diff --git a/src/host/layer23/src/gsm48_rr.c b/src/host/layer23/src/gsm48_rr.c index 383bb4a9..d38c0719 100644 --- a/src/host/layer23/src/gsm48_rr.c +++ b/src/host/layer23/src/gsm48_rr.c @@ -2813,7 +2813,7 @@ static int gsm48_rr_rel_cnf(struct osmocom_ms *ms, struct msgb *msg) release and give new arfcn tx_ph_dm_rel_req(ms, arfcn, rr->chan_desc.chan_desc.chan_nr); #else - l1ctl_tx_ccch_req(ms, rr->cd_now.arfcn); + l1ctl_tx_fbsb_req(ms, rr->cd_now.arfcn, 0x07, 100, 0); #endif /* do nothing, because we aleady IDLE diff --git a/src/host/layer23/src/l1ctl.c b/src/host/layer23/src/l1ctl.c index 70c3683b..9a846ee4 100644 --- a/src/host/layer23/src/l1ctl.c +++ b/src/host/layer23/src/l1ctl.c @@ -70,25 +70,28 @@ static int osmo_make_band_arfcn(struct osmocom_ms *ms, uint16_t arfcn) return arfcn; } -static int rx_l1_ccch_resp(struct osmocom_ms *ms, struct msgb *msg) +static int rx_l1_fbsb_resp(struct osmocom_ms *ms, struct msgb *msg) { struct l1ctl_info_dl *dl; - struct l1ctl_sync_new_ccch_resp *sb; + struct l1ctl_fbsb_resp *sb; struct gsm_time tm; - if (msgb_l3len(msg) < sizeof(*sb)) { - LOGP(DL1C, LOGL_ERROR, "MSG too short for CCCH RESP: %u\n", + if (msgb_l3len(msg) < sizeof(*dl) + sizeof(*sb)) { + LOGP(DL1C, LOGL_ERROR, "MSG too short for FBSB RESP: %u\n", msgb_l3len(msg)); return -1; } dl = (struct l1ctl_info_dl *) msg->l1h; - sb = (struct l1ctl_sync_new_ccch_resp *) dl->payload; + sb = (struct l1ctl_fbsb_resp *) dl->payload; + + if (sb->result != 0) + dispatch_signal(SS_L1CTL, S_L1CTL_FBSB_ERR, ms); gsm_fn2gsmtime(&tm, ntohl(dl->frame_nr)); DEBUGP(DL1C, "SCH: SNR: %u TDMA: (%.4u/%.2u/%.2u) bsic: %d\n", dl->snr, tm.t1, tm.t2, tm.t3, sb->bsic); - dispatch_signal(SS_L1CTL, S_L1CTL_CCCH_RESP, ms); + dispatch_signal(SS_L1CTL, S_L1CTL_FBSB_RESP, ms); return 0; } @@ -214,18 +217,35 @@ int tx_ph_data_req(struct osmocom_ms *ms, struct msgb *msg, return osmo_send_l1(ms, msg); } -/* Transmit NEW_CCCH_REQ */ +/* FIXME: remove this after all code has been ported */ int l1ctl_tx_ccch_req(struct osmocom_ms *ms, uint16_t arfcn) { + LOGP(DL1C, LOGL_ERROR, "CCCH REQ no longer implemented!!!\n"); + return -EINVAL; +} + +/* Transmit FBSB_REQ */ +int l1ctl_tx_fbsb_req(struct osmocom_ms *ms, uint16_t arfcn, + uint8_t flags, uint16_t timeout, uint8_t sync_info_idx) +{ struct msgb *msg; - struct l1ctl_sync_new_ccch_req *req; + struct l1ctl_fbsb_req *req; - msg = osmo_l1_alloc(L1CTL_NEW_CCCH_REQ); + msg = osmo_l1_alloc(L1CTL_FBSB_REQ); if (!msg) return -1; - req = (struct l1ctl_sync_new_ccch_req *) msgb_put(msg, sizeof(*req)); - req->band_arfcn = osmo_make_band_arfcn(ms, arfcn); + req = (struct l1ctl_fbsb_req *) msgb_put(msg, sizeof(*req)); + req->band_arfcn = htons(osmo_make_band_arfcn(ms, arfcn)); + req->timeout = htons(timeout); + /* Threshold when to consider FB_MODE1: 4kHz - 1kHz */ + req->freq_err_thresh1 = htons(4000 - 1000); + /* Threshold when to consider SCH: 1kHz - 200Hz */ + req->freq_err_thresh2 = htons(1000 - 200); + /* not used yet! */ + req->num_freqerr_avg = 3; + req->flags = flags; + req->sync_info_idx = sync_info_idx; return osmo_send_l1(ms, msg); } @@ -355,8 +375,8 @@ int l1ctl_recv(struct osmocom_ms *ms, struct msgb *msg) msg->l1h = l1h->data; switch (l1h->msg_type) { - case L1CTL_NEW_CCCH_RESP: - rc = rx_l1_ccch_resp(ms, msg); + case L1CTL_FBSB_RESP: + rc = rx_l1_fbsb_resp(ms, msg); break; case L1CTL_DATA_IND: rc = rx_ph_data_ind(ms, msg); diff --git a/src/target/firmware/apps/layer1/main.c b/src/target/firmware/apps/layer1/main.c index bc968b42..a4081233 100644 --- a/src/target/firmware/apps/layer1/main.c +++ b/src/target/firmware/apps/layer1/main.c @@ -90,6 +90,7 @@ int main(void) tpu_frame_irq_en(1, 1); while (1) { + l1a_compl_execute(); update_timers(); } diff --git a/src/target/firmware/layer1/afc.c b/src/target/firmware/layer1/afc.c index 909e306a..8e72f74d 100644 --- a/src/target/firmware/layer1/afc.c +++ b/src/target/firmware/layer1/afc.c @@ -51,6 +51,7 @@ static struct afc_state afc_state = { .period = AFC_PERIOD, .min_valid = AFC_MIN_MUN_VALID, }, + .dac_value = 500, }; /* The AFC DAC in the ABB has to be configured as follows: diff --git a/src/target/firmware/layer1/l23_api.c b/src/target/firmware/layer1/l23_api.c index fec6183e..901e01cc 100644 --- a/src/target/firmware/layer1/l23_api.c +++ b/src/target/firmware/layer1/l23_api.c @@ -110,7 +110,7 @@ struct msgb *l1_create_l2_msg(int msg_type, uint32_t fn, uint16_t snr, dl = (struct l1ctl_info_dl *) msgb_put(msg, sizeof(*dl)); dl->frame_nr = htonl(fn); dl->snr = snr; - dl->band_arfcn = arfcn; + dl->band_arfcn = htons(arfcn); return msg; } @@ -143,7 +143,7 @@ static void l1a_l23_rx_cb(uint8_t dlci, struct msgb *msg) { struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data; struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data; - struct l1ctl_sync_new_ccch_req *sync_req; + struct l1ctl_fbsb_req *sync_req; struct l1ctl_rach_req *rach_req; struct l1ctl_dm_est_req *est_req; struct l1ctl_data_ind *data_ind; @@ -165,30 +165,30 @@ static void l1a_l23_rx_cb(uint8_t dlci, struct msgb *msg) } switch (l1h->msg_type) { - case L1CTL_NEW_CCCH_REQ: + case L1CTL_FBSB_REQ: if (sizeof(*sync_req) > msg->len) { printf("Short sync msg. %u\n", msg->len); break; } - sync_req = (struct l1ctl_sync_new_ccch_req *) l1h->data; - printd("L1CTL_NEW_CCCH_REQ (arfcn=%u)\n", sync_req->band_arfcn); + sync_req = (struct l1ctl_fbsb_req *) l1h->data; + printd("L1CTL_FBSB_REQ (arfcn=%u)\n", ntohs(sync_req->band_arfcn)); /* reset scheduler and hardware */ l1s_reset(); /* tune to specified frequency */ - trf6151_rx_window(0, sync_req->band_arfcn, 40, 0); + trf6151_rx_window(0, ntohs(sync_req->band_arfcn), 40, 0); tpu_end_scenario(); printd("Starting FCCH Recognition\n"); - l1s_fb_test(1, 0); + l1s_fbsb_req(1, sync_req); break; case L1CTL_DM_EST_REQ: est_req = (struct l1ctl_dm_est_req *) ul->payload; printd("L1CTL_DM_EST_REQ (arfcn=%u, chan_nr=0x%02x)\n", - est_req->band_arfcn, ul->chan_nr); - if (est_req->band_arfcn != l1s.serving_cell.arfcn) { + ntohs(est_req->band_arfcn), ul->chan_nr); + if (ntohs(est_req->band_arfcn) != l1s.serving_cell.arfcn) { /* FIXME: ARFCN */ puts("We don't support ARFCN switches yet\n"); break; diff --git a/src/target/firmware/layer1/prim_fbsb.c b/src/target/firmware/layer1/prim_fbsb.c index 3cd14c4d..eaa55d04 100644 --- a/src/target/firmware/layer1/prim_fbsb.c +++ b/src/target/firmware/layer1/prim_fbsb.c @@ -24,6 +24,7 @@ #include <stdio.h> #include <string.h> #include <stdlib.h> +#include <errno.h> #include <defines.h> #include <debug.h> @@ -61,8 +62,21 @@ struct mon_state { /* computed values */ int16_t freq_diff; + + /* Sync Burst (SB) */ + uint8_t bsic; + struct gsm_time time; }; +struct l1a_fb_state { + struct mon_state mon; + struct l1ctl_fbsb_req req; + int16_t initial_freq_err; +}; + +static struct l1a_fb_state fbs; +static struct mon_state *last_fb = &fbs.mon; + static void dump_mon_state(struct mon_state *fb) { #if 0 @@ -79,195 +93,26 @@ static void dump_mon_state(struct mon_state *fb) #endif } -static struct mon_state _last_fb, *last_fb = &_last_fb; - -static int read_fb_result(struct mon_state *st, int attempt) +static int l1ctl_fbsb_resp(uint8_t res) { - st->toa = dsp_api.ndb->a_sync_demod[D_TOA]; - st->pm = dsp_api.ndb->a_sync_demod[D_PM]>>3; - st->angle = dsp_api.ndb->a_sync_demod[D_ANGLE]; - st->snr = dsp_api.ndb->a_sync_demod[D_SNR]; - - //last_fb->angle = clip_int16(last_fb->angle, AFC_MAX_ANGLE); - st->freq_diff = ANGLE_TO_FREQ(last_fb->angle); - st->fnr_report = l1s.current_time.fn; - st->attempt = attempt; - - dump_mon_state(st); - - dsp_api.ndb->d_fb_det = 0; - dsp_api.ndb->a_sync_demod[D_TOA] = 0; /* TSM30 does it (really needed ?) */ - - /* Update AFC with current frequency offset */ - afc_correct(st->freq_diff, rf_arfcn); - - //tpu_dsp_frameirq_enable(); - return 1; -} - -/* FCCH Burst *****************************************************************/ - -/* scheduler callback to issue a FB detection task to the DSP */ -static int l1s_fbdet_cmd(__unused uint8_t p1, __unused uint8_t fb_mode, - __unused uint16_t p3) -{ - if (fb_mode == 0) { - putchart('F'); - } else { - putchart('V'); - } - - /* Program DSP */ - dsp_api.db_w->d_task_md = FB_DSP_TASK; /* maybe with I/Q swap? */ - dsp_api.ndb->d_fb_mode = fb_mode; - dsp_end_scenario(); - - /* Program TPU */ - l1s_rx_win_ctrl(rf_arfcn, L1_RXWIN_FB); - tpu_end_scenario(); - - return 0; -} - - -/* scheduler callback to check for a FB detection response */ -static int l1s_fbdet_resp(__unused uint8_t p1, uint8_t attempt, - __unused uint16_t p3) -{ - int ntdma, qbits, fn_offset; - - putchart('f'); - - if (!dsp_api.ndb->d_fb_det) { - /* we did not detect a FB, fall back to mode 0! */ - if (attempt == 12) { - /* If we don't reset here, we get DSP DMA errors */ - tdma_sched_reset(); - - /* if we are already synchronized initially, - * code below has set l1s.fb.mode to 1 and - * we switch to the more narrow mode 1 */ - l1s_fb_test(1, l1s.fb.mode); - } - return 0; - } - - printf("FB%u ", dsp_api.ndb->d_fb_mode); - read_fb_result(last_fb, attempt); - - /* FIXME: where did this magic 23 come from? */ - last_fb->toa -= 23; - - if (last_fb->toa < 0) { - qbits = (last_fb->toa + BITS_PER_TDMA) * 4; - ntdma = -1; - } else { - ntdma = (last_fb->toa) / BITS_PER_TDMA; - qbits = (last_fb->toa - ntdma * BITS_PER_TDMA) * 4; - } - - { - fn_offset = l1s.current_time.fn - attempt + ntdma; - int fnr_delta = last_fb->fnr_report - attempt; - int bits_delta = fnr_delta * BITS_PER_TDMA; - - struct l1_cell_info *cinfo = &l1s.serving_cell; - - cinfo->fn_offset = fnr_delta; - cinfo->time_alignment = qbits; - cinfo->arfcn = rf_arfcn; - - if (last_fb->toa > bits_delta) - printf("=> DSP reports FB in bit that is %d bits in " - "the future?!?\n", last_fb->toa - bits_delta); - else { - int fb_fnr = (last_fb->fnr_report - last_fb->attempt) - + last_fb->toa/BITS_PER_TDMA; - printf("=>FB @ FNR %u fn_offset=%d qbits=%u\n", - fb_fnr, fn_offset, qbits); - } - } - - /* We found a frequency burst, reset everything and start next task */ - l1s_reset_hw(); - tdma_sched_reset(); - - if (dsp_api.frame_ctr > 500 && l1s.fb.mode == 0) { - /* We've done more than 500 rounds of FB detection, so - * the AGC should be synchronized and we switch to the - * more narrow FB detection mode 1 */ - l1s.fb.mode = 1; - /* Don't synchronize_tdma() yet, it does probably not work - * reliable due to the TPU reset) */ - } + struct msgb *msg; + struct l1ctl_fbsb_resp *resp; -#if 1 - /* restart a SB or new FB detection task */ - if (dsp_api.frame_ctr > 1000 && l1s.fb.mode == 1 && - abs(last_fb->freq_diff) < 1000) { - int delay; + msg = l1ctl_msgb_alloc(L1CTL_FBSB_RESP); + if (!msg) + return -ENOMEM; - /* synchronize before reading SB */ - synchronize_tdma(&l1s.serving_cell); + resp = (struct l1ctl_fbsb_resp *) msgb_put(msg, sizeof(*resp)); + resp->band_arfcn = htons(fbs.req.band_arfcn); + resp->initial_freq_err = htons(fbs.initial_freq_err); + resp->result = res; - delay = fn_offset + 11 - l1s.current_time.fn - 1; - dsp_api.ndb->d_fb_det = 0; - dsp_api.ndb->a_sync_demod[D_TOA] = 0; /* TSM30 does it (really needed ?) */ - l1s.fb.mode = 0; - l1s_sb_test(delay); - } else -#endif - { - /* If we don't reset here, we get DSP DMA errors */ - tdma_sched_reset(); - /* use FB_MODE_1 if we are within certain limits */ - if (abs(last_fb->freq_diff < 2000)) - l1s_fb_test(fn_offset + 10 - l1s.current_time.fn - 1, 1); - else - l1s_fb_test(fn_offset + 10 - l1s.current_time.fn - 1, 0); - } + /* no need to set BSIC, as it is never used here */ + l1_queue_for_l2(msg); return 0; } -/* we don't really use this because we need to configure the fb_mode! */ -static const struct tdma_sched_item fb_sched_set[] = { - SCHED_ITEM(l1s_fbdet_cmd, 0, 0), SCHED_END_FRAME(), - SCHED_END_FRAME(), - SCHED_ITEM(l1s_fbdet_resp, 0, 1), SCHED_END_FRAME(), - SCHED_ITEM(l1s_fbdet_resp, 0, 2), SCHED_END_FRAME(), - SCHED_ITEM(l1s_fbdet_resp, 0, 3), SCHED_END_FRAME(), - SCHED_ITEM(l1s_fbdet_resp, 0, 4), SCHED_END_FRAME(), - SCHED_ITEM(l1s_fbdet_resp, 0, 5), SCHED_END_FRAME(), - SCHED_ITEM(l1s_fbdet_resp, 0, 6), SCHED_END_FRAME(), - SCHED_ITEM(l1s_fbdet_resp, 0, 7), SCHED_END_FRAME(), - SCHED_ITEM(l1s_fbdet_resp, 0, 8), SCHED_END_FRAME(), - SCHED_ITEM(l1s_fbdet_resp, 0, 9), SCHED_END_FRAME(), - SCHED_ITEM(l1s_fbdet_resp, 0, 10), SCHED_END_FRAME(), - SCHED_ITEM(l1s_fbdet_resp, 0, 11), SCHED_END_FRAME(), - SCHED_ITEM(l1s_fbdet_resp, 0, 12), SCHED_END_FRAME(), - SCHED_END_SET() -}; - -void l1s_fb_test(uint8_t base_fn, uint8_t fb_mode) -{ -#if 1 - int i; - /* schedule the FB detection command */ - tdma_schedule(base_fn, &l1s_fbdet_cmd, 0, fb_mode, 0); - - /* schedule 12 attempts to read the result */ - for (i = 1; i <= 12; i++) { - uint8_t fn = base_fn + 1 + i; - tdma_schedule(fn, &l1s_fbdet_resp, 0, i, 0); - } -#else - /* use the new scheduler 'set' and simply schedule the whole set */ - /* WARNING: we cannot set FB_MODE_1 this way !!! */ - tdma_schedule_set(base_fn, fb_sched_set, 0); -#endif -} - /* SCH Burst Detection ********************************************************/ /* determine the GSM time and BSIC from a Sync Burst */ @@ -321,8 +166,6 @@ static int l1s_sbdet_resp(__unused uint8_t p1, uint8_t attempt, __unused uint16_t p3) { uint32_t sb; - uint8_t bsic; - static struct gsm_time sb_time; int qbits, fn_offset; struct l1_cell_info *cinfo = &l1s.serving_cell; int fnr_delta, bits_delta; @@ -332,13 +175,14 @@ static int l1s_sbdet_resp(__unused uint8_t p1, uint8_t attempt, putchart('s'); if (dsp_api.db_r->a_sch[0] & (1<<B_SCH_CRC)) { - /* after 2nd attempt, restart */ - if (attempt == 2) - l1s_sb_test(2); - /* mark READ page as being used */ dsp_api.r_page_used = 1; + /* after 2nd attempt, we failed */ + if (attempt == 2) + return l1ctl_fbsb_resp(255); + + /* after 1st attempt, we simply wait for 2nd */ return 0; } @@ -348,10 +192,11 @@ static int l1s_sbdet_resp(__unused uint8_t p1, uint8_t attempt, read_sb_result(last_fb, dsp_api.frame_ctr); sb = dsp_api.db_r->a_sch[3] | dsp_api.db_r->a_sch[4] << 16; - bsic = l1s_decode_sb(&sb_time, sb); - printf("=> SB 0x%08x: BSIC=%u ", sb, bsic); - l1s_time_dump(&sb_time); + fbs.mon.bsic = l1s_decode_sb(&fbs.mon.time, sb); + printf("=> SB 0x%08x: BSIC=%u ", sb, fbs.mon.bsic); + l1s_time_dump(&fbs.mon.time); +#if 0 l1s.serving_cell.bsic = bsic; /* calculate synchronisation value (TODO: only complete for qbits) */ @@ -397,6 +242,7 @@ static int l1s_sbdet_resp(__unused uint8_t p1, uint8_t attempt, l1 = (struct l1ctl_sync_new_ccch_resp *) msgb_put(msg, sizeof(*l1)); l1->bsic = bsic; l1_queue_for_l2(msg); +#endif /* If we call tdma_sched_reset(), which is only needed if there * are further l1s_sbdet_resp() scheduled, we will bring @@ -413,6 +259,7 @@ static int l1s_sbdet_resp(__unused uint8_t p1, uint8_t attempt, l1s_dsp_abort(); } +#if 0 if (l1s.sb.count > 10 && sb_time.t3 == 41) { l1s_reset_hw(); /* enable the MF Task for BCCH reading */ @@ -423,7 +270,7 @@ static int l1s_sbdet_resp(__unused uint8_t p1, uint8_t attempt, * is not in less than 7 TDMA frames from now */ l1s_sb_test(7); } - +#endif return 0; } @@ -443,19 +290,235 @@ static int l1s_sbdet_cmd(__unused uint8_t p1, __unused uint8_t p2, return 0; } +/* This is how it is done by the TSM30 */ +static const struct tdma_sched_item sb_sched_set[] = { + SCHED_ITEM(l1s_sbdet_cmd, 0, 1), SCHED_END_FRAME(), + SCHED_ITEM(l1s_sbdet_cmd, 0, 2), SCHED_END_FRAME(), + SCHED_END_FRAME(), + SCHED_ITEM(l1s_sbdet_resp, 0, 1), SCHED_END_FRAME(), + SCHED_ITEM(l1s_sbdet_resp, 0, 2), SCHED_END_FRAME(), + SCHED_END_SET() +}; + void l1s_sb_test(uint8_t base_fn) { -#if 1 - /* This is how it is done by the TSM30 */ - tdma_schedule(base_fn, &l1s_sbdet_cmd, 0, 1, 0); - tdma_schedule(base_fn + 1, &l1s_sbdet_cmd, 0, 2, 0); - tdma_schedule(base_fn + 3, &l1s_sbdet_resp, 0, 1, 0); - tdma_schedule(base_fn + 4, &l1s_sbdet_resp, 0, 2, 0); -#else - tdma_schedule(base_fn, &l1s_sbdet_cmd, 0, 1, 0); - tdma_schedule(base_fn + 1, &l1s_sbdet_resp, 0, 1, 0); - tdma_schedule(base_fn + 2, &l1s_sbdet_resp, 0, 2, 0); -#endif + tdma_schedule_set(base_fn, sb_sched_set, 0); +} +/* FCCH Burst *****************************************************************/ + +static int read_fb_result(struct mon_state *st, int attempt) +{ + st->toa = dsp_api.ndb->a_sync_demod[D_TOA]; + st->pm = dsp_api.ndb->a_sync_demod[D_PM]>>3; + st->angle = dsp_api.ndb->a_sync_demod[D_ANGLE]; + st->snr = dsp_api.ndb->a_sync_demod[D_SNR]; + + //last_fb->angle = clip_int16(last_fb->angle, AFC_MAX_ANGLE); + st->freq_diff = ANGLE_TO_FREQ(last_fb->angle); + st->fnr_report = l1s.current_time.fn; + st->attempt = attempt; + + dump_mon_state(st); + + dsp_api.ndb->d_fb_det = 0; + dsp_api.ndb->a_sync_demod[D_TOA] = 0; /* TSM30 does it (really needed ?) */ + + /* Update AFC with current frequency offset */ + afc_correct(st->freq_diff, rf_arfcn); + + //tpu_dsp_frameirq_enable(); + return 1; +} + +/* scheduler callback to issue a FB detection task to the DSP */ +static int l1s_fbdet_cmd(__unused uint8_t p1, __unused uint8_t p2, + uint16_t fb_mode) +{ + if (fb_mode == 0) { + putchart('F'); + } else { + putchart('V'); + } + + l1s.fb.mode = fb_mode; + + /* Program DSP */ + dsp_api.db_w->d_task_md = FB_DSP_TASK; /* maybe with I/Q swap? */ + dsp_api.ndb->d_fb_mode = fb_mode; + dsp_end_scenario(); + + /* Program TPU */ + l1s_rx_win_ctrl(fbs.req.band_arfcn, L1_RXWIN_FB); + tpu_end_scenario(); + + return 0; +} + + +static const struct tdma_sched_item fb_sched_set[]; + +/* scheduler callback to check for a FB detection response */ +static int l1s_fbdet_resp(__unused uint8_t p1, uint8_t attempt, + uint16_t fb_mode) +{ + putchart('f'); + + if (dsp_api.ndb->d_fb_det) { + /* We found a frequency burst, reset everything */ + l1s_reset_hw(); + + printf("FB%u ", dsp_api.ndb->d_fb_mode); + read_fb_result(last_fb, attempt); + /* if this is the first success, save freq err */ + if (!fbs.initial_freq_err) + fbs.initial_freq_err = last_fb->freq_diff; + } else { + /* we did not detect a FB */ + + /* attempt < 12, do nothing */ + if (attempt < 12) + return 0; + + /* attempt >= 12, we simply don't find one */ + + /* If we don't reset here, we get DSP DMA errors */ + tdma_sched_reset(); + + last_fb->attempt = 13; + } + + /* If we don't reset here, we get DSP DMA errors */ + tdma_sched_reset(); + + /* Immediately schedule further TDMA tasklets, if requested. Doing + * this directly from L1S means we can do this quickly without any + * additional delays */ + if (fb_mode == 0) { + if (fbs.req.flags & L1CTL_FBSB_F_FB1) { + /* If we don't reset here, we get DSP DMA errors */ + tdma_sched_reset(); + /* FIXME: don't only use the last but an average */ + if (abs(last_fb->freq_diff) < fbs.req.freq_err_thresh1) + tdma_schedule_set(1, fb_sched_set, 1); + else { + /* FIXME: check timeout */ + tdma_schedule_set(1, fb_sched_set, 0); + } + } else + l1s_compl_sched(L1_COMPL_FB); + } else if (fb_mode == 1) { + if (fbs.req.flags & L1CTL_FBSB_F_SB) { + int ntdma, qbits; + /* FIXME: where did this magic 23 come from? */ + last_fb->toa -= 23; + + if (last_fb->toa < 0) { + qbits = (last_fb->toa + BITS_PER_TDMA) * 4; + ntdma = -1; + } else { + ntdma = (last_fb->toa) / BITS_PER_TDMA; + qbits = (last_fb->toa - ntdma * BITS_PER_TDMA) * 4; + } + + + int fn_offset = l1s.current_time.fn - last_fb->attempt + ntdma; + int delay = fn_offset + 11 - l1s.current_time.fn - 1; + if (abs(last_fb->freq_diff) < fbs.req.freq_err_thresh2) { + /* synchronize before reading SB */ + synchronize_tdma(&l1s.serving_cell); + tdma_schedule_set(delay, sb_sched_set, 0); + } else + tdma_schedule_set(delay, fb_sched_set, 1); + } else + l1s_compl_sched(L1_COMPL_FB); + } + + return 0; } +/* FB detection */ +static const struct tdma_sched_item fb_sched_set[] = { + SCHED_ITEM(l1s_fbdet_cmd, 0, 0), SCHED_END_FRAME(), + SCHED_END_FRAME(), + SCHED_ITEM(l1s_fbdet_resp, 0, 1), SCHED_END_FRAME(), + SCHED_ITEM(l1s_fbdet_resp, 0, 2), SCHED_END_FRAME(), + SCHED_ITEM(l1s_fbdet_resp, 0, 3), SCHED_END_FRAME(), + SCHED_ITEM(l1s_fbdet_resp, 0, 4), SCHED_END_FRAME(), + SCHED_ITEM(l1s_fbdet_resp, 0, 5), SCHED_END_FRAME(), + SCHED_ITEM(l1s_fbdet_resp, 0, 6), SCHED_END_FRAME(), + SCHED_ITEM(l1s_fbdet_resp, 0, 7), SCHED_END_FRAME(), + SCHED_ITEM(l1s_fbdet_resp, 0, 8), SCHED_END_FRAME(), + SCHED_ITEM(l1s_fbdet_resp, 0, 9), SCHED_END_FRAME(), + SCHED_ITEM(l1s_fbdet_resp, 0, 10), SCHED_END_FRAME(), + SCHED_ITEM(l1s_fbdet_resp, 0, 11), SCHED_END_FRAME(), + SCHED_ITEM(l1s_fbdet_resp, 0, 12), SCHED_END_FRAME(), + SCHED_END_SET() +}; + +/* Asynchronous completion handler for FB detection */ +static void l1a_fb_compl(__unused enum l1_compl c) +{ + int ntdma, qbits, fn_offset, fnr_delta, bits_delta; + /* FXIME: use l1s.neigh_cell[fbs.cinfo_idx] */ + struct l1_cell_info *cinfo = &l1s.serving_cell; + + if (last_fb->attempt >= 13) { + /* FB detection failed, signal this via L1CTL */ + return l1ctl_fbsb_resp(255); + } + + /* FIXME: where did this magic 23 come from? */ + last_fb->toa -= 23; + + if (last_fb->toa < 0) { + qbits = (last_fb->toa + BITS_PER_TDMA) * 4; + ntdma = -1; + } else { + ntdma = (last_fb->toa) / BITS_PER_TDMA; + qbits = (last_fb->toa - ntdma * BITS_PER_TDMA) * 4; + } + + fn_offset = l1s.current_time.fn - last_fb->attempt + ntdma; + fnr_delta = last_fb->fnr_report - last_fb->attempt; + bits_delta = fnr_delta * BITS_PER_TDMA; + + cinfo->fn_offset = fnr_delta; + cinfo->time_alignment = qbits; + cinfo->arfcn = rf_arfcn; + + if (last_fb->toa > bits_delta) + printf("=> DSP reports FB in bit that is %d bits in " + "the future?!?\n", last_fb->toa - bits_delta); + else { + int fb_fnr = (last_fb->fnr_report - last_fb->attempt) + + last_fb->toa/BITS_PER_TDMA; + printf("=>FB @ FNR %u fn_offset=%d qbits=%u\n", + fb_fnr, fn_offset, qbits); + } + l1ctl_fbsb_resp(0); +} + +void l1s_fbsb_req(uint8_t base_fn, struct l1ctl_fbsb_req *req) +{ + /* copy + endian convert request data */ + fbs.req.band_arfcn = ntohs(req->band_arfcn); + fbs.req.timeout = ntohs(req->timeout); + fbs.req.freq_err_thresh1 = ntohs(req->freq_err_thresh1); + fbs.req.freq_err_thresh2 = ntohs(req->freq_err_thresh2); + fbs.req.num_freqerr_avg = req->num_freqerr_avg; + fbs.req.flags = req->flags; + fbs.req.sync_info_idx = req->sync_info_idx; + + /* clear initial frequency error */ + fbs.initial_freq_err = 0; + + if (fbs.req.flags & L1CTL_FBSB_F_FB0) + tdma_schedule_set(base_fn, fb_sched_set, 0); + else if (fbs.req.flags & L1CTL_FBSB_F_FB1) + tdma_schedule_set(base_fn, fb_sched_set, 0); + else if (fbs.req.flags & L1CTL_FBSB_F_SB) + tdma_schedule_set(base_fn, sb_sched_set, 0); + + l1s.completion[L1_COMPL_FB] = &l1a_fb_compl; +} |