Add handover support to calypso BTS
This commit is contained in:
parent
c736754345
commit
5fc544f901
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 }
|
||||
};
|
||||
|
||||
|
|
|
@ -54,6 +54,7 @@ struct trx {
|
|||
uint8_t bsic;
|
||||
int gain;
|
||||
uint8_t type[8];
|
||||
uint8_t handover[8];
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue