WIP/HACK: bsic decoding of neighbour cells in dedicated mode and partially success in synchronized handover

Change-Id: Ib01460b796d2107c4599d327e184eb42340999d2
This commit is contained in:
Muhammad Awais Aslam 2017-12-19 15:57:20 +05:00 committed by Vadim Yanitskiy
parent 0f5f76f651
commit 8f56258867
31 changed files with 9256 additions and 343 deletions

View File

@ -174,7 +174,8 @@ struct l1ctl_info_ul {
uint8_t chan_nr;
/* GSM 08.58 link identifier (9.3.2) */
uint8_t link_id;
uint8_t padding[2];
/* the ARFCN and the band */
uint16_t band_arfcn;
uint8_t payload[0];
} __attribute__((packed));

View File

@ -21,7 +21,7 @@ int l1ctl_tx_crypto_req(struct osmocom_ms *ms, uint8_t chan_nr,
/* Transmit L1CTL_RACH_REQ */
int l1ctl_tx_rach_req(struct osmocom_ms *ms, uint8_t ra, uint16_t offset,
uint8_t combined);
uint8_t combined, uint16_t arfcn);
/* Transmit L1CTL_DM_EST_REQ */
int l1ctl_tx_dm_est_req_h0(struct osmocom_ms *ms, uint16_t band_arfcn,

View File

@ -432,7 +432,7 @@ int l1ctl_tx_crypto_req(struct osmocom_ms *ms, uint8_t chan_nr,
/* Transmit L1CTL_RACH_REQ */
int l1ctl_tx_rach_req(struct osmocom_ms *ms, uint8_t ra, uint16_t offset,
uint8_t combined)
uint8_t combined, uint16_t band_arfcn)
{
struct msgb *msg;
struct l1ctl_info_ul *ul;
@ -444,6 +444,7 @@ int l1ctl_tx_rach_req(struct osmocom_ms *ms, uint8_t ra, uint16_t offset,
DEBUGP(DL1C, "RACH Req. offset=%d combined=%d\n", offset, combined);
ul = (struct l1ctl_info_ul *) msgb_put(msg, sizeof(*ul));
ul->band_arfcn = htons(band_arfcn); //MTZ - Added
req = (struct l1ctl_rach_req *) msgb_put(msg, sizeof(*req));
req->ra = ra;
req->offset = htons(offset);

View File

@ -52,7 +52,7 @@ int l1ctl_ph_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
pp->u.rach_req.tx_power);
rc = l1ctl_tx_rach_req(ms, pp->u.rach_req.ra,
pp->u.rach_req.offset,
pp->u.rach_req.is_combined_ccch);
pp->u.rach_req.is_combined_ccch, 0);
break;
default:
rc = -EINVAL;

View File

@ -57,12 +57,12 @@ static int try_cbch(struct osmocom_ms *ms, struct gsm48_sysinfo *s)
return l1ctl_tx_dm_est_req_h1(ms,
s->maio, s->hsn, s->hopping, s->hopp_len,
s->chan_nr, s->tsc,
GSM48_CMODE_SIGN, 0);
GSM48_CMODE_SIGN, 0, 1, 0, 0);
} else {
LOGP(DRR, LOGL_INFO, "chan_nr = 0x%02x TSC = %d ARFCN = %d\n",
s->chan_nr, s->tsc, s->arfcn);
return l1ctl_tx_dm_est_req_h0(ms, s->arfcn,
s->chan_nr, s->tsc, GSM48_CMODE_SIGN, 0);
s->chan_nr, s->tsc, GSM48_CMODE_SIGN, 0, 1, 0, 0);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -136,7 +136,7 @@ INCLUDES=-Iinclude/ -I../../../include -I../../shared/libosmocore/include -I../.
#
# Uncomment this line if you want to enable Tx (Transmit) Support.
#CFLAGS += -DCONFIG_TX_ENABLE
CFLAGS += -DCONFIG_TX_ENABLE
# Uncomment this line if you want to write to flash.
#CFLAGS += -DCONFIG_FLASH_WRITE

View File

@ -4,16 +4,14 @@ BOARDS?=mt62xx
# List of all applications (meant to be overridden on command line)
APPLICATIONS?=loader_mtk
APP_loader_mtk_ENVIRONMENTS=mtkram
ENV_mtkram_LDS=board/mediatek/ram.lds
ENV_mtkram_OBJS=board/mediatek/start.ram.o
mtkram_LDS=board/mediatek/ram.lds
mtkram_OBJS=board/mediatek/start.ram.o
mtk_COMMON_OBJS=board/mediatek/uart.o
# Mediatek MT62xx
BOARD_mt62xx_OBJS=$(mtk_COMMON_OBJS) board/mt62xx/init.o
BOARD_mt62xx_ENVIRONMENTS=mtkram
mt62xx_OBJS=$(mtk_COMMON_OBJS) board/mt62xx/init.o
mt62xx_ENVIRONMENTS=mtkram
# Global include path
INCLUDES=-Iinclude/ -I../../../include -I../../shared/libosmocore/include

View File

@ -33,7 +33,7 @@ int l1a_txq_msgb_count(struct llist_head *queue);
void l1a_txq_msgb_flush(struct llist_head *queue);
/* request a RACH */
void l1a_rach_req(uint16_t offset, uint8_t combined, uint8_t ra);
void l1a_rach_req(uint16_t offset, uint8_t combined, uint8_t ra, uint16_t arfcn);
/* schedule frequency change */
void l1a_freq_req(uint32_t fn_sched);

View File

@ -4,6 +4,8 @@
#include <stdint.h>
enum mframe_task {
MF_TASK_TEST1,
MF_TASK_BCCH_NORM,
MF_TASK_BCCH_EXT,
MF_TASK_CCCH,

View File

@ -20,7 +20,7 @@ void l1s_nb_test(uint8_t base_fn);
void l1s_fbsb_req(uint8_t base_fn, struct l1ctl_fbsb_req *req);
void l1a_freq_req(uint32_t fn_sched);
void l1a_rach_req(uint16_t offset, uint8_t combined, uint8_t ra);
void l1a_rach_req(uint16_t offset, uint8_t combined, uint8_t ra, uint16_t arfcn);
/* Primitives raw scheduling sets */
extern const struct tdma_sched_item nb_sched_set[];
@ -29,6 +29,10 @@ extern const struct tdma_sched_item nb_sched_set_ul[];
extern const struct tdma_sched_item tch_sched_set[];
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 neigh_pm_idle_sched_set[];
extern const struct tdma_sched_item neigh_pm_tch_sched_set[];
extern const struct tdma_sched_item neigh_sync_sched_set[];
extern const struct tdma_sched_item test1_sched[];
#endif /* _L1_PRIM_H */

View File

@ -55,6 +55,17 @@ struct l1s_h1 {
};
struct l1s_state {
//MTZ
int new_dm;
uint32_t orig_tpu_offset;
uint32_t tpu_offsets[64];
uint32_t nb_freq_diff[64];
uint32_t nb_frame_diff[64];
int32_t nb_sb_freq_diff[64];
uint32_t nb_sb_snr[64];
uint16_t tpu_offsets_arfcn[64];
struct gsm_time current_time; /* current GSM time */
struct gsm_time next_time; /* GSM time at next TMDMA irq */
@ -127,6 +138,7 @@ struct l1s_state {
GSM_DCHAN_UNKNOWN,
} type;
uint8_t chan_nr;
uint8_t scn;
uint8_t tsc;
uint8_t tn;
@ -145,19 +157,37 @@ struct l1s_state {
struct l1s_h0 st_h0;
struct l1s_h1 st_h1;
};
uint8_t rx_only;
} dedicated;
/* neighbour cell power measurement process */
struct {
uint8_t n, second;
uint8_t pos;
uint8_t running;
uint16_t band_arfcn[64];
uint8_t tn[64];
uint8_t level[64];
uint32_t start_fn; /* frame number of measumrement start */
uint8_t valid; /* we have a complete set of measurements */
uint8_t rounds; /* current rounds of complete measurements */
uint8_t pos; /* current neighbor to measure */
uint8_t running; /* DSP task running */
uint8_t n; /* number of neighbors to measure */
uint16_t band_arfcn[64]; /* list of ARFCNs */
uint8_t tn[64]; /* list of TS offset for each measurement */
uint16_t level_sum[64]; /* sum while processing rounds */
uint8_t level[64]; /* latest results */
uint32_t tpu_offset[64];
} neigh_pm;
/* neighbor cell SCH sync process */
struct {
uint8_t flags_bsic[64]; /* flags + bsic */
uint8_t count; /* counter for sync process */
uint8_t index; /* cell of current sync process (0..63) */
uint8_t running; /* DSP task running */
} neigh_sb;
};
#define NEIGH_PM_FLAG_SCANNED 0x80
#define NEIGH_PM_FLAG_BSIC 0x40
extern struct l1s_state l1s;
struct l1s_meas_hdr {

View File

@ -6,6 +6,8 @@ enum l1_rxwin_type {
L1_RXWIN_FB, /* FCCH burst detection */
L1_RXWIN_SB, /* SCH burst detection */
L1_RXWIN_NB, /* Normal burst decoding */
L1_RXWIN_FB26, /* SCH burst detection of neighbour cell */
L1_RXWIN_SB26, /* SCH burst detection of neighbour cell */
_NUM_L1_RXWIN
};

View File

@ -93,7 +93,10 @@ void afc_correct(int16_t freq_error, uint16_t arfcn)
}
delta = (int16_t) ((afc_norm_factor * (int32_t)freq_error) / AFC_SLOPE);
printd("afc_correct(error=%dHz, arfcn=%u): delta=%d, afc_dac(old=%d,new=%d)\n",
//MTZ
//printd("afc_correct(error=%dHz, arfcn=%u): delta=%d, afc_dac(old=%d,new=%d)\n",
// freq_error, arfcn, delta, afc_state.dac_value, afc_state.dac_value+delta);
printf("afc_correct(error=%dHz, arfcn=%u): delta=%d, afc_dac(old=%d,new=%d)\n",
freq_error, arfcn, delta, afc_state.dac_value, afc_state.dac_value+delta);
afc_state.dac_value += delta;

View File

@ -236,6 +236,10 @@ static void l1ctl_rx_dm_est_req(struct msgb *msg)
struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
struct l1ctl_dm_est_req *est_req = (struct l1ctl_dm_est_req *) ul->payload;
//MTZ - added
l1s.new_dm = 1;
//l1s.ho_arfcn = 0;
printd("L1CTL_DM_EST_REQ (arfcn=%u, chan_nr=0x%02x, tsc=%u)\n",
ntohs(est_req->h0.band_arfcn), ul->chan_nr, est_req->tsc);
@ -243,10 +247,11 @@ static void l1ctl_rx_dm_est_req(struct msgb *msg)
mframe_disable(MF_TASK_NEIGH_PM51_C0T0);
/* configure dedicated channel state */
l1s.dedicated.type = chan_nr2dchan_type(ul->chan_nr);
l1s.dedicated.tsc = est_req->tsc;
l1s.dedicated.tn = ul->chan_nr & 0x7;
l1s.dedicated.h = est_req->h;
l1s.dedicated.chan_nr = ul->chan_nr;
l1s.dedicated.type = chan_nr2dchan_type(ul->chan_nr);
l1s.dedicated.tsc = est_req->tsc;
l1s.dedicated.tn = ul->chan_nr & 0x7;
l1s.dedicated.h = est_req->h;
if (est_req->h) {
int i;
@ -271,8 +276,15 @@ static void l1ctl_rx_dm_est_req(struct msgb *msg)
/* Audio path */
audio_set_enabled(est_req->tch_mode, est_req->audio_mode);
}
/* Handover config */
if ((est_req->flags & L1CTL_EST_F_RXONLY))
l1s.dedicated.rx_only = 1;
else
l1s.dedicated.rx_only = 0;
/* figure out which MF tasks to enable */
l1s.neigh_pm.n = 0; //MTZ - Uncomment
l1a_mftask_set(chan_nr2mf_task_mask(ul->chan_nr, NEIGH_MODE_PM));
}
@ -337,7 +349,7 @@ static void l1ctl_rx_dm_rel_req(struct msgb *msg)
dsp_load_ciph_param(0, NULL);
l1a_tch_mode_set(GSM48_CMODE_SIGN);
audio_set_enabled(GSM48_CMODE_SIGN, 0);
l1s.neigh_pm.n = 0;
l1s.neigh_pm.n = 0; //MTZ - Uncomment
}
/* receive a L1CTL_PARAM_REQ from L23 */
@ -352,6 +364,7 @@ static void l1ctl_rx_param_req(struct msgb *msg)
l1s.ta = par_req->ta;
l1s.tx_power = par_req->tx_power;
l1s.dedicated.rx_only = 0;
}
/* receive a L1CTL_RACH_REQ from L23 */
@ -361,11 +374,12 @@ static void l1ctl_rx_rach_req(struct msgb *msg)
struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
struct l1ctl_rach_req *rach_req = (struct l1ctl_rach_req *) ul->payload;
printd("L1CTL_RACH_REQ (ra=0x%02x, offset=%d combined=%d)\n",
rach_req->ra, ntohs(rach_req->offset), rach_req->combined);
//printd("L1CTL_RACH_REQ (ra=0x%02x, offset=%d combined=%d)\n",
printd("L1CTL_RACH_REQ (ra=0x%02x, offset=%d combined=%d arfcn=%d)\n", //MTZ
rach_req->ra, ntohs(rach_req->offset), rach_req->combined, rach_req->arfcn);
l1a_rach_req(ntohs(rach_req->offset), rach_req->combined,
rach_req->ra);
rach_req->ra, rach_req->arfcn); //MTZ - last added
}
/* receive a L1CTL_DATA_REQ from L23 */
@ -376,14 +390,16 @@ static void l1ctl_rx_data_req(struct msgb *msg)
struct l1ctl_data_ind *data_ind = (struct l1ctl_data_ind *) ul->payload;
struct llist_head *tx_queue;
printd("L1CTL_DATA_REQ (link_id=0x%02x)\n", ul->link_id);
//MTZ - commenting as causing issues in firmware
//printd("L1CTL_DATA_REQ (link_id=0x%02x)\n", ul->link_id);
msg->l3h = data_ind->data;
if (ul->link_id & 0x40) {
struct gsm48_hdr *gh = (struct gsm48_hdr *)(data_ind->data + 5);
if (gh->proto_discr == GSM48_PDISC_RR
&& gh->msg_type == GSM48_MT_RR_MEAS_REP) {
printd("updating measurement report\n");
//MTZ - commenting as causing issues in firmware
//printd("updating measurement report\n");
l1a_meas_msgb_set(msg);
return;
}
@ -445,6 +461,7 @@ static void l1ctl_rx_reset_req(struct msgb *msg)
l1s_reset();
l1s_reset_hw();
audio_set_enabled(GSM48_CMODE_SIGN, 0);
l1s.dedicated.type = GSM_DCHAN_NONE;
l1ctl_tx_reset(L1CTL_RESET_CONF, reset_req->type);
break;
case L1CTL_RES_T_SCHED:
@ -510,6 +527,15 @@ static void l1ctl_tx_tch_mode_conf(uint8_t tch_mode, uint8_t audio_mode)
l1_queue_for_l2(msg);
}
//MTZ
/* Transmit a L1CTL_TCH_MODE_CONF */
static void l1ctl_test(void)
{
struct msgb *msg = l1ctl_msgb_alloc(L1CTL_TEST);
l1_queue_for_l2(msg);
}
/* receive a L1CTL_TCH_MODE_REQ from L23 */
static void l1ctl_rx_tch_mode_req(struct msgb *msg)
{
@ -541,20 +567,32 @@ static void l1ctl_rx_neigh_pm_req(struct msgb *msg)
/* reset list in order to prevent race condition */
l1s.neigh_pm.n = 0; /* atomic */
l1s.neigh_pm.second = 0;
/* now reset pointer and fill list */
l1s.neigh_pm.pos = 0;
l1s.neigh_pm.valid = 0;
l1s.neigh_pm.rounds = 0;
l1s.neigh_pm.running = 0;
if (pm_req->n > 64)
pm_req->n = 64;
for (i = 0; i < pm_req->n; i++) {
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 */
/* on C0 enable PM on frame 51 */
/*
* IDLE: on C0 enable PM on frame 51
* DEDICATED: add neighbor cell task
*/
if (l1s.dedicated.type == GSM_DCHAN_NONE)
mframe_enable(MF_TASK_NEIGH_PM51_C0T0);
else
l1a_mftask_set(chan_nr2mf_task_mask(l1s.dedicated.chan_nr,
NEIGH_MODE_PM));
}
/* receive a L1CTL_TRAFFIC_REQ from L23 */

View File

@ -50,7 +50,9 @@ struct mframe_sched_item {
#define NB_QUAD_FH_DL NB_QUAD_DL
#define NB_QUAD_UL nb_sched_set_ul
#define NB_QUAD_FH_UL NB_QUAD_UL
#define NEIGH_PM neigh_pm_sched_set
#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[] = {
@ -210,17 +212,17 @@ static const struct mframe_sched_item mf_sdcch4_cbch[] = {
/* Measurement for MF 51 C0 */
static const struct mframe_sched_item mf_neigh_pm51_c0t0[] = {
{ .sched_set = NEIGH_PM , .modulo = 51, .frame_nr = 0 },
{ .sched_set = NEIGH_PM , .modulo = 51, .frame_nr = 10 },
{ .sched_set = NEIGH_PM , .modulo = 51, .frame_nr = 20 },
{ .sched_set = NEIGH_PM , .modulo = 51, .frame_nr = 30 },
{ .sched_set = NEIGH_PM , .modulo = 51, .frame_nr = 40 },
{ .sched_set = NEIGH_PM_IDLE, .modulo = 51, .frame_nr = 0 },
{ .sched_set = NEIGH_PM_IDLE, .modulo = 51, .frame_nr = 10 },
{ .sched_set = NEIGH_PM_IDLE, .modulo = 51, .frame_nr = 20 },
{ .sched_set = NEIGH_PM_IDLE, .modulo = 51, .frame_nr = 30 },
{ .sched_set = NEIGH_PM_IDLE, .modulo = 51, .frame_nr = 40 },
{ .sched_set = NULL }
};
/* Measurement for MF 51 */
static const struct mframe_sched_item mf_neigh_pm51[] = {
{ .sched_set = NEIGH_PM , .modulo = 51, .frame_nr = 50 },
{ .sched_set = NEIGH_PM_IDLE , .modulo = 51, .frame_nr = 50 },
{ .sched_set = NULL }
};
@ -275,16 +277,20 @@ static const struct mframe_sched_item mf_tch_h_0[] = {
{ .sched_set = TCH, .modulo = 13, .frame_nr = 6 },
{ .sched_set = TCH_D, .modulo = 13, .frame_nr = 7 },
{ .sched_set = TCH, .modulo = 13, .frame_nr = 8 },
{ .sched_set = TCH_D, .modulo = 13, .frame_nr = 9 },
{ .sched_set = TCH, .modulo = 13, .frame_nr = 10 },
{ .sched_set = TCH_D, .modulo = 13, .frame_nr = 11 },
//{ .sched_set = TCH_D, .modulo = 13, .frame_nr = 9 },
{ .sched_set = TCH_D, .modulo = 26, .frame_nr = 9 },
//{ .sched_set = TCH, .modulo = 13, .frame_nr = 10 },
{ .sched_set = TCH, .modulo = 26, .frame_nr = 10 },
//{ .sched_set = TCH_D, .modulo = 13, .frame_nr = 11 },
{ .sched_set = TCH_D, .modulo = 26, .frame_nr = 11 },
{ .sched_set = TCH_A, .modulo = 26, .frame_nr = 12,
.flags = MF_F_SACCH },
{ .sched_set = NULL }
};
static const struct mframe_sched_item mf_tch_h_1[] = {
{ .sched_set = TCH_D, .modulo = 13, .frame_nr = 0 },
//{ .sched_set = TCH_D, .modulo = 13, .frame_nr = 0 },
{ .sched_set = TCH_D, .modulo = 26, .frame_nr = 0 },
{ .sched_set = TCH, .modulo = 13, .frame_nr = 1 },
{ .sched_set = TCH_D, .modulo = 13, .frame_nr = 2 },
{ .sched_set = TCH, .modulo = 13, .frame_nr = 3 },
@ -294,20 +300,44 @@ static const struct mframe_sched_item mf_tch_h_1[] = {
{ .sched_set = TCH, .modulo = 13, .frame_nr = 7 },
{ .sched_set = TCH_D, .modulo = 13, .frame_nr = 8 },
{ .sched_set = TCH, .modulo = 13, .frame_nr = 9 },
{ .sched_set = TCH_D, .modulo = 13, .frame_nr = 10 },
{ .sched_set = TCH, .modulo = 13, .frame_nr = 11 },
//{ .sched_set = TCH_D, .modulo = 13, .frame_nr = 10 },
{ .sched_set = TCH_D, .modulo = 26, .frame_nr = 23 },
//{ .sched_set = TCH, .modulo = 13, .frame_nr = 11 },
{ .sched_set = TCH, .modulo = 26, .frame_nr = 24 },
{ .sched_set = TCH_A, .modulo = 26, .frame_nr = 25,
.flags = MF_F_SACCH },
{ .sched_set = NULL }
};
/* Measurement for MF 26 */
/*
* Measurement for MF 26
* Note: PM will be read 2 frames, later, so we can only measure every second
* frame.
*/
static const struct mframe_sched_item mf_neigh_pm26_even[] = {
{ .sched_set = NEIGH_PM , .modulo = 26, .frame_nr = 25 },
{ .sched_set = NEIGH_PM_TCH, .modulo = 13, .frame_nr = 0 },
{ .sched_set = NEIGH_PM_TCH, .modulo = 13, .frame_nr = 2 },
{ .sched_set = NEIGH_PM_TCH, .modulo = 13, .frame_nr = 4 },
{ .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 = 26, .frame_nr = 8 },
//{ .sched_set = NEIGH_PM_TCH, .modulo = 13, .frame_nr = 10 },
{ .sched_set = NEIGH_PM_TCH, .modulo = 26, .frame_nr = 10 },
//{ .sched_set = NEIGH_SYNC, .modulo = 26, .frame_nr = 24 },
{ .sched_set = NEIGH_SYNC, .modulo = 26, .frame_nr = 22 },
{ .sched_set = NULL }
};
static const struct mframe_sched_item mf_neigh_pm26_odd[] = {
{ .sched_set = NEIGH_PM , .modulo = 26, .frame_nr = 12 },
//{ .sched_set = NEIGH_PM_TCH, .modulo = 13, .frame_nr = 0 },
{ .sched_set = NEIGH_PM_TCH, .modulo = 26, .frame_nr = 0 },
{ .sched_set = NEIGH_PM_TCH, .modulo = 13, .frame_nr = 2 },
{ .sched_set = NEIGH_PM_TCH, .modulo = 13, .frame_nr = 4 },
{ .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_PM_TCH, .modulo = 26, .frame_nr = 23 },
//{ .sched_set = NEIGH_SYNC, .modulo = 26, .frame_nr = 11 },
{ .sched_set = NEIGH_SYNC, .modulo = 26, .frame_nr = 10 },
{ .sched_set = NULL }
};
@ -318,6 +348,7 @@ static const struct mframe_sched_item mf_tx_all_nb[] = {
};
static const struct mframe_sched_item *sched_set_for_task[32] = {
[MF_TASK_BCCH_NORM] = mf_bcch_norm,
[MF_TASK_BCCH_EXT] = mf_bcch_ext,
[MF_TASK_CCCH] = mf_ccch,

View File

@ -84,6 +84,16 @@ struct l1a_fb_state {
static struct l1a_fb_state fbs;
static struct mon_state *last_fb = &fbs.mon;
static int sb_det = 0; //MTZ - This was added
static int fb_det = 0; //MTZ - This was added
uint32_t old_tpu_offset = 0; //MTZ - This was added
int total_sb_det = 0;
int16_t nb_fb_toa = 0; //MTZ - This was added
uint16_t nb_fb_pm = 0; //MTZ - This was added
uint16_t nb_fb_angle0 = 0; //MTZ - This was added
uint16_t nb_fb_angle1 = 0; //MTZ - This was added
uint16_t nb_fb_snr = 0; //MTZ - This was added
static void dump_mon_state(struct mon_state *fb)
{
@ -141,6 +151,7 @@ static uint8_t l1s_decode_sb(struct gsm_time *time, uint32_t sb)
/* TS 05.02 Chapter 4.3.3 TDMA frame number */
time->fn = gsm_gsmtime2fn(time);
printf("\n\nMTZ: time->fn = %d\n\n", time->fn);
time->tc = (time->fn / 51) % 8;
@ -168,6 +179,30 @@ static void read_sb_result(struct mon_state *st, int attempt)
dsp_api.r_page_used = 1;
}
static void read_sb_result2(struct mon_state *st, int attempt)
{
st->toa = dsp_api.db_r->a_serv_demod[D_TOA];
st->pm = dsp_api.db_r->a_serv_demod[D_PM]>>3;
st->angle = dsp_api.db_r->a_serv_demod[D_ANGLE];
st->snr = dsp_api.db_r->a_serv_demod[D_SNR];
st->freq_diff = ANGLE_TO_FREQ(st->angle);
st->fnr_report = l1s.current_time.fn;
st->attempt = attempt;
dump_mon_state(st);
printf("\n\n\nMTZ: st->freq_diff = %d\n\n\n", st->freq_diff);
//MTZ - commenting out for now
if (st->snr > AFC_SNR_THRESHOLD)
afc_input(st->freq_diff, rf_arfcn, 1);
else
afc_input(st->freq_diff, rf_arfcn, 0);
dsp_api.r_page_used = 1;
}
/* Note: When we get the SB response, it is 2 TDMA frames after the SB
* actually happened, as it is a "C W W R" task */
#define SB2_LATENCY 2
@ -235,6 +270,7 @@ static int l1s_sbdet_resp(__unused uint8_t p1, uint8_t attempt,
synchronize_tdma(&l1s.serving_cell);
/* if we have recived a SYNC burst, update our local GSM time */
printf("\n\nMTZ: current_fn = %d, fn from SB = %d\n\n", gsm_gsmtime2fn(&l1s.current_time), fbs.mon.time.fn + SB2_LATENCY);
gsm_fn2gsmtime(&l1s.current_time, fbs.mon.time.fn + SB2_LATENCY);
/* compute next time from new current time */
l1s.next_time = l1s.current_time;
@ -258,6 +294,7 @@ static int l1s_sbdet_resp(__unused uint8_t p1, uint8_t attempt,
l1s_reset_hw();
/* enable the MF Task for BCCH reading */
mframe_enable(MF_TASK_BCCH_NORM);
printf("\nMTZ: l1s.serving_cell.ccch_mode = %d\n", l1s.serving_cell.ccch_mode);
if (l1s.serving_cell.ccch_mode == CCCH_MODE_COMBINED)
mframe_enable(MF_TASK_CCCH_COMB);
else if (l1s.serving_cell.ccch_mode == CCCH_MODE_NON_COMBINED)
@ -269,6 +306,9 @@ static int l1s_sbdet_resp(__unused uint8_t p1, uint8_t attempt,
l1s_compl_sched(L1_COMPL_FB);
//MTZ - delete this
//mframe_enable(MF_TASK_TEST1);
return 0;
}
@ -284,11 +324,14 @@ static int l1s_sbdet_cmd(__unused uint8_t p1, __unused uint8_t p2,
dsp_api.ndb->d_fb_mode = 0; /* wideband search */
/* Program TPU */
printf("\nMTZ: arfcn in l1s_sbdet_cmd = %d\n", rf_arfcn);
l1s_rx_win_ctrl(rf_arfcn, L1_RXWIN_SB, 0);
return 0;
}
static const struct tdma_sched_item sb_sched_set[];
/* This is how it is done by the TSM30 */
static const struct tdma_sched_item sb_sched_set[] = {
SCHED_ITEM_DT(l1s_sbdet_cmd, 0, 0, 1), SCHED_END_FRAME(),
@ -384,6 +427,7 @@ static int l1s_fbdet_cmd(__unused uint8_t p1, __unused uint8_t p2,
dsp_api.ndb->d_fb_mode = fb_mode;
/* Program TPU */
printf("\nMTZ: arfcn in l1s_fbdet_cmd = %d\n", fbs.req.band_arfcn);
l1s_rx_win_ctrl(fbs.req.band_arfcn, L1_RXWIN_FB, 0);
return 0;
@ -562,15 +606,601 @@ void l1s_fbsb_req(uint8_t base_fn, struct l1ctl_fbsb_req *req)
/* Reset the TOA loop counters */
toa_reset();
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);
tdma_schedule_set(0, fb_sched_set, 0);
//MTZ - Changed
//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);
//MTZ
//l1ctl_test();
//struct msgb *msg1 = l1ctl_msgb_alloc(L1CTL_TEST);
//l1_queue_for_l2(msg1);
}
/* 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;
}
}
//MTZ - The function below has been taken from synchronize_tdma in sync.c and modified for whatever seemed necessary
void synchronize_tdma2()
{
uint32_t tpu_shift;
int ntdma, qbits;
/* FIXME: where did this magic 23 come from? */
nb_fb_toa -= 23;
if (nb_fb_toa < 0) {
qbits = (nb_fb_toa + BITS_PER_TDMA) * 4;
ntdma = -1;
} else {
ntdma = (nb_fb_toa) / BITS_PER_TDMA;
qbits = (nb_fb_toa - ntdma * BITS_PER_TDMA) * 4;
}
tpu_shift = qbits;
old_tpu_offset = l1s.tpu_offset;
/* NB detection only works if the TOA of the SB
* is within 0...8. We have to add 75 to get an SB TOA of 4. */
tpu_shift += 75;
tpu_shift = (l1s.tpu_offset + tpu_shift) % QBITS_PER_TDMA;
//fn_offset = cinfo->fn_offset - 1;
/* if we're already very close to the end of the TPU frame, the
* next interrupt will basically occur now and we need to
* compensate */
//if (tpu_shift < SWITCH_TIME)
// fn_offset++;
l1s.tpu_offset = tpu_shift;
//puts("Synchronize_TDMA\n");
/* request the TPU to adjust the SYNCHRO and OFFSET registers */
tpu_enq_at(SWITCH_TIME);
tpu_enq_sync(l1s.tpu_offset);
}
/*//////////////////////////////////////////////////////////////////////////////////////////////////////
FB/SB detection in dedicated mode
- First of all it must be noted that 3 additional frames have been added to the original idle frame 25 or 12 depending upon the half rate type. This gives us additional time to do any required time and frequency synchronization before detecting the synchronization burst of the neighbour as well as returning to the current settings before the TCH frame that follows. This can be seen in the file firmware/layer1/mframe_sched.c.
- The approach to detect FB and SB in dedicated mode must be kept in mind. In dedicated mode the traffic multiframe is running on the MS that consists of 26 frames with frame 25 as idle frame (in even mode). In order to read FB of neighbour we need to read its control channel that consists of 51 frames. As the control MF size is not a multiple of traffic MF size each time the traffic idle frame appears we are at a different frame number in the control MF of the neighbour. Hence the traffic idle frame coincides with a different control channel each time and actually traverses through it. By looking at the channel assignment accross the control MF it can be seen that we will coincide with a frequency burst on the control channel when we have an idle traffic frame every 10 or 11 idle frames. If we repeatedly search for FB on traffic idle frames we should be able to detect it every 10 or 11 idle frames. The SB would appear the second idle frame following the idle frame on which FB is detected not the next (this can be verified by hand). This is the approach we use.
- It was seen in idle mode FB/SB detection that FB is detected twice, first using FB mode 0 then using FB mode 1 which seem to provide different precision on frequency correction. After each FB detection frequency correction is performed in idle mode using afc_correct. Following FB mode 1 FB detection the quarter-bit synchronization is also performed using TOA (time of arrival of frequency burst) to synch the start of frame with the internal counters by modifying l1s.tpu_offset from what I could find. It is only after these two kinds of synchronizations/corrections that we can read the bursts on the channel properly. Synchronization burst is then read which is used to get the BSIC of the BTS and the absolute frame number it is on to update our internal variables/registers with it. Additionally further frequency correction is performed.
- The same steps need to be performed as above but this time in steps as we can only do this whenever the idle frame appears otherwise we would be in traffic mode and wouldn't have time to perform this. At each step values for frequency compensation/time correction are stored to be used in the next step. At the beginning of every idle frame set (as we have added three more idle frames) the required synchronization/correction is performed and at the end of it it is reversed to return to original settings. l1s_neigh_fbsb_sync is used to perform any synching/correction at the start of the idle frame set.
- fb_det and sb_det are used as control variables to guide through the synchronization process as follows:
fb_det sb_det task
0 0 FB detection mode 0
1 0 FB detection mode 1
0 1 Do nothing - this is the idle frame following FB detection
0 2 SB detection
0 3 Do nothing
0 4 SB detection again
fb_det goes from 0 to 1 upon FB detection in FB mode 0. Then when FB is detected in FB mode 1 sb_det becomes 1 and fb_det goes to 0. Thereafter sb_det increments upon every idle frame. This is important to keep in mind.
* SB detection is done second time to make sure the SB isn't missed as I thought it might be in the middle of the frames. Just a cautious check.
- Whenever FB and/or SB are detected the results are stored in the following variables to be used in case of handover
l1s.tpu_offsets_arfcn[ii] - The corresponding arfcn for the indices
l1s.tpu_offsets[ii] - The quarter-bit offset required for start of frame
l1s.nb_freq_diff[ii] - Frequency correction required from FB mode 0 + 1
l1s.nb_sb_freq_diff[ii] - Additional freq correction from SB detection
l1s.nb_frame_diff[ii] - The difference in frame of serving cell and the neighbour
l1s.nb_sb_snr[ii] - The snr received (might not really be needed)
I know I could have used the l1s.neigh_sb struct but for now that's the way it is. This is so also because the stored number of neighbour gets reset whenever we enter a new dedicated mode but that can be worked around.
- The TOA obtained from FB detection gives the number of GSM bits from the start of the command to detect FB till the actual detection. As it can span more than 1 frame especially in idle mode it is broken down to ntdma and qbits. ntdma denotes the complete frames and qbits the number of quarter-bits following an integer number of frames (the remainder bits x 4). This is the actual difference from the frame start of the serving cell to the frame start of the neighbour cell.
- This schedule is activated using the multiframe scheduler whenever the idle frame comes in dedicated mode. select_neigh_cell() is used to select the next neighbour once SB of one neighbour is obtained or 15 tries to detect FB have failed (or SB is not detected following FB detection).
- l1s.neigh_sb is the struct used to keep track of neigbour bsic/power measurements etc. This can be enhanced to store the values menioned above as well.
- l1s.tpu_offset is the variable storing the quarter-bit offset to the start of frame for the cell to be read/transmitted to. afc_correct(...) is used to do frequency compensation.
- Things could have been coded in a better way but that's the way it is for now. Perhaps someone else can restructure the whole thing and come up with a better approach.
///////////////////////////////////////////////////////////////////////////////////////////////////// */
/* scheduler callback to issue a FB detection task to the DSP */
static int l1s_neigh_fbsb_sync(__unused uint8_t p1, __unused uint8_t p2,
uint16_t fb_mode)
{
uint32_t tpu_shift;
int ntdma, qbits;
if (fb_det == 1) {
//printf("afc_correct in l1s_neigh_fbsb_sync for FB1 - nb_fb_angle0\n\n");
afc_correct(ANGLE_TO_FREQ(nb_fb_angle0), l1s.neigh_pm.band_arfcn[l1s.neigh_sb.index]);
}
if ((sb_det == 2)||(sb_det == 4)) {
//printf("\nMTZ - in l1s_neigh_fbsb_sync, old_tpu_offset = %d\n", l1s.tpu_offset);
/* FIXME: where did this magic 23 come from? */
nb_fb_toa -= 23; //MTZ - uncomment
if (nb_fb_toa < 0) {
qbits = (nb_fb_toa + BITS_PER_TDMA) * 4;
ntdma = -1;
} else {
ntdma = (nb_fb_toa) / BITS_PER_TDMA;
qbits = (nb_fb_toa - ntdma * BITS_PER_TDMA) * 4;
}
tpu_shift = qbits;
old_tpu_offset = l1s.tpu_offset;
/* NB detection only works if the TOA of the SB
* is within 0...8. We have to add 75 to get an SB TOA of 4. */
tpu_shift += 75; //MTZ - uncomment
tpu_shift = (l1s.tpu_offset + tpu_shift) % QBITS_PER_TDMA;
//fn_offset = cinfo->fn_offset - 1;
/* if we're already very close to the end of the TPU frame, the
* next interrupt will basically occur now and we need to
* compensate */
//if (tpu_shift < SWITCH_TIME)
// fn_offset++;
//printf("MTZ - old_tpu_offset = %d, tpu_shift = %d, qbits = %d\n", old_tpu_offset, tpu_shift, qbits);
l1s.neigh_pm.tpu_offset[l1s.neigh_sb.index] = tpu_shift;
int ii =0;
for (ii=0; ii<64; ii++) {
if (l1s.tpu_offsets_arfcn[ii] == l1s.neigh_pm.band_arfcn[l1s.neigh_sb.index]) {
l1s.tpu_offsets[ii] = tpu_shift;
l1s.nb_freq_diff[ii] = ANGLE_TO_FREQ(nb_fb_angle0)+ANGLE_TO_FREQ(nb_fb_angle1);
break;
}
if (l1s.tpu_offsets_arfcn[ii] == 0) {
l1s.tpu_offsets_arfcn[ii] = l1s.neigh_pm.band_arfcn[l1s.neigh_sb.index];
l1s.tpu_offsets[ii] = tpu_shift;
l1s.nb_freq_diff[ii] = ANGLE_TO_FREQ(nb_fb_angle0)+ANGLE_TO_FREQ(nb_fb_angle1);
break;
}
}
//printf("\n\nMTZ: Stored TPU Offsets, Angles:");
//for (ii=0; ii<64; ii++) {
// if (l1s.tpu_offsets_arfcn[ii] == 0)
// break;
// printf(" %d,%d(%d)", l1s.tpu_offsets[ii], l1s.nb_freq_diff[ii], l1s.tpu_offsets_arfcn[ii]);
//}
//printf("\n\n");
//MTZ - possibly remove the >=50 if statement
if (nb_fb_toa >= 50) {
l1s.tpu_offset = tpu_shift;
//tpu_enq_at(SWITCH_TIME);
//tpu_enq_sync(tpu_shift);
}
//printf("afc_correct in l1s_neigh_fbsb_sync for SB - nb_fb_angle0+nb_fb_angle1\n\n");
afc_correct(ANGLE_TO_FREQ(nb_fb_angle0)+ANGLE_TO_FREQ(nb_fb_angle1), l1s.neigh_pm.band_arfcn[l1s.neigh_sb.index]);
}
}
/* scheduler callback to issue a FB and SB detection task to the DSP in dedicated mode */
// READ COMMENTS ABOVE l1s_neigh_fbsb_sync
static int l1s_neigh_fbsb_cmd(__unused uint8_t p1, __unused uint8_t p2,
uint16_t fb_mode)
{
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();
index = l1s.neigh_sb.index;
}
// //MTZ - putting this for now as we wanted to repeatedly detect the remaining ones - remove
// while (!((l1s.neigh_sb.flags_bsic[index] & NEIGH_PM_FLAG_BSIC) == 0)) {
//// printf("\nMTZ: BSIC has been decoded for ARFCN %d (flags_bsic[%d] = %d)\n\n", l1s.neigh_pm.band_arfcn[index], index, l1s.neigh_sb.flags_bsic[index]);
// l1s.neigh_sb.count = 0;
// l1s.neigh_sb.flags_bsic[index] |= NEIGH_PM_FLAG_SCANNED;
// select_neigh_cell();
// index = l1s.neigh_sb.index;
// }
if (sb_det == 0) {
//l1s.fb.mode = fb_mode;
//printf(" - detect FB 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_FB_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); //MTZ - Commented originally
if (fb_det == 1) {
dsp_api.ndb->d_fb_mode = 1;
} else {
dsp_api.ndb->d_fb_mode = 0;
}
/* Program TPU */
//l1s_rx_win_ctrl(l1s.neigh_pm.band_arfcn[index], L1_RXWIN_FB26, 5); //MTZ - Original - don't think works - as we have multiple idle frames now we can use TS 0
l1s_rx_win_ctrl(l1s.neigh_pm.band_arfcn[index], L1_RXWIN_FB26, 0);
/* restore last gain */
rffe_set_gain(last_gain);
} else if ((sb_det == 2)||(sb_det == 4)) {
// 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 */
//MTZ Changed
//dsp_api.db_w->d_task_md = TCH_SB_DSP_TASK; /* maybe with I/Q swap? */
dsp_api.db_w->d_task_md = 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); //MTZ - Commented originally
dsp_api.ndb->d_fb_mode = 0;
// //MTZ - Experimenting
// dsp_api.ndb->a_sync_demod[D_TOA] = nb_fb_toa;
// dsp_api.ndb->a_sync_demod[D_PM] = nb_fb_pm;
// dsp_api.ndb->a_sync_demod[D_ANGLE] = nb_fb_angle;
// dsp_api.ndb->a_sync_demod[D_SNR] = nb_fb_snr;
/* Program TPU */
//l1s_rx_win_ctrl(l1s.neigh_pm.band_arfcn[index], L1_RXWIN_SB26, 5); //MTZ - Original - don't think works - as we have multiple idle frames now we can use TS 0
l1s_rx_win_ctrl(l1s.neigh_pm.band_arfcn[index], L1_RXWIN_SB, 0);
/* restore last gain */
rffe_set_gain(last_gain);
l1s.neigh_sb.running = 1;
}
return 0;
}
/* scheduler callback to issue a FB and SB detection task to the DSP in dedicate mode */
// READ COMMENTS ABOVE l1s_neigh_fbsb_sync
static int l1s_neigh_fbsb_resp(__unused uint8_t p1, uint8_t attempt,
uint16_t fb_mode)
{
int index = l1s.neigh_sb.index;
uint32_t sb;
uint8_t bsic;
int sb_found = 0;
if (sb_det == 0) {
if (fb_det == 1) {
//printf("afc_correct (-ve) in l1s_neigh_fbsb_resp for FB1 - nb_fb_angle0\n\n");
afc_correct(-1*ANGLE_TO_FREQ(nb_fb_angle0), l1s.neigh_pm.band_arfcn[l1s.neigh_sb.index]);
}
if (!dsp_api.ndb->d_fb_det) {
printf("MTZ: ARFCN %d (index %d, power %d dbm, try #%d) FB%d found = 0\n", l1s.neigh_pm.band_arfcn[index], index, rxlev2dbm(l1s.neigh_pm.level[index]), l1s.neigh_sb.count, fb_det);
/* next sync */
if (++l1s.neigh_sb.count == 15) {
//MTZ - a count of 0 will result in select_neigh_cell() being called and next cell being selected
l1s.neigh_sb.count = 0;
l1s.neigh_sb.flags_bsic[index] |= NEIGH_PM_FLAG_SCANNED;
//MTZ - If 15 tries in FB mode 1 then set fb_det to 0
if (fb_det == 1){
fb_det = 0;
}
}
} else {
//MTZ - Capturing the readings from FB detection - these are stored in arrays upon SB detection for use in case handover is required
nb_fb_toa = dsp_api.ndb->a_sync_demod[D_TOA];
nb_fb_pm = dsp_api.ndb->a_sync_demod[D_PM];
if (fb_det == 1)
nb_fb_angle1 = dsp_api.ndb->a_sync_demod[D_ANGLE];
else
nb_fb_angle0 = dsp_api.ndb->a_sync_demod[D_ANGLE];
nb_fb_snr = dsp_api.ndb->a_sync_demod[D_SNR];
printf("\n\nMTZ: ARFCN %d (index %d, power %d dbm, try #%d) FB%d found = 1 >>> nb_fb_toa = %d, angle = %d\n\n", l1s.neigh_pm.band_arfcn[index], index, rxlev2dbm(l1s.neigh_pm.level[index]), l1s.neigh_sb.count, fb_det, nb_fb_toa, dsp_api.ndb->a_sync_demod[D_ANGLE]);
//MTZ - If FB mode was 0 make it 1, it FB mode was one set sb_det to 1 to indicate SB detection step
if (fb_det == 0) {
fb_det = 1;
l1s.neigh_sb.count = 1;
} else {
sb_det = 1;
fb_det = 0;
}
}
//l1s_reset_hw();
tdma_sched_reset();
} else {
if ((sb_det == 2)||(sb_det == 4)) {
/* check if sync was successful */
//MTZ - This was the main change below - we need to read a_sch26 as opposed to a_sch
//if (dsp_api.db_r->a_sch[0] & (1<<B_SCH_CRC)) {
if (dsp_api.ndb->a_sch26[0] & (1<<B_SCH_CRC)) {
// printf("\nSB found = 0 (ARFCN %d, power %d dbm)\n\n", l1s.neigh_pm.band_arfcn[index], rxlev2dbm(l1s.neigh_pm.level[index]));
} else {
uint32_t fn; /* FN count */
uint16_t t1; /* FN div (26*51) */
uint8_t t2; /* FN modulo 26 */
uint8_t t3; /* FN modulo 51 */
uint8_t tc;
uint8_t t3p;
sb_found = 1;
sb = dsp_api.ndb->a_sch26[3] | dsp_api.ndb->a_sch26[4] << 16;
bsic = (sb >> 2) & 0x3f;
t1 = ((sb >> 23) & 1) | ((sb >> 7) & 0x1fe) | ((sb << 9) & 0x600);
t2 = (sb >> 18) & 0x1f;
t3p = ((sb >> 24) & 1) | ((sb >> 15) & 6);
t3 = t3p*10 + 1;
/* TS 05.02 Chapter 4.3.3 TDMA frame number */
fn = (51 * ((t3 - t2 + 26) % 26) + t3 + (26 * 51 * t1)) + SB2_LATENCY;
int ii =0;
for (ii=0; ii<64; ii++) {
if (l1s.tpu_offsets_arfcn[ii] == l1s.neigh_pm.band_arfcn[l1s.neigh_sb.index]) {
l1s.nb_frame_diff[ii] = fn - l1s.current_time.fn;
l1s.nb_sb_freq_diff[ii] = ANGLE_TO_FREQ(dsp_api.db_r->a_serv_demod[D_ANGLE]);
l1s.nb_sb_snr[ii] = dsp_api.db_r->a_serv_demod[D_SNR];
break;
}
}
total_sb_det++;
//printf("=> SB 0x%08"PRIx32": BSIC=%u \n\n", sb, bsic);
printf("\n----------------------------------------------------------------------------\nSB found = 1 (ARFCN %d, power %d dbm) => SB 0x%08"PRIx32": BSIC=%u, TOA=%d, Angle=%d (Total=%d)\n----------------------------------------------------------------------------\n\n", l1s.neigh_pm.band_arfcn[index], rxlev2dbm(l1s.neigh_pm.level[index]), sb, bsic, dsp_api.db_r->a_serv_demod[D_TOA], dsp_api.db_r->a_serv_demod[D_ANGLE], total_sb_det);
l1s.neigh_sb.flags_bsic[index] = bsic | NEIGH_PM_FLAG_BSIC | NEIGH_PM_FLAG_SCANNED;
}
if ((sb_det == 2)||(sb_det == 4)) {
//MTZ - testing this - possibly remove
if (nb_fb_toa >= 50);
l1s.tpu_offset = old_tpu_offset;
//printf("afc_correct (-ve) in l1s_neigh_fbsb_resp for SB - nb_fb_angle0+nb_fb_angle1\n\n");
afc_correct(-1*(ANGLE_TO_FREQ(nb_fb_angle0) + ANGLE_TO_FREQ(nb_fb_angle1)), l1s.neigh_pm.band_arfcn[l1s.neigh_sb.index]);
}
if ((sb_det == 4)||(sb_found == 1)) {
l1s.neigh_sb.count = 0;
//MTZ - need to change this statement based on detection
l1s.neigh_sb.flags_bsic[index] |= NEIGH_PM_FLAG_SCANNED;
l1s.neigh_sb.running = 0;
//dsp_api.r_page_used = 1;
if (sb_found == 0)
printf("\n\n");
}
}
if ((sb_det == 4)||(sb_found == 1))
sb_det = 0;
else
sb_det++;
}
return 0;
}
//MTZ - THIS FUNCTION BELOW IS NOT USED!!!!!
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;
printf("\n\n\nMTZ: In neigh_sb_cmd, l1s.neigh_pm.n = %d\n\n\n", l1s.neigh_pm.n);
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;
}
//MTZ - THIS FUNCTION BELOW IS NOT USED!!!!!
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;
printf("\nMTZ: In l1s_neigh_sb_resp, l1s.serving_cell.arfcn = %d\n", l1s.serving_cell.arfcn);
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()
//};
/* 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_fbsb_sync, 1, 0, 1), SCHED_END_FRAME(),
SCHED_ITEM_DT(l1s_neigh_fbsb_cmd, 1, 0, 1), SCHED_END_FRAME(),
SCHED_END_FRAME(),
SCHED_END_FRAME(),
SCHED_ITEM(l1s_neigh_fbsb_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;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -156,11 +156,43 @@ void l1s_pm_test(uint8_t base_fn, uint16_t arfcn)
}
/*
* perform measurements of neighbour cells
* perform measurements of neighbour cells on idle frame
*/
/* send measurement results */
static void neigh_pm_ind(void)
{
struct msgb *msg;
struct l1ctl_neigh_pm_ind *mi;
int i;
uint8_t half_rounds = l1s.neigh_pm.rounds >> 1;
/* return result */
msg = l1ctl_msgb_alloc(L1CTL_NEIGH_PM_IND);
for (i = 0; i < l1s.neigh_pm.n; i++) {
if (msgb_tailroom(msg) < (int) sizeof(*mi)) {
l1_queue_for_l2(msg);
msg = l1ctl_msgb_alloc(L1CTL_NEIGH_PM_IND);
}
mi = (struct l1ctl_neigh_pm_ind *)
msgb_put(msg, sizeof(*mi));
mi->band_arfcn = htons(l1s.neigh_pm.band_arfcn[i]);
mi->tn = l1s.neigh_pm.tn[i];
l1s.neigh_pm.level[i]
= (l1s.neigh_pm.level_sum[i] + half_rounds)
/ 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;
else
mi->bsic = 255;
}
l1_queue_for_l2(msg);
}
/* scheduler callback to issue a power measurement task to the DSP */
static int l1s_neigh_pm_cmd(uint8_t num_meas,
static int l1s_neigh_pm_idle_cmd(uint8_t num_meas,
__unused uint8_t p2, __unused uint16_t p3)
{
uint8_t last_gain = rffe_get_gain();
@ -188,7 +220,7 @@ static int l1s_neigh_pm_cmd(uint8_t num_meas,
}
/* scheduler callback to read power measurement resposnse from the DSP */
static int l1s_neigh_pm_resp(__unused uint8_t p1, __unused uint8_t p2,
static int l1s_neigh_pm_idle_resp(__unused uint8_t p1, __unused uint8_t p2,
__unused uint16_t p3)
{
uint16_t dbm;
@ -202,29 +234,14 @@ static int l1s_neigh_pm_resp(__unused uint8_t p1, __unused uint8_t p2,
dbm = (uint16_t) ((dsp_api.db_r->a_pm[0] & 0xffff) >> 3);
level = dbm2rxlev(agc_inp_dbm8_by_pm(dbm)/8);
l1s.neigh_pm.level[l1s.neigh_pm.pos] = level;
l1s.neigh_pm.level_sum[l1s.neigh_pm.pos] = level;
if (++l1s.neigh_pm.pos >= l1s.neigh_pm.n) {
struct msgb *msg;
struct l1ctl_neigh_pm_ind *mi;
int i;
l1s.neigh_pm.pos = 0;
/* return result */
msg = l1ctl_msgb_alloc(L1CTL_NEIGH_PM_IND);
for (i = 0; i < l1s.neigh_pm.n; i++) {
if (msgb_tailroom(msg) < (int) sizeof(*mi)) {
l1_queue_for_l2(msg);
msg = l1ctl_msgb_alloc(L1CTL_NEIGH_PM_IND);
}
mi = (struct l1ctl_neigh_pm_ind *)
msgb_put(msg, sizeof(*mi));
mi->band_arfcn = htons(l1s.neigh_pm.band_arfcn[i]);
mi->tn = l1s.neigh_pm.tn[i];
mi->pm[0] = l1s.neigh_pm.level[i];
mi->pm[1] = 0;
}
l1_queue_for_l2(msg);
l1s.neigh_pm.rounds++;
neigh_pm_ind();
l1s.neigh_pm.rounds = 0;
l1s.neigh_pm.valid = 1;
}
out:
@ -233,10 +250,137 @@ out:
return 0;
}
const struct tdma_sched_item neigh_pm_sched_set[] = {
SCHED_ITEM_DT(l1s_neigh_pm_cmd, 0, 1, 0), SCHED_END_FRAME(),
const struct tdma_sched_item neigh_pm_idle_sched_set[] = {
SCHED_ITEM_DT(l1s_neigh_pm_idle_cmd, -1, 1, 0), SCHED_END_FRAME(),
SCHED_END_FRAME(),
SCHED_ITEM(l1s_neigh_pm_resp, -4, 1, 0), SCHED_END_FRAME(),
SCHED_ITEM(l1s_neigh_pm_idle_resp, -4, 1, 0), SCHED_END_FRAME(),
SCHED_END_SET()
};
/*
* Perform measurements of neighbour cells on TCH
*
* Only when number of neighbor cells is > 0, perform measurement.
*
* For each measurement, l1s.neigh_pm.running is set. In case of an update
* of neighbor cell list, this state is cleared, so a pending measurement would
* be ignored.
*
* The measuement starts at position 0 (first neighbor cell). After each
* measurement result, the position is incremented until the number of neighbor
* cells are reached.
*
* All measurement results are added to level_sum array. It will be used to
* calculate an average from multiple measurements.
*
* All measurements start at round 0. When all neighbors have been measured,
* the number of rounds is increased and the measurement start over. At start
* of round 0, the start_fn is recorded. It will be used to calculate the
* elapsed time from the beginning.
*
* After reach round, the number of elapsed frames is checked. If at least 104
* frames have been elapsed, this would be the last round. The average of
* measurements are calculated from the level_sum array. Then the result is
* indicated to layer, the measurement states are reset, the measurments are
* maked as valid, and the measurement process starts over.
*/
/* scheduler callback to issue a power measurement task to the DSP */
static int l1s_neigh_pm_tch_cmd(uint8_t num_meas,
__unused uint8_t p2, __unused uint16_t p3)
{
uint8_t last_gain;
if (l1s.neigh_pm.n == 0)
return 0;
/* set start_fn for the first round */
if (l1s.neigh_pm.pos == 0 && l1s.neigh_pm.rounds == 0)
l1s.neigh_pm.start_fn = l1s.next_time.fn;
/* save current gain */
last_gain = rffe_get_gain();
dsp_api.db_w->d_task_md = num_meas; /* number of measurements */
// dsp_api.ndb->d_fb_mode = 0; /* wideband search */
/* Tell the RF frontend to set the gain appropriately (keep last) */
rffe_compute_gain(-85, CAL_DSP_TGT_BB_LVL);
/*
* Program TPU
* Use TS 5 (two TS after TX)
*/
l1s_rx_win_ctrl((l1s.neigh_pm.n) ?
l1s.neigh_pm.band_arfcn[l1s.neigh_pm.pos] : 0,
L1_RXWIN_PW, 5);
/* restore last gain */
rffe_set_gain(last_gain);
l1s.neigh_pm.running = 1;
return 0;
}
/* scheduler callback to read power measurement resposnse from the DSP */
static int l1s_neigh_pm_tch_resp(__unused uint8_t p1, __unused uint8_t p2,
__unused uint16_t p3)
{
uint16_t dbm;
uint8_t level;
dsp_api.r_page_used = 1;
if (l1s.neigh_pm.n == 0 || !l1s.neigh_pm.running)
goto out;
dbm = (uint16_t) ((dsp_api.db_r->a_pm[0] & 0xffff) >> 3);
level = dbm2rxlev(agc_inp_dbm8_by_pm(dbm)/8);
//MTZ: The code below is to artificially induce handover
//////////////////////////////////////////////
if (((l1s.serving_cell.arfcn == 25) && ((l1s.neigh_pm.band_arfcn[l1s.neigh_pm.pos] == 57)||(l1s.neigh_pm.band_arfcn[l1s.neigh_pm.pos] == 52)||(l1s.neigh_pm.band_arfcn[l1s.neigh_pm.pos] == 49))) || ((l1s.serving_cell.arfcn == 57) && ((l1s.neigh_pm.band_arfcn[l1s.neigh_pm.pos] == 25)||(l1s.neigh_pm.band_arfcn[l1s.neigh_pm.pos] == 52)||(l1s.neigh_pm.band_arfcn[l1s.neigh_pm.pos] == 58)))) {
l1s.neigh_pm.level_sum[l1s.neigh_pm.pos] += 63;
} else {
l1s.neigh_pm.level_sum[l1s.neigh_pm.pos] += level;
}
///////////////////////////////////////////////
//MTZ: This if statement is used because it was seen that sometimes a level of 0 was read off in dedicated mode which is not valid
if (level > 0) {
if (++l1s.neigh_pm.pos >= l1s.neigh_pm.n) {
uint32_t elapsed = (l1s.next_time.fn + 2715648
- l1s.neigh_pm.start_fn) % 2715648;
l1s.neigh_pm.pos = 0;
l1s.neigh_pm.rounds++;
/*
* We want at least 104 frames before indicating the
* measurement(s). Add two, since the measurement was
* started two frames ago.
*/
if (elapsed >= 104 + 2) {
neigh_pm_ind();
l1s.neigh_pm.rounds = 0;
l1s.neigh_pm.valid = 1;
}
}
}
out:
l1s.neigh_pm.running = 0;
return 0;
}
/* NOTE: Prio 1 is below TCH's TX+RX prio 0 */
const struct tdma_sched_item neigh_pm_tch_sched_set[] = {
SCHED_ITEM_DT(l1s_neigh_pm_tch_cmd, 1, 1, 0), SCHED_END_FRAME(),
SCHED_END_FRAME(),
SCHED_ITEM(l1s_neigh_pm_tch_resp, -4, 1, 0), SCHED_END_FRAME(),
SCHED_END_SET()
};

View File

@ -50,6 +50,10 @@
#include <l1ctl_proto.h>
int hando_access_flag = 0;
int16_t hando_arfcn = 0;
int ho_flag = 0;
struct {
uint32_t fn;
uint16_t band_arfcn;
@ -60,11 +64,18 @@ static int l1s_tx_rach_cmd(__unused uint8_t p1, __unused uint8_t p2, __unused ui
{
uint16_t *info_ptr;
uint16_t arfcn;
uint8_t tsc, tn;
uint8_t data[2];
putchart('T');
l1s_tx_apc_helper(l1s.serving_cell.arfcn);
if (hando_access_flag == 1)
arfcn = hando_arfcn;
else
arfcn = l1s.serving_cell.arfcn;
//l1s_tx_apc_helper(l1s.serving_cell.arfcn);
l1s_tx_apc_helper(arfcn);
data[0] = l1s.serving_cell.bsic << 2;
data[1] = l1s.rach.ra;
@ -72,7 +83,11 @@ static int l1s_tx_rach_cmd(__unused uint8_t p1, __unused uint8_t p2, __unused ui
info_ptr = &dsp_api.ndb->d_rach;
info_ptr[0] = ((uint16_t)(data[0])) | ((uint16_t)(data[1])<<8);
arfcn = l1s.serving_cell.arfcn;
//rfch_get_params(&l1s.next_time, &arfcn, &tsc, &tn); //MTZ - ADDED LATER - POSSIBLY REMOVE
//hando_access_flag = 0;
printf("\n\nMTZ - arfcn in l1s_tx_rach_cmd = %d, serving cell arfcn = %d\n\n", arfcn, l1s.serving_cell.arfcn);
dsp_api.db_w->d_task_ra = dsp_task_iq_swap(RACH_DSP_TASK, arfcn, 1);
@ -85,14 +100,50 @@ static int l1s_tx_rach_cmd(__unused uint8_t p1, __unused uint8_t p2, __unused ui
static int l1s_tx_rach_resp(__unused uint8_t p1, __unused uint8_t burst_id,
__unused uint16_t p3)
{
uint16_t arfcn;
if (hando_access_flag == 1)
arfcn = hando_arfcn;
else
arfcn = l1s.serving_cell.arfcn;
hando_access_flag = 0;
putchart('t');
dsp_api.r_page_used = 1;
if (ho_flag == 1) {
ho_flag = 0;
int ii = 0;
for (ii =0; ii<64; ii++) {
if (l1s.tpu_offsets_arfcn[ii] == arfcn) {
if (l1s.nb_sb_snr[ii] > 0)
afc_input(l1s.nb_sb_freq_diff[ii], arfcn, 1);
else
afc_input(l1s.nb_sb_freq_diff[ii], arfcn, 0);
//mframe_disable(MF_TASK_TCH_F_EVEN);
//mframe_disable(MF_TASK_TCH_F_ODD);
//mframe_disable(MF_TASK_TCH_H_0);
//mframe_disable(MF_TASK_TCH_H_1);
//mframe_disable(MF_TASK_NEIGH_PM51_C0T0);
//mframe_disable(MF_TASK_NEIGH_PM51);
//mframe_disable(MF_TASK_NEIGH_PM26E);
//mframe_disable(MF_TASK_NEIGH_PM26O);
//mframe_enable(MF_TASK_BCCH_NORM);
}
}
}
/* schedule a confirmation back indicating the GSM time at which
* the RACH burst was transmitted to the BTS */
last_rach.fn = l1s.current_time.fn - 1;
last_rach.band_arfcn = l1s.serving_cell.arfcn;
last_rach.band_arfcn = arfcn;
l1s_compl_sched(L1_COMPL_RACH);
return 0;
@ -111,6 +162,7 @@ static void l1a_rach_compl(__unused enum l1_compl c)
{
struct msgb *msg;
printf("\n\nMTZ: L1CTL_RACH_CONF message being sent!\n\n\n");
msg = l1_create_l2_msg(L1CTL_RACH_CONF, last_rach.fn, 0,
last_rach.band_arfcn);
l1_queue_for_l2(msg);
@ -131,16 +183,72 @@ static uint8_t rach_to_t3_comb[27] = {
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
45, 46};
/* request a RACH request at the next multiframe T3 = fn51 */
void l1a_rach_req(uint16_t offset, uint8_t combined, uint8_t ra)
/* schedule access burst */
void l1a_rach_req(uint16_t offset, uint8_t combined, uint8_t ra, uint16_t arfcn)
{
uint32_t fn_sched;
unsigned long flags;
if (arfcn > 0) {
hando_arfcn = arfcn;
hando_access_flag = 1;
//printf("\n\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\nMTZ: CP1\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n\n");
uint32_t new_fn;
if (l1s.new_dm) {
int ii = 0;
for (ii =0; ii<64; ii++) {
if (l1s.tpu_offsets_arfcn[ii] == arfcn) {
printf("\n\n\n\n\n\n\n-------------------------------------------\n\n\n\n\nMTZ: SYNCHING TO NEW ARFCN %d\n\n\n\n\n-------------------------------------------\n\n\n\n\n\n\n\n", arfcn);
//printf("\n\n\n\n\n\n\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!MTZ: SYNCHING TO NEW ARFCN %d (offset=%d, freq_diff=%d, sb_fb_freq_diff=%d, sb_snr=%d, frame_diff=%d)!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n\n\n\n\n\n\n\n", arfcn, l1s.tpu_offsets[ii], l1s.nb_freq_diff[ii], l1s.nb_sb_freq_diff[ii], l1s.nb_sb_snr[ii], l1s.nb_frame_diff[ii]);
//MTZ - Setting tpu_offset for frame start synchronization as well as doing frequency compensation
l1s.orig_tpu_offset = l1s.tpu_offset;
l1s.tpu_offset = l1s.tpu_offsets[ii];
afc_correct(l1s.nb_freq_diff[ii], arfcn);
//if (l1s.nb_sb_snr[ii] > 0)
// afc_input(l1s.nb_sb_freq_diff[ii], arfcn, 1);
//else
// afc_input(l1s.nb_sb_freq_diff[ii], arfcn, 0);
//MTZ - Setting frame number using the difference computed before
new_fn = l1s.current_time.fn + l1s.nb_frame_diff[ii];
while (new_fn < 0)
new_fn += 2715647;
new_fn = new_fn % 2715647;
gsm_fn2gsmtime(&l1s.current_time, new_fn);
/* compute next time from new current time */
l1s.next_time = l1s.current_time;
l1s_time_inc(&l1s.next_time, 1);
tdma_sched_reset();
ho_flag = 1;
}
}
l1s.new_dm = 0;
}
}
offset += 3;
//printf("\n\nMTZ: In l1a_rach_req, serving cell = %d\n\n", l1s.serving_cell.arfcn);
local_firq_save(flags);
if (combined) {
if (l1s.dedicated.type == GSM_DCHAN_TCH_F) {
fn_sched = l1s.current_time.fn + offset;
/* go next DCCH frame TCH/F channel */
if ((fn_sched % 13) == 12)
fn_sched++;
} else if (l1s.dedicated.type == GSM_DCHAN_TCH_H) {
fn_sched = l1s.current_time.fn + offset;
/* go next DCCH frame of TCH/H channel */
if ((fn_sched % 13) == 12)
fn_sched++;
if ((l1s.dedicated.chan_nr & 1) != ((fn_sched % 13) & 1))
fn_sched++;
} else if (combined) {
/* add elapsed RACH slots to offset */
offset += t3_to_rach_comb[l1s.current_time.t3];
/* offset is the number of RACH slots in the future */
@ -150,6 +258,7 @@ void l1a_rach_req(uint16_t offset, uint8_t combined, uint8_t ra)
} else
fn_sched = l1s.current_time.fn + offset;
l1s.rach.ra = ra;
fn_sched %= 2715648;
sched_gsmtime(rach_sched_set_ul, fn_sched, 0);
local_irq_restore(flags);

View File

@ -0,0 +1,265 @@
/* Layer 1 Random Access Channel Burst */
/* (C) 2010 by Dieter Spaar <spaar@mirider.augusta.de>
* (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 <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 <asm/system.h>
#include <layer1/sync.h>
#include <layer1/async.h>
#include <layer1/tdma_sched.h>
#include <layer1/tpu_window.h>
#include <layer1/l23_api.h>
#include <layer1/sched_gsmtime.h>
#include <l1ctl_proto.h>
int hando_access_flag = 0;
int16_t hando_arfcn = 0;
int ho_flag = 0;
struct {
uint32_t fn;
uint16_t band_arfcn;
} last_rach;
/* p1: type of operation (0: one NB, 1: one RACH burst, 2: four NB */
static int l1s_tx_rach_cmd(__unused uint8_t p1, __unused uint8_t p2, __unused uint16_t p3)
{
uint16_t *info_ptr;
uint16_t arfcn;
uint8_t tsc, tn;
uint8_t data[2];
putchart('T');
if (hando_access_flag == 1)
arfcn = hando_arfcn;
else
arfcn = l1s.serving_cell.arfcn;
//l1s_tx_apc_helper(l1s.serving_cell.arfcn);
l1s_tx_apc_helper(arfcn);
data[0] = l1s.serving_cell.bsic << 2;
data[1] = l1s.rach.ra;
info_ptr = &dsp_api.ndb->d_rach;
info_ptr[0] = ((uint16_t)(data[0])) | ((uint16_t)(data[1])<<8);
//rfch_get_params(&l1s.next_time, &arfcn, &tsc, &tn); //MTZ - ADDED LATER - POSSIBLY REMOVE
//hando_access_flag = 0;
printf("\n\nMTZ - arfcn in l1s_tx_rach_cmd = %d, serving cell arfcn = %d\n\n", arfcn, l1s.serving_cell.arfcn);
dsp_api.db_w->d_task_ra = dsp_task_iq_swap(RACH_DSP_TASK, arfcn, 1);
l1s_tx_win_ctrl(arfcn | ARFCN_UPLINK, L1_TXWIN_AB, 0, 3);
return 0;
}
/* p1: type of operation (0: one NB, 1: one RACH burst, 2: four NB */
static int l1s_tx_rach_resp(__unused uint8_t p1, __unused uint8_t burst_id,
__unused uint16_t p3)
{
uint16_t arfcn;
if (hando_access_flag == 1)
arfcn = hando_arfcn;
else
arfcn = l1s.serving_cell.arfcn;
hando_access_flag = 0;
putchart('t');
dsp_api.r_page_used = 1;
if (ho_flag == 1) {
ho_flag = 0;
int ii = 0;
for (ii =0; ii<64; ii++) {
if (l1s.tpu_offsets_arfcn[ii] == arfcn) {
if (l1s.nb_sb_snr[ii] > 0)
afc_input(l1s.nb_sb_freq_diff[ii], arfcn, 1);
else
afc_input(l1s.nb_sb_freq_diff[ii], arfcn, 0);
}
}
}
/* schedule a confirmation back indicating the GSM time at which
* the RACH burst was transmitted to the BTS */
last_rach.fn = l1s.current_time.fn - 1;
last_rach.band_arfcn = arfcn;
l1s_compl_sched(L1_COMPL_RACH);
return 0;
}
/* sched sets for uplink */
const struct tdma_sched_item rach_sched_set_ul[] = {
SCHED_ITEM_DT(l1s_tx_rach_cmd, 3, 1, 0), SCHED_END_FRAME(),
SCHED_END_FRAME(),
SCHED_ITEM(l1s_tx_rach_resp, -4, 1, 0), SCHED_END_FRAME(),
SCHED_END_SET()
};
/* Asynchronous completion handler for FB detection */
static void l1a_rach_compl(__unused enum l1_compl c)
{
struct msgb *msg;
printf("\n\nMTZ: L1CTL_RACH_CONF message being sent!\n\n\n");
msg = l1_create_l2_msg(L1CTL_RACH_CONF, last_rach.fn, 0,
last_rach.band_arfcn);
l1_queue_for_l2(msg);
}
static uint8_t t3_to_rach_comb[51] = {
0, 0, 0, 0,
0, 1,
2, 2, 2, 2, 2, 2, 2, 2,
2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 25, 25, 25, 25, 25, 25, 25,
25, 26,
27, 27, 27, 27};
static uint8_t rach_to_t3_comb[27] = {
4, 5,
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
45, 46};
/* schedule access burst */
void l1a_rach_req(uint16_t offset, uint8_t combined, uint8_t ra, uint16_t arfcn)
{
uint32_t fn_sched;
unsigned long flags;
if (arfcn > 0) {
hando_arfcn = arfcn;
hando_access_flag = 1;
printf("\n\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\nMTZ: CP1\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n\n");
uint32_t new_fn;
if (l1s.new_dm2) {
int ii = 0;
for (ii =0; ii<64; ii++) {
if (l1s.tpu_offsets_arfcn[ii] == arfcn) {
printf("\n\n\n\n----------------------------------------------------------\n\n\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!MTZ: SYNCHING TO NEW ARFCN %d (offset=%d, freq_diff=%d, sb_fb_freq_diff=%d, sb_snr=%d, frame_diff=%d)!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n\n----------------------------------------------------------\n\n\n\n\n\n", arfcn, l1s.tpu_offsets[ii], l1s.nb_freq_diff[ii], l1s.nb_sb_freq_diff[ii], l1s.nb_sb_snr[ii], l1s.nb_frame_diff[ii]);
l1s.orig_tpu_offset = l1s.tpu_offset;
l1s.tpu_offset = l1s.tpu_offsets[ii];
afc_correct(l1s.nb_freq_diff[ii], arfcn);
new_fn = l1s.current_time.fn + l1s.nb_frame_diff[ii];
if (new_fn < 0)
new_fn += 2715647;
new_fn = new_fn % 2715647;
gsm_fn2gsmtime(&l1s.current_time, new_fn);
/* compute next time from new current time */
l1s.next_time = l1s.current_time;
l1s_time_inc(&l1s.next_time, 1);
tdma_sched_reset();
ho_flag = 1;
//if (l1s.nb_sb_snr[ii] > 0)
// afc_input(l1s.nb_sb_freq_diff[ii], arfcn, 1);
//else
// afc_input(l1s.nb_sb_freq_diff[ii], arfcn, 0);
//mframe_disable(MF_TASK_TCH_F_EVEN);
//mframe_disable(MF_TASK_TCH_F_ODD);
//mframe_disable(MF_TASK_TCH_H_0);
//mframe_disable(MF_TASK_TCH_H_1);
//mframe_disable(MF_TASK_NEIGH_PM51_C0T0);
//mframe_disable(MF_TASK_NEIGH_PM51);
//mframe_disable(MF_TASK_NEIGH_PM26E);
//mframe_disable(MF_TASK_NEIGH_PM26O);
//mframe_enable(MF_TASK_BCCH_NORM);
}
}
l1s.new_dm2 = 0;
}
}
offset += 3;
//printf("\n\nMTZ: In l1a_rach_req, serving cell = %d\n\n", l1s.serving_cell.arfcn);
local_firq_save(flags);
if (l1s.dedicated.type == GSM_DCHAN_TCH_F) {
fn_sched = l1s.current_time.fn + offset;
/* go next DCCH frame TCH/F channel */
if ((fn_sched % 13) == 12)
fn_sched++;
} else if (l1s.dedicated.type == GSM_DCHAN_TCH_H) {
fn_sched = l1s.current_time.fn + offset;
/* go next DCCH frame of TCH/H channel */
if ((fn_sched % 13) == 12)
fn_sched++;
if ((l1s.dedicated.chan_nr & 1) != ((fn_sched % 13) & 1))
fn_sched++;
} else if (combined) {
/* add elapsed RACH slots to offset */
offset += t3_to_rach_comb[l1s.current_time.t3];
/* offset is the number of RACH slots in the future */
fn_sched = l1s.current_time.fn - l1s.current_time.t3;
fn_sched += offset / 27 * 51;
fn_sched += rach_to_t3_comb[offset % 27];
} else
fn_sched = l1s.current_time.fn + offset;
l1s.rach.ra = ra;
fn_sched %= 2715648;
sched_gsmtime(rach_sched_set_ul, fn_sched, 0);
local_irq_restore(flags);
memset(&last_rach, 0, sizeof(last_rach));
}
static __attribute__ ((constructor)) void prim_rach_init(void)
{
l1s.completion[L1_COMPL_RACH] = &l1a_rach_compl;
}

View File

@ -89,6 +89,9 @@ static int l1s_nb_resp(__unused uint8_t p1, uint8_t burst_id, uint16_t p3)
gsm_fn2gsmtime(&rx_time, l1s.current_time.fn - 1);
rfch_get_params(&rx_time, &rf_arfcn, &tsc, &tn);
//As causing held issues
//printf("\nMTZ:l1s_nb_resp, sc=%d\n", l1s.serving_cell.arfcn);
/* collect measurements */
rxnb.meas[burst_id].toa_qbit = dsp_api.db_r->a_serv_demod[D_TOA];
rxnb.meas[burst_id].pm_dbm8 =
@ -204,6 +207,7 @@ static int l1s_nb_cmd(__unused uint8_t p1, uint8_t burst_id,
burst_id, tsc
);
//printf("\nMTZ: arfcn in l1s_nb_cmd = %d\n", arfcn);
l1s_rx_win_ctrl(arfcn, L1_RXWIN_NB, 0);
return 0;

View File

@ -56,6 +56,9 @@
#include <l1ctl_proto.h>
/* FIXME: count of what? use better name */
static int count11 = 0;
static inline int msb_get_bit(uint8_t *buf, int bn)
{
int pos_byte = bn >> 3;
@ -213,6 +216,13 @@ static int l1s_tch_resp(__unused uint8_t p1, __unused uint8_t p2, uint16_t p3)
meas_id = (meas_id + 1) % FACCH_MEAS_HIST; /* absolute value doesn't matter */
count11++;
if (count11 == 20){
count11=0;
//printf("\nMTZ: arfcn in l1s_tch_resp = %d, sc = %d\n", arfcn, l1s.serving_cell.arfcn);
}
//printf("\nMTZ: arfcn in l1s_tch_resp = %d, sc = %d\n", arfcn, l1s.serving_cell.arfcn);
/* Collect measurements */
rx_tch.meas[meas_id].toa_qbit = dsp_api.db_r->a_serv_demod[D_TOA];
rx_tch.meas[meas_id].pm_dbm8 =
@ -258,6 +268,9 @@ static int l1s_tch_resp(__unused uint8_t p1, __unused uint8_t p2, uint16_t p3)
/* Allocate msgb */
/* FIXME: we actually want all allocation out of L1S! */
msg = l1ctl_msgb_alloc(L1CTL_DATA_IND);
//MTZ
//printf("\n\n\n---------------------------------\nFACCH\n---------------------------------\n\n\n");
//printf("\n\n\n---------------------------------\nFACCH\n---------------------------------\n\n\n");
if(!msg) {
printf("TCH FACCH: unable to allocate msgb\n");
goto skip_rx_facch;
@ -272,6 +285,8 @@ static int l1s_tch_resp(__unused uint8_t p1, __unused uint8_t p2, uint16_t p3)
dl->band_arfcn = htons(arfcn);
dl->frame_nr = htonl(rx_time.fn);
printf("\n\nMTZ: FACCH received - chan_nr=%x\n\n", chan_nr);
/* Average SNR & RX level */
n = tch_f_hn ? 8 : 6;
for (i=0; i<n; i++) {
@ -429,8 +444,10 @@ static int l1s_tch_cmd(__unused uint8_t p1, __unused uint8_t p2, uint16_t p3)
msg = NULL;
/* If TX is empty and we're signalling only, use dummy frame */
if (msg)
data = msg->l3h;
if (msg) { //MTZ
//printf("\n\n\n---------------------------------\nFACCH\n---------------------------------\n\n\n");
//printf("\n\n\n---------------------------------\nFACCH\n---------------------------------\n\n\n");
data = msg->l3h;}
else if (tch_mode == SIG_ONLY_MODE)
data = pu_get_idle_frame();
else
@ -533,8 +550,16 @@ skip_tx_traffic:
dsp_task_iq_swap(TCHT_DSP_TASK, arfcn, 0),
0, tsc /* burst_id unused for TCH */
);
//printf("\nMTZ: arfcn in l1s_tch_cmd = %d, sc = %d\n", arfcn, l1s.serving_cell.arfcn);
l1s_rx_win_ctrl(arfcn, L1_RXWIN_NB, 0);
/* stop here, if TX is disabled */
if (l1s.dedicated.rx_only)
return 0;
dsp_load_tx_task(
dsp_task_iq_swap(TCHT_DSP_TASK, arfcn, 1),
0, tsc /* burst_id unused for TCH */
@ -798,8 +823,14 @@ static int l1s_tch_a_cmd(__unused uint8_t p1, __unused uint8_t p2, uint16_t p3)
dsp_task_iq_swap(TCHA_DSP_TASK, arfcn, 0),
0, tsc /* burst_id unused for TCHA */
);
//printf("\nMTZ: arfcn in l1s_tch_a_cmd = %d, sc=%d\n", arfcn, l1s.serving_cell.arfcn);
l1s_rx_win_ctrl(arfcn, L1_RXWIN_NB, 0);
/* stop here, if TX is disabled */
if (l1s.dedicated.rx_only)
return 0;
dsp_load_tx_task(
dsp_task_iq_swap(TCHA_DSP_TASK, arfcn, 1),
0, tsc /* burst_id unused for TCHA */

View File

@ -125,6 +125,7 @@ static int l1s_tx_cmd(uint8_t p1, uint8_t burst_id, uint16_t p3)
burst_id, tsc
);
//printf("\nMTZ: arfcn in l1s_tx_cmd = %d, sc=%d\n", arfcn, l1s.serving_cell.arfcn);
l1s_tx_win_ctrl(arfcn | ARFCN_UPLINK, L1_TXWIN_NB, 0, 3);
return 0;

View File

@ -187,6 +187,8 @@ void l1s_reset_hw(void)
static int last_timestamp;
static int last_ts;
static inline void check_lost_frame(void)
{
int diff, timestamp = hwtimer_read(1);
@ -195,6 +197,26 @@ static inline void check_lost_frame(void)
last_timestamp += (4*TIMER_TICKS_PER_TDMA);
diff = last_timestamp - timestamp;
/* TS change compensation */
if (l1s.dedicated.type) {
if (l1s.dedicated.tn < last_ts) {
int ediff = ((8 - last_ts + l1s.dedicated.tn) * TIMER_TICKS_PER_TDMA) >> 3;
printf("TS Chg back: %d -> %d | %d %d\n",
last_ts, l1s.dedicated.tn, diff, ediff);
// if (((ediff - 2) < diff) && ((ediff + 2) > diff)) {
puts("ADV !\n");
l1s.current_time = l1s.next_time;
l1s_time_inc(&l1s.next_time, 1);
// }
} else if (l1s.dedicated.tn > last_ts)
printf("TS Chg forth: %d -> %d | %d\n",
last_ts, l1s.dedicated.tn, diff);
last_ts = l1s.dedicated.tn;
}
// } else
// last_ts = 0;
/* allow for a bit of jitter */
if (diff < TIMER_TICKS_PER_TDMA - TIMER_TICK_JITTER ||
@ -367,6 +389,7 @@ void l1s_reset(void)
/* Leave dedicated mode */
l1s.dedicated.type = GSM_DCHAN_NONE;
last_ts = 0;
/* reset scheduler and hardware */
sched_gsmtime_reset();
@ -382,10 +405,20 @@ void l1s_init(void)
{
unsigned int i;
for (i = 0; i < 64; i++) {
l1s.tpu_offsets_arfcn[i] = 0;
l1s.tpu_offsets[i] = 0;
l1s.nb_freq_diff[i] = 0;
l1s.nb_sb_freq_diff[i] = 0;
l1s.nb_sb_snr[i] = 0;
l1s.nb_frame_diff[i] = 0;
}
for (i = 0; i < ARRAY_SIZE(l1s.tx_queue); i++)
INIT_LLIST_HEAD(&l1s.tx_queue[i]);
l1s.tx_meas = NULL;
sched_gsmtime_init();
/* register FRAME interrupt as FIQ so it can interrupt normal IRQs */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,937 @@
/* Layer 1 - FCCH and SCH burst handling */
/* (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 <errno.h>
#include <inttypes.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/agc.h>
#include <l1ctl_proto.h>
#define FB0_RETRY_COUNT 3
#define AFC_RETRY_COUNT 30
extern uint16_t rf_arfcn; // TODO
struct mon_state {
uint32_t fnr_report; /* frame number when DSP reported it */
int attempt; /* which attempt was this ? */
int16_t toa;
uint16_t pm;
uint16_t angle;
uint16_t snr;
/* 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;
uint8_t fb_retries;
uint8_t afc_retries;
};
static struct l1a_fb_state fbs;
static struct mon_state *last_fb = &fbs.mon;
static int sb_det = 0; //MTZ - This was added
uint32_t old_tpu_offset = 0; //MTZ - This was added
int16_t nb_fb_toa = 0; //MTZ - This was added
uint16_t nb_fb_pm = 0; //MTZ - This was added
uint16_t nb_fb_angle = 0; //MTZ - This was added
uint16_t nb_fb_snr = 0; //MTZ - This was added
static void dump_mon_state(struct mon_state *fb)
{
#if 0
printf("(%"PRIu32":%u): TOA=%5u, Power=%4ddBm, Angle=%5dHz, "
"SNR=%04x(%d.%u) OFFSET=%u SYNCHRO=%u\n",
fb->fnr_report, fb->attempt, fb->toa,
agc_inp_dbm8_by_pm(fb->pm)/8, ANGLE_TO_FREQ(fb->angle),
fb->snr, l1s_snr_int(fb->snr), l1s_snr_fract(fb->snr),
tpu_get_offset(), tpu_get_synchro());
#else
printf("(%"PRIu32":%u): TOA=%5u, Power=%4ddBm, Angle=%5dHz\n",
fb->fnr_report, fb->attempt, fb->toa,
agc_inp_dbm8_by_pm(fb->pm)/8, ANGLE_TO_FREQ(fb->angle));
#endif
}
static int l1ctl_fbsb_resp(uint8_t res)
{
struct msgb *msg;
struct l1ctl_fbsb_conf *resp;
msg = l1_create_l2_msg(L1CTL_FBSB_CONF, fbs.mon.time.fn,
l1s_snr_int(fbs.mon.snr),
fbs.req.band_arfcn);
if (!msg)
return -ENOMEM;
resp = (struct l1ctl_fbsb_conf *) msgb_put(msg, sizeof(*resp));
resp->initial_freq_err = htons(fbs.initial_freq_err);
resp->result = res;
resp->bsic = fbs.mon.bsic;
/* no need to set BSIC, as it is never used here */
l1_queue_for_l2(msg);
return 0;
}
/* SCH Burst Detection ********************************************************/
/* determine the GSM time and BSIC from a Sync Burst */
static uint8_t l1s_decode_sb(struct gsm_time *time, uint32_t sb)
{
uint8_t bsic = (sb >> 2) & 0x3f;
uint8_t t3p;
memset(time, 0, sizeof(*time));
/* TS 05.02 Chapter 3.3.2.2.1 SCH Frame Numbers */
time->t1 = ((sb >> 23) & 1) | ((sb >> 7) & 0x1fe) | ((sb << 9) & 0x600);
time->t2 = (sb >> 18) & 0x1f;
t3p = ((sb >> 24) & 1) | ((sb >> 15) & 6);
time->t3 = t3p*10 + 1;
/* TS 05.02 Chapter 4.3.3 TDMA frame number */
time->fn = gsm_gsmtime2fn(time);
time->tc = (time->fn / 51) % 8;
return bsic;
}
static void read_sb_result(struct mon_state *st, int attempt)
{
st->toa = dsp_api.db_r->a_serv_demod[D_TOA];
st->pm = dsp_api.db_r->a_serv_demod[D_PM]>>3;
st->angle = dsp_api.db_r->a_serv_demod[D_ANGLE];
st->snr = dsp_api.db_r->a_serv_demod[D_SNR];
st->freq_diff = ANGLE_TO_FREQ(st->angle);
st->fnr_report = l1s.current_time.fn;
st->attempt = attempt;
dump_mon_state(st);
if (st->snr > AFC_SNR_THRESHOLD)
afc_input(st->freq_diff, rf_arfcn, 1);
else
afc_input(st->freq_diff, rf_arfcn, 0);
dsp_api.r_page_used = 1;
}
/* Note: When we get the SB response, it is 2 TDMA frames after the SB
* actually happened, as it is a "C W W R" task */
#define SB2_LATENCY 2
static int l1s_sbdet_resp(__unused uint8_t p1, uint8_t attempt,
__unused uint16_t p3)
{
uint32_t sb;
int qbits, fn_offset;
struct l1_cell_info *cinfo = &l1s.serving_cell;
int fnr_delta, bits_delta;
putchart('s');
if (dsp_api.db_r->a_sch[0] & (1<<B_SCH_CRC)) {
/* mark READ page as being used */
dsp_api.r_page_used = 1;
/* after 2nd attempt, we failed */
if (attempt == 2) {
last_fb->attempt = 13;
l1s_compl_sched(L1_COMPL_FB);
}
/* after 1st attempt, we simply wait for 2nd */
return 0;
}
printf("SB%d ", attempt);
read_sb_result(last_fb, attempt);
sb = dsp_api.db_r->a_sch[3] | dsp_api.db_r->a_sch[4] << 16;
fbs.mon.bsic = l1s_decode_sb(&fbs.mon.time, sb);
printf("=> SB 0x%08"PRIx32": BSIC=%u ", sb, fbs.mon.bsic);
l1s_time_dump(&fbs.mon.time);
l1s.serving_cell.bsic = fbs.mon.bsic;
/* calculate synchronisation value (TODO: only complete for qbits) */
last_fb->toa -= 23;
qbits = last_fb->toa * 4;
fn_offset = l1s.current_time.fn; // TODO
if (qbits > QBITS_PER_TDMA) {
qbits -= QBITS_PER_TDMA;
fn_offset -= 1;
} else if (qbits < 0) {
qbits += QBITS_PER_TDMA;
fn_offset += 1;
}
fnr_delta = last_fb->fnr_report - 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 SB in bit that is %d bits in the "
"future?!?\n", last_fb->toa - bits_delta);
else
printf(" qbits=%u\n", qbits);
synchronize_tdma(&l1s.serving_cell);
/* if we have recived a SYNC burst, update our local GSM time */
gsm_fn2gsmtime(&l1s.current_time, fbs.mon.time.fn + SB2_LATENCY);
/* compute next time from new current time */
l1s.next_time = l1s.current_time;
l1s_time_inc(&l1s.next_time, 1);
/* If we call tdma_sched_reset(), which is only needed if there
* are further l1s_sbdet_resp() scheduled, we will bring
* dsp_api.db_r and dsp_api.db_w out of sync because we changed
* dsp_api.db_w for l1s_sbdet_cmd() and canceled
* l1s_sbdet_resp() which would change dsp_api.db_r. The DSP
* however expects dsp_api.db_w and dsp_api.db_r to be in sync
* (either "0 - 0" or "1 - 1"). So we have to bring dsp_api.db_w
* and dsp_api.db_r into sync again, otherwise NB reading will
* complain. We probably don't need the Abort command and could
* just bring dsp_api.db_w and dsp_api.db_r into sync. */
if (attempt != 2) {
tdma_sched_reset();
l1s_dsp_abort();
}
l1s_reset_hw();
/* enable the MF Task for BCCH reading */
mframe_enable(MF_TASK_BCCH_NORM);
if (l1s.serving_cell.ccch_mode == CCCH_MODE_COMBINED)
mframe_enable(MF_TASK_CCCH_COMB);
else if (l1s.serving_cell.ccch_mode == CCCH_MODE_NON_COMBINED)
mframe_enable(MF_TASK_CCCH);
l1s_compl_sched(L1_COMPL_FB);
return 0;
}
static int l1s_sbdet_cmd(__unused uint8_t p1, __unused uint8_t p2,
__unused uint16_t p3)
{
putchart('S');
fbs.mon.bsic = 0;
fbs.mon.time.fn = 0;
dsp_api.db_w->d_task_md = SB_DSP_TASK;
dsp_api.ndb->d_fb_mode = 0; /* wideband search */
/* Program TPU */
l1s_rx_win_ctrl(rf_arfcn, L1_RXWIN_SB, 0);
return 0;
}
/* This is how it is done by the TSM30 */
static const struct tdma_sched_item sb_sched_set[] = {
SCHED_ITEM_DT(l1s_sbdet_cmd, 0, 0, 1), SCHED_END_FRAME(),
SCHED_ITEM_DT(l1s_sbdet_cmd, 0, 0, 2), SCHED_END_FRAME(),
SCHED_END_FRAME(),
SCHED_ITEM(l1s_sbdet_resp, -4, 0, 1), SCHED_END_FRAME(),
SCHED_ITEM(l1s_sbdet_resp, -4, 0, 2), SCHED_END_FRAME(),
SCHED_END_SET()
};
void l1s_sb_test(uint8_t base_fn)
{
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;
}
static void fbinfo2cellinfo(struct l1_cell_info *cinfo,
const struct mon_state *mon)
{
int ntdma, qbits, fn_offset, fnr_delta, bits_delta;
/* 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);
}
}
/* 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;
/* Tell the RF frontend to set the gain appropriately */
rffe_compute_gain(rxlev2dbm(fbs.req.rxlev_exp), CAL_DSP_TGT_BB_LVL);
/* 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;
/* Program TPU */
l1s_rx_win_ctrl(fbs.req.band_arfcn, L1_RXWIN_FB, 0);
return 0;
}
#if 0
#define FB0_SNR_THRESH 2000
#define FB1_SNR_THRESH 3000
#else
#define FB0_SNR_THRESH 0
#define FB1_SNR_THRESH 0
#endif
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 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();
if (fbs.fb_retries < FB0_RETRY_COUNT) {
/* retry once more */
tdma_schedule_set(1, fb_sched_set, 0);
fbs.fb_retries++;
} else {
last_fb->attempt = 13;
l1s_compl_sched(L1_COMPL_FB);
}
return 0;
}
/* 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;
/* 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 &&
last_fb->snr > FB0_SNR_THRESH) {
/* continue with FB1 task in DSP */
tdma_schedule_set(1, fb_sched_set, 1);
} else {
if (fbs.afc_retries < AFC_RETRY_COUNT) {
tdma_schedule_set(1, fb_sched_set, 0);
fbs.afc_retries++;
} else {
/* Abort */
last_fb->attempt = 13;
l1s_compl_sched(L1_COMPL_FB);
}
}
} 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;
printf(" fn_offset=%d (fn=%"PRIu32" + attempt=%u + ntdma = %d)\n",
fn_offset, l1s.current_time.fn, last_fb->attempt, ntdma);
printf(" delay=%d (fn_offset=%d + 11 - fn=%"PRIu32" - 1\n", delay,
fn_offset, l1s.current_time.fn);
printf(" scheduling next FB/SB detection task with delay %u\n", delay);
if (abs(last_fb->freq_diff) < fbs.req.freq_err_thresh2 &&
last_fb->snr > FB1_SNR_THRESH) {
/* synchronize before reading SB */
fbinfo2cellinfo(&l1s.serving_cell, last_fb);
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_DT(l1s_fbdet_cmd, 0, 0, 0), SCHED_END_FRAME(),
SCHED_END_FRAME(),
SCHED_ITEM(l1s_fbdet_resp, -4, 0, 1), SCHED_END_FRAME(),
SCHED_ITEM(l1s_fbdet_resp, -4, 0, 2), SCHED_END_FRAME(),
SCHED_ITEM(l1s_fbdet_resp, -4, 0, 3), SCHED_END_FRAME(),
SCHED_ITEM(l1s_fbdet_resp, -4, 0, 4), SCHED_END_FRAME(),
SCHED_ITEM(l1s_fbdet_resp, -4, 0, 5), SCHED_END_FRAME(),
SCHED_ITEM(l1s_fbdet_resp, -4, 0, 6), SCHED_END_FRAME(),
SCHED_ITEM(l1s_fbdet_resp, -4, 0, 7), SCHED_END_FRAME(),
SCHED_ITEM(l1s_fbdet_resp, -4, 0, 8), SCHED_END_FRAME(),
SCHED_ITEM(l1s_fbdet_resp, -4, 0, 9), SCHED_END_FRAME(),
SCHED_ITEM(l1s_fbdet_resp, -4, 0, 10), SCHED_END_FRAME(),
SCHED_ITEM(l1s_fbdet_resp, -4, 0, 11), SCHED_END_FRAME(),
SCHED_ITEM(l1s_fbdet_resp, -4, 0, 12), SCHED_END_FRAME(),
SCHED_END_SET()
};
/* Asynchronous completion handler for FB detection */
static void l1a_fb_compl(__unused enum l1_compl c)
{
if (last_fb->attempt >= 13) {
/* FB detection failed, signal this via L1CTL */
l1ctl_fbsb_resp(255);
return;
}
/* FIME: use l1s.neigh_cell[fbs.cinfo_idx] */
fbinfo2cellinfo(&l1s.serving_cell, last_fb);
/* send FBSB_CONF success message via L1CTL */
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;
fbs.req.rxlev_exp = req->rxlev_exp;
/* clear initial frequency error */
fbs.initial_freq_err = 0;
fbs.fb_retries = 0;
fbs.afc_retries = 0;
/* Make sure we start at a 'center' AFCDAC output value */
afc_reset();
/* Reset the TOA loop counters */
toa_reset();
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);
}
/* 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;
}
}
void synchronize_tdma2()
{
uint32_t tpu_shift;
int ntdma, qbits;
/* FIXME: where did this magic 23 come from? */
nb_fb_toa -= 23;
if (nb_fb_toa < 0) {
qbits = (nb_fb_toa + BITS_PER_TDMA) * 4;
ntdma = -1;
} else {
ntdma = (nb_fb_toa) / BITS_PER_TDMA;
qbits = (nb_fb_toa - ntdma * BITS_PER_TDMA) * 4;
}
tpu_shift = qbits;
old_tpu_offset = l1s.tpu_offset;
/* NB detection only works if the TOA of the SB
* is within 0...8. We have to add 75 to get an SB TOA of 4. */
tpu_shift += 75;
tpu_shift = (l1s.tpu_offset + tpu_shift) % QBITS_PER_TDMA;
//fn_offset = cinfo->fn_offset - 1;
/* if we're already very close to the end of the TPU frame, the
* next interrupt will basically occur now and we need to
* compensate */
//if (tpu_shift < SWITCH_TIME)
// fn_offset++;
//if (tpu_instr_test) { //MTZ - uncomment
l1s.tpu_offset = tpu_shift;
//puts("Synchronize_TDMA\n");
/* request the TPU to adjust the SYNCHRO and OFFSET registers */
tpu_enq_at(SWITCH_TIME);
tpu_enq_sync(l1s.tpu_offset);
//}
}
/* scheduler callback to issue a FB detection task to the DSP */
static int l1s_neigh_fb_cmd(__unused uint8_t p1, __unused uint8_t p2,
uint16_t fb_mode)
{
int index = l1s.neigh_sb.index;
uint8_t last_gain;
printf("\n\n\nMTZ: In neigh_fb_cmd, l1s.neigh_pm.n = %d\n\n\n", l1s.neigh_pm.n);
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();
}
index = 0; //MTZ - hardcoded - the above logic needs to be modified
if (sb_det == 0) {
//l1s.fb.mode = fb_mode;
//printf("detect FB arfcn %d (#%d) %d dbm\n", l1s.neigh_pm.band_arfcn[index], l1s.neigh_sb.count, rxlev2dbm(l1s.neigh_pm.level[index])); //MTZ - Uncomment
printf("detect FB arfcn %d (serving cell) (#%d) %d dbm\n", l1s.serving_cell.arfcn, l1s.neigh_sb.count, rxlev2dbm(fbs.req.rxlev_exp));
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); //MTZ- Uncomment
rffe_compute_gain(rxlev2dbm(fbs.req.rxlev_exp), CAL_DSP_TGT_BB_LVL);
/* Program DSP */
dsp_api.db_w->d_task_md = TCH_FB_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_FB26, 5);
//l1s_rx_win_ctrl(l1s.neigh_pm.band_arfcn[index], L1_RXWIN_FB26, 0);
l1s_rx_win_ctrl(l1s.serving_cell.arfcn, L1_RXWIN_FB26, 0); //MTZ - Uncomment
/* restore last gain */
rffe_set_gain(last_gain);
} else if (sb_det ==2) {
//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])); //Uncomment
printf("detect SB arfcn %d (serving cell) (#%d) %d dbm\n", l1s.serving_cell.arfcn, l1s.neigh_sb.count, rxlev2dbm(fbs.req.rxlev_exp));
synchronize_tdma2();
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); //MTZ - Uncomment
rffe_compute_gain(rxlev2dbm(fbs.req.rxlev_exp), 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;
//MTZ - Experimenting
dsp_api.ndb->a_sync_demod[D_TOA] = nb_fb_toa;
dsp_api.ndb->a_sync_demod[D_PM] = nb_fb_pm;
dsp_api.ndb->a_sync_demod[D_ANGLE] = nb_fb_angle;
dsp_api.ndb->a_sync_demod[D_SNR] = nb_fb_snr;
/* Program TPU */
//l1s_rx_win_ctrl(l1s.neigh_pm.band_arfcn[index], L1_RXWIN_SB26, 5);
//l1s_rx_win_ctrl(l1s.neigh_pm.band_arfcn[index], L1_RXWIN_SB26, 0);
l1s_rx_win_ctrl(l1s.serving_cell.arfcn, L1_RXWIN_SB26, 0);
/* restore last gain */
rffe_set_gain(last_gain);
l1s.neigh_sb.running = 1;
}
return 0;
}
/* scheduler callback to issue a FB detection task to the DSP */
static int l1s_neigh_fb_resp(__unused uint8_t p1, uint8_t attempt,
uint16_t fb_mode)
{
if (sb_det == 0) {
if (!dsp_api.ndb->d_fb_det) {
printf("\nMTZ: FB found = 0\n\n");
} else {
nb_fb_toa = dsp_api.ndb->a_sync_demod[D_TOA];
nb_fb_pm = dsp_api.ndb->a_sync_demod[D_PM];
nb_fb_angle = dsp_api.ndb->a_sync_demod[D_ANGLE];
nb_fb_snr = dsp_api.ndb->a_sync_demod[D_SNR];
printf("\nMTZ: FB found = 1, FB%u, nb_fb_toa = %d\n\n", dsp_api.ndb->d_fb_mode, nb_fb_toa);
sb_det = 1;
}
//l1s_reset_hw();
tdma_sched_reset();
} else {
if (sb_det == 2) {
/* check if sync was successful */
if (dsp_api.db_r->a_sch[0] & (1<<B_SCH_CRC)) {
printf("\nSB found1 = 0\n\n");
} else {
printf("\nSB found1 = 1\n\n");
}
if (dsp_api.ndb->a_sch26[0] & (1<<B_SCH_CRC)) {
printf("\nSB found2 = 0\n\n");
} else {
printf("\nSB found2 = 1\n\n");
}
l1s.neigh_sb.running = 0;
dsp_api.r_page_used = 1;
//if (tpu_instr_test) {
l1s.tpu_offset = old_tpu_offset;
tpu_enq_at(SWITCH_TIME);
tpu_enq_sync(l1s.tpu_offset);
//}
}
sb_det++;
if (sb_det == 3)
sb_det = 0;
}
return 0;
}
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;
printf("\n\n\nMTZ: In neigh_sb_cmd, l1s.neigh_pm.n = %d\n\n\n", l1s.neigh_pm.n);
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) {
if (++l1s.neigh_sb.count == 35) {
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()
//};
/* 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_fb_cmd, 1, 0, 1), SCHED_END_FRAME(),
SCHED_END_FRAME(),
SCHED_END_FRAME(),
SCHED_ITEM(l1s_neigh_fb_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;
}

View File

@ -47,7 +47,9 @@
#define L1_NB_DURATION_Q (L1_BURST_LENGTH_Q + 2 * L1_NB_MARGIN_Q - L1_TAIL_DURATION_Q)
#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_FB26_DURATION_Q (L1_TDMA_LENGTH_Q + 798)
#define L1_FB26_DURATION_Q (2*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 +59,8 @@ 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_FB26] = L1_FB26_DURATION_Q,
[L1_RXWIN_SB26] = L1_SB26_DURATION_Q,
};
#define L1_TX_NB_DURATION_Q 626
@ -129,6 +133,15 @@ void l1s_rx_win_ctrl(uint16_t arfcn, enum l1_rxwin_type wtype, uint8_t tn_ofs)
stop -= 11 * L1_TDMA_LENGTH_Q;
}
/* Delay 11 full TDMA frames */
if (wtype == L1_RXWIN_FB26) {
uint8_t i;
for (i = 0; i < 2; i++)
tpu_enq_at(0);
stop -= 2 * L1_TDMA_LENGTH_Q;
}
/* Window close for ABB */
twl3025_downlink(0, stop & 0xffff);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff