From 5fc544f90135ed0dc34e35c9f1bc4420ccc654ed Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Wed, 12 Jun 2013 16:57:20 +0200 Subject: [PATCH] Add handover support to calypso BTS --- include/l1ctl_proto.h | 2 + src/host/layer23/src/transceiver/l1ctl.c | 7 +- src/host/layer23/src/transceiver/l1ctl.h | 2 +- src/host/layer23/src/transceiver/trx.c | 48 +++++++++++- src/host/layer23/src/transceiver/trx.h | 1 + src/target/firmware/Makefile | 2 + src/target/firmware/include/layer1/sync.h | 1 + src/target/firmware/layer1/l23_api.c | 4 +- src/target/firmware/layer1/prim_bts.c | 92 ++++++++++++++++++----- 9 files changed, 130 insertions(+), 29 deletions(-) diff --git a/include/l1ctl_proto.h b/include/l1ctl_proto.h index 4aa3ad761..8d5061543 100644 --- a/include/l1ctl_proto.h +++ b/include/l1ctl_proto.h @@ -313,6 +313,7 @@ struct l1ctl_bts_mode { uint8_t tx_mask; uint8_t rx_mask; uint8_t type[8]; + uint8_t handover[8]; uint8_t bsic; uint16_t band_arfcn; uint8_t gain; @@ -338,6 +339,7 @@ struct l1ctl_bts_burst_nb_ind { /* BTS mode: AB Burst Indication */ struct l1ctl_bts_burst_ab_ind { uint32_t fn; + uint8_t tn; uint8_t toa; uint8_t iq[2*88]; } __attribute__((packed)); diff --git a/src/host/layer23/src/transceiver/l1ctl.c b/src/host/layer23/src/transceiver/l1ctl.c index 494d6ad51..5bcabe3f0 100644 --- a/src/host/layer23/src/transceiver/l1ctl.c +++ b/src/host/layer23/src/transceiver/l1ctl.c @@ -117,7 +117,7 @@ l1ctl_tx_fbsb_req(struct l1ctl_link *l1l, int l1ctl_tx_bts_mode(struct l1ctl_link *l1l, uint8_t enabled, uint8_t *type, uint8_t bsic, uint16_t band_arfcn, int gain, uint8_t tx_mask, - uint8_t rx_mask) + uint8_t rx_mask, uint8_t *handover) { struct msgb *msg; struct l1ctl_bts_mode *be; @@ -142,6 +142,7 @@ l1ctl_tx_bts_mode(struct l1ctl_link *l1l, uint8_t enabled, uint8_t *type, be->gain = gain; be->tx_mask = tx_mask; be->rx_mask = rx_mask; + memcpy(be->handover, handover, sizeof(be->handover)); return l1l_send(l1l, msg); } @@ -252,7 +253,7 @@ _l1ctl_rx_bts_burst_ab_ind(struct l1ctl_link *l1l, struct msgb *msg) LOGP(DL1C, LOGL_INFO, "Access Burst Indication (fn=%d iq toa=%f)\n", fn, toa); - trx_data_ind(l1l->trx, fn, 0, data, toa, 0); + trx_data_ind(l1l->trx, fn, bi->tn, data, toa, 0); exit: msgb_free(msg); @@ -336,7 +337,7 @@ _l1ctl_rx_fbsb_conf(struct l1ctl_link *l1l, struct msgb *msg) } else { LOGP(DAPP, LOGL_INFO, "Sync acquired, setting BTS mode ...\n"); l1l->sync = 1; - l1ctl_tx_bts_mode(l1l, l1l->trx->power, l1l->trx->type, l1l->trx->bsic, l1l->trx->arfcn, l1l->trx->gain, l1l->tx_mask, l1l->rx_mask); + l1ctl_tx_bts_mode(l1l, l1l->trx->power, l1l->trx->type, l1l->trx->bsic, l1l->trx->arfcn, l1l->trx->gain, l1l->tx_mask, l1l->rx_mask, l1l->trx->handover); } rc = 0; diff --git a/src/host/layer23/src/transceiver/l1ctl.h b/src/host/layer23/src/transceiver/l1ctl.h index 31d69037c..07f79990e 100644 --- a/src/host/layer23/src/transceiver/l1ctl.h +++ b/src/host/layer23/src/transceiver/l1ctl.h @@ -40,7 +40,7 @@ int l1ctl_tx_fbsb_req(struct l1ctl_link *l1l, uint8_t sync_info_idx, uint8_t ccch_mode); int l1ctl_tx_bts_mode(struct l1ctl_link *l1l, uint8_t enabled, uint8_t *type, uint8_t bsic, uint16_t band_arfcn, int gain, uint8_t tx_mask, - uint8_t rx_mask); + uint8_t rx_mask, uint8_t *handover); int l1ctl_tx_bts_burst_req(struct l1ctl_link *l1l, uint32_t fn, uint8_t tn, struct burst_data *burst); diff --git a/src/host/layer23/src/transceiver/trx.c b/src/host/layer23/src/transceiver/trx.c index ec50b89e8..8432dcae2 100644 --- a/src/host/layer23/src/transceiver/trx.c +++ b/src/host/layer23/src/transceiver/trx.c @@ -236,7 +236,7 @@ _trx_ctrl_cmd_poweroff(struct trx *trx, const char *cmd, const char *args) trx->power = 0; for (i = 0; i < 8; i++) if (trx->l1l[i]) - l1ctl_tx_bts_mode(trx->l1l[i], 0, trx->type, 0, 0, 0, 0, 0); + l1ctl_tx_bts_mode(trx->l1l[i], 0, trx->type, 0, 0, 0, 0, 0, trx->handover); return _trx_ctrl_send_resp(trx, cmd, "%d", 0); } @@ -253,9 +253,10 @@ _trx_ctrl_cmd_poweron(struct trx *trx, const char *cmd, const char *args) rv = -EINVAL; } else { trx->power = 1; + memset(trx->handover, 0, sizeof(trx->handover)); for (i = 0; i < 8; i++) if (trx->l1l[i]) - l1ctl_tx_bts_mode(trx->l1l[i], 1, trx->type, trx->bsic, trx->arfcn, trx->gain, trx->l1l[i]->tx_mask, trx->l1l[i]->rx_mask); + l1ctl_tx_bts_mode(trx->l1l[i], 1, trx->type, trx->bsic, trx->arfcn, trx->gain, trx->l1l[i]->tx_mask, trx->l1l[i]->rx_mask, trx->handover); } return _trx_ctrl_send_resp(trx, cmd, "%d", rv); @@ -302,7 +303,7 @@ _trx_ctrl_cmd_setrxgain(struct trx *trx, const char *cmd, const char *args) if (trx->power) { for (i = 0; i < 8; i++) if (trx->l1l[i]) - l1ctl_tx_bts_mode(trx->l1l[i], 1, trx->type, trx->bsic, trx->arfcn, trx->gain, trx->l1l[i]->tx_mask, trx->l1l[i]->rx_mask); + l1ctl_tx_bts_mode(trx->l1l[i], 1, trx->type, trx->bsic, trx->arfcn, trx->gain, trx->l1l[i]->tx_mask, trx->l1l[i]->rx_mask, trx->handover); } return _trx_ctrl_send_resp(trx, cmd, "%d %d", 0, db); @@ -337,7 +338,7 @@ _trx_ctrl_cmd_setslot(struct trx *trx, const char *cmd, const char *args) trx->type[tn] = type; if (trx->l1l[tn]) - l1ctl_tx_bts_mode(trx->l1l[tn], 1, trx->type, trx->bsic, trx->arfcn, trx->gain, trx->l1l[tn]->tx_mask, trx->l1l[tn]->rx_mask); + l1ctl_tx_bts_mode(trx->l1l[tn], 1, trx->type, trx->bsic, trx->arfcn, trx->gain, trx->l1l[tn]->tx_mask, trx->l1l[tn]->rx_mask, trx->handover); return _trx_ctrl_send_resp(trx, cmd, "%d %d", 0, type); } @@ -395,6 +396,42 @@ done: return _trx_ctrl_send_resp(trx, cmd, "%d %d", rv, freq_khz); } +static int +_trx_ctrl_cmd_handover(struct trx *trx, const char *cmd, const char *args) +{ + int n, tn, ss = 0; + + n = sscanf(args, "%d %d", &tn, &ss); + + if ((n < 1) || (tn < 0) || (tn > 7) || (ss < 0) || ((ss > 8))) + return _trx_ctrl_send_resp(trx, cmd, "%d %d %d", -1, tn, ss); + + trx->handover[tn] |= (1 << ss); + + if (trx->l1l[tn]) + l1ctl_tx_bts_mode(trx->l1l[tn], 1, trx->type, trx->bsic, trx->arfcn, trx->gain, trx->l1l[tn]->tx_mask, trx->l1l[tn]->rx_mask, trx->handover); + + return _trx_ctrl_send_resp(trx, cmd, "%d %d %d", 0, tn, ss); +} + +static int +_trx_ctrl_cmd_nohandover(struct trx *trx, const char *cmd, const char *args) +{ + int n, tn, ss = 0; + + n = sscanf(args, "%d %d", &tn, &ss); + + if ((n < 1) || (tn < 0) || (tn > 7) || (ss < 0) || ((ss > 8))) + return _trx_ctrl_send_resp(trx, cmd, "%d %d %d", -1, tn, ss); + + trx->handover[tn] &= ~(1 << ss); + + if (trx->l1l[tn]) + l1ctl_tx_bts_mode(trx->l1l[tn], 1, trx->type, trx->bsic, trx->arfcn, trx->gain, trx->l1l[tn]->tx_mask, trx->l1l[tn]->rx_mask, trx->handover); + + return _trx_ctrl_send_resp(trx, cmd, "%d %d %d", 0, tn, ss); +} + struct trx_cmd_handler { const char *cmd; int (*handler)(struct trx *trx, const char *cmd, const char *args); @@ -409,8 +446,11 @@ static const struct trx_cmd_handler trx_handlers[] = { { "SETRXGAIN", _trx_ctrl_cmd_setrxgain }, { "SETMAXDLY", _trx_ctrl_cmd_setmaxdly }, { "SETSLOT", _trx_ctrl_cmd_setslot }, + { "SETSLOT", _trx_ctrl_cmd_setslot }, { "RXTUNE", _trx_ctrl_cmd_rxtune }, { "TXTUNE", _trx_ctrl_cmd_txtune }, + { "HANDOVER", _trx_ctrl_cmd_handover }, + { "NOHANDOVER", _trx_ctrl_cmd_nohandover }, { NULL, NULL } }; diff --git a/src/host/layer23/src/transceiver/trx.h b/src/host/layer23/src/transceiver/trx.h index 65816c6d5..d5c40e7f8 100644 --- a/src/host/layer23/src/transceiver/trx.h +++ b/src/host/layer23/src/transceiver/trx.h @@ -54,6 +54,7 @@ struct trx { uint8_t bsic; int gain; uint8_t type[8]; + uint8_t handover[8]; }; diff --git a/src/target/firmware/Makefile b/src/target/firmware/Makefile index 9b02033b1..5303d3d21 100644 --- a/src/target/firmware/Makefile +++ b/src/target/firmware/Makefile @@ -89,6 +89,8 @@ APPLICATIONS?=hello_world compal_dsp_dump layer1 loader rssi trx # Applications specific env requirements APP_loader_ENVIRONMENTS=compalram highram APP_rssi_ENVIRONMENTS=* -compalram +APP_layer1_ENVIRONMENTS=* -compalram +APP_trx_ENVIRONMENTS=* -compalram # Various objects that are currently linked into all applications FLASH_OBJS=flash/cfi_flash.o diff --git a/src/target/firmware/include/layer1/sync.h b/src/target/firmware/include/layer1/sync.h index 51fec14cb..db6f1b464 100644 --- a/src/target/firmware/include/layer1/sync.h +++ b/src/target/firmware/include/layer1/sync.h @@ -160,6 +160,7 @@ struct l1s_state { uint8_t tx_start, tx_num; uint8_t rx_start, rx_num; uint8_t type[8]; + uint8_t handover[8]; uint16_t arfcn; uint8_t bsic; uint8_t gain; diff --git a/src/target/firmware/layer1/l23_api.c b/src/target/firmware/layer1/l23_api.c index 78ae2e445..6841f80e4 100644 --- a/src/target/firmware/layer1/l23_api.c +++ b/src/target/firmware/layer1/l23_api.c @@ -609,8 +609,10 @@ static int l1ctl_bts_mode(struct msgb *msg) mframe_enable(MF_TASK_BTS_SYNC); mframe_enable(MF_TASK_BTS); - for (i = 0; i < 8; i++) + for (i = 0; i < 8; i++) { l1s.bts.type[i] = bm->type[i]; + l1s.bts.handover[i] = bm->handover[i]; + } l1s.bts.gain = bm->gain; /* Calculate TX and RX windows by bit masks */ diff --git a/src/target/firmware/layer1/prim_bts.c b/src/target/firmware/layer1/prim_bts.c index 5564f8035..91b18dc62 100644 --- a/src/target/firmware/layer1/prim_bts.c +++ b/src/target/firmware/layer1/prim_bts.c @@ -117,6 +117,20 @@ sb_build(uint8_t bsic, uint16_t t1, uint8_t t2, uint8_t t3p) ((bsic & 0x3f) << 2); } +static uint8_t tchh_subslot[26] = + { 0,1,0,1,0,1,0,1,0,1,0,1,0,0,1,0,1,0,1,0,1,0,1,0,1,1 }; +static uint8_t sdcch4_subslot[102] = + { 3,3,3,3,0,0,2,2,2,2,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,2,2,2,2, + 3,3,3,3,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,2,2,2,2 }; +static uint8_t sdcch8_subslot[102] = + { 5,5,5,5,6,6,6,6,7,7,7,7,0,0,0,0,0,0,0,1,1,1,1,2,2,2, + 2,3,3,3,3,4,4,4,4,5,5,5,5,6,6,6,6,7,7,7,7,0,0,0,0, + 1,1,1,1,2,2,2,2,3,3,3,3,0,0,0,0,0,0,0,1,1,1,1,2,2,2, + 2,3,3,3,3,4,4,4,4,5,5,5,5,6,6,6,6,7,7,7,7,4,4,4,4 }; + + static int l1s_bts_resp(uint8_t p1, uint8_t p2, uint16_t p3) @@ -135,17 +149,21 @@ l1s_bts_resp(uint8_t p1, uint8_t p2, uint16_t p3) /* Access Burst ? */ if (db->rx[0].cmd == DSP_EXT_RX_CMD_AB) { - static struct l1ctl_bts_burst_ab_ind _bi[51]; - static int energy[51]; - struct l1ctl_bts_burst_ab_ind *bi = &_bi[rx_time.t3]; + static int burst_count = 0; + static struct l1ctl_bts_burst_ab_ind _bi[10]; + static int energy[10]; + struct l1ctl_bts_burst_ab_ind *bi = &_bi[burst_count]; int i, j; uint16_t *iq = &db->data[32]; - energy[rx_time.t3] = 0; + energy[burst_count] = 0; /* Frame number */ bi->fn = htonl(rx_time.fn); + /* Timeslot */ + bi->tn = l1s.bts.rx_start; + /* Data (cut to 8 bits */ bi->toa = db->rx[1].cmd; if (bi->toa > 68) @@ -154,15 +172,17 @@ l1s_bts_resp(uint8_t p1, uint8_t p2, uint16_t p3) bi->iq[i] = iq[j] >> 8; /* energy */ - energy[rx_time.t3] = db->rx[0].data; + energy[burst_count] = db->rx[0].data; - if (rx_time.t3 == 46) { + if (++burst_count == 10) { struct msgb *msg; int energy_max = 0, energy_avg = 0; - /* find strongest burst */ + burst_count = 0; + + /* find strongest burst out of 10 */ j = 0; - for (i = 0; i < 51; i++) { + for (i = 0; i < 10; i++) { energy_avg += energy[i]; if (energy[i] > energy_max) { energy_max = energy[i]; @@ -255,7 +275,7 @@ l1s_bts_cmd(uint8_t p1, uint8_t p2, uint16_t p3) uint32_t sb; uint8_t data[15]; - int type, i, t3; + int type, i, t3, fn_mod_26, fn_mod_102; /* Enable extensions */ dsp_ext_api.ndb->active = 1; @@ -276,20 +296,52 @@ l1s_bts_cmd(uint8_t p1, uint8_t p2, uint16_t p3) { /* We're really a frame in advance since we RX in the next frame ! */ t3 = t3 - 1; + fn_mod_26 = (l1s.next_time.fn + 2715648 - 1) % 26; + fn_mod_102 = (l1s.next_time.fn + 2715648 - 1) % 102; /* Select which type of burst */ - if ((l1s.bts.type[l1s.bts.rx_start] >> 1) != 2) /* not type 4,5 */ - db->rx[0].cmd = DSP_EXT_RX_CMD_NB; - else if (l1s.bts.type[0] == 4) /* type 4 */ - db->rx[0].cmd = DSP_EXT_RX_CMD_AB; - else if ((t3 >= 14) && (t3 <= 36)) - db->rx[0].cmd = DSP_EXT_RX_CMD_AB; - else if ((t3 == 4) || (t3 == 5)) - db->rx[0].cmd = DSP_EXT_RX_CMD_AB; - else if ((t3 == 45) || (t3 == 46)) - db->rx[0].cmd = DSP_EXT_RX_CMD_AB; - else + switch (l1s.bts.type[l1s.bts.rx_start]) { + case 1: /* TCH/F */ + if (l1s.bts.handover[l1s.bts.rx_start] & (1 << 0)) + db->rx[0].cmd = DSP_EXT_RX_CMD_AB; + else + db->rx[0].cmd = DSP_EXT_RX_CMD_NB; + break; + case 2: /* TCH/H */ + case 3: + if ((l1s.bts.handover[l1s.bts.rx_start] + & (1 << tchh_subslot[fn_mod_26]))) + db->rx[0].cmd = DSP_EXT_RX_CMD_AB; + else + db->rx[0].cmd = DSP_EXT_RX_CMD_NB; + break; + case 4: + case 6: + db->rx[0].cmd = DSP_EXT_RX_CMD_AB; + break; + case 5: /* BCCH+SDCCH/4 */ + if ((t3 >= 14) && (t3 <= 36)) + db->rx[0].cmd = DSP_EXT_RX_CMD_AB; + else if ((t3 == 4) || (t3 == 5)) + db->rx[0].cmd = DSP_EXT_RX_CMD_AB; + else if ((t3 == 45) || (t3 == 46)) + db->rx[0].cmd = DSP_EXT_RX_CMD_AB; + else if ((l1s.bts.handover[l1s.bts.rx_start] + & (1 << sdcch4_subslot[fn_mod_102]))) + db->rx[0].cmd = DSP_EXT_RX_CMD_AB; + else + db->rx[0].cmd = DSP_EXT_RX_CMD_NB; + break; + case 7: /* SDCCH/8 */ + if ((l1s.bts.handover[l1s.bts.rx_start] + & (1 << sdcch8_subslot[fn_mod_102]))) + db->rx[0].cmd = DSP_EXT_RX_CMD_AB; + else + db->rx[0].cmd = DSP_EXT_RX_CMD_NB; + break; + default: db->rx[0].cmd = DSP_EXT_RX_CMD_NB; + } /* Enable dummy bursts detection */ dsp_api.db_w->d_ctrl_system |= (1 << B_BCCH_FREQ_IND);