Currently uninitialized elements of the femtobts_sysprim_type array are mistaken as L1P_T_REQ (which is accidently the first element and thus 0).
This patch adds a new element to the enum that has the value 0 to detect uninitialized elements of the femtobts_sysprim_type array. Those will then show up in the log as 'SYS Prim XXX is not a Request!'.
This patch also adds missing definitions of the CalibTbl messages in the femtobts_sysprim_type mapping so that the requests can still be identified as such.
Sponsored-by: On-Waves ehf --- src/osmo-bts-sysmo/femtobts.c | 10 ++++++++++ src/osmo-bts-sysmo/femtobts.h | 1 + 2 files changed, 11 insertions(+)
diff --git a/src/osmo-bts-sysmo/femtobts.c b/src/osmo-bts-sysmo/femtobts.c index 6bd9ce4..1e513bf 100644 --- a/src/osmo-bts-sysmo/femtobts.c +++ b/src/osmo-bts-sysmo/femtobts.c @@ -106,6 +106,16 @@ const enum l1prim_type femtobts_sysprim_type[SuperFemto_PrimId_NUM] = { [SuperFemto_PrimId_RfClockSetupCnf] = L1P_T_CONF, [SuperFemto_PrimId_Layer1ResetReq] = L1P_T_REQ, [SuperFemto_PrimId_Layer1ResetCnf] = L1P_T_CONF, +#if SUPERFEMTO_API_VERSION >= SUPERFEMTO_API(2,1,0) + [SuperFemto_PrimId_GetTxCalibTblReq] = L1P_T_REQ, + [SuperFemto_PrimId_GetTxCalibTblCnf] = L1P_T_CONF, + [SuperFemto_PrimId_SetTxCalibTblReq] = L1P_T_REQ, + [SuperFemto_PrimId_SetTxCalibTblCnf] = L1P_T_CONF, + [SuperFemto_PrimId_GetRxCalibTblReq] = L1P_T_REQ, + [SuperFemto_PrimId_GetRxCalibTblCnf] = L1P_T_CONF, + [SuperFemto_PrimId_SetRxCalibTblReq] = L1P_T_REQ, + [SuperFemto_PrimId_SetRxCalibTblCnf] = L1P_T_CONF, +#endif };
const struct value_string femtobts_sysprim_names[SuperFemto_PrimId_NUM+1] = { diff --git a/src/osmo-bts-sysmo/femtobts.h b/src/osmo-bts-sysmo/femtobts.h index 7239757..a2b8dea 100644 --- a/src/osmo-bts-sysmo/femtobts.h +++ b/src/osmo-bts-sysmo/femtobts.h @@ -44,6 +44,7 @@ (OSMO_MAX(sizeof(SuperFemto_Prim_t), sizeof(GsmL1_Prim_t)) + 128)
enum l1prim_type { + L1P_T_INVALID, /* this must be 0 to detect uninitialized elements */ L1P_T_REQ, L1P_T_CONF, L1P_T_IND,
This add the mappings for SuperFemto_PrimId_MuteRfReq and SuperFemto_PrimId_MuteRfCnf to the arrays femtobts_sysprim_type, femtobts_sysprim_names, and femtobts_sysprim_req2conf.
Sponsored-by: On-Waves ehf --- src/osmo-bts-sysmo/femtobts.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
diff --git a/src/osmo-bts-sysmo/femtobts.c b/src/osmo-bts-sysmo/femtobts.c index 1e513bf..28d861c 100644 --- a/src/osmo-bts-sysmo/femtobts.c +++ b/src/osmo-bts-sysmo/femtobts.c @@ -116,6 +116,10 @@ const enum l1prim_type femtobts_sysprim_type[SuperFemto_PrimId_NUM] = { [SuperFemto_PrimId_SetRxCalibTblReq] = L1P_T_REQ, [SuperFemto_PrimId_SetRxCalibTblCnf] = L1P_T_CONF, #endif +#if SUPERFEMTO_API_VERSION >= SUPERFEMTO_API(3,6,0) + [SuperFemto_PrimId_MuteRfReq] = L1P_T_REQ, + [SuperFemto_PrimId_MuteRfCnf] = L1P_T_CONF, +#endif };
const struct value_string femtobts_sysprim_names[SuperFemto_PrimId_NUM+1] = { @@ -143,6 +147,10 @@ const struct value_string femtobts_sysprim_names[SuperFemto_PrimId_NUM+1] = { { SuperFemto_PrimId_SetRxCalibTblReq, "SET-RX-CALIB.req" }, { SuperFemto_PrimId_SetRxCalibTblCnf, "SET-RX-CALIB.cnf" }, #endif +#if SUPERFEMTO_API_VERSION >= SUPERFEMTO_API(3,6,0) + { SuperFemto_PrimId_MuteRfReq, "MUTE-RF.req" }, + { SuperFemto_PrimId_MuteRfCnf, "MUTE-RF.cnf" }, +#endif { 0, NULL } };
@@ -159,6 +167,9 @@ const SuperFemto_PrimId_t femtobts_sysprim_req2conf[SuperFemto_PrimId_NUM] = { [SuperFemto_PrimId_GetRxCalibTblReq] = SuperFemto_PrimId_GetRxCalibTblCnf, [SuperFemto_PrimId_SetRxCalibTblReq] = SuperFemto_PrimId_SetRxCalibTblCnf, #endif +#if SUPERFEMTO_API_VERSION >= SUPERFEMTO_API(3,6,0) + [SuperFemto_PrimId_MuteRfReq] = SuperFemto_PrimId_MuteRfCnf, +#endif };
const struct value_string femtobts_l1sapi_names[GsmL1_Sapi_NUM+1] = {
This adds a new function
l1if_mute_rf(femtol1_hdl, ch_mute[8])
to set the mute state for each radio channel. On completion and iff l1if_mute_rf() returned 0 the callback
oml_mo_rf_lock_chg(mo, ch_mute_state[8], success)
is invoked when the response from the superfemto DSP is received.
Ticket: OW#976 Sponsored-by: On-Waves ehf --- include/osmo-bts/oml.h | 4 ++++ src/osmo-bts-sysmo/l1_if.c | 48 ++++++++++++++++++++++++++++++++++++++++++++ src/osmo-bts-sysmo/l1_if.h | 3 +++ src/osmo-bts-sysmo/oml.c | 6 ++++++ 4 files changed, 61 insertions(+)
diff --git a/include/osmo-bts/oml.h b/include/osmo-bts/oml.h index 5e9c880..92695ca 100644 --- a/include/osmo-bts/oml.h +++ b/include/osmo-bts/oml.h @@ -17,6 +17,10 @@ int oml_mo_state_chg(struct gsm_abis_mo *mo, int op_state, int avail_state); /* First initialization of MO, does _not_ generate state changes */ void oml_mo_state_init(struct gsm_abis_mo *mo, int op_state, int avail_state);
+/* Update admin state and send ACK/NACK */ +int oml_mo_rf_lock_chg(struct gsm_abis_mo *mo, uint8_t mute_state[8], + int success); + /* Transmit STATE CHG REP even if there was no state change */ int oml_tx_state_changed(struct gsm_abis_mo *mo);
diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c index 3dbcd53..36df462 100644 --- a/src/osmo-bts-sysmo/l1_if.c +++ b/src/osmo-bts-sysmo/l1_if.c @@ -1103,6 +1103,54 @@ int l1if_activate_rf(struct femtol1_hdl *hdl, int on) return l1if_req_compl(hdl, msg, activate_rf_compl_cb); }
+static int mute_rf_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp) +{ + struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx); + SuperFemto_Prim_t *sysp = msgb_sysprim(resp); + GsmL1_Status_t status; + + status = sysp->u.muteRfCnf.status; + + if (status != GsmL1_Status_Success) { + LOGP(DL1C, LOGL_ERROR, "Rx RF-MUTE.conf with status %s\n", + get_value_string(femtobts_l1status_names, status)); + oml_mo_rf_lock_chg(&trx->mo, fl1h->last_rf_mute, 0); + } else { + LOGP(DL1C, LOGL_INFO, "Rx RF-MUTE.conf with status=%s\n", + get_value_string(femtobts_l1status_names, status)); + sysmobts_led_set(LED_RF_ACTIVE, !fl1h->last_rf_mute[0]); + oml_mo_rf_lock_chg(&trx->mo, fl1h->last_rf_mute, 1); + } + + msgb_free(resp); + + return 0; +} + +/* mute/unmute RF time slots */ +int l1if_mute_rf(struct femtol1_hdl *hdl, uint8_t mute[8]) +{ + struct msgb *msg = sysp_msgb_alloc(); + SuperFemto_Prim_t *sysp = msgb_sysprim(msg); + + LOGP(DL1C, LOGL_INFO, "Tx RF-MUTE.req (%d, %d, %d, %d, %d, %d, %d, %d)\n", + mute[0], mute[1], mute[2], mute[3], + mute[4], mute[5], mute[6], mute[7] + ); + +#if SUPERFEMTO_API_VERSION < SUPERFEMTO_API(3,6,0) + LOGP(DL1C, LOGL_ERROR, "RF-MUTE.req not supported by SuperFemto\n"); + return -ENOTSUP; +#endif /* < 3.6.0 */ + + sysp->id = SuperFemto_PrimId_MuteRfReq; + memcpy(sysp->u.muteRfReq.u8Mute, mute, sizeof(sysp->u.muteRfReq.u8Mute)); + /* save for later use */ + memcpy(hdl->last_rf_mute, mute, sizeof(hdl->last_rf_mute)); + + return l1if_req_compl(hdl, msg, mute_rf_compl_cb); +} + /* call-back on arrival of DSP+FPGA version + band capability */ static int info_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp) { diff --git a/src/osmo-bts-sysmo/l1_if.h b/src/osmo-bts-sysmo/l1_if.h index 8d63569..d659841 100644 --- a/src/osmo-bts-sysmo/l1_if.h +++ b/src/osmo-bts-sysmo/l1_if.h @@ -76,6 +76,8 @@ struct femtol1_hdl { int fixup_needed;
struct calib_send_state st; + + uint8_t last_rf_mute[8]; };
#define msgb_l1prim(msg) ((GsmL1_Prim_t *)(msg)->l1h) @@ -95,6 +97,7 @@ int l1if_reset(struct femtol1_hdl *hdl); int l1if_activate_rf(struct femtol1_hdl *hdl, int on); int l1if_set_trace_flags(struct femtol1_hdl *hdl, uint32_t flags); int l1if_set_txpower(struct femtol1_hdl *fl1h, float tx_power); +int l1if_mute_rf(struct femtol1_hdl *hdl, uint8_t mute[8]);
struct msgb *l1p_msgb_alloc(void); struct msgb *sysp_msgb_alloc(void); diff --git a/src/osmo-bts-sysmo/oml.c b/src/osmo-bts-sysmo/oml.c index c09b3f3..822453f 100644 --- a/src/osmo-bts-sysmo/oml.c +++ b/src/osmo-bts-sysmo/oml.c @@ -326,6 +326,12 @@ int bts_model_trx_close(struct gsm_bts_trx *trx) return l1if_gsm_req_compl(fl1h, msg, trx_close_compl_cb); }
+int oml_mo_rf_lock_chg(struct gsm_abis_mo *mo, uint8_t mute_state[8], + int success) +{ + return 0; +} + static int ts_connect(struct gsm_bts_trx_ts *ts) { struct msgb *msg = l1p_msgb_alloc();
On Mon, Nov 04, 2013 at 02:56:11PM +0100, Jacob Erlbeck wrote:
Thanks for the patch! Nice to have this implemented. Can you please send the diff for OpenBSC to add the flag for procedure pending?
I added/changed the following guards for < 3.6.0 compilation.
#if SUPERFEMTO_API_VERSION >= SUPERFEMTO_API(3,6,0)
+static int mute_rf_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp) +{
...
+}
#endif
+/* mute/unmute RF time slots */ +int l1if_mute_rf(struct femtol1_hdl *hdl, uint8_t mute[8]) +{
...
+#if SUPERFEMTO_API_VERSION < SUPERFEMTO_API(3,6,0)
- LOGP(DL1C, LOGL_ERROR, "RF-MUTE.req not supported by SuperFemto\n");
- return -ENOTSUP;
+#endif /* < 3.6.0 */
#else
- return l1if_req_compl(hdl, msg, mute_rf_compl_cb);
#endif
Currently a Change Administrative State Request is just applied unconditionally to the object's state object and then acknowledged.
This patch implements the special handling of setting the Radio Carriers state to LOCK or UNLOCK. This is done by passing the appropriate mute command to the L1 layer. Always all radio channels are affected, it is not possible to lock single radio channels. On success, an ACK is sent back to the bsc with the new state (based on the state passed in the callback by the L1 layer). If something went wrong or the firmware doesn't support RF mute, a NACK (REQ_NOT_GRANTED) is sent instead.
Note that a NACK for such a request hasn't been sent by the BTS to the BSC yet, so (albeit it's spec conformant to do so) the BSC must be prepared to handle this correctly.
Ticket: OW#976 Sponsored-by: On-Waves ehf --- include/osmo-bts/oml.h | 1 + src/common/oml.c | 5 ++++ src/osmo-bts-sysmo/oml.c | 70 +++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 72 insertions(+), 4 deletions(-)
diff --git a/include/osmo-bts/oml.h b/include/osmo-bts/oml.h index 92695ca..4281fd3 100644 --- a/include/osmo-bts/oml.h +++ b/include/osmo-bts/oml.h @@ -10,6 +10,7 @@ int oml_mo_send_msg(struct gsm_abis_mo *mo, struct msgb *msg, uint8_t msg_type); int oml_mo_opstart_ack(struct gsm_abis_mo *mo); int oml_mo_opstart_nack(struct gsm_abis_mo *mo, uint8_t nack_cause); int oml_mo_statechg_ack(struct gsm_abis_mo *mo); +int oml_mo_statechg_nack(struct gsm_abis_mo *mo, uint8_t nack_cause);
/* Change the state and send STATE CHG REP */ int oml_mo_state_chg(struct gsm_abis_mo *mo, int op_state, int avail_state); diff --git a/src/common/oml.c b/src/common/oml.c index 1c38c66..bf174b5 100644 --- a/src/common/oml.c +++ b/src/common/oml.c @@ -299,6 +299,11 @@ int oml_mo_statechg_ack(struct gsm_abis_mo *mo) return oml_mo_send_msg(mo, msg, NM_MT_CHG_ADM_STATE_ACK); }
+int oml_mo_statechg_nack(struct gsm_abis_mo *mo, uint8_t nack_cause) +{ + return oml_mo_fom_ack_nack(mo, NM_MT_CHG_ADM_STATE, nack_cause); +} + int oml_mo_opstart_ack(struct gsm_abis_mo *mo) { return oml_mo_fom_ack_nack(mo, NM_MT_OPSTART, 0); diff --git a/src/osmo-bts-sysmo/oml.c b/src/osmo-bts-sysmo/oml.c index 822453f..8e76093 100644 --- a/src/osmo-bts-sysmo/oml.c +++ b/src/osmo-bts-sysmo/oml.c @@ -326,10 +326,31 @@ int bts_model_trx_close(struct gsm_bts_trx *trx) return l1if_gsm_req_compl(fl1h, msg, trx_close_compl_cb); }
+static int trx_rf_lock(struct gsm_bts_trx *trx, int locked) +{ + struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx); + uint8_t mute[8]; + int i; + + for (i = 0; i < ARRAY_SIZE(mute); ++i) + mute[i] = locked ? 1 : 0; + + return l1if_mute_rf(fl1h, mute); +} + int oml_mo_rf_lock_chg(struct gsm_abis_mo *mo, uint8_t mute_state[8], int success) { - return 0; + if (success) { + /* assume mute_state[i] == mute_state[k] */ + mo->nm_state.administrative = + mute_state[0] ? NM_STATE_LOCKED : NM_STATE_UNLOCKED; + mo->procedure_pending = 0; + return oml_mo_statechg_ack(mo); + } else { + mo->procedure_pending = 0; + return oml_mo_statechg_nack(mo, NM_NACK_REQ_NOT_GRANT); + } }
static int ts_connect(struct gsm_bts_trx_ts *ts) @@ -1461,9 +1482,50 @@ int bts_model_opstart(struct gsm_bts *bts, struct gsm_abis_mo *mo, int bts_model_chg_adm_state(struct gsm_bts *bts, struct gsm_abis_mo *mo, void *obj, uint8_t adm_state) { - /* blindly accept all state changes */ - mo->nm_state.administrative = adm_state; - return oml_mo_statechg_ack(mo); + int rc; + int granted = 0; + + switch (mo->obj_class) { + case NM_OC_RADIO_CARRIER: + + if (mo->procedure_pending) { + LOGP(DL1C, LOGL_ERROR, "Discarding adm change command: " + "pending procedure on RC %d\n", + ((struct gsm_bts_trx *)obj)->nr); + return 0; + } + mo->procedure_pending = 1; + switch (adm_state) { + case NM_STATE_LOCKED: + rc = trx_rf_lock(obj, 1); + break; + case NM_STATE_UNLOCKED: + rc = trx_rf_lock(obj, 0); + break; + default: + granted = 1; + break; + } + + if (!granted && rc == 0) + /* in progress, will send ack/nack after completion */ + return 0; + + mo->procedure_pending = 0; + + break; + default: + /* blindly accept all state changes */ + granted = 1; + break; + } + + if (granted) { + mo->nm_state.administrative = adm_state; + return oml_mo_statechg_ack(mo); + } else + return oml_mo_statechg_nack(mo, NM_NACK_REQ_NOT_GRANT); + } int bts_model_rsl_chan_act(struct gsm_lchan *lchan, struct tlv_parsed *tp) {
Currently a Change Administrative State Request is just applied unconditionally to the object's state object and then acknowledged.
This patch implements the special handling of setting the Radio Carriers state to LOCK or UNLOCK. This is done by passing the appropriate mute command to the L1 layer. Always all radio channels are affected, it is not possible to lock single radio channels. On success, an ACK is sent back to the bsc with the new state (based on the state passed in the callback by the L1 layer). If something went wrong or the firmware doesn't support RF mute, a NACK (REQ_NOT_GRANTED) is sent instead.
Note that a NACK for such a request hasn't been sent by the BTS to the BSC yet, so (albeit it's spec conformant to do so) the BSC must be prepared to handle this correctly.
Ticket: OW#976 Sponsored-by: On-Waves ehf --- include/osmo-bts/oml.h | 1 + src/common/oml.c | 5 ++++ src/osmo-bts-sysmo/oml.c | 70 +++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 72 insertions(+), 4 deletions(-)
diff --git a/include/osmo-bts/oml.h b/include/osmo-bts/oml.h index 92695ca..4281fd3 100644 --- a/include/osmo-bts/oml.h +++ b/include/osmo-bts/oml.h @@ -10,6 +10,7 @@ int oml_mo_send_msg(struct gsm_abis_mo *mo, struct msgb *msg, uint8_t msg_type); int oml_mo_opstart_ack(struct gsm_abis_mo *mo); int oml_mo_opstart_nack(struct gsm_abis_mo *mo, uint8_t nack_cause); int oml_mo_statechg_ack(struct gsm_abis_mo *mo); +int oml_mo_statechg_nack(struct gsm_abis_mo *mo, uint8_t nack_cause);
/* Change the state and send STATE CHG REP */ int oml_mo_state_chg(struct gsm_abis_mo *mo, int op_state, int avail_state); diff --git a/src/common/oml.c b/src/common/oml.c index 1c38c66..bf174b5 100644 --- a/src/common/oml.c +++ b/src/common/oml.c @@ -299,6 +299,11 @@ int oml_mo_statechg_ack(struct gsm_abis_mo *mo) return oml_mo_send_msg(mo, msg, NM_MT_CHG_ADM_STATE_ACK); }
+int oml_mo_statechg_nack(struct gsm_abis_mo *mo, uint8_t nack_cause) +{ + return oml_mo_fom_ack_nack(mo, NM_MT_CHG_ADM_STATE, nack_cause); +} + int oml_mo_opstart_ack(struct gsm_abis_mo *mo) { return oml_mo_fom_ack_nack(mo, NM_MT_OPSTART, 0); diff --git a/src/osmo-bts-sysmo/oml.c b/src/osmo-bts-sysmo/oml.c index 822453f..c87acb6 100644 --- a/src/osmo-bts-sysmo/oml.c +++ b/src/osmo-bts-sysmo/oml.c @@ -326,10 +326,31 @@ int bts_model_trx_close(struct gsm_bts_trx *trx) return l1if_gsm_req_compl(fl1h, msg, trx_close_compl_cb); }
+static int trx_rf_lock(struct gsm_bts_trx *trx, int locked) +{ + struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx); + uint8_t mute[8]; + int i; + + for (i = 0; i < ARRAY_SIZE(mute); ++i) + mute[i] = locked ? 1 : 0; + + return l1if_mute_rf(fl1h, mute); +} + int oml_mo_rf_lock_chg(struct gsm_abis_mo *mo, uint8_t mute_state[8], int success) { - return 0; + if (success) { + /* assume mute_state[i] == mute_state[k] */ + mo->nm_state.administrative = + mute_state[0] ? NM_STATE_LOCKED : NM_STATE_UNLOCKED; + mo->procedure_pending = 0; + return oml_mo_statechg_ack(mo); + } else { + mo->procedure_pending = 0; + return oml_mo_statechg_nack(mo, NM_NACK_REQ_NOT_GRANT); + } }
static int ts_connect(struct gsm_bts_trx_ts *ts) @@ -1461,9 +1482,50 @@ int bts_model_opstart(struct gsm_bts *bts, struct gsm_abis_mo *mo, int bts_model_chg_adm_state(struct gsm_bts *bts, struct gsm_abis_mo *mo, void *obj, uint8_t adm_state) { - /* blindly accept all state changes */ - mo->nm_state.administrative = adm_state; - return oml_mo_statechg_ack(mo); + int rc = -EINVAL; + int granted = 0; + + switch (mo->obj_class) { + case NM_OC_RADIO_CARRIER: + + if (mo->procedure_pending) { + LOGP(DL1C, LOGL_ERROR, "Discarding adm change command: " + "pending procedure on RC %d\n", + ((struct gsm_bts_trx *)obj)->nr); + return 0; + } + mo->procedure_pending = 1; + switch (adm_state) { + case NM_STATE_LOCKED: + rc = trx_rf_lock(obj, 1); + break; + case NM_STATE_UNLOCKED: + rc = trx_rf_lock(obj, 0); + break; + default: + granted = 1; + break; + } + + if (!granted && rc == 0) + /* in progress, will send ack/nack after completion */ + return 0; + + mo->procedure_pending = 0; + + break; + default: + /* blindly accept all state changes */ + granted = 1; + break; + } + + if (granted) { + mo->nm_state.administrative = adm_state; + return oml_mo_statechg_ack(mo); + } else + return oml_mo_statechg_nack(mo, NM_NACK_REQ_NOT_GRANT); + } int bts_model_rsl_chan_act(struct gsm_lchan *lchan, struct tlv_parsed *tp) {