aboutsummaryrefslogtreecommitdiffstats
path: root/src/osmo-bts-sysmo/l1_if.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/osmo-bts-sysmo/l1_if.c')
-rw-r--r--src/osmo-bts-sysmo/l1_if.c421
1 files changed, 250 insertions, 171 deletions
diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c
index df39e2f4..9ca1c323 100644
--- a/src/osmo-bts-sysmo/l1_if.c
+++ b/src/osmo-bts-sysmo/l1_if.c
@@ -13,7 +13,7 @@
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
@@ -51,6 +51,7 @@
#include <osmo-bts/msg_utils.h>
#include <osmo-bts/dtx_dl_amr_fsm.h>
#include <osmo-bts/tx_power.h>
+#include <osmo-bts/nm_common_fsm.h>
#include <sysmocom/femtobts/superfemto.h>
#include <sysmocom/femtobts/gsml1prim.h>
@@ -343,7 +344,7 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg,
abort();
}
- len = msgb_l2len(msg);
+ len = (msg->l2h) ? msgb_l2len(msg) : 0;
chan_nr = l1sap->u.data.chan_nr;
link_id = l1sap->u.data.link_id;
@@ -391,9 +392,8 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg,
else
sapi = GsmL1_Sapi_Agch;
} else {
- LOGPFN(DL1C, LOGL_NOTICE, u32Fn, "unknown prim %d op %d "
- "chan_nr %d link_id %d\n", l1sap->oph.primitive,
- l1sap->oph.operation, chan_nr, link_id);
+ LOGPLCFN(lchan, u32Fn, DL1C, LOGL_NOTICE, "unknown prim %d op %d " "chan_nr %d link_id %d\n",
+ l1sap->oph.primitive, l1sap->oph.operation, chan_nr, link_id);
msgb_free(l1msg);
return -EINVAL;
}
@@ -454,9 +454,8 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg,
memcpy(l1p->u.phDataReq.msgUnitParam.u8Buffer, msg->l2h,
msgb_l2len(msg));
}
- LOGPFN(DL1P, LOGL_DEBUG, u32Fn, "PH-DATA.req(%s)\n",
- osmo_hexdump(l1p->u.phDataReq.msgUnitParam.u8Buffer,
- l1p->u.phDataReq.msgUnitParam.u8Size));
+ LOGPLCFN(lchan, u32Fn, DL1P, LOGL_DEBUG, "PH-DATA.req(%s)\n",
+ osmo_hexdump(l1p->u.phDataReq.msgUnitParam.u8Buffer, l1p->u.phDataReq.msgUnitParam.u8Size));
} else {
/* empty frame */
GsmL1_Prim_t *l1p = msgb_l1prim(l1msg);
@@ -466,7 +465,7 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg,
/* send message to DSP's queue */
if (osmo_wqueue_enqueue(&fl1->write_q[MQ_L1_WRITE], l1msg) != 0) {
- LOGPFN(DL1P, LOGL_ERROR, u32Fn, "MQ_L1_WRITE queue full. Dropping msg.\n");
+ LOGPLCFN(lchan, u32Fn, DL1P, LOGL_ERROR, "MQ_L1_WRITE queue full. Dropping msg.\n");
msgb_free(l1msg);
} else
dtx_int_signal(lchan);
@@ -504,7 +503,6 @@ static int ph_tch_req(struct gsm_bts_trx *trx, struct msgb *msg,
/* create new message and fill data */
if (msg) {
- msgb_pull(msg, sizeof(*l1sap));
/* create new message */
nmsg = l1p_msgb_alloc();
if (!nmsg)
@@ -513,7 +511,7 @@ static int ph_tch_req(struct gsm_bts_trx *trx, struct msgb *msg,
rc = l1if_tch_encode(lchan,
l1p->u.phDataReq.msgUnitParam.u8Buffer,
&l1p->u.phDataReq.msgUnitParam.u8Size,
- msg->data, msg->len, u32Fn, use_cache,
+ msgb_l2(msg), msgb_l2len(msg), u32Fn, use_cache,
l1sap->u.tch.marker);
if (rc < 0) {
/* no data encoded for L1: smth will be generated below */
@@ -550,7 +548,7 @@ static int ph_tch_req(struct gsm_bts_trx *trx, struct msgb *msg,
}
/* send message to DSP's queue */
if (osmo_wqueue_enqueue(&fl1->write_q[MQ_L1_WRITE], nmsg) != 0) {
- LOGPFN(DL1P, LOGL_ERROR, u32Fn, "MQ_L1_WRITE queue full. Dropping msg.\n");
+ LOGPLCFN(lchan, u32Fn, DL1P, LOGL_ERROR, "MQ_L1_WRITE queue full. Dropping msg.\n");
msgb_free(nmsg);
return -ENOBUFS;
}
@@ -606,6 +604,15 @@ static int mph_info_req(struct gsm_bts_trx *trx, struct msgb *msg,
else
l1if_rsl_chan_rel(lchan);
break;
+ case PRIM_INFO_ACT_UL_ACC:
+ case PRIM_INFO_DEACT_UL_ACC:
+ chan_nr = l1sap->u.info.u.ulacc_req.chan_nr;
+ lchan = get_lchan_by_chan_nr(trx, chan_nr);
+ if (l1sap->u.info.type == PRIM_INFO_ACT_UL_ACC)
+ l1if_set_ul_acc(lchan, true);
+ else
+ l1if_set_ul_acc(lchan, false);
+ break;
default:
LOGP(DL1C, LOGL_NOTICE, "unknown MPH-INFO.req %d\n",
l1sap->u.info.type);
@@ -682,7 +689,7 @@ static enum gsm_phys_chan_config pick_pchan(struct gsm_bts_trx_ts *ts)
if (ts->flags & TS_F_PDCH_ACTIVE)
return GSM_PCHAN_PDCH;
return GSM_PCHAN_TCH_F;
- case GSM_PCHAN_TCH_F_TCH_H_PDCH:
+ case GSM_PCHAN_OSMO_DYN:
return ts->dyn.pchan_is;
default:
return ts->pchan;
@@ -696,7 +703,7 @@ static uint8_t chan_nr_by_sapi(struct gsm_bts_trx_ts *ts,
uint8_t cbits = 0;
enum gsm_phys_chan_config pchan = pick_pchan(ts);
OSMO_ASSERT(pchan != GSM_PCHAN_TCH_F_PDCH);
- OSMO_ASSERT(pchan != GSM_PCHAN_TCH_F_TCH_H_PDCH);
+ OSMO_ASSERT(pchan != GSM_PCHAN_OSMO_DYN);
switch (sapi) {
case GsmL1_Sapi_Bcch:
@@ -796,6 +803,45 @@ static uint8_t chan_nr_by_sapi(struct gsm_bts_trx_ts *ts,
return (cbits << 3) | u8Tn;
}
+static const enum l1sap_common_sapi common_sapi_by_sapi_t[] = {
+ [GsmL1_Sapi_Idle] = L1SAP_COMMON_SAPI_IDLE,
+ [GsmL1_Sapi_Fcch] = L1SAP_COMMON_SAPI_FCCH,
+ [GsmL1_Sapi_Sch] = L1SAP_COMMON_SAPI_SCH,
+ [GsmL1_Sapi_Sacch] = L1SAP_COMMON_SAPI_SACCH,
+ [GsmL1_Sapi_Sdcch] = L1SAP_COMMON_SAPI_SDCCH,
+ [GsmL1_Sapi_Bcch] = L1SAP_COMMON_SAPI_BCCH,
+ [GsmL1_Sapi_Pch] = L1SAP_COMMON_SAPI_PCH,
+ [GsmL1_Sapi_Agch] = L1SAP_COMMON_SAPI_AGCH,
+ [GsmL1_Sapi_Cbch] = L1SAP_COMMON_SAPI_CBCH,
+ [GsmL1_Sapi_Rach] = L1SAP_COMMON_SAPI_RACH,
+ [GsmL1_Sapi_TchF] = L1SAP_COMMON_SAPI_TCH_F,
+ [GsmL1_Sapi_FacchF] = L1SAP_COMMON_SAPI_FACCH_F,
+ [GsmL1_Sapi_TchH] = L1SAP_COMMON_SAPI_TCH_H,
+ [GsmL1_Sapi_FacchH] = L1SAP_COMMON_SAPI_FACCH_H,
+ [GsmL1_Sapi_Nch] = L1SAP_COMMON_SAPI_NCH,
+ [GsmL1_Sapi_Pdtch] = L1SAP_COMMON_SAPI_PDTCH,
+ [GsmL1_Sapi_Pacch] = L1SAP_COMMON_SAPI_PACCH,
+ [GsmL1_Sapi_Pbcch] = L1SAP_COMMON_SAPI_PBCCH,
+ [GsmL1_Sapi_Pagch] = L1SAP_COMMON_SAPI_PAGCH,
+ [GsmL1_Sapi_Ppch] = L1SAP_COMMON_SAPI_PPCH,
+ [GsmL1_Sapi_Pnch] = L1SAP_COMMON_SAPI_PNCH,
+ [GsmL1_Sapi_Ptcch] = L1SAP_COMMON_SAPI_PTCCH,
+ [GsmL1_Sapi_Prach] = L1SAP_COMMON_SAPI_PRACH,
+};
+
+static enum l1sap_common_sapi get_common_sapi(GsmL1_Sapi_t sapi)
+{
+ if (sapi >= GsmL1_Sapi_NUM)
+ return L1SAP_COMMON_SAPI_UNKNOWN;
+ return common_sapi_by_sapi_t[sapi];
+}
+
+static void set_log_ctx_sapi(GsmL1_Sapi_t sapi)
+{
+ l1sap_log_ctx_sapi = get_common_sapi(sapi);
+ log_set_context(LOG_CTX_L1_SAPI, &l1sap_log_ctx_sapi);
+}
+
static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1,
GsmL1_PhReadyToSendInd_t *rts_ind,
struct msgb *l1p_msg)
@@ -812,6 +858,8 @@ static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1,
uint8_t chan_nr, link_id;
uint32_t fn;
+ set_log_ctx_sapi(rts_ind->sapi);
+
/* check if primitive should be handled by common part */
chan_nr = chan_nr_by_sapi(&trx->ts[rts_ind->u8Tn], rts_ind->sapi,
rts_ind->subCh, rts_ind->u8Tn, rts_ind->u32Fn);
@@ -896,31 +944,8 @@ empty_frame:
goto tx;
}
-static void dump_meas_res(int ll, GsmL1_MeasParam_t *m)
-{
- LOGPC(DL1C, ll, ", Meas: RSSI %-3.2f dBm, Qual %-3.2f dB, "
- "BER %-3.2f, Timing %d\n", m->fRssi, m->fLinkQuality,
- m->fBer, m->i16BurstTiming);
-}
-
-static int process_meas_res(struct gsm_bts_trx *trx, uint8_t chan_nr,
- uint32_t fn, GsmL1_MeasParam_t *m)
-{
- struct osmo_phsap_prim l1sap;
- memset(&l1sap, 0, sizeof(l1sap));
- osmo_prim_init(&l1sap.oph, SAP_GSM_PH, PRIM_MPH_INFO,
- PRIM_OP_INDICATION, NULL);
- l1sap.u.info.type = PRIM_INFO_MEAS;
- l1sap.u.info.u.meas_ind.chan_nr = chan_nr;
- l1sap.u.info.u.meas_ind.ta_offs_256bits = m->i16BurstTiming * 64;
- l1sap.u.info.u.meas_ind.ber10k = (unsigned int) (m->fBer * 10000);
- l1sap.u.info.u.meas_ind.inv_rssi = (uint8_t) (m->fRssi * -1);
- l1sap.u.info.u.meas_ind.fn = fn;
-
- /* l1sap wants to take msgb ownership. However, as there is no
- * msg, it will msgb_free(l1sap.oph.msg == NULL) */
- return l1sap_up(trx, &l1sap);
-}
+#define LOG_FMT_MEAS "Meas: RSSI %-3.2f dBm, Qual %-3.2f dB, BER %-3.2f, Timing %d"
+#define LOG_PARAM_MEAS(meas_param) (meas_param)->fRssi, (meas_param)->fLinkQuality, (meas_param)->fBer, (meas_param)->i16BurstTiming
static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_ind,
struct msgb *l1p_msg)
@@ -933,6 +958,8 @@ static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_i
struct gsm_time g_time;
int rc = 0;
+ set_log_ctx_sapi(data_ind->sapi);
+
chan_nr = chan_nr_by_sapi(&trx->ts[data_ind->u8Tn], data_ind->sapi,
data_ind->subCh, data_ind->u8Tn, data_ind->u32Fn);
if (!chan_nr) {
@@ -944,14 +971,12 @@ static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_i
fn = data_ind->u32Fn;
link_id = (data_ind->sapi == GsmL1_Sapi_Sacch) ? LID_SACCH : LID_DEDIC;
- process_meas_res(trx, chan_nr, fn, &data_ind->measParam);
-
gsm_fn2gsmtime(&g_time, fn);
- DEBUGPGT(DL1P, &g_time, "Rx PH-DATA.ind %s (hL2 %08x): %s\n",
+ DEBUGPGT(DL1P, &g_time, "Rx PH-DATA.ind %s (hL2 %08x): %s, " LOG_FMT_MEAS "\n",
get_value_string(femtobts_l1sapi_names, data_ind->sapi), data_ind->hLayer2,
- osmo_hexdump(data_ind->msgUnitParam.u8Buffer, data_ind->msgUnitParam.u8Size));
- dump_meas_res(LOGL_DEBUG, &data_ind->measParam);
+ osmo_hexdump(data_ind->msgUnitParam.u8Buffer, data_ind->msgUnitParam.u8Size),
+ LOG_PARAM_MEAS(&data_ind->measParam));
/* check for TCH */
if (data_ind->sapi == GsmL1_Sapi_TchF
@@ -962,6 +987,25 @@ static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_i
return rc;
}
+ /* If we got FACCH, the RTP clock needs to account for it,
+ * and if we have rtp continuous-streaming enabled,
+ * an actual BFI packet will be emitted.
+ *
+ * Only the case of TCH/F is currently handled; the task of
+ * supporting TCH/H is left as a FIXME for other/later
+ * developers. The difficulty with supporting FACCH/H is that
+ * only one GsmL1_Sapi_FacchH message will be received,
+ * covering 40 ms of time, but two RTP "tick" output calls
+ * will need to be made, with appropriately adjusted frame
+ * numbers. As a further consideration for rtp continuous-streaming
+ * mode, having the two RTP BFI packets sent directly back to back,
+ * as opposed to proper 20 ms timing, may be so undesirable
+ * that some deployments may rather disable TCH/H (use only TCH/F)
+ * than deal with the extra pain, or use TCH/H only on SDR-based
+ * BTS with osmo-bts-trx where correct timing is easily achieved. */
+ if (data_ind->sapi == GsmL1_Sapi_FacchF)
+ l1if_tch_rx_facch(trx, chan_nr, l1p_msg);
+
/* fill L1SAP header */
sap_msg = l1sap_msgb_alloc(data_ind->msgUnitParam.u8Size);
l1sap = msgb_l1sap_prim(sap_msg);
@@ -971,11 +1015,10 @@ static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_i
l1sap->u.data.chan_nr = chan_nr;
l1sap->u.data.fn = fn;
l1sap->u.data.rssi = (int8_t) (data_ind->measParam.fRssi);
- if (!pcu_direct) { /* FIXME: if pcu_direct=1, then this is not set, what to do in pcu_tx_data_ind() in this case ?*/
- l1sap->u.data.ber10k = data_ind->measParam.fBer * 10000;
- l1sap->u.data.ta_offs_256bits = data_ind->measParam.i16BurstTiming * 64;
- l1sap->u.data.lqual_cb = data_ind->measParam.fLinkQuality * 10;
- }
+ l1sap->u.data.ber10k = data_ind->measParam.fBer * 10000;
+ l1sap->u.data.ta_offs_256bits = data_ind->measParam.i16BurstTiming * 64;
+ l1sap->u.data.lqual_cb = data_ind->measParam.fLinkQuality * 10;
+
/* copy data from L1 primitive to L1SAP primitive */
sap_msg->l2h = msgb_put(sap_msg, data_ind->msgUnitParam.u8Size);
memcpy(sap_msg->l2h, data_ind->msgUnitParam.u8Buffer,
@@ -996,7 +1039,9 @@ static int handle_ph_ra_ind(struct femtol1_hdl *fl1, GsmL1_PhRaInd_t *ra_ind,
int rc;
struct ph_rach_ind_param rach_ind_param;
- dump_meas_res(LOGL_DEBUG, &ra_ind->measParam);
+ set_log_ctx_sapi(ra_ind->sapi);
+ LOGPFN(DL1C, LOGL_DEBUG, ra_ind->u32Fn, "Rx PH-RA.ind, " LOG_FMT_MEAS "\n",
+ LOG_PARAM_MEAS(&ra_ind->measParam));
if ((ra_ind->msgUnitParam.u8Size != 1) &&
(ra_ind->msgUnitParam.u8Size != 2)) {
@@ -1192,13 +1237,127 @@ int l1if_handle_sysprim(struct femtol1_hdl *fl1h, struct msgb *msg)
return l1if_handle_ind(fl1h, msg);
}
+static void mute_handle_ts(struct gsm_bts_trx_ts *ts, int is_muted)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ts->lchan); i++) {
+ struct gsm_lchan *lchan = &ts->lchan[i];
+
+ if (!is_muted)
+ continue;
+
+ if (lchan->state != LCHAN_S_ACTIVE)
+ continue;
+
+ /* skip channels that might be active for another reason */
+ if (lchan->type == GSM_LCHAN_CCCH)
+ continue;
+ if (lchan->type == GSM_LCHAN_PDTCH)
+ continue;
+
+ if (lchan->s <= 0)
+ continue;
+
+ lchan->s = 0;
+ rsl_tx_conn_fail(lchan, RSL_ERR_RADIO_LINK_FAIL);
+ }
+}
+
+#if SUPERFEMTO_API_VERSION >= SUPERFEMTO_API(3, 6, 0)
+static int mute_rf_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp,
+ void *data)
+{
+ 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));
+ if (trx->mo.fi->state != NM_RCARRIER_ST_OP_DISABLED_NOTINSTALLED)
+ oml_mo_rf_lock_chg(&trx->mo, fl1h->last_rf_mute, 0);
+ } else {
+ int i;
+
+ LOGP(DL1C, LOGL_INFO, "Rx RF-MUTE.conf with status=%s\n",
+ get_value_string(femtobts_l1status_names, status));
+ bts_update_status(BTS_STATUS_RF_MUTE, fl1h->last_rf_mute[0]);
+ if (trx->mo.fi->state != NM_RCARRIER_ST_OP_DISABLED_NOTINSTALLED)
+ oml_mo_rf_lock_chg(&trx->mo, fl1h->last_rf_mute, 1);
+
+ osmo_static_assert(
+ ARRAY_SIZE(trx->ts) >= ARRAY_SIZE(fl1h->last_rf_mute),
+ ts_array_size);
+
+ for (i = 0; i < ARRAY_SIZE(fl1h->last_rf_mute); ++i)
+ mute_handle_ts(&trx->ts[i], fl1h->last_rf_mute[i]);
+ }
+
+ msgb_free(resp);
+
+ return 0;
+}
+#endif
+
+/* mute/unmute RF time slots */
+int l1if_mute_rf(struct femtol1_hdl *hdl, uint8_t mute[8], l1if_compl_cb *cb)
+{
+
+ 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)
+ const uint8_t unmuted[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+ struct gsm_bts_trx *trx = hdl->phy_inst->trx;
+ int i;
+ LOGP(DL1C, LOGL_ERROR, "RF-MUTE.req not supported by SuperFemto\n");
+ /* always acknowledge an un-MUTE (which is a no-op if MUTE is not supported */
+ if (!memcmp(mute, unmuted, ARRAY_SIZE(unmuted))) {
+ bts_update_status(BTS_STATUS_RF_MUTE, mute[0]);
+ oml_mo_rf_lock_chg(&trx->mo, mute, 1);
+ for (i = 0; i < ARRAY_SIZE(unmuted); ++i)
+ mute_handle_ts(&trx->ts[i], mute[i]);
+ return 0;
+ }
+ return -ENOTSUP;
+#else
+ struct msgb *msg = sysp_msgb_alloc();
+ SuperFemto_Prim_t *sysp = msgb_sysprim(msg);
+ 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, cb ? cb : mute_rf_compl_cb, NULL);
+#endif /* < 3.6.0 */
+}
+
+static int activate_rf_mute_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data)
+{
+#if SUPERFEMTO_API_VERSION >= SUPERFEMTO_API(3, 6, 0)
+ mute_rf_compl_cb(trx, resp, data);
+#endif
+
+ /* signal availability */
+ osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_SW_ACT, NULL);
+ osmo_fsm_inst_dispatch(trx->bb_transc.mo.fi, NM_EV_SW_ACT, NULL);
+
+ return 0;
+}
+
+int trx_rf_lock(struct gsm_bts_trx *trx, int locked, l1if_compl_cb *cb);
+
static int activate_rf_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp,
void *data)
{
SuperFemto_Prim_t *sysp = msgb_sysprim(resp);
GsmL1_Status_t status;
int on = 0;
- unsigned int i;
if (sysp->id == SuperFemto_PrimId_ActivateRfCnf)
on = 1;
@@ -1217,21 +1376,18 @@ 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(femtobts_l1status_names, status));
bts_shutdown(trx->bts, "RF-ACT failure");
- } else
+ } else {
bts_update_status(BTS_STATUS_RF_ACTIVE, 1);
-
- /* signal availability */
- oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OK);
- oml_mo_tx_sw_act_rep(&trx->mo);
- oml_mo_state_chg(&trx->bb_transc.mo, -1, NM_AVSTATE_OK);
- oml_mo_tx_sw_act_rep(&trx->bb_transc.mo);
-
- for (i = 0; i < ARRAY_SIZE(trx->ts); i++)
- oml_mo_state_chg(&trx->ts[i].mo, NM_OPSTATE_DISABLED, NM_AVSTATE_DEPENDENCY);
+#if SUPERFEMTO_API_VERSION >= SUPERFEMTO_API(3, 6, 0)
+ trx_rf_lock(trx, 1, activate_rf_mute_compl_cb);
+#else
+ activate_rf_mute_compl_cb(trx, resp, NULL);
+#endif
+ }
} else {
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);
+ osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_DISABLE, NULL);
+ osmo_fsm_inst_dispatch(trx->bb_transc.mo.fi, NM_EV_DISABLE, NULL);
}
msgb_free(resp);
@@ -1325,104 +1481,6 @@ int l1if_activate_rf(struct femtol1_hdl *hdl, int on)
return l1if_req_compl(hdl, msg, activate_rf_compl_cb, NULL);
}
-static void mute_handle_ts(struct gsm_bts_trx_ts *ts, int is_muted)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(ts->lchan); i++) {
- struct gsm_lchan *lchan = &ts->lchan[i];
-
- if (!is_muted)
- continue;
-
- if (lchan->state != LCHAN_S_ACTIVE)
- continue;
-
- /* skip channels that might be active for another reason */
- if (lchan->type == GSM_LCHAN_CCCH)
- continue;
- if (lchan->type == GSM_LCHAN_PDTCH)
- continue;
-
- if (lchan->s <= 0)
- continue;
-
- lchan->s = 0;
- rsl_tx_conn_fail(lchan, RSL_ERR_RADIO_LINK_FAIL);
- }
-}
-
-#if SUPERFEMTO_API_VERSION >= SUPERFEMTO_API(3,6,0)
-static int mute_rf_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp,
- void *data)
-{
- 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 {
- int i;
-
- LOGP(DL1C, LOGL_INFO, "Rx RF-MUTE.conf with status=%s\n",
- get_value_string(femtobts_l1status_names, status));
- bts_update_status(BTS_STATUS_RF_MUTE, fl1h->last_rf_mute[0]);
- oml_mo_rf_lock_chg(&trx->mo, fl1h->last_rf_mute, 1);
-
- osmo_static_assert(
- ARRAY_SIZE(trx->ts) >= ARRAY_SIZE(fl1h->last_rf_mute),
- ts_array_size);
-
- for (i = 0; i < ARRAY_SIZE(fl1h->last_rf_mute); ++i)
- mute_handle_ts(&trx->ts[i], fl1h->last_rf_mute[i]);
- }
-
- msgb_free(resp);
-
- return 0;
-}
-#endif
-
-/* mute/unmute RF time slots */
-int l1if_mute_rf(struct femtol1_hdl *hdl, uint8_t mute[8], l1if_compl_cb *cb)
-{
-
- 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)
- const uint8_t unmuted[8] = { 0,0,0,0,0,0,0,0 };
- struct gsm_bts_trx *trx = hdl->phy_inst->trx;
- int i;
- LOGP(DL1C, LOGL_ERROR, "RF-MUTE.req not supported by SuperFemto\n");
- /* always acknowledge an un-MUTE (which is a no-op if MUTE is not supported */
- if (!memcmp(mute, unmuted, ARRAY_SIZE(unmuted))) {
- bts_update_status(BTS_STATUS_RF_MUTE, mute[0]);
- oml_mo_rf_lock_chg(&trx->mo, mute, 1);
- for (i = 0; i < ARRAY_SIZE(unmuted); ++i)
- mute_handle_ts(&trx->ts[i], mute[i]);
- return 0;
- }
- return -ENOTSUP;
-#else
- struct msgb *msg = sysp_msgb_alloc();
- SuperFemto_Prim_t *sysp = msgb_sysprim(msg);
- 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, cb ? cb : mute_rf_compl_cb, NULL);
-#endif /* < 3.6.0 */
-}
-
/* call-back on arrival of DSP+FPGA version + band capability */
static int info_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp,
void *data)
@@ -1444,10 +1502,12 @@ static int info_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp,
fl1h->hw_info.ver_minor = sic->boardVersion.option;
#endif
- LOGP(DL1C, LOGL_INFO, "DSP v%u.%u.%u, FPGA v%u.%u.%u\nn",
- sic->dspVersion.major, sic->dspVersion.minor,
- sic->dspVersion.build, sic->fpgaVersion.major,
- sic->fpgaVersion.minor, sic->fpgaVersion.build);
+ snprintf(trx->pinst->version, sizeof(trx->pinst->version), "%u.%u dsp %u.%u.%u fpga %u.%u.%u",
+ fl1h->hw_info.ver_major, fl1h->hw_info.ver_minor,
+ fl1h->hw_info.dsp_version[0], fl1h->hw_info.dsp_version[1], fl1h->hw_info.dsp_version[2],
+ fl1h->hw_info.fpga_version[0], fl1h->hw_info.fpga_version[1], fl1h->hw_info.fpga_version[2]);
+
+ LOGP(DL1C, LOGL_INFO, "%s\n", trx->pinst->version);
#ifdef HW_SYSMOBTS_V1
if (sic->rfBand.gsm850)
@@ -1483,6 +1543,8 @@ static int info_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp,
msgb_free(resp);
+ phy_link_state_set(trx->pinst->phy_link, PHY_LINK_CONNECTED);
+
/* FIXME: clock related */
return 0;
}
@@ -1846,7 +1908,8 @@ static void fill_trx_power_params(struct gsm_bts_trx *trx,
LOGP(DL1C, LOGL_NOTICE, "Assuming 1002 for sysmoBTS "
"Model number %u\n", fl1h->hw_info.model_nr);
/* fall-through */
- case 1002:
+ case 1002: /* sysmoBTS 1002 */
+ case 1003: /* sysmoBTS 1002 with GPS and PoE */
set_power_param(&trx->power_params, 23, 0);
}
}
@@ -1883,12 +1946,28 @@ int bts_model_phy_link_open(struct phy_link *plink)
hdl = pinst->u.sysmobts.hdl;
osmo_strlcpy(bts->sub_model, sysmobts_model(hdl->hw_info.model_nr, hdl->hw_info.trx_nr), sizeof(bts->sub_model));
- snprintf(pinst->version, sizeof(pinst->version), "%u.%u dsp %u.%u.%u fpga %u.%u.%u",
- hdl->hw_info.ver_major, hdl->hw_info.ver_minor,
- hdl->hw_info.dsp_version[0], hdl->hw_info.dsp_version[1], hdl->hw_info.dsp_version[2],
- hdl->hw_info.fpga_version[0], hdl->hw_info.fpga_version[1], hdl->hw_info.fpga_version[2]);
- phy_link_state_set(plink, PHY_LINK_CONNECTED);
+ /* Frequency bands indicated to the BSC */
+ for (unsigned int i = 0; i < sizeof(hdl->hw_info.band_support) * 8; i++) {
+ if (~hdl->hw_info.band_support & (1 << i))
+ continue;
+ switch (1 << i) {
+ case GSM_BAND_850:
+ pinst->trx->support.freq_bands |= NM_IPAC_F_FREQ_BAND_850;
+ break;
+ case GSM_BAND_900:
+ pinst->trx->support.freq_bands |= NM_IPAC_F_FREQ_BAND_PGSM;
+ /* XXX: does GSM_BAND_900 include NM_IPAC_F_FREQ_BAND_EGSM? */
+ /* XXX: does GSM_BAND_900 include NM_IPAC_F_FREQ_BAND_RGSM? */
+ break;
+ case GSM_BAND_1800:
+ pinst->trx->support.freq_bands |= NM_IPAC_F_FREQ_BAND_DCS;
+ break;
+ case GSM_BAND_1900:
+ pinst->trx->support.freq_bands |= NM_IPAC_F_FREQ_BAND_PCS;
+ break;
+ }
+ }
return 0;
}