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 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));

View File

@ -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;

View File

@ -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);

View File

@ -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 }
};

View File

@ -54,6 +54,7 @@ struct trx {
uint8_t bsic;
int gain;
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
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

View File

@ -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;

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);
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 */

View File

@ -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);