<p>laforge <strong>submitted</strong> this change.</p><p><a href="https://gerrit.osmocom.org/c/osmo-bts/+/20284">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  laforge: Looks good to me, approved
  Jenkins Builder: Verified

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">Introduce NM Radio Carrier and Baseband Transceiver FSMs<br><br>All the Operative State logic to manage a RadioCarrier//BBTransc NM objects is<br>centralized in these FSM, where other parts of the code simply send<br>events to it.<br>This allows keeping state consistent and offloading logic from each bts<br>backend, since they are only required to submit events now.<br>The idea in the long run is to also replace other NM objects with<br>similar FSMs.<br><br>This improved logic fixes bug where PHY + RSL link became available before<br>OPSTART and hence op state changed to Enabled before receiving any OPSTART message.<br><br>Change-Id: Ifb249a821c4270918699b6375a72b3a618e8cfbe<br>---<br>M include/osmo-bts/bts_trx.h<br>M include/osmo-bts/nm_common_fsm.h<br>M src/common/Makefile.am<br>M src/common/bts_trx.c<br>A src/common/nm_bb_transc_fsm.c<br>M src/common/nm_common_fsm.c<br>A src/common/nm_radio_carrier_fsm.c<br>M src/common/phy_link.c<br>M src/osmo-bts-litecell15/l1_if.c<br>M src/osmo-bts-litecell15/oml.c<br>M src/osmo-bts-oc2g/l1_if.c<br>M src/osmo-bts-oc2g/oml.c<br>M src/osmo-bts-octphy/l1_if.c<br>M src/osmo-bts-octphy/l1_oml.c<br>M src/osmo-bts-omldummy/bts_model.c<br>M src/osmo-bts-sysmo/l1_if.c<br>M src/osmo-bts-sysmo/oml.c<br>M src/osmo-bts-trx/l1_if.c<br>M src/osmo-bts-virtual/bts_model.c<br>19 files changed, 632 insertions(+), 160 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/osmo-bts/bts_trx.h b/include/osmo-bts/bts_trx.h</span><br><span>index ce2d4d4..08eaf65 100644</span><br><span>--- a/include/osmo-bts/bts_trx.h</span><br><span>+++ b/include/osmo-bts/bts_trx.h</span><br><span>@@ -2,6 +2,10 @@</span><br><span> </span><br><span> #include <osmo-bts/gsm_data.h></span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct gsm_bts_bb_trx {</span><br><span style="color: hsl(120, 100%, 40%);">+    struct gsm_abis_mo mo;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* One TRX in a BTS */</span><br><span> struct gsm_bts_trx {</span><br><span>       /* list header in bts->trx_list */</span><br><span>@@ -16,10 +20,9 @@</span><br><span>   uint8_t rsl_tei;</span><br><span>     struct e1inp_sign_link *rsl_link;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* NM Radio Carrier and Baseband Transciever */</span><br><span>      struct gsm_abis_mo mo;</span><br><span style="color: hsl(0, 100%, 40%);">-  struct {</span><br><span style="color: hsl(0, 100%, 40%);">-                struct gsm_abis_mo mo;</span><br><span style="color: hsl(0, 100%, 40%);">-  } bb_transc;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct gsm_bts_bb_trx bb_transc;</span><br><span> </span><br><span>         uint16_t arfcn;</span><br><span>      int nominal_power;              /* in dBm */</span><br><span>@@ -45,6 +48,9 @@</span><br><span>     struct gsm_bts_trx_ts ts[TRX_NR_TS];</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static inline struct gsm_bts_trx *gsm_bts_bb_trx_get_trx(struct gsm_bts_bb_trx *bb_transc) {</span><br><span style="color: hsl(120, 100%, 40%);">+  return (struct gsm_bts_trx *)container_of(bb_transc, struct gsm_bts_trx, bb_transc);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span> </span><br><span> struct gsm_bts_trx *gsm_bts_trx_alloc(struct gsm_bts *bts);</span><br><span> int bts_trx_init(struct gsm_bts_trx *trx);</span><br><span>diff --git a/include/osmo-bts/nm_common_fsm.h b/include/osmo-bts/nm_common_fsm.h</span><br><span>index 93e4bde..4671725 100644</span><br><span>--- a/include/osmo-bts/nm_common_fsm.h</span><br><span>+++ b/include/osmo-bts/nm_common_fsm.h</span><br><span>@@ -31,6 +31,12 @@</span><br><span>   NM_EV_SW_ACT,</span><br><span>        NM_EV_OPSTART_ACK,</span><br><span>   NM_EV_OPSTART_NACK,</span><br><span style="color: hsl(120, 100%, 40%);">+   NM_EV_RSL_UP, /* RadioCarrier and BaseBand Transceiver only */</span><br><span style="color: hsl(120, 100%, 40%);">+        NM_EV_RSL_DOWN,  /* RadioCarrier and BaseBand Transceiver only */</span><br><span style="color: hsl(120, 100%, 40%);">+     NM_EV_PHYLINK_UP, /* RadioCarrier and BaseBand Transceiver only */</span><br><span style="color: hsl(120, 100%, 40%);">+    NM_EV_PHYLINK_DOWN,  /* RadioCarrier and BaseBand Transceiver only */</span><br><span style="color: hsl(120, 100%, 40%);">+ NM_EV_DISABLE,  /* RadioCarrier and BaseBand Transceiver only */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> };</span><br><span> extern const struct value_string nm_fsm_event_names[];</span><br><span> </span><br><span>@@ -50,3 +56,19 @@</span><br><span>  NM_BTS_ST_OP_ENABLED,</span><br><span> };</span><br><span> extern struct osmo_fsm nm_bts_fsm;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* BaseBand Transceiver */</span><br><span style="color: hsl(120, 100%, 40%);">+enum nm_bb_transc_op_fsm_states {</span><br><span style="color: hsl(120, 100%, 40%);">+    NM_BBTRANSC_ST_OP_DISABLED_NOTINSTALLED,</span><br><span style="color: hsl(120, 100%, 40%);">+      NM_BBTRANSC_ST_OP_DISABLED_OFFLINE,</span><br><span style="color: hsl(120, 100%, 40%);">+   NM_BBTRANSC_ST_OP_ENABLED,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+extern struct osmo_fsm nm_bb_transc_fsm;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Radio Carrier */</span><br><span style="color: hsl(120, 100%, 40%);">+enum nm_rcarrier_op_fsm_states {</span><br><span style="color: hsl(120, 100%, 40%);">+     NM_RCARRIER_ST_OP_DISABLED_NOTINSTALLED,</span><br><span style="color: hsl(120, 100%, 40%);">+      NM_RCARRIER_ST_OP_DISABLED_OFFLINE,</span><br><span style="color: hsl(120, 100%, 40%);">+   NM_RCARRIER_ST_OP_ENABLED,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+extern struct osmo_fsm nm_rcarrier_fsm;</span><br><span>diff --git a/src/common/Makefile.am b/src/common/Makefile.am</span><br><span>index 463797e..7156785 100644</span><br><span>--- a/src/common/Makefile.am</span><br><span>+++ b/src/common/Makefile.am</span><br><span>@@ -40,6 +40,8 @@</span><br><span>     nm_common_fsm.c \</span><br><span>    nm_bts_sm_fsm.c \</span><br><span>    nm_bts_fsm.c \</span><br><span style="color: hsl(120, 100%, 40%);">+        nm_bb_transc_fsm.c \</span><br><span style="color: hsl(120, 100%, 40%);">+  nm_radio_carrier_fsm.c \</span><br><span>     $(NULL)</span><br><span> </span><br><span> libl1sched_a_SOURCES = scheduler.c</span><br><span>diff --git a/src/common/bts_trx.c b/src/common/bts_trx.c</span><br><span>index 93e15c3..04c21c3 100644</span><br><span>--- a/src/common/bts_trx.c</span><br><span>+++ b/src/common/bts_trx.c</span><br><span>@@ -17,6 +17,8 @@</span><br><span>  *</span><br><span>  */</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/fsm.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #include <osmocom/gsm/abis_nm.h></span><br><span> </span><br><span> #include <osmo-bts/logging.h></span><br><span>@@ -26,6 +28,20 @@</span><br><span> #include <osmo-bts/bts_model.h></span><br><span> #include <osmo-bts/rsl.h></span><br><span> #include <osmo-bts/phy_link.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/nm_common_fsm.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int gsm_bts_trx_talloc_destructor(struct gsm_bts_trx *trx)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   if (trx->bb_transc.mo.fi) {</span><br><span style="color: hsl(120, 100%, 40%);">+                osmo_fsm_inst_free(trx->bb_transc.mo.fi);</span><br><span style="color: hsl(120, 100%, 40%);">+          trx->bb_transc.mo.fi = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (trx->mo.fi) {</span><br><span style="color: hsl(120, 100%, 40%);">+          osmo_fsm_inst_free(trx->mo.fi);</span><br><span style="color: hsl(120, 100%, 40%);">+            trx->mo.fi = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+     return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span> </span><br><span> struct gsm_bts_trx *gsm_bts_trx_alloc(struct gsm_bts *bts)</span><br><span> {</span><br><span>@@ -35,12 +51,20 @@</span><br><span>    if (!trx)</span><br><span>            return NULL;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+      talloc_set_destructor(trx, gsm_bts_trx_talloc_destructor);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         trx->bts = bts;</span><br><span>   trx->nr = bts->num_trx++;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+   trx->mo.fi = osmo_fsm_inst_alloc(&nm_rcarrier_fsm, trx, trx,</span><br><span style="color: hsl(120, 100%, 40%);">+                                             LOGL_INFO, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+   osmo_fsm_inst_update_id_f(trx->mo.fi, "bts%d-trx%d", bts->nr, trx->nr);</span><br><span>   gsm_mo_init(&trx->mo, bts, NM_OC_RADIO_CARRIER,</span><br><span>                   bts->nr, trx->nr, 0xff);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+        trx->bb_transc.mo.fi = osmo_fsm_inst_alloc(&nm_bb_transc_fsm, trx, &trx->bb_transc,</span><br><span style="color: hsl(120, 100%, 40%);">+                                               LOGL_INFO, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+   osmo_fsm_inst_update_id_f(trx->bb_transc.mo.fi, "bts%d-trx%d", bts->nr, trx->nr);</span><br><span>         gsm_mo_init(&trx->bb_transc.mo, bts, NM_OC_BASEB_TRANSC,</span><br><span>                  bts->nr, trx->nr, 0xff);</span><br><span> </span><br><span>@@ -161,7 +185,7 @@</span><br><span>         LOGPTRX(trx, DSUM, LOGL_INFO, "RSL link %s\n",</span><br><span>             link ? "up" : "down");</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  trx_operability_update(trx);</span><br><span style="color: hsl(120, 100%, 40%);">+  osmo_fsm_inst_dispatch(trx->mo.fi, link ? NM_EV_RSL_UP : NM_EV_RSL_DOWN, NULL);</span><br><span> </span><br><span>       if (link)</span><br><span>            rc = rsl_tx_rf_res(trx);</span><br><span>@@ -177,22 +201,6 @@</span><br><span>      return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/* set the availability of the TRX based on internal state (RSL + phy link) */</span><br><span style="color: hsl(0, 100%, 40%);">-void trx_operability_update(struct gsm_bts_trx *trx)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-   enum abis_nm_op_state op_st;</span><br><span style="color: hsl(0, 100%, 40%);">-    enum abis_nm_avail_state avail_st;</span><br><span style="color: hsl(0, 100%, 40%);">-      struct phy_instance *pinst = trx_phy_instance(trx);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     op_st = (trx->rsl_link && phy_link_state_get(pinst->phy_link) == PHY_LINK_CONNECTED) ?</span><br><span style="color: hsl(0, 100%, 40%);">-            NM_OPSTATE_ENABLED : NM_OPSTATE_DISABLED;</span><br><span style="color: hsl(0, 100%, 40%);">-       avail_st = (op_st == NM_OPSTATE_ENABLED) ? NM_AVSTATE_OK : NM_AVSTATE_NOT_INSTALLED;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    LOGPTRX(trx, DSUM, LOGL_INFO, "Setting operative = %s\n", abis_nm_opstate_name(op_st));</span><br><span style="color: hsl(0, 100%, 40%);">-       oml_mo_state_chg(&trx->mo, op_st, avail_st);</span><br><span style="color: hsl(0, 100%, 40%);">-     oml_mo_state_chg(&trx->bb_transc.mo, -1, avail_st);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> </span><br><span> bool trx_ms_pwr_ctrl_is_osmo(const struct gsm_bts_trx *trx)</span><br><span> {</span><br><span>diff --git a/src/common/nm_bb_transc_fsm.c b/src/common/nm_bb_transc_fsm.c</span><br><span>new file mode 100644</span><br><span>index 0000000..b23ff53</span><br><span>--- /dev/null</span><br><span>+++ b/src/common/nm_bb_transc_fsm.c</span><br><span>@@ -0,0 +1,211 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* NM Radio Carrier FSM */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* (C) 2020 by sysmocom - s.m.f.c. GmbH <info@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+ * Author: Pau Espin Pedrol <pespin@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * All Rights Reserved</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+ * it under the terms of the GNU Affero General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; either version 3 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+ * (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(120, 100%, 40%);">+ * GNU General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * You should have received a copy of the GNU Affero General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <unistd.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <inttypes.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/fsm.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/tdef.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/protocol/gsm_12_21.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/logging.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/gsm_data.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/bts_model.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/bts.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/rsl.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/nm_common_fsm.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/phy_link.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define X(s) (1 << (s))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define nm_bb_transc_fsm_state_chg(fi, NEXT_STATE) \</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fsm_inst_state_chg(fi, NEXT_STATE, 0, 0)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+//////////////////////////</span><br><span style="color: hsl(120, 100%, 40%);">+// FSM STATE ACTIONS</span><br><span style="color: hsl(120, 100%, 40%);">+//////////////////////////</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void st_op_disabled_notinstalled_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct gsm_bts_bb_trx *bb_transc = (struct gsm_bts_bb_trx *)fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+      bb_transc->mo.opstart_success = false;</span><br><span style="color: hsl(120, 100%, 40%);">+     oml_mo_state_chg(&bb_transc->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_NOT_INSTALLED);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void st_op_disabled_notinstalled(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct gsm_bts_bb_trx *bb_transc = (struct gsm_bts_bb_trx *)fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    switch (event) {</span><br><span style="color: hsl(120, 100%, 40%);">+      case NM_EV_SW_ACT:</span><br><span style="color: hsl(120, 100%, 40%);">+            oml_mo_tx_sw_act_rep(&bb_transc->mo);</span><br><span style="color: hsl(120, 100%, 40%);">+          nm_bb_transc_fsm_state_chg(fi, NM_BBTRANSC_ST_OP_DISABLED_OFFLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+           return;</span><br><span style="color: hsl(120, 100%, 40%);">+       case NM_EV_RSL_UP:</span><br><span style="color: hsl(120, 100%, 40%);">+            return;</span><br><span style="color: hsl(120, 100%, 40%);">+       case NM_EV_RSL_DOWN:</span><br><span style="color: hsl(120, 100%, 40%);">+          return;</span><br><span style="color: hsl(120, 100%, 40%);">+       case NM_EV_PHYLINK_UP:</span><br><span style="color: hsl(120, 100%, 40%);">+                return;</span><br><span style="color: hsl(120, 100%, 40%);">+       case NM_EV_PHYLINK_DOWN:</span><br><span style="color: hsl(120, 100%, 40%);">+              return;</span><br><span style="color: hsl(120, 100%, 40%);">+       case NM_EV_DISABLE:</span><br><span style="color: hsl(120, 100%, 40%);">+           return;</span><br><span style="color: hsl(120, 100%, 40%);">+       default:</span><br><span style="color: hsl(120, 100%, 40%);">+              OSMO_ASSERT(0);</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void st_op_disabled_offline_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gsm_bts_bb_trx *bb_transc = (struct gsm_bts_bb_trx *)fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+      bb_transc->mo.opstart_success = false;</span><br><span style="color: hsl(120, 100%, 40%);">+     oml_mo_state_chg(&bb_transc->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void st_op_disabled_offline(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct gsm_bts_bb_trx *bb_transc = (struct gsm_bts_bb_trx *)fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gsm_bts_trx *trx = gsm_bts_bb_trx_get_trx(bb_transc);</span><br><span style="color: hsl(120, 100%, 40%);">+  bool phy_state_connected;</span><br><span style="color: hsl(120, 100%, 40%);">+     bool rsl_link_connected;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    switch (event) {</span><br><span style="color: hsl(120, 100%, 40%);">+      case NM_EV_OPSTART_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+               bb_transc->mo.opstart_success = true;</span><br><span style="color: hsl(120, 100%, 40%);">+              oml_mo_opstart_ack(&bb_transc->mo);</span><br><span style="color: hsl(120, 100%, 40%);">+            break; /* check statechg below */</span><br><span style="color: hsl(120, 100%, 40%);">+     case NM_EV_OPSTART_NACK:</span><br><span style="color: hsl(120, 100%, 40%);">+              bb_transc->mo.opstart_success = false;</span><br><span style="color: hsl(120, 100%, 40%);">+             oml_mo_opstart_nack(&bb_transc->mo, (int)(intptr_t)data);</span><br><span style="color: hsl(120, 100%, 40%);">+              return;</span><br><span style="color: hsl(120, 100%, 40%);">+       case NM_EV_RSL_UP:</span><br><span style="color: hsl(120, 100%, 40%);">+            break; /* check statechg below */</span><br><span style="color: hsl(120, 100%, 40%);">+     case NM_EV_RSL_DOWN:</span><br><span style="color: hsl(120, 100%, 40%);">+          return;</span><br><span style="color: hsl(120, 100%, 40%);">+       case NM_EV_PHYLINK_UP:</span><br><span style="color: hsl(120, 100%, 40%);">+                break; /* check statechg below */</span><br><span style="color: hsl(120, 100%, 40%);">+     case NM_EV_PHYLINK_DOWN:</span><br><span style="color: hsl(120, 100%, 40%);">+              return;</span><br><span style="color: hsl(120, 100%, 40%);">+       case NM_EV_DISABLE:</span><br><span style="color: hsl(120, 100%, 40%);">+           return;</span><br><span style="color: hsl(120, 100%, 40%);">+       default:</span><br><span style="color: hsl(120, 100%, 40%);">+              OSMO_ASSERT(0);</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (trx->bts->variant != BTS_OSMO_OMLDUMMY) { /* In OMLDUMMY, phy=NULL */</span><br><span style="color: hsl(120, 100%, 40%);">+               struct phy_instance *pinst = trx_phy_instance(trx);</span><br><span style="color: hsl(120, 100%, 40%);">+           phy_state_connected = phy_link_state_get(pinst->phy_link) == PHY_LINK_CONNECTED;</span><br><span style="color: hsl(120, 100%, 40%);">+           rsl_link_connected = !!trx->rsl_link;</span><br><span style="color: hsl(120, 100%, 40%);">+      } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              phy_state_connected = true;</span><br><span style="color: hsl(120, 100%, 40%);">+           rsl_link_connected = true;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rsl_link_connected && phy_state_connected &&</span><br><span style="color: hsl(120, 100%, 40%);">+          bb_transc->mo.opstart_success) {</span><br><span style="color: hsl(120, 100%, 40%);">+               nm_bb_transc_fsm_state_chg(fi, NM_BBTRANSC_ST_OP_ENABLED);</span><br><span style="color: hsl(120, 100%, 40%);">+    } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGPFSML(fi, LOGL_INFO, "Delay switch to operative state Enabled, wait for:%s%s%s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                        rsl_link_connected ? "": " rsl",</span><br><span style="color: hsl(120, 100%, 40%);">+                  phy_state_connected ? "": " phy",</span><br><span style="color: hsl(120, 100%, 40%);">+                         bb_transc->mo.opstart_success ? "": " opstart");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void st_op_enabled_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct gsm_bts_bb_trx *bb_transc = (struct gsm_bts_bb_trx *)fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+      oml_mo_state_chg(&bb_transc->mo, NM_OPSTATE_ENABLED, NM_AVSTATE_OK);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void st_op_enabled(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  switch (event) {</span><br><span style="color: hsl(120, 100%, 40%);">+      case NM_EV_RSL_DOWN:</span><br><span style="color: hsl(120, 100%, 40%);">+          break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case NM_EV_PHYLINK_DOWN:</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case NM_EV_DISABLE:</span><br><span style="color: hsl(120, 100%, 40%);">+           break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              OSMO_ASSERT(0);</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   nm_bb_transc_fsm_state_chg(fi, NM_BBTRANSC_ST_OP_DISABLED_OFFLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct osmo_fsm_state nm_bb_transc_fsm_states[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+  [NM_BBTRANSC_ST_OP_DISABLED_NOTINSTALLED] = {</span><br><span style="color: hsl(120, 100%, 40%);">+         .in_event_mask =</span><br><span style="color: hsl(120, 100%, 40%);">+                      X(NM_EV_SW_ACT) |</span><br><span style="color: hsl(120, 100%, 40%);">+                     X(NM_EV_RSL_UP) |</span><br><span style="color: hsl(120, 100%, 40%);">+                     X(NM_EV_RSL_DOWN) |</span><br><span style="color: hsl(120, 100%, 40%);">+                   X(NM_EV_PHYLINK_UP) |</span><br><span style="color: hsl(120, 100%, 40%);">+                 X(NM_EV_PHYLINK_DOWN),</span><br><span style="color: hsl(120, 100%, 40%);">+                .out_state_mask =</span><br><span style="color: hsl(120, 100%, 40%);">+                     X(NM_BBTRANSC_ST_OP_DISABLED_OFFLINE),</span><br><span style="color: hsl(120, 100%, 40%);">+                .name = "DISABLED_NOTINSTALLED",</span><br><span style="color: hsl(120, 100%, 40%);">+            .onenter = st_op_disabled_notinstalled_on_enter,</span><br><span style="color: hsl(120, 100%, 40%);">+              .action = st_op_disabled_notinstalled,</span><br><span style="color: hsl(120, 100%, 40%);">+        },</span><br><span style="color: hsl(120, 100%, 40%);">+    [NM_BBTRANSC_ST_OP_DISABLED_OFFLINE] = {</span><br><span style="color: hsl(120, 100%, 40%);">+              .in_event_mask =</span><br><span style="color: hsl(120, 100%, 40%);">+                      X(NM_EV_OPSTART_ACK) |</span><br><span style="color: hsl(120, 100%, 40%);">+                        X(NM_EV_OPSTART_NACK) |</span><br><span style="color: hsl(120, 100%, 40%);">+                       X(NM_EV_RSL_UP) |</span><br><span style="color: hsl(120, 100%, 40%);">+                     X(NM_EV_RSL_DOWN) |</span><br><span style="color: hsl(120, 100%, 40%);">+                   X(NM_EV_PHYLINK_UP) |</span><br><span style="color: hsl(120, 100%, 40%);">+                 X(NM_EV_PHYLINK_DOWN),</span><br><span style="color: hsl(120, 100%, 40%);">+                .out_state_mask =</span><br><span style="color: hsl(120, 100%, 40%);">+                     X(NM_BBTRANSC_ST_OP_ENABLED),</span><br><span style="color: hsl(120, 100%, 40%);">+         .name = "DISABLED_OFFLINE",</span><br><span style="color: hsl(120, 100%, 40%);">+         .onenter = st_op_disabled_offline_on_enter,</span><br><span style="color: hsl(120, 100%, 40%);">+           .action = st_op_disabled_offline,</span><br><span style="color: hsl(120, 100%, 40%);">+     },</span><br><span style="color: hsl(120, 100%, 40%);">+    [NM_BBTRANSC_ST_OP_ENABLED] = {</span><br><span style="color: hsl(120, 100%, 40%);">+               .in_event_mask =</span><br><span style="color: hsl(120, 100%, 40%);">+                      X(NM_EV_RSL_DOWN) |</span><br><span style="color: hsl(120, 100%, 40%);">+                   X(NM_EV_PHYLINK_DOWN),</span><br><span style="color: hsl(120, 100%, 40%);">+                .out_state_mask =</span><br><span style="color: hsl(120, 100%, 40%);">+                     X(NM_BBTRANSC_ST_OP_DISABLED_OFFLINE),</span><br><span style="color: hsl(120, 100%, 40%);">+                .name = "ENABLED",</span><br><span style="color: hsl(120, 100%, 40%);">+          .onenter = st_op_enabled_on_enter,</span><br><span style="color: hsl(120, 100%, 40%);">+            .action = st_op_enabled,</span><br><span style="color: hsl(120, 100%, 40%);">+      },</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_fsm nm_bb_transc_fsm = {</span><br><span style="color: hsl(120, 100%, 40%);">+        .name = "NM_BBTRANSC_OP",</span><br><span style="color: hsl(120, 100%, 40%);">+   .states = nm_bb_transc_fsm_states,</span><br><span style="color: hsl(120, 100%, 40%);">+    .num_states = ARRAY_SIZE(nm_bb_transc_fsm_states),</span><br><span style="color: hsl(120, 100%, 40%);">+    .event_names = nm_fsm_event_names,</span><br><span style="color: hsl(120, 100%, 40%);">+    .log_subsys = DOML,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static __attribute__((constructor)) void nm_bb_transc_fsm_init(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(osmo_fsm_register(&nm_bb_transc_fsm) == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/common/nm_common_fsm.c b/src/common/nm_common_fsm.c</span><br><span>index 662a760..8804569 100644</span><br><span>--- a/src/common/nm_common_fsm.c</span><br><span>+++ b/src/common/nm_common_fsm.c</span><br><span>@@ -27,5 +27,10 @@</span><br><span>     { NM_EV_SW_ACT, "SW_ACT" },</span><br><span>        { NM_EV_OPSTART_ACK, "OPSTART_ACK" },</span><br><span>      { NM_EV_OPSTART_NACK, "OPSTART_NACK" },</span><br><span style="color: hsl(120, 100%, 40%);">+     { NM_EV_RSL_UP, "RSL_UP" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { NM_EV_RSL_DOWN, "RSL_DOWN" },</span><br><span style="color: hsl(120, 100%, 40%);">+     { NM_EV_PHYLINK_UP, "PHYLINK_UP" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { NM_EV_PHYLINK_DOWN, "PHYLINK_DOWN" },</span><br><span style="color: hsl(120, 100%, 40%);">+     { NM_EV_DISABLE, "DISABLE" },</span><br><span>      { 0, NULL }</span><br><span> };</span><br><span>diff --git a/src/common/nm_radio_carrier_fsm.c b/src/common/nm_radio_carrier_fsm.c</span><br><span>new file mode 100644</span><br><span>index 0000000..01849d1</span><br><span>--- /dev/null</span><br><span>+++ b/src/common/nm_radio_carrier_fsm.c</span><br><span>@@ -0,0 +1,218 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* NM Radio Carrier FSM */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* (C) 2020 by sysmocom - s.m.f.c. GmbH <info@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+ * Author: Pau Espin Pedrol <pespin@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * All Rights Reserved</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+ * it under the terms of the GNU Affero General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; either version 3 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+ * (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(120, 100%, 40%);">+ * GNU General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * You should have received a copy of the GNU Affero General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <unistd.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <inttypes.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/fsm.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/tdef.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/protocol/gsm_12_21.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/logging.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/gsm_data.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/bts_model.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/bts.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/rsl.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/nm_common_fsm.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/phy_link.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define X(s) (1 << (s))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define nm_rcarrier_fsm_state_chg(fi, NEXT_STATE) \</span><br><span style="color: hsl(120, 100%, 40%);">+        osmo_fsm_inst_state_chg(fi, NEXT_STATE, 0, 0)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+//////////////////////////</span><br><span style="color: hsl(120, 100%, 40%);">+// FSM STATE ACTIONS</span><br><span style="color: hsl(120, 100%, 40%);">+//////////////////////////</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void st_op_disabled_notinstalled_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct gsm_bts_trx *trx = (struct gsm_bts_trx *)fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+  trx->mo.opstart_success = false;</span><br><span style="color: hsl(120, 100%, 40%);">+   oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_NOT_INSTALLED);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void st_op_disabled_notinstalled(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gsm_bts_trx *trx = (struct gsm_bts_trx *)fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        switch (event) {</span><br><span style="color: hsl(120, 100%, 40%);">+      case NM_EV_SW_ACT:</span><br><span style="color: hsl(120, 100%, 40%);">+            oml_mo_tx_sw_act_rep(&trx->mo);</span><br><span style="color: hsl(120, 100%, 40%);">+                nm_rcarrier_fsm_state_chg(fi, NM_RCARRIER_ST_OP_DISABLED_OFFLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+            return;</span><br><span style="color: hsl(120, 100%, 40%);">+       case NM_EV_RSL_UP:</span><br><span style="color: hsl(120, 100%, 40%);">+            return;</span><br><span style="color: hsl(120, 100%, 40%);">+       case NM_EV_RSL_DOWN:</span><br><span style="color: hsl(120, 100%, 40%);">+          return;</span><br><span style="color: hsl(120, 100%, 40%);">+       case NM_EV_PHYLINK_UP:</span><br><span style="color: hsl(120, 100%, 40%);">+                return;</span><br><span style="color: hsl(120, 100%, 40%);">+       case NM_EV_PHYLINK_DOWN:</span><br><span style="color: hsl(120, 100%, 40%);">+              return;</span><br><span style="color: hsl(120, 100%, 40%);">+       case NM_EV_DISABLE:</span><br><span style="color: hsl(120, 100%, 40%);">+           return;</span><br><span style="color: hsl(120, 100%, 40%);">+       default:</span><br><span style="color: hsl(120, 100%, 40%);">+              OSMO_ASSERT(0);</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void st_op_disabled_offline_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gsm_bts_trx *trx = (struct gsm_bts_trx *)fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+  trx->mo.opstart_success = false;</span><br><span style="color: hsl(120, 100%, 40%);">+   oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void st_op_disabled_offline(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct gsm_bts_trx *trx = (struct gsm_bts_trx *)fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+  bool phy_state_connected;</span><br><span style="color: hsl(120, 100%, 40%);">+     bool rsl_link_connected;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    switch (event) {</span><br><span style="color: hsl(120, 100%, 40%);">+      case NM_EV_OPSTART_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+               trx->mo.opstart_success = true;</span><br><span style="color: hsl(120, 100%, 40%);">+            oml_mo_opstart_ack(&trx->mo);</span><br><span style="color: hsl(120, 100%, 40%);">+          break; /* check statechg below */</span><br><span style="color: hsl(120, 100%, 40%);">+     case NM_EV_OPSTART_NACK:</span><br><span style="color: hsl(120, 100%, 40%);">+              trx->mo.opstart_success = false;</span><br><span style="color: hsl(120, 100%, 40%);">+           oml_mo_opstart_nack(&trx->mo, (int)(intptr_t)data);</span><br><span style="color: hsl(120, 100%, 40%);">+            return;</span><br><span style="color: hsl(120, 100%, 40%);">+       case NM_EV_RSL_UP:</span><br><span style="color: hsl(120, 100%, 40%);">+            break; /* check statechg below */</span><br><span style="color: hsl(120, 100%, 40%);">+     case NM_EV_RSL_DOWN:</span><br><span style="color: hsl(120, 100%, 40%);">+          return;</span><br><span style="color: hsl(120, 100%, 40%);">+       case NM_EV_PHYLINK_UP:</span><br><span style="color: hsl(120, 100%, 40%);">+                break; /* check statechg below */</span><br><span style="color: hsl(120, 100%, 40%);">+     case NM_EV_PHYLINK_DOWN:</span><br><span style="color: hsl(120, 100%, 40%);">+              return;</span><br><span style="color: hsl(120, 100%, 40%);">+       case NM_EV_DISABLE:</span><br><span style="color: hsl(120, 100%, 40%);">+           return;</span><br><span style="color: hsl(120, 100%, 40%);">+       default:</span><br><span style="color: hsl(120, 100%, 40%);">+              OSMO_ASSERT(0);</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (trx->bts->variant != BTS_OSMO_OMLDUMMY) { /* In OMLDUMMY, phy=NULL */</span><br><span style="color: hsl(120, 100%, 40%);">+               struct phy_instance *pinst = trx_phy_instance(trx);</span><br><span style="color: hsl(120, 100%, 40%);">+           phy_state_connected = phy_link_state_get(pinst->phy_link) == PHY_LINK_CONNECTED;</span><br><span style="color: hsl(120, 100%, 40%);">+           rsl_link_connected = !!trx->rsl_link;</span><br><span style="color: hsl(120, 100%, 40%);">+      } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              phy_state_connected = true;</span><br><span style="color: hsl(120, 100%, 40%);">+           rsl_link_connected = true;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rsl_link_connected && phy_state_connected &&</span><br><span style="color: hsl(120, 100%, 40%);">+          trx->mo.opstart_success) {</span><br><span style="color: hsl(120, 100%, 40%);">+             nm_rcarrier_fsm_state_chg(fi, NM_RCARRIER_ST_OP_ENABLED);</span><br><span style="color: hsl(120, 100%, 40%);">+     } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGPFSML(fi, LOGL_INFO, "Delay switch to operative state Enabled, wait for:%s%s%s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                        rsl_link_connected ? "": " rsl",</span><br><span style="color: hsl(120, 100%, 40%);">+                  phy_state_connected ? "": " phy",</span><br><span style="color: hsl(120, 100%, 40%);">+                         trx->mo.opstart_success ? "": " opstart");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void st_op_enabled_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct gsm_bts_trx *trx = (struct gsm_bts_trx *)fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+  uint8_t tn;</span><br><span style="color: hsl(120, 100%, 40%);">+   oml_mo_state_chg(&trx->mo, NM_OPSTATE_ENABLED, NM_AVSTATE_OK);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /* Mark Dependency TS as Offline (ready to be Opstarted) */</span><br><span style="color: hsl(120, 100%, 40%);">+   for (tn = 0; tn < TRX_NR_TS; tn++) {</span><br><span style="color: hsl(120, 100%, 40%);">+               if (trx->ts[tn].mo.nm_state.operational == NM_OPSTATE_DISABLED &&</span><br><span style="color: hsl(120, 100%, 40%);">+              trx->ts[tn].mo.nm_state.availability ==  NM_AVSTATE_DEPENDENCY) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      oml_mo_state_chg(&trx->ts[tn].mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE);</span><br><span style="color: hsl(120, 100%, 40%);">+           }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void st_op_enabled(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    switch (event) {</span><br><span style="color: hsl(120, 100%, 40%);">+      case NM_EV_RSL_DOWN:</span><br><span style="color: hsl(120, 100%, 40%);">+          break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case NM_EV_PHYLINK_DOWN:</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case NM_EV_DISABLE:</span><br><span style="color: hsl(120, 100%, 40%);">+           break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              OSMO_ASSERT(0);</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   nm_rcarrier_fsm_state_chg(fi, NM_RCARRIER_ST_OP_DISABLED_OFFLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct osmo_fsm_state nm_rcarrier_fsm_states[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+    [NM_RCARRIER_ST_OP_DISABLED_NOTINSTALLED] = {</span><br><span style="color: hsl(120, 100%, 40%);">+         .in_event_mask =</span><br><span style="color: hsl(120, 100%, 40%);">+                      X(NM_EV_SW_ACT) |</span><br><span style="color: hsl(120, 100%, 40%);">+                     X(NM_EV_RSL_UP) |</span><br><span style="color: hsl(120, 100%, 40%);">+                     X(NM_EV_RSL_DOWN) |</span><br><span style="color: hsl(120, 100%, 40%);">+                   X(NM_EV_PHYLINK_UP) |</span><br><span style="color: hsl(120, 100%, 40%);">+                 X(NM_EV_PHYLINK_DOWN),</span><br><span style="color: hsl(120, 100%, 40%);">+                .out_state_mask =</span><br><span style="color: hsl(120, 100%, 40%);">+                     X(NM_RCARRIER_ST_OP_DISABLED_OFFLINE),</span><br><span style="color: hsl(120, 100%, 40%);">+                .name = "DISABLED_NOTINSTALLED",</span><br><span style="color: hsl(120, 100%, 40%);">+            .onenter = st_op_disabled_notinstalled_on_enter,</span><br><span style="color: hsl(120, 100%, 40%);">+              .action = st_op_disabled_notinstalled,</span><br><span style="color: hsl(120, 100%, 40%);">+        },</span><br><span style="color: hsl(120, 100%, 40%);">+    [NM_RCARRIER_ST_OP_DISABLED_OFFLINE] = {</span><br><span style="color: hsl(120, 100%, 40%);">+              .in_event_mask =</span><br><span style="color: hsl(120, 100%, 40%);">+                      X(NM_EV_OPSTART_ACK) |</span><br><span style="color: hsl(120, 100%, 40%);">+                        X(NM_EV_OPSTART_NACK) |</span><br><span style="color: hsl(120, 100%, 40%);">+                       X(NM_EV_RSL_UP) |</span><br><span style="color: hsl(120, 100%, 40%);">+                     X(NM_EV_RSL_DOWN) |</span><br><span style="color: hsl(120, 100%, 40%);">+                   X(NM_EV_PHYLINK_UP) |</span><br><span style="color: hsl(120, 100%, 40%);">+                 X(NM_EV_PHYLINK_DOWN),</span><br><span style="color: hsl(120, 100%, 40%);">+                .out_state_mask =</span><br><span style="color: hsl(120, 100%, 40%);">+                     X(NM_RCARRIER_ST_OP_ENABLED),</span><br><span style="color: hsl(120, 100%, 40%);">+         .name = "DISABLED_OFFLINE",</span><br><span style="color: hsl(120, 100%, 40%);">+         .onenter = st_op_disabled_offline_on_enter,</span><br><span style="color: hsl(120, 100%, 40%);">+           .action = st_op_disabled_offline,</span><br><span style="color: hsl(120, 100%, 40%);">+     },</span><br><span style="color: hsl(120, 100%, 40%);">+    [NM_RCARRIER_ST_OP_ENABLED] = {</span><br><span style="color: hsl(120, 100%, 40%);">+               .in_event_mask =</span><br><span style="color: hsl(120, 100%, 40%);">+                      X(NM_EV_RSL_DOWN) |</span><br><span style="color: hsl(120, 100%, 40%);">+                   X(NM_EV_PHYLINK_DOWN),</span><br><span style="color: hsl(120, 100%, 40%);">+                .out_state_mask =</span><br><span style="color: hsl(120, 100%, 40%);">+                     X(NM_RCARRIER_ST_OP_DISABLED_OFFLINE),</span><br><span style="color: hsl(120, 100%, 40%);">+                .name = "ENABLED",</span><br><span style="color: hsl(120, 100%, 40%);">+          .onenter = st_op_enabled_on_enter,</span><br><span style="color: hsl(120, 100%, 40%);">+            .action = st_op_enabled,</span><br><span style="color: hsl(120, 100%, 40%);">+      },</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_fsm nm_rcarrier_fsm = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .name = "NM_RCARRIER_OP",</span><br><span style="color: hsl(120, 100%, 40%);">+   .states = nm_rcarrier_fsm_states,</span><br><span style="color: hsl(120, 100%, 40%);">+     .num_states = ARRAY_SIZE(nm_rcarrier_fsm_states),</span><br><span style="color: hsl(120, 100%, 40%);">+     .event_names = nm_fsm_event_names,</span><br><span style="color: hsl(120, 100%, 40%);">+    .log_subsys = DOML,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static __attribute__((constructor)) void nm_rcarrier_fsm_init(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(osmo_fsm_register(&nm_rcarrier_fsm) == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/common/phy_link.c b/src/common/phy_link.c</span><br><span>index 48ba283..77d7aa6 100644</span><br><span>--- a/src/common/phy_link.c</span><br><span>+++ b/src/common/phy_link.c</span><br><span>@@ -2,6 +2,7 @@</span><br><span> </span><br><span> #include <osmocom/core/linuxlist.h></span><br><span> #include <osmocom/core/talloc.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/fsm.h></span><br><span> </span><br><span> #include <osmo-bts/bts.h></span><br><span> #include <osmo-bts/gsm_data.h></span><br><span>@@ -9,6 +10,7 @@</span><br><span> #include <osmo-bts/oml.h></span><br><span> #include <osmo-bts/logging.h></span><br><span> #include <osmo-bts/bts_model.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/nm_common_fsm.h></span><br><span> </span><br><span> static LLIST_HEAD(g_phy_links);</span><br><span> </span><br><span>@@ -65,7 +67,14 @@</span><br><span>             if (!trx)</span><br><span>                    continue;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-           trx_operability_update(trx);</span><br><span style="color: hsl(120, 100%, 40%);">+          osmo_fsm_inst_dispatch(trx->mo.fi,</span><br><span style="color: hsl(120, 100%, 40%);">+                                state == PHY_LINK_CONNECTED ? NM_EV_PHYLINK_UP :</span><br><span style="color: hsl(120, 100%, 40%);">+                                                                    NM_EV_PHYLINK_DOWN,</span><br><span style="color: hsl(120, 100%, 40%);">+                                     NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+         osmo_fsm_inst_dispatch(trx->bb_transc.mo.fi,</span><br><span style="color: hsl(120, 100%, 40%);">+                                      state == PHY_LINK_CONNECTED ? NM_EV_PHYLINK_UP :</span><br><span style="color: hsl(120, 100%, 40%);">+                                                                    NM_EV_PHYLINK_DOWN,</span><br><span style="color: hsl(120, 100%, 40%);">+                                     NULL);</span><br><span>        }</span><br><span> }</span><br><span> </span><br><span>diff --git a/src/osmo-bts-litecell15/l1_if.c b/src/osmo-bts-litecell15/l1_if.c</span><br><span>index 23f7c3d..94fd165 100644</span><br><span>--- a/src/osmo-bts-litecell15/l1_if.c</span><br><span>+++ b/src/osmo-bts-litecell15/l1_if.c</span><br><span>@@ -54,6 +54,7 @@</span><br><span> #include <osmo-bts/l1sap.h></span><br><span> #include <osmo-bts/msg_utils.h></span><br><span> #include <osmo-bts/dtx_dl_amr_fsm.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/nm_common_fsm.h></span><br><span> </span><br><span> #include <nrw/litecell15/litecell15.h></span><br><span> #include <nrw/litecell15/gsml1prim.h></span><br><span>@@ -1270,18 +1271,16 @@</span><br><span>                }</span><br><span> </span><br><span>          /* signal availability */</span><br><span style="color: hsl(0, 100%, 40%);">-               oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OK);</span><br><span style="color: hsl(0, 100%, 40%);">-          oml_mo_tx_sw_act_rep(&trx->mo);</span><br><span style="color: hsl(0, 100%, 40%);">-          oml_mo_state_chg(&trx->bb_transc.mo, -1, NM_AVSTATE_OK);</span><br><span style="color: hsl(0, 100%, 40%);">-         oml_mo_tx_sw_act_rep(&trx->bb_transc.mo);</span><br><span style="color: hsl(120, 100%, 40%);">+              osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_SW_ACT, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+            osmo_fsm_inst_dispatch(trx->bb_transc.mo.fi, NM_EV_SW_ACT, NULL);</span><br><span> </span><br><span>             for (i = 0; i < ARRAY_SIZE(trx->ts); i++)</span><br><span>                      oml_mo_state_chg(&trx->ts[i].mo, NM_OPSTATE_DISABLED, NM_AVSTATE_DEPENDENCY);</span><br><span>         } else {</span><br><span>             if (bts_lc15->led_ctrl_mode == LC15_LED_CONTROL_BTS)</span><br><span>                      bts_update_status(BTS_STATUS_RF_ACTIVE, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-             oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE);</span><br><span style="color: hsl(0, 100%, 40%);">-            oml_mo_state_chg(&trx->bb_transc.mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE);</span><br><span style="color: hsl(120, 100%, 40%);">+                        osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_DISABLE, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+                   osmo_fsm_inst_dispatch(trx->bb_transc.mo.fi, NM_EV_DISABLE, NULL);</span><br><span>        }</span><br><span> </span><br><span>        msgb_free(resp);</span><br><span>diff --git a/src/osmo-bts-litecell15/oml.c b/src/osmo-bts-litecell15/oml.c</span><br><span>index 03f787b..d810987 100644</span><br><span>--- a/src/osmo-bts-litecell15/oml.c</span><br><span>+++ b/src/osmo-bts-litecell15/oml.c</span><br><span>@@ -26,6 +26,7 @@</span><br><span> </span><br><span> #include <osmocom/core/talloc.h></span><br><span> #include <osmocom/core/utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/fsm.h></span><br><span> </span><br><span> #include <nrw/litecell15/gsml1prim.h></span><br><span> #include <nrw/litecell15/gsml1const.h></span><br><span>@@ -270,31 +271,28 @@</span><br><span>         GsmL1_Prim_t *l1p = msgb_l1prim(l1_msg);</span><br><span>     GsmL1_Status_t status = prim_status(l1p);</span><br><span>    struct gsm_bts_trx *trx = gsm_bts_trx_num(mo->bts, mo->obj_inst.trx_nr);</span><br><span style="color: hsl(0, 100%, 40%);">-  uint8_t tn;</span><br><span> </span><br><span>      if (status != GsmL1_Status_Success) {</span><br><span>                LOGP(DL1C, LOGL_ERROR, "Rx %s, status: %s\n",</span><br><span>                      get_value_string(lc15bts_l1prim_names, l1p->id),</span><br><span>                  get_value_string(lc15bts_l1status_names, status));</span><br><span>           msgb_free(l1_msg);</span><br><span style="color: hsl(0, 100%, 40%);">-              return oml_mo_opstart_nack(mo, NM_NACK_CANT_PERFORM);</span><br><span style="color: hsl(120, 100%, 40%);">+         if (mo->obj_class == NM_OC_RADIO_CARRIER)</span><br><span style="color: hsl(120, 100%, 40%);">+                  return osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_OPSTART_NACK,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                    (void*)(intptr_t)NM_NACK_CANT_PERFORM);</span><br><span style="color: hsl(120, 100%, 40%);">+         else</span><br><span style="color: hsl(120, 100%, 40%);">+                  return oml_mo_opstart_nack(mo, NM_NACK_CANT_PERFORM);</span><br><span>        }</span><br><span> </span><br><span>        msgb_free(l1_msg);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+        /* We already have a FSM for Radio Carrier, handle it there */</span><br><span style="color: hsl(120, 100%, 40%);">+        if (mo->obj_class == NM_OC_RADIO_CARRIER)</span><br><span style="color: hsl(120, 100%, 40%);">+          return osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_OPSTART_ACK, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     /* Set to Operational State: Enabled */</span><br><span>      oml_mo_state_chg(mo, NM_OPSTATE_ENABLED, NM_AVSTATE_OK);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    if (mo->obj_class == NM_OC_RADIO_CARRIER) {</span><br><span style="color: hsl(0, 100%, 40%);">-          /* Mark Dependency TS as Offline (ready to be Opstarted) */</span><br><span style="color: hsl(0, 100%, 40%);">-             for (tn = 0; tn < TRX_NR_TS; tn++) {</span><br><span style="color: hsl(0, 100%, 40%);">-                 if (trx->ts[tn].mo.nm_state.operational == NM_OPSTATE_DISABLED &&</span><br><span style="color: hsl(0, 100%, 40%);">-                        trx->ts[tn].mo.nm_state.availability ==  NM_AVSTATE_DEPENDENCY) {</span><br><span style="color: hsl(0, 100%, 40%);">-                                oml_mo_state_chg(&trx->ts[tn].mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE);</span><br><span style="color: hsl(0, 100%, 40%);">-                     }</span><br><span style="color: hsl(0, 100%, 40%);">-               }</span><br><span style="color: hsl(0, 100%, 40%);">-       }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>    /* ugly hack to auto-activate all SAPIs for the BCCH/CCCH on TS0 */</span><br><span>  if (mo->obj_class == NM_OC_CHANNEL && mo->obj_inst.trx_nr == 0 &&</span><br><span>          mo->obj_inst.ts_nr == 0) {</span><br><span>@@ -403,8 +401,9 @@</span><br><span>                                  ARRAY_SIZE(trx_rqd_attr))) {</span><br><span>             /* HACK: spec says we need to decline, but openbsc</span><br><span>            * doesn't deal with this very well */</span><br><span style="color: hsl(0, 100%, 40%);">-              return oml_mo_opstart_ack(&trx->mo);</span><br><span style="color: hsl(0, 100%, 40%);">-             //return oml_mo_opstart_nack(&trx->mo, NM_NACK_CANT_PERFORM);</span><br><span style="color: hsl(120, 100%, 40%);">+          return osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_OPSTART_ACK, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+                //return osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_OPSTART_NACK,</span><br><span style="color: hsl(120, 100%, 40%);">+            //                              (void*)(intptr_t)NM_NACK_CANT_PERFORM);</span><br><span>      }</span><br><span> </span><br><span>        /* Update TRX band */</span><br><span>@@ -1885,6 +1884,8 @@</span><br><span> int bts_model_opstart(struct gsm_bts *bts, struct gsm_abis_mo *mo,</span><br><span>                void *obj)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gsm_bts_bb_trx *bb_transc;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct gsm_bts_trx *trx;</span><br><span>     int rc;</span><br><span> </span><br><span>  switch (mo->obj_class) {</span><br><span>@@ -1895,12 +1896,16 @@</span><br><span>                rc = osmo_fsm_inst_dispatch(bts->mo.fi, NM_EV_OPSTART_ACK, NULL);</span><br><span>                 break;</span><br><span>       case NM_OC_RADIO_CARRIER:</span><br><span style="color: hsl(0, 100%, 40%);">-               rc = trx_init(obj);</span><br><span style="color: hsl(120, 100%, 40%);">+           trx = (struct gsm_bts_trx *) obj;</span><br><span style="color: hsl(120, 100%, 40%);">+             rc = trx_init(trx);</span><br><span style="color: hsl(120, 100%, 40%);">+           break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case NM_OC_BASEB_TRANSC:</span><br><span style="color: hsl(120, 100%, 40%);">+              bb_transc = (struct gsm_bts_bb_trx *) obj;</span><br><span style="color: hsl(120, 100%, 40%);">+            rc = osmo_fsm_inst_dispatch(bb_transc->mo.fi, NM_EV_OPSTART_ACK, NULL);</span><br><span>           break;</span><br><span>       case NM_OC_CHANNEL:</span><br><span>          rc = ts_opstart(obj);</span><br><span>                break;</span><br><span style="color: hsl(0, 100%, 40%);">-  case NM_OC_BASEB_TRANSC:</span><br><span>     case NM_OC_GPRS_NSE:</span><br><span>         case NM_OC_GPRS_CELL:</span><br><span>        case NM_OC_GPRS_NSVC:</span><br><span>diff --git a/src/osmo-bts-oc2g/l1_if.c b/src/osmo-bts-oc2g/l1_if.c</span><br><span>index 8e48674..4044f43 100644</span><br><span>--- a/src/osmo-bts-oc2g/l1_if.c</span><br><span>+++ b/src/osmo-bts-oc2g/l1_if.c</span><br><span>@@ -37,6 +37,7 @@</span><br><span> #include <osmocom/core/select.h></span><br><span> #include <osmocom/core/timer.h></span><br><span> #include <osmocom/core/write_queue.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/fsm.h></span><br><span> #include <osmocom/gsm/gsm_utils.h></span><br><span> #include <osmocom/gsm/lapdm.h></span><br><span> </span><br><span>@@ -55,6 +56,7 @@</span><br><span> #include <osmo-bts/msg_utils.h></span><br><span> #include <osmo-bts/dtx_dl_amr_fsm.h></span><br><span> #include <osmo-bts/cbch.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/nm_common_fsm.h></span><br><span> </span><br><span> #include <nrw/oc2g/oc2g.h></span><br><span> #include <nrw/oc2g/gsml1prim.h></span><br><span>@@ -1324,17 +1326,15 @@</span><br><span>                       bts_update_status(BTS_STATUS_RF_ACTIVE, 1);</span><br><span> </span><br><span>              /* signal availability */</span><br><span style="color: hsl(0, 100%, 40%);">-               oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OK);</span><br><span style="color: hsl(0, 100%, 40%);">-          oml_mo_tx_sw_act_rep(&trx->mo);</span><br><span style="color: hsl(0, 100%, 40%);">-          oml_mo_state_chg(&trx->bb_transc.mo, -1, NM_AVSTATE_OK);</span><br><span style="color: hsl(0, 100%, 40%);">-         oml_mo_tx_sw_act_rep(&trx->bb_transc.mo);</span><br><span style="color: hsl(120, 100%, 40%);">+              osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_SW_ACT, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+            osmo_fsm_inst_dispatch(trx->bb_transc.mo.fi, NM_EV_SW_ACT, NULL);</span><br><span> </span><br><span>             for (i = 0; i < ARRAY_SIZE(trx->ts); i++)</span><br><span>                      oml_mo_state_chg(&trx->ts[i].mo, NM_OPSTATE_DISABLED, NM_AVSTATE_DEPENDENCY);</span><br><span>         } else {</span><br><span>             bts_update_status(BTS_STATUS_RF_ACTIVE, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-             oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE);</span><br><span style="color: hsl(0, 100%, 40%);">-            oml_mo_state_chg(&trx->bb_transc.mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE);</span><br><span style="color: hsl(120, 100%, 40%);">+                osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_DISABLE, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+           osmo_fsm_inst_dispatch(trx->bb_transc.mo.fi, NM_EV_DISABLE, NULL);</span><br><span>        }</span><br><span> </span><br><span>        msgb_free(resp);</span><br><span>diff --git a/src/osmo-bts-oc2g/oml.c b/src/osmo-bts-oc2g/oml.c</span><br><span>index 15513d1..2efa577 100644</span><br><span>--- a/src/osmo-bts-oc2g/oml.c</span><br><span>+++ b/src/osmo-bts-oc2g/oml.c</span><br><span>@@ -26,6 +26,7 @@</span><br><span> </span><br><span> #include <osmocom/core/talloc.h></span><br><span> #include <osmocom/core/utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/fsm.h></span><br><span> </span><br><span> #include <nrw/oc2g/gsml1prim.h></span><br><span> #include <nrw/oc2g/gsml1const.h></span><br><span>@@ -270,31 +271,28 @@</span><br><span>     GsmL1_Prim_t *l1p = msgb_l1prim(l1_msg);</span><br><span>     GsmL1_Status_t status = prim_status(l1p);</span><br><span>    struct gsm_bts_trx *trx = gsm_bts_trx_num(mo->bts, mo->obj_inst.trx_nr);</span><br><span style="color: hsl(0, 100%, 40%);">-  uint8_t tn;</span><br><span> </span><br><span>      if (status != GsmL1_Status_Success) {</span><br><span>                LOGP(DL1C, LOGL_ERROR, "Rx %s, status: %s\n",</span><br><span>                      get_value_string(oc2gbts_l1prim_names, l1p->id),</span><br><span>                  get_value_string(oc2gbts_l1status_names, status));</span><br><span>           msgb_free(l1_msg);</span><br><span style="color: hsl(0, 100%, 40%);">-              return oml_mo_opstart_nack(mo, NM_NACK_CANT_PERFORM);</span><br><span style="color: hsl(120, 100%, 40%);">+         if (mo->obj_class == NM_OC_RADIO_CARRIER)</span><br><span style="color: hsl(120, 100%, 40%);">+                  return osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_OPSTART_NACK,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                    (void*)(intptr_t)NM_NACK_CANT_PERFORM);</span><br><span style="color: hsl(120, 100%, 40%);">+         else</span><br><span style="color: hsl(120, 100%, 40%);">+                  return oml_mo_opstart_nack(mo, NM_NACK_CANT_PERFORM);</span><br><span>        }</span><br><span> </span><br><span>        msgb_free(l1_msg);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+        /* We already have a FSM for Radio Carrier, handle it there */</span><br><span style="color: hsl(120, 100%, 40%);">+        if (mo->obj_class == NM_OC_RADIO_CARRIER)</span><br><span style="color: hsl(120, 100%, 40%);">+          return osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_OPSTART_ACK, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     /* Set to Operational State: Enabled */</span><br><span>      oml_mo_state_chg(mo, NM_OPSTATE_ENABLED, NM_AVSTATE_OK);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    if (mo->obj_class == NM_OC_RADIO_CARRIER) {</span><br><span style="color: hsl(0, 100%, 40%);">-          /* Mark Dependency TS as Offline (ready to be Opstarted) */</span><br><span style="color: hsl(0, 100%, 40%);">-             for (tn = 0; tn < TRX_NR_TS; tn++) {</span><br><span style="color: hsl(0, 100%, 40%);">-                 if (trx->ts[tn].mo.nm_state.operational == NM_OPSTATE_DISABLED &&</span><br><span style="color: hsl(0, 100%, 40%);">-                        trx->ts[tn].mo.nm_state.availability ==  NM_AVSTATE_DEPENDENCY) {</span><br><span style="color: hsl(0, 100%, 40%);">-                                oml_mo_state_chg(&trx->ts[tn].mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE);</span><br><span style="color: hsl(0, 100%, 40%);">-                     }</span><br><span style="color: hsl(0, 100%, 40%);">-               }</span><br><span style="color: hsl(0, 100%, 40%);">-       }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>    /* ugly hack to auto-activate all SAPIs for the BCCH/CCCH on TS0 */</span><br><span>  if (mo->obj_class == NM_OC_CHANNEL && mo->obj_inst.trx_nr == 0 &&</span><br><span>          mo->obj_inst.ts_nr == 0) {</span><br><span>@@ -1894,6 +1892,8 @@</span><br><span> int bts_model_opstart(struct gsm_bts *bts, struct gsm_abis_mo *mo,</span><br><span>                    void *obj)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gsm_bts_bb_trx *bb_transc;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct gsm_bts_trx* trx;</span><br><span>     int rc;</span><br><span> </span><br><span>  switch (mo->obj_class) {</span><br><span>@@ -1908,12 +1908,16 @@</span><br><span>                oml_mo_state_chg(&bts->gprs.nsvc[0].mo, -1, NM_AVSTATE_OK);</span><br><span>           break;</span><br><span>       case NM_OC_RADIO_CARRIER:</span><br><span style="color: hsl(0, 100%, 40%);">-               rc = trx_init(obj);</span><br><span style="color: hsl(120, 100%, 40%);">+           trx = (struct gsm_bts_trx *) obj;</span><br><span style="color: hsl(120, 100%, 40%);">+             rc = trx_init(trx);</span><br><span style="color: hsl(120, 100%, 40%);">+           break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case NM_OC_BASEB_TRANSC:</span><br><span style="color: hsl(120, 100%, 40%);">+              bb_transc = (struct gsm_bts_bb_trx *) obj;</span><br><span style="color: hsl(120, 100%, 40%);">+            rc = osmo_fsm_inst_dispatch(bb_transc->mo.fi, NM_EV_OPSTART_ACK, NULL);</span><br><span>           break;</span><br><span>       case NM_OC_CHANNEL:</span><br><span>          rc = ts_opstart(obj);</span><br><span>                break;</span><br><span style="color: hsl(0, 100%, 40%);">-  case NM_OC_BASEB_TRANSC:</span><br><span>     case NM_OC_GPRS_NSE:</span><br><span>         case NM_OC_GPRS_CELL:</span><br><span>        case NM_OC_GPRS_NSVC:</span><br><span>diff --git a/src/osmo-bts-octphy/l1_if.c b/src/osmo-bts-octphy/l1_if.c</span><br><span>index f20f21a..c7e0b42 100644</span><br><span>--- a/src/osmo-bts-octphy/l1_if.c</span><br><span>+++ b/src/osmo-bts-octphy/l1_if.c</span><br><span>@@ -36,6 +36,7 @@</span><br><span> </span><br><span> #include <osmocom/core/talloc.h></span><br><span> #include <osmocom/core/socket.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/fsm.h></span><br><span> </span><br><span> #include <osmo-bts/gsm_data.h></span><br><span> #include <osmo-bts/bts_model.h></span><br><span>@@ -44,6 +45,7 @@</span><br><span> #include <osmo-bts/l1sap.h></span><br><span> #include <osmo-bts/handover.h></span><br><span> #include <osmo-bts/bts.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/nm_common_fsm.h></span><br><span> </span><br><span> #include "l1_if.h"</span><br><span> #include "l1_oml.h"</span><br><span>@@ -311,19 +313,15 @@</span><br><span>     int i;</span><br><span>       if (on) {</span><br><span>            /* signal availability */</span><br><span style="color: hsl(0, 100%, 40%);">-               oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OK);</span><br><span style="color: hsl(0, 100%, 40%);">-          oml_mo_tx_sw_act_rep(&trx->mo);</span><br><span style="color: hsl(0, 100%, 40%);">-          oml_mo_state_chg(&trx->bb_transc.mo, -1, NM_AVSTATE_OK);</span><br><span style="color: hsl(0, 100%, 40%);">-         oml_mo_tx_sw_act_rep(&trx->bb_transc.mo);</span><br><span style="color: hsl(120, 100%, 40%);">+              osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_SW_ACT, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+            osmo_fsm_inst_dispatch(trx->bb_transc.mo.fi, NM_EV_SW_ACT, NULL);</span><br><span> </span><br><span>             for (i = 0; i < ARRAY_SIZE(trx->ts); i++)</span><br><span>                      oml_mo_state_chg(&trx->ts[i].mo, NM_OPSTATE_DISABLED,</span><br><span>                                          NM_AVSTATE_DEPENDENCY);</span><br><span>     } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED,</span><br><span style="color: hsl(0, 100%, 40%);">-                           NM_AVSTATE_OFF_LINE);</span><br><span style="color: hsl(0, 100%, 40%);">-          oml_mo_state_chg(&trx->bb_transc.mo, NM_OPSTATE_DISABLED,</span><br><span style="color: hsl(0, 100%, 40%);">-                                 NM_AVSTATE_OFF_LINE);</span><br><span style="color: hsl(120, 100%, 40%);">+                osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_DISABLE, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+           osmo_fsm_inst_dispatch(trx->bb_transc.mo.fi, NM_EV_DISABLE, NULL);</span><br><span>        }</span><br><span> </span><br><span>        return 0;</span><br><span>diff --git a/src/osmo-bts-octphy/l1_oml.c b/src/osmo-bts-octphy/l1_oml.c</span><br><span>index 2062be3..a72367c 100644</span><br><span>--- a/src/osmo-bts-octphy/l1_oml.c</span><br><span>+++ b/src/osmo-bts-octphy/l1_oml.c</span><br><span>@@ -28,6 +28,7 @@</span><br><span> </span><br><span> #include <osmocom/core/talloc.h></span><br><span> #include <osmocom/core/utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/fsm.h></span><br><span> </span><br><span> #include <osmo-bts/gsm_data.h></span><br><span> #include <osmo-bts/logging.h></span><br><span>@@ -187,22 +188,15 @@</span><br><span> static int opstart_compl(struct gsm_abis_mo *mo)</span><br><span> {</span><br><span>   struct gsm_bts_trx *trx = gsm_bts_trx_num(mo->bts, mo->obj_inst.trx_nr);</span><br><span style="color: hsl(0, 100%, 40%);">-  uint8_t tn;</span><br><span>  /* TODO: Send NACK in case of error! */</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+   /* We already have a FSM for Radio Carrier, handle it there */</span><br><span style="color: hsl(120, 100%, 40%);">+        if (mo->obj_class == NM_OC_RADIO_CARRIER)</span><br><span style="color: hsl(120, 100%, 40%);">+          return osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_OPSTART_ACK, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     /* Set to Operational State: Enabled */</span><br><span>      oml_mo_state_chg(mo, NM_OPSTATE_ENABLED, NM_AVSTATE_OK);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    if (mo->obj_class == NM_OC_RADIO_CARRIER) {</span><br><span style="color: hsl(0, 100%, 40%);">-          /* Mark Dependency TS as Offline (ready to be Opstarted) */</span><br><span style="color: hsl(0, 100%, 40%);">-             for (tn = 0; tn < TRX_NR_TS; tn++) {</span><br><span style="color: hsl(0, 100%, 40%);">-                 if (trx->ts[tn].mo.nm_state.operational == NM_OPSTATE_DISABLED &&</span><br><span style="color: hsl(0, 100%, 40%);">-                        trx->ts[tn].mo.nm_state.availability ==  NM_AVSTATE_DEPENDENCY) {</span><br><span style="color: hsl(0, 100%, 40%);">-                                oml_mo_state_chg(&trx->ts[tn].mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE);</span><br><span style="color: hsl(0, 100%, 40%);">-                     }</span><br><span style="color: hsl(0, 100%, 40%);">-               }</span><br><span style="color: hsl(0, 100%, 40%);">-       }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>    /* hack to auto-activate all SAPIs for the BCCH/CCCH on TS0 */</span><br><span>       if (mo->obj_class == NM_OC_CHANNEL && mo->obj_inst.trx_nr == 0 &&</span><br><span>          mo->obj_inst.ts_nr == 7) {</span><br><span>@@ -1450,8 +1444,9 @@</span><br><span>                                ARRAY_SIZE(trx_rqd_attr))) {</span><br><span>             /* HACK: spec says we need to decline, but openbsc</span><br><span>            * doesn't deal with this very well */</span><br><span style="color: hsl(0, 100%, 40%);">-              return oml_mo_opstart_ack(&trx->mo);</span><br><span style="color: hsl(0, 100%, 40%);">-             /* return oml_mo_opstart_nack(&trx->mo, NM_NACK_CANT_PERFORM); */</span><br><span style="color: hsl(120, 100%, 40%);">+              return osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_OPSTART_ACK, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+                //return osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_OPSTART_NACK,</span><br><span style="color: hsl(120, 100%, 40%);">+            //                              (void*)(intptr_t)NM_NACK_CANT_PERFORM);</span><br><span>      }</span><br><span> </span><br><span>        l1if_check_app_version(trx);</span><br><span>@@ -1763,8 +1758,10 @@</span><br><span> /* callback from OML */</span><br><span> int bts_model_opstart(struct gsm_bts *bts, struct gsm_abis_mo *mo, void *obj)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-  int rc = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct gsm_bts_bb_trx *bb_transc;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct gsm_bts_trx* trx;</span><br><span>     struct gsm_bts_trx_ts *ts;</span><br><span style="color: hsl(120, 100%, 40%);">+    int rc;</span><br><span> </span><br><span>  switch (mo->obj_class) {</span><br><span>  case NM_OC_SITE_MANAGER:</span><br><span>@@ -1774,13 +1771,17 @@</span><br><span>           rc = osmo_fsm_inst_dispatch(bts->mo.fi, NM_EV_OPSTART_ACK, NULL);</span><br><span>                 break;</span><br><span>       case NM_OC_RADIO_CARRIER:</span><br><span style="color: hsl(0, 100%, 40%);">-               rc = trx_init(obj);</span><br><span style="color: hsl(120, 100%, 40%);">+           trx = (struct gsm_bts_trx*) obj;</span><br><span style="color: hsl(120, 100%, 40%);">+              rc = trx_init(trx);</span><br><span style="color: hsl(120, 100%, 40%);">+           break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case NM_OC_BASEB_TRANSC:</span><br><span style="color: hsl(120, 100%, 40%);">+              bb_transc = (struct gsm_bts_bb_trx *) obj;</span><br><span style="color: hsl(120, 100%, 40%);">+            rc = osmo_fsm_inst_dispatch(bb_transc->mo.fi, NM_EV_OPSTART_ACK, NULL);</span><br><span>           break;</span><br><span>       case NM_OC_CHANNEL:</span><br><span>          ts = (struct gsm_bts_trx_ts*) obj;</span><br><span>           rc = ts_connect_as(ts, ts->pchan, pchan_act_compl_cb, NULL);</span><br><span>              break;</span><br><span style="color: hsl(0, 100%, 40%);">-  case NM_OC_BASEB_TRANSC:</span><br><span>     case NM_OC_GPRS_NSE:</span><br><span>         case NM_OC_GPRS_CELL:</span><br><span>        case NM_OC_GPRS_NSVC:</span><br><span>diff --git a/src/osmo-bts-omldummy/bts_model.c b/src/osmo-bts-omldummy/bts_model.c</span><br><span>index ad007ec..06e1373 100644</span><br><span>--- a/src/osmo-bts-omldummy/bts_model.c</span><br><span>+++ b/src/osmo-bts-omldummy/bts_model.c</span><br><span>@@ -23,6 +23,7 @@</span><br><span> #include <osmocom/core/talloc.h></span><br><span> #include <osmocom/core/utils.h></span><br><span> #include <osmocom/codec/codec.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/fsm.h></span><br><span> </span><br><span> #include <osmo-bts/gsm_data.h></span><br><span> #include <osmo-bts/phy_link.h></span><br><span>@@ -75,15 +76,13 @@</span><br><span>       uint8_t tn;</span><br><span> </span><br><span>      llist_for_each_entry(trx, &bts->trx_list, list) {</span><br><span style="color: hsl(0, 100%, 40%);">-                oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OK);</span><br><span style="color: hsl(0, 100%, 40%);">-          oml_mo_state_chg(&trx->bb_transc.mo, -1, NM_AVSTATE_OK);</span><br><span> </span><br><span>          for (tn = 0; tn < TRX_NR_TS; tn++)</span><br><span>                        oml_mo_state_chg(&trx->ts[tn].mo, NM_OPSTATE_DISABLED, NM_AVSTATE_DEPENDENCY);</span><br><span> </span><br><span>            /* report availability of trx to the bts. this will trigger the rsl connection */</span><br><span style="color: hsl(0, 100%, 40%);">-               oml_mo_tx_sw_act_rep(&trx->mo);</span><br><span style="color: hsl(0, 100%, 40%);">-          oml_mo_tx_sw_act_rep(&trx->bb_transc.mo);</span><br><span style="color: hsl(120, 100%, 40%);">+              osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_SW_ACT, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+            osmo_fsm_inst_dispatch(trx->bb_transc.mo.fi, NM_EV_SW_ACT, NULL);</span><br><span>         }</span><br><span>    return 0;</span><br><span> }</span><br><span>@@ -123,8 +122,8 @@</span><br><span> int bts_model_opstart(struct gsm_bts *bts, struct gsm_abis_mo *mo, void *obj)</span><br><span> {</span><br><span>   int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct gsm_bts_bb_trx *bb_transc;</span><br><span>    struct gsm_bts_trx* trx;</span><br><span style="color: hsl(0, 100%, 40%);">-        uint8_t tn;</span><br><span> </span><br><span>      switch (mo->obj_class) {</span><br><span>  case NM_OC_SITE_MANAGER:</span><br><span>@@ -135,18 +134,12 @@</span><br><span>             break;</span><br><span>       case NM_OC_RADIO_CARRIER:</span><br><span>            trx = (struct gsm_bts_trx*) obj;</span><br><span style="color: hsl(0, 100%, 40%);">-                /* Mark Dependency TS as Offline (ready to be Opstarted) */</span><br><span style="color: hsl(0, 100%, 40%);">-             for (tn = 0; tn < TRX_NR_TS; tn++) {</span><br><span style="color: hsl(0, 100%, 40%);">-                 if (trx->ts[tn].mo.nm_state.operational == NM_OPSTATE_DISABLED &&</span><br><span style="color: hsl(0, 100%, 40%);">-                        trx->ts[tn].mo.nm_state.availability == NM_AVSTATE_DEPENDENCY) {</span><br><span style="color: hsl(0, 100%, 40%);">-                         oml_mo_state_chg(&trx->ts[tn].mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE);</span><br><span style="color: hsl(0, 100%, 40%);">-                     }</span><br><span style="color: hsl(0, 100%, 40%);">-               }</span><br><span style="color: hsl(0, 100%, 40%);">-               oml_mo_state_chg(mo, NM_OPSTATE_ENABLED, NM_AVSTATE_OK);</span><br><span style="color: hsl(0, 100%, 40%);">-                rc = oml_mo_opstart_ack(mo);</span><br><span style="color: hsl(120, 100%, 40%);">+          rc = osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_OPSTART_ACK, NULL);</span><br><span>                 break;</span><br><span style="color: hsl(0, 100%, 40%);">-  case NM_OC_CHANNEL:</span><br><span>  case NM_OC_BASEB_TRANSC:</span><br><span style="color: hsl(120, 100%, 40%);">+              bb_transc = (struct gsm_bts_bb_trx *) obj;</span><br><span style="color: hsl(120, 100%, 40%);">+            rc = osmo_fsm_inst_dispatch(bb_transc->mo.fi, NM_EV_OPSTART_ACK, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span>       case NM_OC_GPRS_NSE:</span><br><span>         case NM_OC_GPRS_CELL:</span><br><span>        case NM_OC_GPRS_NSVC:</span><br><span>diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c</span><br><span>index 2e5e5b6..4d228bb 100644</span><br><span>--- a/src/osmo-bts-sysmo/l1_if.c</span><br><span>+++ b/src/osmo-bts-sysmo/l1_if.c</span><br><span>@@ -51,6 +51,7 @@</span><br><span> #include <osmo-bts/msg_utils.h></span><br><span> #include <osmo-bts/dtx_dl_amr_fsm.h></span><br><span> #include <osmo-bts/tx_power.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/nm_common_fsm.h></span><br><span> </span><br><span> #include <sysmocom/femtobts/superfemto.h></span><br><span> #include <sysmocom/femtobts/gsml1prim.h></span><br><span>@@ -1240,17 +1241,15 @@</span><br><span>                  bts_update_status(BTS_STATUS_RF_ACTIVE, 1);</span><br><span> </span><br><span>              /* signal availability */</span><br><span style="color: hsl(0, 100%, 40%);">-               oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OK);</span><br><span style="color: hsl(0, 100%, 40%);">-          oml_mo_tx_sw_act_rep(&trx->mo);</span><br><span style="color: hsl(0, 100%, 40%);">-          oml_mo_state_chg(&trx->bb_transc.mo, -1, NM_AVSTATE_OK);</span><br><span style="color: hsl(0, 100%, 40%);">-         oml_mo_tx_sw_act_rep(&trx->bb_transc.mo);</span><br><span style="color: hsl(120, 100%, 40%);">+              osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_SW_ACT, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+            osmo_fsm_inst_dispatch(trx->bb_transc.mo.fi, NM_EV_SW_ACT, NULL);</span><br><span> </span><br><span>             for (i = 0; i < ARRAY_SIZE(trx->ts); i++)</span><br><span>                      oml_mo_state_chg(&trx->ts[i].mo, NM_OPSTATE_DISABLED, NM_AVSTATE_DEPENDENCY);</span><br><span>         } else {</span><br><span>             bts_update_status(BTS_STATUS_RF_ACTIVE, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-             oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE);</span><br><span style="color: hsl(0, 100%, 40%);">-            oml_mo_state_chg(&trx->bb_transc.mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE);</span><br><span style="color: hsl(120, 100%, 40%);">+                osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_DISABLE, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+           osmo_fsm_inst_dispatch(trx->bb_transc.mo.fi, NM_EV_DISABLE, NULL);</span><br><span>        }</span><br><span> </span><br><span>        msgb_free(resp);</span><br><span>diff --git a/src/osmo-bts-sysmo/oml.c b/src/osmo-bts-sysmo/oml.c</span><br><span>index 7d9aa2a..9a82647 100644</span><br><span>--- a/src/osmo-bts-sysmo/oml.c</span><br><span>+++ b/src/osmo-bts-sysmo/oml.c</span><br><span>@@ -23,6 +23,7 @@</span><br><span> </span><br><span> #include <osmocom/core/talloc.h></span><br><span> #include <osmocom/core/utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/fsm.h></span><br><span> </span><br><span> #include <sysmocom/femtobts/gsml1prim.h></span><br><span> #include <sysmocom/femtobts/gsml1const.h></span><br><span>@@ -269,31 +270,28 @@</span><br><span>       GsmL1_Prim_t *l1p = msgb_l1prim(l1_msg);</span><br><span>     GsmL1_Status_t status = prim_status(l1p);</span><br><span>    struct gsm_bts_trx *trx = gsm_bts_trx_num(mo->bts, mo->obj_inst.trx_nr);</span><br><span style="color: hsl(0, 100%, 40%);">-  uint8_t tn;</span><br><span> </span><br><span>      if (status != GsmL1_Status_Success) {</span><br><span>                LOGP(DL1C, LOGL_ERROR, "Rx %s, status: %s\n",</span><br><span>                      get_value_string(femtobts_l1prim_names, l1p->id),</span><br><span>                         get_value_string(femtobts_l1status_names, status));</span><br><span>          msgb_free(l1_msg);</span><br><span style="color: hsl(0, 100%, 40%);">-              return oml_mo_opstart_nack(mo, NM_NACK_CANT_PERFORM);</span><br><span style="color: hsl(120, 100%, 40%);">+         if (mo->obj_class == NM_OC_RADIO_CARRIER)</span><br><span style="color: hsl(120, 100%, 40%);">+                  return osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_OPSTART_NACK,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                    (void*)(intptr_t)NM_NACK_CANT_PERFORM);</span><br><span style="color: hsl(120, 100%, 40%);">+         else</span><br><span style="color: hsl(120, 100%, 40%);">+                  return oml_mo_opstart_nack(mo, NM_NACK_CANT_PERFORM);</span><br><span>        }</span><br><span> </span><br><span>        msgb_free(l1_msg);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+        /* We already have a FSM for Radio Carrier, handle it there */</span><br><span style="color: hsl(120, 100%, 40%);">+        if (mo->obj_class == NM_OC_RADIO_CARRIER)</span><br><span style="color: hsl(120, 100%, 40%);">+          return osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_OPSTART_ACK, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     /* Set to Operational State: Enabled */</span><br><span>      oml_mo_state_chg(mo, NM_OPSTATE_ENABLED, NM_AVSTATE_OK);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    if (mo->obj_class == NM_OC_RADIO_CARRIER) {</span><br><span style="color: hsl(0, 100%, 40%);">-          /* Mark Dependency TS as Offline (ready to be Opstarted) */</span><br><span style="color: hsl(0, 100%, 40%);">-             for (tn = 0; tn < TRX_NR_TS; tn++) {</span><br><span style="color: hsl(0, 100%, 40%);">-                 if (trx->ts[tn].mo.nm_state.operational == NM_OPSTATE_DISABLED &&</span><br><span style="color: hsl(0, 100%, 40%);">-                        trx->ts[tn].mo.nm_state.availability ==  NM_AVSTATE_DEPENDENCY) {</span><br><span style="color: hsl(0, 100%, 40%);">-                                oml_mo_state_chg(&trx->ts[tn].mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE);</span><br><span style="color: hsl(0, 100%, 40%);">-                     }</span><br><span style="color: hsl(0, 100%, 40%);">-               }</span><br><span style="color: hsl(0, 100%, 40%);">-       }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>    /* ugly hack to auto-activate all SAPIs for the BCCH/CCCH on TS0 */</span><br><span>  if (mo->obj_class == NM_OC_CHANNEL && mo->obj_inst.trx_nr == 0 &&</span><br><span>          mo->obj_inst.ts_nr == 0) {</span><br><span>@@ -407,8 +405,9 @@</span><br><span>                                  ARRAY_SIZE(trx_rqd_attr))) {</span><br><span>             /* HACK: spec says we need to decline, but openbsc</span><br><span>            * doesn't deal with this very well */</span><br><span style="color: hsl(0, 100%, 40%);">-              return oml_mo_opstart_ack(&trx->mo);</span><br><span style="color: hsl(0, 100%, 40%);">-             //return oml_mo_opstart_nack(&trx->mo, NM_NACK_CANT_PERFORM);</span><br><span style="color: hsl(120, 100%, 40%);">+          return osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_OPSTART_ACK, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+                //return osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_OPSTART_NACK,</span><br><span style="color: hsl(120, 100%, 40%);">+            //                              (void*)(intptr_t)NM_NACK_CANT_PERFORM);</span><br><span>      }</span><br><span> </span><br><span>        femto_band = sysmobts_select_femto_band(trx, trx->arfcn);</span><br><span>@@ -1771,6 +1770,8 @@</span><br><span> int bts_model_opstart(struct gsm_bts *bts, struct gsm_abis_mo *mo,</span><br><span>                 void *obj)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gsm_bts_bb_trx *bb_transc;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct gsm_bts_trx* trx;</span><br><span>     int rc;</span><br><span> </span><br><span>  switch (mo->obj_class) {</span><br><span>@@ -1785,12 +1786,16 @@</span><br><span>                oml_mo_state_chg(&bts->gprs.nsvc[0].mo, -1, NM_AVSTATE_OK);</span><br><span>           break;</span><br><span>       case NM_OC_RADIO_CARRIER:</span><br><span style="color: hsl(0, 100%, 40%);">-               rc = trx_init(obj);</span><br><span style="color: hsl(120, 100%, 40%);">+           trx = (struct gsm_bts_trx *) obj;</span><br><span style="color: hsl(120, 100%, 40%);">+             rc = trx_init(trx);</span><br><span style="color: hsl(120, 100%, 40%);">+           break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case NM_OC_BASEB_TRANSC:</span><br><span style="color: hsl(120, 100%, 40%);">+              bb_transc = (struct gsm_bts_bb_trx *) obj;</span><br><span style="color: hsl(120, 100%, 40%);">+            rc = osmo_fsm_inst_dispatch(bb_transc->mo.fi, NM_EV_OPSTART_ACK, NULL);</span><br><span>           break;</span><br><span>       case NM_OC_CHANNEL:</span><br><span>          rc = ts_opstart(obj);</span><br><span>                break;</span><br><span style="color: hsl(0, 100%, 40%);">-  case NM_OC_BASEB_TRANSC:</span><br><span>     case NM_OC_GPRS_NSE:</span><br><span>         case NM_OC_GPRS_CELL:</span><br><span>        case NM_OC_GPRS_NSVC:</span><br><span>diff --git a/src/osmo-bts-trx/l1_if.c b/src/osmo-bts-trx/l1_if.c</span><br><span>index 916f6a2..9c8069a 100644</span><br><span>--- a/src/osmo-bts-trx/l1_if.c</span><br><span>+++ b/src/osmo-bts-trx/l1_if.c</span><br><span>@@ -97,11 +97,9 @@</span><br><span>       * transceiver */</span><br><span>    if (avail) {</span><br><span>                 /* signal availability */</span><br><span style="color: hsl(0, 100%, 40%);">-               oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OK);</span><br><span style="color: hsl(0, 100%, 40%);">-          oml_mo_state_chg(&trx->bb_transc.mo, -1, NM_AVSTATE_OK);</span><br><span>              if (!pinst->u.osmotrx.sw_act_reported) {</span><br><span style="color: hsl(0, 100%, 40%);">-                     oml_mo_tx_sw_act_rep(&trx->mo);</span><br><span style="color: hsl(0, 100%, 40%);">-                  oml_mo_tx_sw_act_rep(&trx->bb_transc.mo);</span><br><span style="color: hsl(120, 100%, 40%);">+                      osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_SW_ACT, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+                    osmo_fsm_inst_dispatch(trx->bb_transc.mo.fi, NM_EV_SW_ACT, NULL);</span><br><span>                         pinst->u.osmotrx.sw_act_reported = true;</span><br><span>          }</span><br><span> </span><br><span>@@ -111,10 +109,8 @@</span><br><span>                                         NM_AVSTATE_DEPENDENCY :</span><br><span>                                      NM_AVSTATE_NOT_INSTALLED);</span><br><span>   } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED,</span><br><span style="color: hsl(0, 100%, 40%);">-                  NM_AVSTATE_OFF_LINE);</span><br><span style="color: hsl(0, 100%, 40%);">-           oml_mo_state_chg(&trx->bb_transc.mo, NM_OPSTATE_DISABLED,</span><br><span style="color: hsl(0, 100%, 40%);">-                        NM_AVSTATE_OFF_LINE);</span><br><span style="color: hsl(120, 100%, 40%);">+         osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_DISABLE, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+           osmo_fsm_inst_dispatch(trx->bb_transc.mo.fi, NM_EV_DISABLE, NULL);</span><br><span> </span><br><span>            for (tn = 0; tn < TRX_NR_TS; tn++)</span><br><span>                        oml_mo_state_chg(&trx->ts[tn].mo, NM_OPSTATE_DISABLED,</span><br><span>@@ -200,25 +196,17 @@</span><br><span>        struct phy_instance *pinst = trx_phy_instance(trx);</span><br><span>  struct trx_l1h *l1h = pinst->u.osmotrx.hdl;</span><br><span>       int rc;</span><br><span style="color: hsl(0, 100%, 40%);">- uint8_t tn;</span><br><span> </span><br><span>      rc = osmo_fsm_inst_dispatch(l1h->provision_fi, TRX_PROV_EV_CFG_ENABLE, (void*)(intptr_t)true);</span><br><span>    if (rc != 0)</span><br><span style="color: hsl(0, 100%, 40%);">-            return oml_mo_opstart_nack(&trx->mo, NM_NACK_CANT_PERFORM);</span><br><span style="color: hsl(120, 100%, 40%);">+            return osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_OPSTART_NACK,</span><br><span style="color: hsl(120, 100%, 40%);">+                                            (void*)(intptr_t)NM_NACK_CANT_PERFORM);</span><br><span> </span><br><span>    if (trx == trx->bts->c0)</span><br><span>               lchan_init_lapdm(&trx->ts[0].lchan[CCCH_LCHAN]);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     /* Mark Dependency TS as Offline (ready to be Opstarted) */</span><br><span style="color: hsl(0, 100%, 40%);">-     for (tn = 0; tn < TRX_NR_TS; tn++) {</span><br><span style="color: hsl(0, 100%, 40%);">-         if (trx->ts[tn].mo.nm_state.operational == NM_OPSTATE_DISABLED &&</span><br><span style="color: hsl(0, 100%, 40%);">-                trx->ts[tn].mo.nm_state.availability ==  NM_AVSTATE_DEPENDENCY) {</span><br><span style="color: hsl(0, 100%, 40%);">-                        oml_mo_state_chg(&trx->ts[tn].mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE);</span><br><span style="color: hsl(0, 100%, 40%);">-             }</span><br><span style="color: hsl(0, 100%, 40%);">-       }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>    /* Send OPSTART ack */</span><br><span style="color: hsl(0, 100%, 40%);">-  return oml_mo_opstart_ack(&trx->mo);</span><br><span style="color: hsl(120, 100%, 40%);">+   return osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_OPSTART_ACK, NULL);</span><br><span> }</span><br><span> </span><br><span> /* Deact RF on transceiver */</span><br><span>@@ -614,6 +602,8 @@</span><br><span> int bts_model_opstart(struct gsm_bts *bts, struct gsm_abis_mo *mo,</span><br><span>                       void *obj)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gsm_bts_bb_trx *bb_transc;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct gsm_bts_trx *trx;</span><br><span>     int rc;</span><br><span> </span><br><span>  switch (mo->obj_class) {</span><br><span>@@ -625,10 +615,14 @@</span><br><span>          break;</span><br><span>       case NM_OC_RADIO_CARRIER:</span><br><span>            /* activate transceiver */</span><br><span style="color: hsl(0, 100%, 40%);">-              rc = trx_init(obj);</span><br><span style="color: hsl(120, 100%, 40%);">+           trx = (struct gsm_bts_trx *) obj;</span><br><span style="color: hsl(120, 100%, 40%);">+             rc = trx_init(trx);</span><br><span style="color: hsl(120, 100%, 40%);">+           break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case NM_OC_BASEB_TRANSC:</span><br><span style="color: hsl(120, 100%, 40%);">+              bb_transc = (struct gsm_bts_bb_trx *) obj;</span><br><span style="color: hsl(120, 100%, 40%);">+            rc = osmo_fsm_inst_dispatch(bb_transc->mo.fi, NM_EV_OPSTART_ACK, NULL);</span><br><span>           break;</span><br><span>       case NM_OC_CHANNEL:</span><br><span style="color: hsl(0, 100%, 40%);">-     case NM_OC_BASEB_TRANSC:</span><br><span>     case NM_OC_GPRS_NSE:</span><br><span>         case NM_OC_GPRS_CELL:</span><br><span>        case NM_OC_GPRS_NSVC:</span><br><span>diff --git a/src/osmo-bts-virtual/bts_model.c b/src/osmo-bts-virtual/bts_model.c</span><br><span>index 9ba632c..c3a75f4 100644</span><br><span>--- a/src/osmo-bts-virtual/bts_model.c</span><br><span>+++ b/src/osmo-bts-virtual/bts_model.c</span><br><span>@@ -23,6 +23,7 @@</span><br><span> #include <osmocom/core/talloc.h></span><br><span> #include <osmocom/core/utils.h></span><br><span> #include <osmocom/codec/codec.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/fsm.h></span><br><span> </span><br><span> #include <osmo-bts/gsm_data.h></span><br><span> #include <osmo-bts/phy_link.h></span><br><span>@@ -85,15 +86,13 @@</span><br><span>   uint8_t tn;</span><br><span> </span><br><span>      llist_for_each_entry(trx, &bts->trx_list, list) {</span><br><span style="color: hsl(0, 100%, 40%);">-                oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OK);</span><br><span style="color: hsl(0, 100%, 40%);">-          oml_mo_state_chg(&trx->bb_transc.mo, -1, NM_AVSTATE_OK);</span><br><span> </span><br><span>          for (tn = 0; tn < TRX_NR_TS; tn++)</span><br><span>                        oml_mo_state_chg(&trx->ts[tn].mo, NM_OPSTATE_DISABLED, NM_AVSTATE_DEPENDENCY);</span><br><span> </span><br><span>            /* report availability of trx to the bts. this will trigger the rsl connection */</span><br><span style="color: hsl(0, 100%, 40%);">-               oml_mo_tx_sw_act_rep(&trx->mo);</span><br><span style="color: hsl(0, 100%, 40%);">-          oml_mo_tx_sw_act_rep(&trx->bb_transc.mo);</span><br><span style="color: hsl(120, 100%, 40%);">+              osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_SW_ACT, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+            osmo_fsm_inst_dispatch(trx->bb_transc.mo.fi, NM_EV_SW_ACT, NULL);</span><br><span>         }</span><br><span>    return 0;</span><br><span> }</span><br><span>@@ -140,8 +139,8 @@</span><br><span> int bts_model_opstart(struct gsm_bts *bts, struct gsm_abis_mo *mo, void *obj)</span><br><span> {</span><br><span>   int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct gsm_bts_bb_trx *bb_transc;</span><br><span>    struct gsm_bts_trx* trx;</span><br><span style="color: hsl(0, 100%, 40%);">-        uint8_t tn;</span><br><span> </span><br><span>      switch (mo->obj_class) {</span><br><span>  case NM_OC_SITE_MANAGER:</span><br><span>@@ -152,18 +151,12 @@</span><br><span>             break;</span><br><span>       case NM_OC_RADIO_CARRIER:</span><br><span>            trx = (struct gsm_bts_trx*) obj;</span><br><span style="color: hsl(0, 100%, 40%);">-                /* Mark Dependency TS as Offline (ready to be Opstarted) */</span><br><span style="color: hsl(0, 100%, 40%);">-             for (tn = 0; tn < TRX_NR_TS; tn++) {</span><br><span style="color: hsl(0, 100%, 40%);">-                 if (trx->ts[tn].mo.nm_state.operational == NM_OPSTATE_DISABLED &&</span><br><span style="color: hsl(0, 100%, 40%);">-                        trx->ts[tn].mo.nm_state.availability == NM_AVSTATE_DEPENDENCY) {</span><br><span style="color: hsl(0, 100%, 40%);">-                         oml_mo_state_chg(&trx->ts[tn].mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE);</span><br><span style="color: hsl(0, 100%, 40%);">-                     }</span><br><span style="color: hsl(0, 100%, 40%);">-               }</span><br><span style="color: hsl(0, 100%, 40%);">-               oml_mo_state_chg(mo, NM_OPSTATE_ENABLED, NM_AVSTATE_OK);</span><br><span style="color: hsl(0, 100%, 40%);">-                rc = oml_mo_opstart_ack(mo);</span><br><span style="color: hsl(120, 100%, 40%);">+          rc = osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_OPSTART_ACK, NULL);</span><br><span>                 break;</span><br><span style="color: hsl(0, 100%, 40%);">-  case NM_OC_CHANNEL:</span><br><span>  case NM_OC_BASEB_TRANSC:</span><br><span style="color: hsl(120, 100%, 40%);">+              bb_transc = (struct gsm_bts_bb_trx *) obj;</span><br><span style="color: hsl(120, 100%, 40%);">+            rc = osmo_fsm_inst_dispatch(bb_transc->mo.fi, NM_EV_OPSTART_ACK, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span>       case NM_OC_GPRS_NSE:</span><br><span>         case NM_OC_GPRS_CELL:</span><br><span>        case NM_OC_GPRS_NSVC:</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-bts/+/20284">change 20284</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/c/osmo-bts/+/20284"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmo-bts </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: Ifb249a821c4270918699b6375a72b3a618e8cfbe </div>
<div style="display:none"> Gerrit-Change-Number: 20284 </div>
<div style="display:none"> Gerrit-PatchSet: 12 </div>
<div style="display:none"> Gerrit-Owner: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder </div>
<div style="display:none"> Gerrit-Reviewer: laforge <laforge@osmocom.org> </div>
<div style="display:none"> Gerrit-Reviewer: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>