Add handover support to calypso BTS

This commit is contained in:
Andreas Eversberg 2013-06-12 16:57:20 +02:00
parent c736754345
commit 5fc544f901
9 changed files with 130 additions and 29 deletions

View File

@ -313,6 +313,7 @@ struct l1ctl_bts_mode {
uint8_t tx_mask; uint8_t tx_mask;
uint8_t rx_mask; uint8_t rx_mask;
uint8_t type[8]; uint8_t type[8];
uint8_t handover[8];
uint8_t bsic; uint8_t bsic;
uint16_t band_arfcn; uint16_t band_arfcn;
uint8_t gain; uint8_t gain;
@ -338,6 +339,7 @@ struct l1ctl_bts_burst_nb_ind {
/* BTS mode: AB Burst Indication */ /* BTS mode: AB Burst Indication */
struct l1ctl_bts_burst_ab_ind { struct l1ctl_bts_burst_ab_ind {
uint32_t fn; uint32_t fn;
uint8_t tn;
uint8_t toa; uint8_t toa;
uint8_t iq[2*88]; uint8_t iq[2*88];
} __attribute__((packed)); } __attribute__((packed));

View File

@ -117,7 +117,7 @@ l1ctl_tx_fbsb_req(struct l1ctl_link *l1l,
int int
l1ctl_tx_bts_mode(struct l1ctl_link *l1l, uint8_t enabled, uint8_t *type, 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 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 msgb *msg;
struct l1ctl_bts_mode *be; 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->gain = gain;
be->tx_mask = tx_mask; be->tx_mask = tx_mask;
be->rx_mask = rx_mask; be->rx_mask = rx_mask;
memcpy(be->handover, handover, sizeof(be->handover));
return l1l_send(l1l, msg); 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); 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: exit:
msgb_free(msg); msgb_free(msg);
@ -336,7 +337,7 @@ _l1ctl_rx_fbsb_conf(struct l1ctl_link *l1l, struct msgb *msg)
} else { } else {
LOGP(DAPP, LOGL_INFO, "Sync acquired, setting BTS mode ...\n"); LOGP(DAPP, LOGL_INFO, "Sync acquired, setting BTS mode ...\n");
l1l->sync = 1; 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; rc = 0;

View File

@ -40,7 +40,7 @@ int l1ctl_tx_fbsb_req(struct l1ctl_link *l1l,
uint8_t sync_info_idx, uint8_t ccch_mode); uint8_t sync_info_idx, uint8_t ccch_mode);
int l1ctl_tx_bts_mode(struct l1ctl_link *l1l, uint8_t enabled, uint8_t *type, 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 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, int l1ctl_tx_bts_burst_req(struct l1ctl_link *l1l,
uint32_t fn, uint8_t tn, struct burst_data *burst); uint32_t fn, uint8_t tn, struct burst_data *burst);

View File

@ -236,7 +236,7 @@ _trx_ctrl_cmd_poweroff(struct trx *trx, const char *cmd, const char *args)
trx->power = 0; trx->power = 0;
for (i = 0; i < 8; i++) for (i = 0; i < 8; i++)
if (trx->l1l[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); 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; rv = -EINVAL;
} else { } else {
trx->power = 1; trx->power = 1;
memset(trx->handover, 0, sizeof(trx->handover));
for (i = 0; i < 8; i++) for (i = 0; i < 8; i++)
if (trx->l1l[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); 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) { if (trx->power) {
for (i = 0; i < 8; i++) for (i = 0; i < 8; i++)
if (trx->l1l[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); 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; trx->type[tn] = type;
if (trx->l1l[tn]) 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); 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); 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 { struct trx_cmd_handler {
const char *cmd; const char *cmd;
int (*handler)(struct trx *trx, const char *cmd, const char *args); 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 }, { "SETRXGAIN", _trx_ctrl_cmd_setrxgain },
{ "SETMAXDLY", _trx_ctrl_cmd_setmaxdly }, { "SETMAXDLY", _trx_ctrl_cmd_setmaxdly },
{ "SETSLOT", _trx_ctrl_cmd_setslot }, { "SETSLOT", _trx_ctrl_cmd_setslot },
{ "SETSLOT", _trx_ctrl_cmd_setslot },
{ "RXTUNE", _trx_ctrl_cmd_rxtune }, { "RXTUNE", _trx_ctrl_cmd_rxtune },
{ "TXTUNE", _trx_ctrl_cmd_txtune }, { "TXTUNE", _trx_ctrl_cmd_txtune },
{ "HANDOVER", _trx_ctrl_cmd_handover },
{ "NOHANDOVER", _trx_ctrl_cmd_nohandover },
{ NULL, NULL } { NULL, NULL }
}; };

View File

@ -54,6 +54,7 @@ struct trx {
uint8_t bsic; uint8_t bsic;
int gain; int gain;
uint8_t type[8]; uint8_t type[8];
uint8_t handover[8];
}; };

View File

@ -89,6 +89,8 @@ APPLICATIONS?=hello_world compal_dsp_dump layer1 loader rssi trx
# Applications specific env requirements # Applications specific env requirements
APP_loader_ENVIRONMENTS=compalram highram APP_loader_ENVIRONMENTS=compalram highram
APP_rssi_ENVIRONMENTS=* -compalram APP_rssi_ENVIRONMENTS=* -compalram
APP_layer1_ENVIRONMENTS=* -compalram
APP_trx_ENVIRONMENTS=* -compalram
# Various objects that are currently linked into all applications # Various objects that are currently linked into all applications
FLASH_OBJS=flash/cfi_flash.o FLASH_OBJS=flash/cfi_flash.o

View File

@ -160,6 +160,7 @@ struct l1s_state {
uint8_t tx_start, tx_num; uint8_t tx_start, tx_num;
uint8_t rx_start, rx_num; uint8_t rx_start, rx_num;
uint8_t type[8]; uint8_t type[8];
uint8_t handover[8];
uint16_t arfcn; uint16_t arfcn;
uint8_t bsic; uint8_t bsic;
uint8_t gain; uint8_t gain;

View File

@ -609,8 +609,10 @@ static int l1ctl_bts_mode(struct msgb *msg)
mframe_enable(MF_TASK_BTS_SYNC); mframe_enable(MF_TASK_BTS_SYNC);
mframe_enable(MF_TASK_BTS); 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.type[i] = bm->type[i];
l1s.bts.handover[i] = bm->handover[i];
}
l1s.bts.gain = bm->gain; l1s.bts.gain = bm->gain;
/* Calculate TX and RX windows by bit masks */ /* Calculate TX and RX windows by bit masks */

View File

@ -117,6 +117,20 @@ sb_build(uint8_t bsic, uint16_t t1, uint8_t t2, uint8_t t3p)
((bsic & 0x3f) << 2); ((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 static int
l1s_bts_resp(uint8_t p1, uint8_t p2, uint16_t p3) 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 ? */ /* Access Burst ? */
if (db->rx[0].cmd == DSP_EXT_RX_CMD_AB) if (db->rx[0].cmd == DSP_EXT_RX_CMD_AB)
{ {
static struct l1ctl_bts_burst_ab_ind _bi[51]; static int burst_count = 0;
static int energy[51]; static struct l1ctl_bts_burst_ab_ind _bi[10];
struct l1ctl_bts_burst_ab_ind *bi = &_bi[rx_time.t3]; static int energy[10];
struct l1ctl_bts_burst_ab_ind *bi = &_bi[burst_count];
int i, j; int i, j;
uint16_t *iq = &db->data[32]; uint16_t *iq = &db->data[32];
energy[rx_time.t3] = 0; energy[burst_count] = 0;
/* Frame number */ /* Frame number */
bi->fn = htonl(rx_time.fn); bi->fn = htonl(rx_time.fn);
/* Timeslot */
bi->tn = l1s.bts.rx_start;
/* Data (cut to 8 bits */ /* Data (cut to 8 bits */
bi->toa = db->rx[1].cmd; bi->toa = db->rx[1].cmd;
if (bi->toa > 68) 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; bi->iq[i] = iq[j] >> 8;
/* energy */ /* 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; struct msgb *msg;
int energy_max = 0, energy_avg = 0; int energy_max = 0, energy_avg = 0;
/* find strongest burst */ burst_count = 0;
/* find strongest burst out of 10 */
j = 0; j = 0;
for (i = 0; i < 51; i++) { for (i = 0; i < 10; i++) {
energy_avg += energy[i]; energy_avg += energy[i];
if (energy[i] > energy_max) { if (energy[i] > energy_max) {
energy_max = energy[i]; energy_max = energy[i];
@ -255,7 +275,7 @@ l1s_bts_cmd(uint8_t p1, uint8_t p2, uint16_t p3)
uint32_t sb; uint32_t sb;
uint8_t data[15]; uint8_t data[15];
int type, i, t3; int type, i, t3, fn_mod_26, fn_mod_102;
/* Enable extensions */ /* Enable extensions */
dsp_ext_api.ndb->active = 1; 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 ! */ /* We're really a frame in advance since we RX in the next frame ! */
t3 = t3 - 1; 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 */ /* Select which type of burst */
if ((l1s.bts.type[l1s.bts.rx_start] >> 1) != 2) /* not type 4,5 */ switch (l1s.bts.type[l1s.bts.rx_start]) {
db->rx[0].cmd = DSP_EXT_RX_CMD_NB; case 1: /* TCH/F */
else if (l1s.bts.type[0] == 4) /* type 4 */ if (l1s.bts.handover[l1s.bts.rx_start] & (1 << 0))
db->rx[0].cmd = DSP_EXT_RX_CMD_AB; db->rx[0].cmd = DSP_EXT_RX_CMD_AB;
else if ((t3 >= 14) && (t3 <= 36)) else
db->rx[0].cmd = DSP_EXT_RX_CMD_AB; db->rx[0].cmd = DSP_EXT_RX_CMD_NB;
else if ((t3 == 4) || (t3 == 5)) break;
db->rx[0].cmd = DSP_EXT_RX_CMD_AB; case 2: /* TCH/H */
else if ((t3 == 45) || (t3 == 46)) case 3:
db->rx[0].cmd = DSP_EXT_RX_CMD_AB; if ((l1s.bts.handover[l1s.bts.rx_start]
else & (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; db->rx[0].cmd = DSP_EXT_RX_CMD_NB;
}
/* Enable dummy bursts detection */ /* Enable dummy bursts detection */
dsp_api.db_w->d_ctrl_system |= (1 << B_BCCH_FREQ_IND); dsp_api.db_w->d_ctrl_system |= (1 << B_BCCH_FREQ_IND);