From 3784850c76457a2a7fd0150ab12b1755f0a585fc Mon Sep 17 00:00:00 2001 From: Rafael Diniz Date: Tue, 14 Apr 2020 03:49:04 -0300 Subject: osmo-bts-litecell15: Implement missing features. Many hardware parameters of the LC 1.5 were not exposed to the user. This patchset introduces most of the features, being very similar to osmo-bts-oc2g code. Change-Id: Id41bba798440b00a3b11441b64b2e8094a946bf2 --- include/osmo-bts/phy_link.h | 1 + src/osmo-bts-litecell15/l1_if.c | 111 ++++++++++++++++- src/osmo-bts-litecell15/l1_if.h | 12 ++ src/osmo-bts-litecell15/lc15bts.c | 15 +++ src/osmo-bts-litecell15/lc15bts.h | 33 +++++ src/osmo-bts-litecell15/lc15bts_vty.c | 219 ++++++++++++++++++++++++++++++++++ src/osmo-bts-litecell15/main.c | 9 +- src/osmo-bts-litecell15/oml.c | 140 +++++++++++++++++++++- 8 files changed, 530 insertions(+), 10 deletions(-) diff --git a/include/osmo-bts/phy_link.h b/include/osmo-bts/phy_link.h index 116297b6..cf877bde 100644 --- a/include/osmo-bts/phy_link.h +++ b/include/osmo-bts/phy_link.h @@ -135,6 +135,7 @@ struct phy_instance { uint8_t dsp_alive_period; /* DSP alive timer period */ uint8_t tx_pwr_adj_mode; /* 0: no auto adjust power, 1: auto adjust power using RMS detector */ uint8_t tx_pwr_red_8psk; /* 8-PSK maximum Tx power reduction level in dB */ + uint8_t tx_c0_idle_pwr_red; /* C0 idle slot Tx power reduction level in dB */ } lc15; struct { /* configuration */ diff --git a/src/osmo-bts-litecell15/l1_if.c b/src/osmo-bts-litecell15/l1_if.c index abf48bcd..0b289fc0 100644 --- a/src/osmo-bts-litecell15/l1_if.c +++ b/src/osmo-bts-litecell15/l1_if.c @@ -1263,8 +1263,10 @@ static int activate_rf_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, LOGP(DL1C, LOGL_FATAL, "RF-ACT.conf with status %s\n", get_value_string(lc15bts_l1status_names, status)); bts_shutdown(trx->bts, "RF-ACT failure"); - } else - bts_update_status(BTS_STATUS_RF_ACTIVE, 1); + } else { + if(trx->bts->lc15.led_ctrl_mode == LC15_LED_CONTROL_BTS) + bts_update_status(BTS_STATUS_RF_ACTIVE, 1); + } /* signal availability */ oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OK); @@ -1275,7 +1277,8 @@ static int activate_rf_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, for (i = 0; i < ARRAY_SIZE(trx->ts); i++) oml_mo_state_chg(&trx->ts[i].mo, NM_OPSTATE_DISABLED, NM_AVSTATE_DEPENDENCY); } else { - bts_update_status(BTS_STATUS_RF_ACTIVE, 0); + if(trx->bts->lc15.led_ctrl_mode == LC15_LED_CONTROL_BTS) + bts_update_status(BTS_STATUS_RF_ACTIVE, 0); oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE); oml_mo_state_chg(&trx->bb_transc.mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE); } @@ -1290,17 +1293,26 @@ int l1if_activate_rf(struct lc15l1_hdl *hdl, int on) { struct msgb *msg = sysp_msgb_alloc(); Litecell15_Prim_t *sysp = msgb_sysprim(msg); + struct phy_instance *pinst = hdl->phy_inst; if (on) { sysp->id = Litecell15_PrimId_ActivateRfReq; sysp->u.activateRfReq.msgq.u8UseTchMsgq = 0; sysp->u.activateRfReq.msgq.u8UsePdtchMsgq = pcu_direct; - sysp->u.activateRfReq.u8UnusedTsMode = 0; + sysp->u.activateRfReq.u8UnusedTsMode = pinst->u.lc15.pedestal_mode; + sysp->u.activateRfReq.u8McCorrMode = 0; + /* diversity mode: 0: SISO-A, 1: SISO-B, 2: MRC */ + sysp->u.activateRfReq.u8DiversityMode = pinst->u.lc15.diversity_mode; + /* maximum cell size in quarter-bits, 90 == 12.456 km */ - sysp->u.activateRfReq.u8MaxCellSize = 90; + sysp->u.activateRfReq.u8MaxCellSize = pinst->u.lc15.max_cell_size; + + /* auto tx power adjustment mode 0:none, 1: automatic*/ + sysp->u.activateRfReq.u8EnAutoPowerAdjust = pinst->u.lc15.tx_pwr_adj_mode; + } else { sysp->id = Litecell15_PrimId_DeactivateRfReq; } @@ -1589,6 +1601,54 @@ int l1if_close(struct lc15l1_hdl *fl1h) return 0; } +static void dsp_alive_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data) +{ + Litecell15_Prim_t *sysp = msgb_sysprim(resp); + Litecell15_IsAliveCnf_t *sac = &sysp->u.isAliveCnf; + struct lc15l1_hdl *fl1h = trx_lc15l1_hdl(trx); + + fl1h->hw_alive.dsp_alive_cnt++; + LOGP(DL1C, LOGL_DEBUG, "Rx SYS prim %s, status=%d (%d)\n", + get_value_string(lc15bts_sysprim_names, sysp->id), sac->status, trx->nr); + + msgb_free(resp); +} + +static int dsp_alive_timer_cb(void *data) +{ + struct lc15l1_hdl *fl1h = data; + struct gsm_bts_trx *trx = fl1h->phy_inst->trx; + struct msgb *msg = sysp_msgb_alloc(); + int rc; + + Litecell15_Prim_t *sys_prim = msgb_sysprim(msg); + sys_prim->id = Litecell15_PrimId_IsAliveReq; + + if (fl1h->hw_alive.dsp_alive_cnt == 0) { + LOGP(DL1C, LOGL_ERROR, "Timeout waiting for SYS prim %s primitive (%d)\n", + get_value_string(lc15bts_sysprim_names, sys_prim->id + 1), trx->nr); + + if( fl1h->phy_inst->trx ){ + fl1h->phy_inst->trx->mo.obj_inst.trx_nr = fl1h->phy_inst->trx->nr; + } + } + + LOGP(DL1C, LOGL_DEBUG, "Tx SYS prim %s (%d)\n", + get_value_string(lc15bts_sysprim_names, sys_prim->id), trx->nr); + + rc = l1if_req_compl(fl1h, msg, dsp_alive_compl_cb, NULL); + if (rc < 0) { + LOGP(DL1C, LOGL_FATAL, "Failed to send %s primitive\n", get_value_string(lc15bts_sysprim_names, sys_prim->id)); + return -EIO; + } + + /* restart timer */ + fl1h->hw_alive.dsp_alive_cnt = 0; + osmo_timer_schedule(&fl1h->hw_alive.dsp_alive_timer, fl1h->hw_alive.dsp_alive_period, 0); + + return 0; +} + int bts_model_phy_link_open(struct phy_link *plink) { struct phy_instance *pinst = phy_instance_by_num(plink, 0); @@ -1608,6 +1668,27 @@ int bts_model_phy_link_open(struct phy_link *plink) return -EIO; } + /* Set default PHY parameters */ + if (!pinst->u.lc15.max_cell_size) + pinst->u.lc15.max_cell_size = LC15_BTS_MAX_CELL_SIZE_DEFAULT; + + if (!pinst->u.lc15.diversity_mode) + pinst->u.lc15.diversity_mode = LC15_BTS_DIVERSITY_MODE_DEFAULT; + + if (!pinst->u.lc15.pedestal_mode) + pinst->u.lc15.pedestal_mode = LC15_BTS_PEDESTAL_MODE_DEFAULT; + + if (!pinst->u.lc15.dsp_alive_period) + pinst->u.lc15.dsp_alive_period = LC15_BTS_DSP_ALIVE_TMR_DEFAULT; + + if (!pinst->u.lc15.tx_pwr_adj_mode) + pinst->u.lc15.tx_pwr_adj_mode = LC15_BTS_TX_PWR_ADJ_DEFAULT; + + if (!pinst->u.lc15.tx_pwr_red_8psk) + pinst->u.lc15.tx_pwr_red_8psk = LC15_BTS_TX_RED_PWR_8PSK_DEFAULT; + + if (!pinst->u.lc15.tx_c0_idle_pwr_red) + pinst->u.lc15.tx_c0_idle_pwr_red = LC15_BTS_TX_C0_IDLE_RED_PWR_DEFAULT; struct lc15l1_hdl *fl1h = pinst->u.lc15.hdl; fl1h->dsp_trace_f = dsp_trace; @@ -1616,5 +1697,25 @@ int bts_model_phy_link_open(struct phy_link *plink) phy_link_state_set(plink, PHY_LINK_CONNECTED); + /* Send first IS_ALIVE primitive */ + struct msgb *msg = sysp_msgb_alloc(); + int rc; + + Litecell15_Prim_t *sys_prim = msgb_sysprim(msg); + sys_prim->id = Litecell15_PrimId_IsAliveReq; + + rc = l1if_req_compl(fl1h, msg, dsp_alive_compl_cb, NULL); + if (rc < 0) { + LOGP(DL1C, LOGL_FATAL, "Failed to send %s primitive\n", get_value_string(lc15bts_sysprim_names, sys_prim->id)); + return -EIO; + } + + /* initialize DSP heart beat alive timer */ + fl1h->hw_alive.dsp_alive_timer.cb = dsp_alive_timer_cb; + fl1h->hw_alive.dsp_alive_timer.data = fl1h; + fl1h->hw_alive.dsp_alive_cnt = 0; + fl1h->hw_alive.dsp_alive_period = pinst->u.lc15.dsp_alive_period; + osmo_timer_schedule(&fl1h->hw_alive.dsp_alive_timer, fl1h->hw_alive.dsp_alive_period, 0); + return 0; } diff --git a/src/osmo-bts-litecell15/l1_if.h b/src/osmo-bts-litecell15/l1_if.h index aac26075..45f0ddd3 100644 --- a/src/osmo-bts-litecell15/l1_if.h +++ b/src/osmo-bts-litecell15/l1_if.h @@ -30,6 +30,12 @@ enum { _NUM_MQ_WRITE }; +/* gsm_bts->model_priv, specific to Litecell 1.5 BTS */ +struct bts_lc15_priv { + uint8_t led_ctrl_mode; /* 0: control by BTS, 1: not control by BTS */ + unsigned int rtp_drift_thres_ms; /* RTP timestamp drift detection threshold */ +}; + struct calib_send_state { FILE *fp; const char *path; @@ -62,6 +68,12 @@ struct lc15l1_hdl { struct calib_send_state st; uint8_t last_rf_mute[8]; + + struct { + struct osmo_timer_list dsp_alive_timer; + unsigned int dsp_alive_cnt; + uint8_t dsp_alive_period; + } hw_alive; }; #define msgb_l1prim(msg) ((GsmL1_Prim_t *)(msg)->l1h) diff --git a/src/osmo-bts-litecell15/lc15bts.c b/src/osmo-bts-litecell15/lc15bts.c index 172a7e45..8ebc3a22 100644 --- a/src/osmo-bts-litecell15/lc15bts.c +++ b/src/osmo-bts-litecell15/lc15bts.c @@ -121,6 +121,12 @@ enum l1prim_type lc15bts_get_sysprim_type(Litecell15_PrimId_t id) case Litecell15_PrimId_MuteRfCnf: return L1P_T_CONF; case Litecell15_PrimId_SetRxAttenReq: return L1P_T_REQ; case Litecell15_PrimId_SetRxAttenCnf: return L1P_T_CONF; + case Litecell15_PrimId_IsAliveReq: return L1P_T_REQ; + case Litecell15_PrimId_IsAliveCnf: return L1P_T_CONF; + case Litecell15_PrimId_SetMaxCellSizeReq: return L1P_T_REQ; + case Litecell15_PrimId_SetMaxCellSizeCnf: return L1P_T_CONF; + case Litecell15_PrimId_SetC0IdleSlotPowerReductionReq: return L1P_T_REQ; + case Litecell15_PrimId_SetC0IdleSlotPowerReductionCnf: return L1P_T_CONF; default: return L1P_T_INVALID; } } @@ -142,6 +148,12 @@ const struct value_string lc15bts_sysprim_names[Litecell15_PrimId_NUM+1] = { { Litecell15_PrimId_MuteRfCnf, "MUTE-RF.cnf" }, { Litecell15_PrimId_SetRxAttenReq, "SET-RX-ATTEN.req" }, { Litecell15_PrimId_SetRxAttenCnf, "SET-RX-ATTEN-CNF.cnf" }, + { Litecell15_PrimId_IsAliveReq, "IS-ALIVE.req" }, + { Litecell15_PrimId_IsAliveCnf, "IS-ALIVE-CNF.cnf" }, + { Litecell15_PrimId_SetMaxCellSizeReq, "SET-MAX-CELL-SIZE.req" }, + { Litecell15_PrimId_SetMaxCellSizeCnf, "SET-MAX-CELL-SIZE.cnf" }, + { Litecell15_PrimId_SetC0IdleSlotPowerReductionReq, "SET-C0-IDLE-PWR-RED.req" }, + { Litecell15_PrimId_SetC0IdleSlotPowerReductionCnf, "SET-C0-IDLE-PWR-RED.cnf" }, { 0, NULL } }; @@ -155,6 +167,9 @@ Litecell15_PrimId_t lc15bts_get_sysprim_conf(Litecell15_PrimId_t id) case Litecell15_PrimId_SetCalibTblReq: return Litecell15_PrimId_SetCalibTblCnf; case Litecell15_PrimId_MuteRfReq: return Litecell15_PrimId_MuteRfCnf; case Litecell15_PrimId_SetRxAttenReq: return Litecell15_PrimId_SetRxAttenCnf; + case Litecell15_PrimId_IsAliveReq: return Litecell15_PrimId_IsAliveCnf; + case Litecell15_PrimId_SetMaxCellSizeReq: return Litecell15_PrimId_SetMaxCellSizeCnf; + case Litecell15_PrimId_SetC0IdleSlotPowerReductionReq: return Litecell15_PrimId_SetC0IdleSlotPowerReductionCnf; default: return -1; // Weak } } diff --git a/src/osmo-bts-litecell15/lc15bts.h b/src/osmo-bts-litecell15/lc15bts.h index 4c40db0f..6360826b 100644 --- a/src/osmo-bts-litecell15/lc15bts.h +++ b/src/osmo-bts-litecell15/lc15bts.h @@ -22,6 +22,28 @@ enum l1prim_type { L1P_T_IND, }; + +enum lc15_diversity_mode{ + LC15_DIVERSITY_SISO_A = 0, + LC15_DIVERSITY_SISO_B, + LC15_DIVERSITY_MRC, +}; + +enum lc15_pedestal_mode{ + LC15_PEDESTAL_OFF = 0, + LC15_PEDESTAL_ON, +}; + +enum lc15_led_control_mode{ + LC15_LED_CONTROL_BTS = 0, + LC15_LED_CONTROL_EXT, +}; + +enum lc15_auto_pwr_adjust_mode{ + LC15_TX_PWR_ADJ_NONE = 0, + LC15_TX_PWR_ADJ_AUTO, +}; + enum l1prim_type lc15bts_get_l1prim_type(GsmL1_PrimId_t id); const struct value_string lc15bts_l1prim_names[GsmL1_PrimId_NUM+1]; GsmL1_PrimId_t lc15bts_get_l1prim_conf(GsmL1_PrimId_t id); @@ -61,4 +83,15 @@ enum pdch_cs { const uint8_t pdch_msu_size[_NUM_PDCH_CS]; +/* LC15 default parameters */ +#define LC15_BTS_MAX_CELL_SIZE_DEFAULT 166 /* 166 qbits is default value */ +#define LC15_BTS_DIVERSITY_MODE_DEFAULT 0 /* SISO-A is default mode */ +#define LC15_BTS_PEDESTAL_MODE_DEFAULT 0 /* Unused TS is off by default */ +#define LC15_BTS_LED_CTRL_MODE_DEFAULT 0 /* LED is controlled by BTS by default */ +#define LC15_BTS_DSP_ALIVE_TMR_DEFAULT 5 /* Default DSP alive timer is 5 seconds */ +#define LC15_BTS_TX_PWR_ADJ_DEFAULT 0 /* Default Tx power auto adjustment is none */ +#define LC15_BTS_TX_RED_PWR_8PSK_DEFAULT 0 /* Default 8-PSK maximum power level is 0 dB */ +#define LC15_BTS_RTP_DRIFT_THRES_DEFAULT 0 /* Default RTP drift threshold is 0 ms (disabled) */ +#define LC15_BTS_TX_C0_IDLE_RED_PWR_DEFAULT 0 /* Default C0 idle slot reduction power level is 0 dB */ + #endif /* LC15BTS_H */ diff --git a/src/osmo-bts-litecell15/lc15bts_vty.c b/src/osmo-bts-litecell15/lc15bts_vty.c index d27ec281..e895ab83 100644 --- a/src/osmo-bts-litecell15/lc15bts_vty.c +++ b/src/osmo-bts-litecell15/lc15bts_vty.c @@ -43,6 +43,11 @@ #include #include +#include +#include +#include +#include + #include #include #include @@ -55,6 +60,7 @@ #include "utils.h" extern int lchan_activate(struct gsm_lchan *lchan); +extern int rsl_tx_preproc_meas_res(struct gsm_lchan *lchan); #define TRX_STR "Transceiver related commands\n" "TRX number\n" @@ -65,6 +71,31 @@ extern int lchan_activate(struct gsm_lchan *lchan); static struct gsm_bts *vty_bts; +static const struct value_string lc15_diversity_mode_strs[] = { + { LC15_DIVERSITY_SISO_A, "siso-a" }, + { LC15_DIVERSITY_SISO_B, "siso-b" }, + { LC15_DIVERSITY_MRC, "mrc" }, + { 0, NULL } +}; + +static const struct value_string lc15_pedestal_mode_strs[] = { + { LC15_PEDESTAL_OFF, "off" }, + { LC15_PEDESTAL_ON, "on" }, + { 0, NULL } +}; + +static const struct value_string lc15_led_mode_strs[] = { + { LC15_LED_CONTROL_BTS, "bts" }, + { LC15_LED_CONTROL_EXT, "external" }, + { 0, NULL } +}; + +static const struct value_string lc15_auto_adj_pwr_strs[] = { + { LC15_TX_PWR_ADJ_NONE, "none" }, + { LC15_TX_PWR_ADJ_AUTO, "auto" }, + { 0, NULL } +}; + /* configuration */ DEFUN(cfg_phy_cal_path, cfg_phy_cal_path_cmd, @@ -321,8 +352,164 @@ DEFUN(cfg_trx_nominal_power, cfg_trx_nominal_power_cmd, return CMD_SUCCESS; } +DEFUN(cfg_phy_max_cell_size, cfg_phy_max_cell_size_cmd, + "max-cell-size <0-166>", + "Set the maximum cell size in qbits\n") +{ + struct phy_instance *pinst = vty->index; + int cell_size = (uint8_t)atoi(argv[0]); + + if (( cell_size > 166 ) || ( cell_size < 0 )) { + vty_out(vty, "Max cell size must be between 0 and 166 qbits (%d) %s", + cell_size, VTY_NEWLINE); + return CMD_WARNING; + } + + pinst->u.lc15.max_cell_size = (uint8_t)cell_size; + return CMD_SUCCESS; +} + +DEFUN(cfg_phy_diversity_mode, cfg_phy_diversity_mode_cmd, + "diversity-mode (siso-a|siso-b|mrc)", + "Set reception diversity mode \n" + "Reception diversity mode can be (siso-a, siso-b, mrc)\n") +{ + struct phy_instance *pinst = vty->index; + int val = get_string_value(lc15_diversity_mode_strs, argv[0]); + + if((val < LC15_DIVERSITY_SISO_A) || (val > LC15_DIVERSITY_MRC)) { + vty_out(vty, "Invalid reception diversity mode %d%s", val, VTY_NEWLINE); + return CMD_WARNING; + } + + pinst->u.lc15.diversity_mode = (uint8_t)val; + return CMD_SUCCESS; +} + +DEFUN(cfg_phy_pedestal_mode, cfg_phy_pedestal_mode_cmd, + "pedestal-mode (on|off)", + "Set unused time-slot transmission in pedestal mode\n" + "Transmission pedestal mode can be (off, on)\n") +{ + struct phy_instance *pinst = vty->index; + int val = get_string_value(lc15_pedestal_mode_strs, argv[0]); + + if((val < LC15_PEDESTAL_OFF) || (val > LC15_PEDESTAL_ON)) { + vty_out(vty, "Invalid unused time-slot transmission mode %d%s", val, VTY_NEWLINE); + return CMD_WARNING; + } + + pinst->u.lc15.pedestal_mode = (uint8_t)val; + return CMD_SUCCESS; +} + +DEFUN(cfg_bts_led_mode, cfg_bts_led_mode_cmd, + "led-control-mode (bts|external)", + "Set LED controlled by BTS or external software\n" + "LED can be controlled by (bts, external)\n") +{ + struct gsm_bts *bts = vty->index; + int val = get_string_value(lc15_led_mode_strs, argv[0]); + + if((val < LC15_LED_CONTROL_BTS) || (val > LC15_LED_CONTROL_EXT)) { + vty_out(vty, "Invalid LED control mode %d%s", val, VTY_NEWLINE); + return CMD_WARNING; + } + + struct bts_lc15_priv *bts_lc15 = bts->model_priv; + bts_lc15->led_ctrl_mode = (uint8_t)val; + return CMD_SUCCESS; +} + +DEFUN(cfg_phy_dsp_alive_timer, cfg_phy_dsp_alive_timer_cmd, + "dsp-alive-period <0-60>", + "Set DSP alive timer period in second\n") +{ + struct phy_instance *pinst = vty->index; + uint8_t period = (uint8_t)atoi(argv[0]); + + if (( period > 60 ) || ( period < 0 )) { + vty_out(vty, "DSP heart beat alive timer period must be between 0 and 60 seconds (%d) %s", + period, VTY_NEWLINE); + return CMD_WARNING; + } + + pinst->u.lc15.dsp_alive_period = period; + return CMD_SUCCESS; +} + +DEFUN(cfg_phy_auto_tx_pwr_adj, cfg_phy_auto_tx_pwr_adj_cmd, + "pwr-adj-mode (none|auto)", + "Set output power adjustment mode\n") +{ + struct phy_instance *pinst = vty->index; + int val = get_string_value(lc15_auto_adj_pwr_strs, argv[0]); + + if((val < LC15_TX_PWR_ADJ_NONE) || (val > LC15_TX_PWR_ADJ_AUTO)) { + vty_out(vty, "Invalid output power adjustment mode %d%s", val, VTY_NEWLINE); + return CMD_WARNING; + } + + pinst->u.lc15.tx_pwr_adj_mode = (uint8_t)val; + return CMD_SUCCESS; +} + +DEFUN(cfg_phy_tx_red_pwr_8psk, cfg_phy_tx_red_pwr_8psk_cmd, + "tx-red-pwr-8psk <0-40>", + "Set reduction output power for 8-PSK scheme in dB unit\n") +{ + struct phy_instance *pinst = vty->index; + int val = atoi(argv[0]); + + if ((val > 40) || (val < 0)) { + vty_out(vty, "Reduction Tx power level must be between 0 and 40 dB (%d) %s", + val, VTY_NEWLINE); + return CMD_WARNING; + } + + pinst->u.lc15.tx_pwr_red_8psk = (uint8_t)val; + return CMD_SUCCESS; +} + +DEFUN(cfg_phy_c0_idle_red_pwr, cfg_phy_c0_idle_red_pwr_cmd, + "c0-idle-red-pwr <0-40>", + "Set reduction output power for C0 idle slot in dB unit\n") +{ + struct phy_instance *pinst = vty->index; + int val = atoi(argv[0]); + + if ((val > 40) || (val < 0)) { + vty_out(vty, "Reduction Tx power level must be between 0 and 40 dB (%d) %s", + val, VTY_NEWLINE); + return CMD_WARNING; + } + + pinst->u.lc15.tx_c0_idle_pwr_red = (uint8_t)val; + return CMD_SUCCESS; +} + +DEFUN(cfg_bts_rtp_drift_threshold, cfg_bts_rtp_drift_threshold_cmd, + "rtp-drift-threshold <0-10000>", + "RTP parameters\n" + "RTP timestamp drift threshold in ms\n") +{ + struct gsm_bts *bts = vty->index; + + struct bts_lc15_priv *bts_lc15 = bts->model_priv; + bts_lc15->rtp_drift_thres_ms = (unsigned int) atoi(argv[0]); + + return CMD_SUCCESS; +} + void bts_model_config_write_bts(struct vty *vty, struct gsm_bts *bts) { + struct bts_lc15_priv *bts_lc15 = bts->model_priv; + vty_out(vty, " led-control-mode %s%s", + get_value_string(lc15_led_mode_strs, bts_lc15->led_ctrl_mode), VTY_NEWLINE); + + vty_out(vty, " rtp-drift-threshold %d%s", + bts_lc15->rtp_drift_thres_ms, VTY_NEWLINE); + } void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx) @@ -349,6 +536,28 @@ void bts_model_config_write_phy_inst(struct vty *vty, struct phy_instance *pinst if (pinst->u.lc15.calib_path) vty_out(vty, " trx-calibration-path %s%s", pinst->u.lc15.calib_path, VTY_NEWLINE); + + vty_out(vty, " max-cell-size %d%s", + pinst->u.lc15.max_cell_size, VTY_NEWLINE); + + vty_out(vty, " diversity-mode %s%s", + get_value_string(lc15_diversity_mode_strs, pinst->u.lc15.diversity_mode), VTY_NEWLINE); + + vty_out(vty, " pedestal-mode %s%s", + get_value_string(lc15_pedestal_mode_strs, pinst->u.lc15.pedestal_mode) , VTY_NEWLINE); + + vty_out(vty, " dsp-alive-period %d%s", + pinst->u.lc15.dsp_alive_period, VTY_NEWLINE); + + vty_out(vty, " pwr-adj-mode %s%s", + get_value_string(lc15_auto_adj_pwr_strs, pinst->u.lc15.tx_pwr_adj_mode), VTY_NEWLINE); + + vty_out(vty, " tx-red-pwr-8psk %d%s", + pinst->u.lc15.tx_pwr_red_8psk, VTY_NEWLINE); + + vty_out(vty, " c0-idle-red-pwr %d%s", + pinst->u.lc15.tx_c0_idle_pwr_red, VTY_NEWLINE); + } int bts_model_vty_init(struct gsm_bts *bts) @@ -401,6 +610,8 @@ int bts_model_vty_init(struct gsm_bts *bts) install_element(BTS_NODE, &cfg_bts_auto_band_cmd); install_element(BTS_NODE, &cfg_bts_no_auto_band_cmd); + install_element(BTS_NODE, &cfg_bts_led_mode_cmd); + install_element(BTS_NODE, &cfg_bts_rtp_drift_threshold_cmd); install_element(TRX_NODE, &cfg_trx_nominal_power_cmd); @@ -408,6 +619,14 @@ int bts_model_vty_init(struct gsm_bts *bts) install_element(PHY_INST_NODE, &cfg_phy_no_dsp_trace_f_cmd); install_element(PHY_INST_NODE, &cfg_phy_cal_path_cmd); + install_element(PHY_INST_NODE, &cfg_phy_diversity_mode_cmd); + install_element(PHY_INST_NODE, &cfg_phy_pedestal_mode_cmd); + install_element(PHY_INST_NODE, &cfg_phy_max_cell_size_cmd); + install_element(PHY_INST_NODE, &cfg_phy_dsp_alive_timer_cmd); + install_element(PHY_INST_NODE, &cfg_phy_auto_tx_pwr_adj_cmd); + install_element(PHY_INST_NODE, &cfg_phy_tx_red_pwr_8psk_cmd); + install_element(PHY_INST_NODE, &cfg_phy_c0_idle_red_pwr_cmd); + return 0; } diff --git a/src/osmo-bts-litecell15/main.c b/src/osmo-bts-litecell15/main.c index 6f3fc006..ef021352 100644 --- a/src/osmo-bts-litecell15/main.c +++ b/src/osmo-bts-litecell15/main.c @@ -83,14 +83,21 @@ unsigned int dsp_trace = 0x00000000; int bts_model_init(struct gsm_bts *bts) { - struct gsm_bts_trx *trx; struct stat st; static struct osmo_fd accept_fd, read_fd; int rc; + struct bts_lc15_priv *bts_lc15 = talloc(bts, struct bts_lc15_priv); + + bts->model_priv = bts_lc15; bts->variant = BTS_OSMO_LITECELL15; bts->support.ciphers = CIPHER_A5(1) | CIPHER_A5(2) | CIPHER_A5(3); + /* specific default values for LC15 platform */ + bts_lc15->led_ctrl_mode = LC15_BTS_LED_CTRL_MODE_DEFAULT; + /* RTP drift threshold default */ + bts_lc15->rtp_drift_thres_ms = LC15_BTS_RTP_DRIFT_THRES_DEFAULT; + rc = oml_router_init(bts, OML_ROUTER_PATH, &accept_fd, &read_fd); if (rc < 0) { fprintf(stderr, "Error creating the OML router: %s rc=%d\n", diff --git a/src/osmo-bts-litecell15/oml.c b/src/osmo-bts-litecell15/oml.c index edc49ec7..a519b382 100644 --- a/src/osmo-bts-litecell15/oml.c +++ b/src/osmo-bts-litecell15/oml.c @@ -384,7 +384,7 @@ static int trx_init(struct gsm_bts_trx *trx) struct msgb *msg; GsmL1_MphInitReq_t *mi_req; GsmL1_DeviceParam_t *dev_par; - int lc15_band; + int rc, lc15_band; if (!gsm_abis_mo_check_attr(&trx->mo, trx_rqd_attr, ARRAY_SIZE(trx_rqd_attr))) { @@ -394,6 +394,15 @@ static int trx_init(struct gsm_bts_trx *trx) //return oml_mo_opstart_nack(&trx->mo, NM_NACK_CANT_PERFORM); } + /* Update TRX band */ + rc = gsm_arfcn2band_rc(trx->arfcn, &trx->bts->band); + if (rc) { + /* FIXME: abort initialization? */ + LOGP(DL1C, LOGL_ERROR, "Could not pick GSM band " + "for ARFCN %u\n", trx->arfcn); + trx->bts->band = 0x00; + } + lc15_band = lc15bts_select_lc15_band(trx, trx->arfcn); if (lc15_band < 0) { LOGP(DL1C, LOGL_ERROR, "Unsupported GSM band %s\n", @@ -1170,6 +1179,7 @@ const struct value_string lc15bts_l1cfgt_names[] = { { GsmL1_ConfigParamId_SetTxPowerLevel, "Set Tx power level" }, { GsmL1_ConfigParamId_SetLogChParams, "Set logical channel params" }, { GsmL1_ConfigParamId_SetCipheringParams,"Configure ciphering params" }, + { GsmL1_ConfigParamId_Set8pskPowerReduction, "Set 8PSK Tx power reduction" }, { 0, NULL } }; @@ -1227,6 +1237,56 @@ static int chmod_txpower_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg, return 0; } +static int chmod_txpower_backoff_8psk_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg, + void *data) +{ + GsmL1_Prim_t *l1p = msgb_l1prim(l1_msg); + GsmL1_MphConfigCnf_t *cc = &l1p->u.mphConfigCnf; + + LOGP(DL1C, LOGL_INFO, "%s MPH-CONFIG.conf (%s) ", + gsm_trx_name(trx), + get_value_string(lc15bts_l1cfgt_names, cc->cfgParamId)); + + LOGPC(DL1C, LOGL_INFO, "Backoff %u dB\n", + cc->cfgParams.set8pskPowerReduction.u8PowerReduction); + + msgb_free(l1_msg); + + return 0; +} + +static int chmod_max_cell_size_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, + void *data) +{ + Litecell15_Prim_t *sysp = msgb_sysprim(resp); + Litecell15_SetMaxCellSizeCnf_t *sac = &sysp->u.setMaxCellSizeCnf; + + LOGP(DL1C, LOGL_INFO, "%s Rx SYS prim %s -> %s\n", + gsm_trx_name(trx), + get_value_string(lc15bts_sysprim_names, sysp->id), + get_value_string(lc15bts_l1status_names, sac->status)); + + msgb_free(resp); + + return 0; +} + +static int chmod_c0_idle_pwr_red_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, + void *data) +{ + Litecell15_Prim_t *sysp = msgb_sysprim(resp); + Litecell15_SetC0IdleSlotPowerReductionCnf_t *sac = &sysp->u.setC0IdleSlotPowerReductionCnf; + + LOGP(DL1C, LOGL_INFO, "%s Rx SYS prim %s -> %s\n", + gsm_trx_name(trx), + get_value_string(lc15bts_sysprim_names, sysp->id), + get_value_string(lc15bts_l1status_names, sac->status)); + + msgb_free(resp); + + return 0; +} + static int chmod_modif_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg, void *data) { @@ -1368,6 +1428,47 @@ int l1if_set_txpower(struct lc15l1_hdl *fl1h, float tx_power) return l1if_gsm_req_compl(fl1h, msg, chmod_txpower_compl_cb, NULL); } +int l1if_set_txpower_backoff_8psk(struct lc15l1_hdl *fl1h, uint8_t backoff) +{ + struct msgb *msg = l1p_msgb_alloc(); + GsmL1_MphConfigReq_t *conf_req; + + conf_req = prim_init(msgb_l1prim(msg), GsmL1_PrimId_MphConfigReq, fl1h, 0); + conf_req->cfgParamId = GsmL1_ConfigParamId_Set8pskPowerReduction; + conf_req->cfgParams.set8pskPowerReduction.u8PowerReduction = backoff; + + return l1if_gsm_req_compl(fl1h, msg, chmod_txpower_backoff_8psk_compl_cb, NULL); +} + +int l1if_set_max_cell_size(struct lc15l1_hdl *fl1h, uint8_t cell_size) +{ + struct msgb *msg = sysp_msgb_alloc(); + Litecell15_Prim_t *sys_prim = msgb_sysprim(msg); + sys_prim->id = Litecell15_PrimId_SetMaxCellSizeReq; + sys_prim->u.setMaxCellSizeReq.u8MaxCellSize = cell_size; + + LOGP(DL1C, LOGL_INFO, "%s Set max cell size = %d qbits\n", + gsm_trx_name(fl1h->phy_inst->trx), + cell_size); + + return l1if_req_compl(fl1h, msg, chmod_max_cell_size_compl_cb, NULL); + +} + +int l1if_set_txpower_c0_idle_pwr_red(struct lc15l1_hdl *fl1h, uint8_t red) +{ + struct msgb *msg = sysp_msgb_alloc(); + Litecell15_Prim_t *sys_prim = msgb_sysprim(msg); + sys_prim->id = Litecell15_PrimId_SetC0IdleSlotPowerReductionReq; + sys_prim->u.setC0IdleSlotPowerReductionReq.u8PowerReduction = red; + + LOGP(DL1C, LOGL_INFO, "%s Set C0 idle slot power reduction = %d dB\n", + gsm_trx_name(fl1h->phy_inst->trx), + red); + + return l1if_req_compl(fl1h, msg, chmod_c0_idle_pwr_red_compl_cb, NULL); +} + const enum GsmL1_CipherId_t rsl2l1_ciph[] = { [0] = GsmL1_CipherId_A50, [1] = GsmL1_CipherId_A50, @@ -1700,7 +1801,8 @@ int bts_model_check_oml(struct gsm_bts *bts, uint8_t msg_type, /* our L1 only supports one global TSC for all channels * one one TRX, so we need to make sure not to activate * channels with a different TSC!! */ - if (TLVP_PRES_LEN(new_attr, NM_ATT_TSC, 1) && + if (TLVP_PRESENT(new_attr, NM_ATT_TSC) && + TLVP_LEN(new_attr, NM_ATT_TSC) >= 1 && *TLVP_VAL(new_attr, NM_ATT_TSC) != (bts->bsic & 7)) { LOGP(DOML, LOGL_ERROR, "Channel TSC %u != BSIC-TSC %u\n", *TLVP_VAL(new_attr, NM_ATT_TSC), bts->bsic & 7); @@ -1718,12 +1820,38 @@ int bts_model_apply_oml(struct gsm_bts *bts, struct msgb *msg, if (kind == NM_OC_RADIO_CARRIER) { struct gsm_bts_trx *trx = obj; struct lc15l1_hdl *fl1h = trx_lc15l1_hdl(trx); + /* convert max TA to max cell size in qbits */ + uint8_t cell_size = bts->max_ta << 2; + + /* We do not need to check for L1 handle + * because the max cell size parameter can receive before MphInit */ + if (fl1h->phy_inst->u.lc15.max_cell_size != cell_size) { + /* instruct L1 to apply max cell size */ + l1if_set_max_cell_size(fl1h, cell_size); + /* update current max cell size */ + fl1h->phy_inst->u.lc15.max_cell_size = cell_size; + } + /* Did we go through MphInit yet? If yes fire and forget */ - if (fl1h->hLayer1) + if (fl1h->hLayer1) { power_ramp_start(trx, get_p_target_mdBm(trx, 0), 0); - } + if (fl1h->phy_inst->u.lc15.tx_pwr_red_8psk != trx->max_power_backoff_8psk) { + /* update current Tx power backoff for 8-PSK */ + fl1h->phy_inst->u.lc15.tx_pwr_red_8psk = trx->max_power_backoff_8psk; + /* instruct L1 to apply Tx power backoff for 8 PSK */ + l1if_set_txpower_backoff_8psk(fl1h, fl1h->phy_inst->u.lc15.tx_pwr_red_8psk); + } + + if (fl1h->phy_inst->u.lc15.tx_c0_idle_pwr_red != trx->c0_idle_power_red) { + /* update current C0 idle slot Tx power reduction */ + fl1h->phy_inst->u.lc15.tx_c0_idle_pwr_red = trx->c0_idle_power_red; + /* instruct L1 to apply C0 idle slot power reduction */ + l1if_set_txpower_c0_idle_pwr_red(fl1h, fl1h->phy_inst->u.lc15.tx_c0_idle_pwr_red); + } + } + } /* FIXME: we actually need to send a ACK or NACK for the OML message */ return oml_fom_ack_nack(msg, 0); } @@ -1893,6 +2021,8 @@ static int ts_disconnect_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg, cb_ts_disconnected(ts); + msgb_free(l1_msg); + return 0; } @@ -1927,6 +2057,8 @@ static int ts_connect_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg, cb_ts_connected(ts, 0); + msgb_free(l1_msg); + return 0; } -- cgit v1.2.3