summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/l1a_l23_interface.h26
-rw-r--r--src/host/layer23/include/osmocom/l1ctl.h5
-rw-r--r--src/host/layer23/include/osmocom/osmocom_data.h3
-rw-r--r--src/host/layer23/src/app_phone.c2
-rw-r--r--src/host/layer23/src/bcch_scan.c2
-rw-r--r--[-rwxr-xr-x]src/host/layer23/src/gsm322.c2
-rw-r--r--src/host/layer23/src/gsm48_rr.c2
-rw-r--r--src/host/layer23/src/l1ctl.c46
-rw-r--r--src/target/firmware/apps/layer1/main.c1
-rw-r--r--src/target/firmware/layer1/afc.c1
-rw-r--r--src/target/firmware/layer1/l23_api.c18
-rw-r--r--src/target/firmware/layer1/prim_fbsb.c467
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;
+}