OM2000: Add support for sending TX, RX and TS configuration requests

They can be triggered from the VTY
This commit is contained in:
Harald Welte 2011-03-05 14:13:14 +01:00
parent c08e8be4ee
commit a0ce349f0c
3 changed files with 244 additions and 13 deletions

View File

@ -22,6 +22,18 @@
*
*/
enum abis_om2k_mo_cls {
OM2K_MO_CLS_TRXC = 0x01,
OM2K_MO_CLS_TS = 0x03,
OM2K_MO_CLS_TF = 0x04,
OM2K_MO_CLS_IS = 0x05,
OM2K_MO_CLS_CON = 0x06,
OM2K_MO_CLS_DP = 0x07,
OM2K_MO_CLS_CF = 0x0a,
OM2K_MO_CLS_TX = 0x0b,
OM2K_MO_CLS_RX = 0x0c,
};
struct abis_om2k_mo {
uint8_t class;
uint8_t bts;
@ -53,6 +65,9 @@ int abis_om2k_tx_op_info(struct gsm_bts *bts, const struct abis_om2k_mo *mo,
uint8_t operational);
int abis_om2k_tx_is_conf_req(struct gsm_bts *bts, struct om2k_is_conn_grp *cg,
unsigned int num_cg);
int abis_om2k_tx_rx_conf_req(struct gsm_bts_trx *trx);
int abis_om2k_tx_tx_conf_req(struct gsm_bts_trx *trx);
int abis_om2k_tx_ts_conf_req(struct gsm_bts_trx_ts *ts);
int abis_om2k_vty_init(void);

View File

@ -117,7 +117,12 @@ enum abis_om2k_msgtype {
OM2K_MSGT_RESET_CMD = 0x0078,
OM2K_MSGT_RESET_COMPL = 0x007a,
OM2K_MSGT_RESET_REJ = 0x007b,
OM2K_MSGT_RX_CONF_REQ = 0x007c,
OM2K_MSGT_RX_CONF_REQ_ACK = 0x007e,
OM2K_MSGT_RX_CONF_REQ_REJ = 0x007f,
OM2K_MSGT_RX_CONF_RES_ACK = 0x0080,
OM2K_MSGT_RX_CONF_RES_NACK = 0x0081,
OM2K_MSGT_RX_CONF_RES = 0x0082,
OM2K_MSGT_START_REQ = 0x0084,
OM2K_MSGT_START_REQ_ACK = 0x0086,
OM2K_MSGT_START_REQ_REJ = 0x0087,
@ -135,34 +140,49 @@ enum abis_om2k_msgtype {
OM2K_MSGT_TEST_RES_NACK = 0x0099,
OM2K_MSGT_TEST_RES = 0x009a,
OM2K_MSGT_TS_CONF_REQ = 0x00a8,
OM2K_MSGT_TS_CONF_REQ_ACK = 0x00aa,
OM2K_MSGT_TS_CONF_REQ_REJ = 0x00ab,
OM2K_MSGT_TS_CONF_RES_ACK = 0x00ac,
OM2K_MSGT_TS_CONF_RES_NACK = 0x00ad,
OM2K_MSGT_TS_CONF_RES = 0x00ae,
OM2K_MSGT_TX_CONF_REQ = 0x00b0,
OM2K_MSGT_TX_CONF_REQ_ACK = 0x00b2,
OM2K_MSGT_TX_CONF_REQ_REJ = 0x00b3,
OM2K_MSGT_TX_CONF_RES_ACK = 0x00b4,
OM2K_MSGT_TX_CONF_RES_NACK = 0x00b5,
OM2K_MSGT_TX_CONF_RES = 0x00b6,
OM2K_MSGT_NEGOT_REQ_ACK = 0x0104,
OM2K_MSGT_NEGOT_REQ_NACK = 0x0105,
OM2K_MSGT_NEGOT_REQ = 0x0106,
};
enum abis_om2k_dei {
OM2K_DEI_BCC = 0x06,
OM2K_DEI_BSIC = 0x09,
OM2K_DEI_CAL_TIME = 0x0d,
OM2K_DEI_COMBINATION = 0x0f,
OM2K_DEI_CON_CONN_LIST = 0x10,
OM2K_DEI_END_LIST_NR = 0x13,
OM2K_DEI_FILLING_MARKER = 0x1c,
OM2K_DEI_FN_OFFSET = 0x1d,
OM2K_DEI_FREQ_LIST = 0x1e,
OM2K_DEI_FREQ_SPEC_RX = 0x1f,
OM2K_DEI_FREQ_SPEC_TX = 0x20,
OM2K_DEI_HSN = 0x21,
OM2K_DEI_IS_CONN_LIST = 0x27,
OM2K_DEI_LIST_NR = 0x28,
OM2K_DEI_MAIO = 0x2b,
OM2K_DEI_OP_INFO = 0x2e,
OM2K_DEI_POWER = 0x2f,
OM2K_DEI_RX_DIVERSITY = 0x33,
OM2K_DEI_TS_NR = 0x3c,
OM2K_DEI_EXT_RANGE = 0x47,
OM2K_DEI_NEGOT_REC1 = 0x90,
OM2K_DEI_NEGOT_REC2 = 0x91,
};
enum abis_om2k_mo_cls {
OM2K_MO_CLS_TRXC = 0x01,
OM2K_MO_CLS_TS = 0x03,
OM2K_MO_CLS_TF = 0x04,
OM2K_MO_CLS_IS = 0x05,
OM2K_MO_CLS_CON = 0x06,
OM2K_MO_CLS_DP = 0x07,
OM2K_MO_CLS_CF = 0x0a,
OM2K_MO_CLS_TX = 0x0b,
OM2K_MO_CLS_RX = 0x0c,
};
static const struct value_string om2k_msgcode_vals[] = {
{ 0x0000, "Abort SP Command" },
{ 0x0002, "Abort SP Complete" },
@ -683,6 +703,136 @@ int abis_om2k_tx_con_conf_req(struct gsm_bts *bts, uint8_t *data,
return abis_om2k_sendmsg(bts, msg);
}
static void om2k_trx_to_mo(struct abis_om2k_mo *mo,
const struct gsm_bts_trx *trx,
enum abis_om2k_mo_cls cls)
{
mo->class = cls;
mo->bts = 0;
mo->inst = trx->nr;
mo->assoc_so = 0;
}
static void om2k_ts_to_mo(struct abis_om2k_mo *mo,
const struct gsm_bts_trx_ts *ts)
{
mo->class = OM2K_MO_CLS_TS;
mo->bts = 0;
mo->inst = ts->nr;
mo->assoc_so = ts->trx->nr;
}
/* Configure a Receiver MO */
int abis_om2k_tx_rx_conf_req(struct gsm_bts_trx *trx)
{
struct msgb *msg = om2k_msgb_alloc();
struct abis_om2k_hdr *o2k;
struct abis_om2k_mo mo;
om2k_trx_to_mo(&mo, trx, OM2K_MO_CLS_RX);
o2k = (struct abis_om2k_hdr *) msgb_put(msg, sizeof(*o2k));
fill_om2k_hdr(o2k, &mo, OM2K_MSGT_RX_CONF_REQ, 3+2);
msgb_tv16_put(msg, OM2K_DEI_FREQ_SPEC_RX, trx->arfcn);
msgb_tv_put(msg, OM2K_DEI_RX_DIVERSITY, 0x03); /* A+B */
return abis_om2k_sendmsg(trx->bts, msg);
}
/* Configure a Transmitter MO */
int abis_om2k_tx_tx_conf_req(struct gsm_bts_trx *trx)
{
struct msgb *msg = om2k_msgb_alloc();
struct abis_om2k_hdr *o2k;
struct abis_om2k_mo mo;
om2k_trx_to_mo(&mo, trx, OM2K_MO_CLS_TX);
o2k = (struct abis_om2k_hdr *) msgb_put(msg, sizeof(*o2k));
fill_om2k_hdr(o2k, &mo, OM2K_MSGT_TX_CONF_REQ, 3+2+2+2);
msgb_tv16_put(msg, OM2K_DEI_FREQ_SPEC_TX, trx->arfcn);
msgb_tv_put(msg, OM2K_DEI_POWER, trx->nominal_power-trx->max_power_red);
msgb_tv_put(msg, OM2K_DEI_FILLING_MARKER, 0); /* Filling enabled */
msgb_tv_put(msg, OM2K_DEI_BCC, trx->bts->bsic & 0x7);
/* Dedication Information is optional */
return abis_om2k_sendmsg(trx->bts, msg);
}
static uint8_t pchan2comb(enum gsm_phys_chan_config pchan)
{
switch (pchan) {
case GSM_PCHAN_CCCH:
return 4;
case GSM_PCHAN_CCCH_SDCCH4:
return 5;
case GSM_PCHAN_SDCCH8_SACCH8C:
return 3;
case GSM_PCHAN_TCH_F:
case GSM_PCHAN_TCH_H:
case GSM_PCHAN_PDCH:
case GSM_PCHAN_TCH_F_PDCH:
return 8;
default:
return 0;
}
}
/* Compute a frequency list in OM2000 fomrmat */
static int om2k_gen_freq_list(uint8_t *list, struct gsm_bts_trx_ts *ts)
{
uint8_t *cur = list;
if (ts->hopping.enabled) {
unsigned int i;
for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
*cur++ = 0x00;
*cur++ = i >> 8;
*cur++ = i & 0xff;
}
}
} else {
*cur++ = 0x00; /* TX/RX address */
*cur++ = ts->trx->arfcn >> 8;
*cur++ = ts->trx->arfcn && 0xff;
}
return (cur - list);
}
int abis_om2k_tx_ts_conf_req(struct gsm_bts_trx_ts *ts)
{
struct msgb *msg = om2k_msgb_alloc();
struct abis_om2k_hdr *o2k;
struct abis_om2k_mo mo;
uint8_t freq_list[64*3]; /* BA max size: 64 ARFCN */
int freq_list_len;
om2k_ts_to_mo(&mo, ts);
freq_list_len = om2k_gen_freq_list(freq_list, ts);
if (freq_list_len < 0)
return freq_list_len;
o2k = (struct abis_om2k_hdr *) msgb_put(msg, sizeof(*o2k));
fill_om2k_hdr(o2k, &mo, OM2K_MSGT_TS_CONF_REQ,
2+2+TLV_GROSS_LEN(freq_list_len)+2+2+2+2+3+2);
msgb_tv_put(msg, OM2K_DEI_COMBINATION, pchan2comb(ts->pchan));
msgb_tv_put(msg, OM2K_DEI_TS_NR, ts->nr);
msgb_tlv_put(msg, OM2K_DEI_FREQ_LIST, freq_list_len, freq_list);
msgb_tv_put(msg, OM2K_DEI_HSN, ts->hopping.hsn);
msgb_tv_put(msg, OM2K_DEI_MAIO, ts->hopping.maio);
msgb_tv_put(msg, OM2K_DEI_BSIC, ts->trx->bts->bsic);
msgb_tv_put(msg, OM2K_DEI_RX_DIVERSITY, 0x03); /* A+B */
msgb_tv16_put(msg, OM2K_DEI_FN_OFFSET, 0);
msgb_tv_put(msg, OM2K_DEI_EXT_RANGE, 0); /* Off */
/* Optional: Interference Rejection Combining */
return abis_om2k_sendmsg(ts->trx->bts, msg);
}
static int abis_om2k_tx_negot_req_ack(struct gsm_bts *bts, const struct abis_om2k_mo *mo,
uint8_t *data, unsigned int len)
@ -844,6 +994,15 @@ int abis_om2k_rcvmsg(struct msgb *msg)
case OM2K_MSGT_CON_CONF_RES:
rc = abis_om2k_tx_simple(bts, &o2h->mo, OM2K_MSGT_CON_CONF_RES_ACK);
break;
case OM2K_MSGT_TX_CONF_RES:
rc = abis_om2k_tx_simple(bts, &o2h->mo, OM2K_MSGT_TX_CONF_RES_ACK);
break;
case OM2K_MSGT_RX_CONF_RES:
rc = abis_om2k_tx_simple(bts, &o2h->mo, OM2K_MSGT_RX_CONF_RES_ACK);
break;
case OM2K_MSGT_TS_CONF_RES:
rc = abis_om2k_tx_simple(bts, &o2h->mo, OM2K_MSGT_TS_CONF_RES_ACK);
break;
case OM2K_MSGT_CONNECT_COMPL:
rc = abis_om2k_tx_simple(bts, &o2h->mo, OM2K_MSGT_RESET_CMD);
break;
@ -864,6 +1023,9 @@ int abis_om2k_rcvmsg(struct msgb *msg)
case OM2K_MSGT_START_REQ_ACK:
case OM2K_MSGT_CON_CONF_REQ_ACK:
case OM2K_MSGT_IS_CONF_REQ_ACK:
case OM2K_MSGT_TX_CONF_REQ_ACK:
case OM2K_MSGT_RX_CONF_REQ_ACK:
case OM2K_MSGT_TS_CONF_REQ_ACK:
case OM2K_MSGT_ENABLE_REQ_ACK:
case OM2K_MSGT_ALARM_STATUS_REQ_ACK:
case OM2K_MSGT_DISABLE_REQ_ACK:

View File

@ -410,6 +410,59 @@ DEFUN(om2k_is_conf_req, om2k_is_conf_req_cmd,
return CMD_SUCCESS;
}
DEFUN(om2k_conf_req, om2k_conf_req_cmd,
"configuration-request",
"Send the configuration request for current MO\n")
{
struct oml_node_state *oms = vty->index;
struct gsm_bts *bts = oms->bts;
struct gsm_bts_trx *trx = NULL;
struct gsm_bts_trx_ts *ts = NULL;
switch (oms->mo.class) {
case OM2K_MO_CLS_TS:
trx = gsm_bts_trx_by_nr(bts, oms->mo.assoc_so);
if (!trx) {
vty_out(vty, "%% BTS %u has no TRX %u%s", bts->nr,
oms->mo.assoc_so, VTY_NEWLINE);
return CMD_WARNING;
}
if (oms->mo.inst >= ARRAY_SIZE(trx->ts)) {
vty_out(vty, "%% Timeslot %u out of range%s",
oms->mo.inst, VTY_NEWLINE);
return CMD_WARNING;
}
ts = &trx->ts[oms->mo.inst];
abis_om2k_tx_ts_conf_req(ts);
break;
case OM2K_MO_CLS_RX:
case OM2K_MO_CLS_TX:
case OM2K_MO_CLS_TRXC:
trx = gsm_bts_trx_by_nr(bts, oms->mo.inst);
if (!trx) {
vty_out(vty, "%% BTS %u has no TRX %u%s", bts->nr,
oms->mo.inst, VTY_NEWLINE);
return CMD_WARNING;
}
switch (oms->mo.class) {
case OM2K_MO_CLS_RX:
abis_om2k_tx_rx_conf_req(trx);
break;
case OM2K_MO_CLS_TX:
abis_om2k_tx_rx_conf_req(trx);
break;
default:
break;
}
break;
default:
vty_out(vty, "%% Don't know how to configure MO%s",
VTY_NEWLINE);
}
return CMD_SUCCESS;
}
void abis_om2k_config_write_bts(struct vty *vty, struct gsm_bts *bts)
{
struct is_conn_group *igrp;
@ -446,6 +499,7 @@ int abis_om2k_vty_init(void)
install_element(OM2K_NODE, &om2k_disable_cmd);
install_element(OM2K_NODE, &om2k_op_info_cmd);
install_element(OM2K_NODE, &om2k_test_cmd);
install_element(OM2K_NODE, &om2k_conf_req_cmd);
install_element(OM2K_NODE, &om2k_is_conf_req_cmd);
install_element(OM2K_NODE, &om2k_con_list_dec_cmd);
install_element(OM2K_NODE, &om2k_con_list_tei_cmd);