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

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">bts-trx: introduce TRX provisioning FSM<br><br>With prior code state managing the TRXC side of osmo-bts-trx, there are<br>plenty o cases (race conditions) where things can go wrong/unexpected,<br>because there's really no infrastructure to wait and synchronize between<br>different TRXs (eg wait until all are configured to POWERON), or to<br>simply keep well known per-trx state regarding lower layers.<br><br>In order to fix in the future all of those issues and to sanitize<br>current code, a new per-trx FSM is introduced, which takes care of<br>submitting TRXC commands and waiting for response when needed to manage<br>the state of the TRX.<br><br>Related: OS#4364<br>Change-Id: I2a00c23df15840e33fbb232c9e1dd6db128f63f6<br>---<br>M src/osmo-bts-trx/Makefile.am<br>M src/osmo-bts-trx/l1_if.c<br>M src/osmo-bts-trx/l1_if.h<br>M src/osmo-bts-trx/trx_if.c<br>A src/osmo-bts-trx/trx_provision_fsm.c<br>A src/osmo-bts-trx/trx_provision_fsm.h<br>6 files changed, 537 insertions(+), 224 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/src/osmo-bts-trx/Makefile.am b/src/osmo-bts-trx/Makefile.am</span><br><span>index ae69000..54d1af9 100644</span><br><span>--- a/src/osmo-bts-trx/Makefile.am</span><br><span>+++ b/src/osmo-bts-trx/Makefile.am</span><br><span>@@ -32,6 +32,7 @@</span><br><span>     trx_if.h \</span><br><span>   l1_if.h \</span><br><span>    loops.h \</span><br><span style="color: hsl(120, 100%, 40%);">+     trx_provision_fsm.h \</span><br><span>        $(NULL)</span><br><span> </span><br><span> bin_PROGRAMS = osmo-bts-trx</span><br><span>@@ -47,6 +48,7 @@</span><br><span>       sched_lchan_pdtch.c \</span><br><span>        sched_lchan_tchf.c \</span><br><span>         sched_lchan_tchh.c \</span><br><span style="color: hsl(120, 100%, 40%);">+  trx_provision_fsm.c \</span><br><span>        trx_vty.c \</span><br><span>  loops.c \</span><br><span>    $(NULL)</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 a3bdf01..d65900f 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>@@ -29,6 +29,7 @@</span><br><span> </span><br><span> #include <osmocom/core/talloc.h></span><br><span> #include <osmocom/core/bits.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/fsm.h></span><br><span> #include <osmocom/codec/ecu.h></span><br><span> #include <osmocom/gsm/abis_nm.h></span><br><span> </span><br><span>@@ -45,6 +46,7 @@</span><br><span> </span><br><span> #include "l1_if.h"</span><br><span> #include "trx_if.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "trx_provision_fsm.h"</span><br><span> </span><br><span> #define RF_DISABLED_mdB to_mdB(-10)</span><br><span> </span><br><span>@@ -62,7 +64,7 @@</span><br><span>      [GSM_PCHAN_UNKNOWN]             = 0,</span><br><span> };</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static enum gsm_phys_chan_config transceiver_chan_type_2_pchan(uint8_t type)</span><br><span style="color: hsl(120, 100%, 40%);">+enum gsm_phys_chan_config transceiver_chan_type_2_pchan(uint8_t type)</span><br><span> {</span><br><span>       int i;</span><br><span>       for (i = 0; i < _GSM_PCHAN_MAX; i++) {</span><br><span>@@ -77,6 +79,8 @@</span><br><span>        struct trx_l1h *l1h;</span><br><span>         l1h = talloc_zero(tall_ctx, struct trx_l1h);</span><br><span>         l1h->phy_inst = pinst;</span><br><span style="color: hsl(120, 100%, 40%);">+     l1h->provision_fi = osmo_fsm_inst_alloc(&trx_prov_fsm, l1h, l1h, LOGL_INFO, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(osmo_fsm_inst_update_id_f_sanitize(l1h->provision_fi, '-', phy_instance_name(pinst)) == 0);</span><br><span>   trx_if_init(l1h);</span><br><span>    return l1h;</span><br><span> }</span><br><span>@@ -140,7 +144,7 @@</span><br><span>       return trx_sched_set_lchan(&l1h->l1s, gsm_lchan2chan_nr(lchan), LID_SACCH, false);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static int l1if_trx_start_power_ramp(struct gsm_bts_trx *trx, ramp_compl_cb_t ramp_compl_cb)</span><br><span style="color: hsl(120, 100%, 40%);">+int l1if_trx_start_power_ramp(struct gsm_bts_trx *trx, ramp_compl_cb_t ramp_compl_cb)</span><br><span> {</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>@@ -174,78 +178,6 @@</span><br><span>        l1if_trx_start_power_ramp(trx, NULL);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static void l1if_getnompower_cb(struct trx_l1h *l1h, int nominal_power, int rc)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-  struct phy_instance *pinst = l1h->phy_inst;</span><br><span style="color: hsl(0, 100%, 40%);">-  struct gsm_bts_trx *trx = pinst->trx;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        LOGPPHI(pinst, DL1C, LOGL_DEBUG, "l1if_getnompower_cb(nominal_power=%d, rc=%d)\n", nominal_power, rc);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        l1if_trx_set_nominal_power(trx, nominal_power);</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%);">-static void l1if_setslot_cb(struct trx_l1h *l1h, uint8_t tn, uint8_t type, int rc)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-     struct phy_instance *pinst = l1h->phy_inst;</span><br><span style="color: hsl(0, 100%, 40%);">-  struct gsm_bts_trx *trx = pinst->trx;</span><br><span style="color: hsl(0, 100%, 40%);">-        struct gsm_bts_trx_ts *ts;</span><br><span style="color: hsl(0, 100%, 40%);">-      enum gsm_phys_chan_config pchan;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        if (tn >= TRX_NR_TS) {</span><br><span style="color: hsl(0, 100%, 40%);">-               LOGPPHI(pinst, DL1C, LOGL_ERROR, "transceiver SETSLOT invalid param TN (%" PRIu8 ")\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                     tn);</span><br><span style="color: hsl(0, 100%, 40%);">-            return;</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%);">-       pchan = transceiver_chan_type_2_pchan(type);</span><br><span style="color: hsl(0, 100%, 40%);">-    if (pchan == GSM_PCHAN_UNKNOWN) {</span><br><span style="color: hsl(0, 100%, 40%);">-               LOGPPHI(pinst, DL1C, LOGL_ERROR, "transceiver SETSLOT invalid param TS_TYPE (%" PRIu8 ")\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                        type);</span><br><span style="color: hsl(0, 100%, 40%);">-          return;</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%);">-       ts = &trx->ts[tn];</span><br><span style="color: hsl(0, 100%, 40%);">-       LOGPPHI(pinst, DL1C, LOGL_DEBUG, "%s l1if_setslot_cb(as_pchan=%s),"</span><br><span style="color: hsl(0, 100%, 40%);">-        " calling cb_ts_connected(rc=%d)\n",</span><br><span style="color: hsl(0, 100%, 40%);">-          gsm_ts_name(ts), gsm_pchan_name(pchan), rc);</span><br><span style="color: hsl(0, 100%, 40%);">-       cb_ts_connected(ts, rc);</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%);">-static void l1if_poweronoff_cb(struct trx_l1h *l1h, bool poweronoff, int rc)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-  struct phy_instance *pinst = l1h->phy_inst;</span><br><span style="color: hsl(0, 100%, 40%);">-  struct phy_link *plink = pinst->phy_link;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    plink->u.osmotrx.powered = poweronoff;</span><br><span style="color: hsl(0, 100%, 40%);">-       plink->u.osmotrx.poweronoff_sent = false;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    if (poweronoff) {</span><br><span style="color: hsl(0, 100%, 40%);">-               if (rc == 0 && plink->state != PHY_LINK_CONNECTED) {</span><br><span style="color: hsl(0, 100%, 40%);">-                 trx_sched_clock_started(pinst->trx->bts);</span><br><span style="color: hsl(0, 100%, 40%);">-                 phy_link_state_set(plink, PHY_LINK_CONNECTED);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                  /* Begin to ramp up the power on all TRX associated with this phy */</span><br><span style="color: hsl(0, 100%, 40%);">-                    llist_for_each_entry(pinst, &plink->instances, list) {</span><br><span style="color: hsl(0, 100%, 40%);">-                           if (pinst->trx->mo.nm_state.administrative == NM_STATE_UNLOCKED)</span><br><span style="color: hsl(0, 100%, 40%);">-                                  l1if_trx_start_power_ramp(pinst->trx, NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-                 }</span><br><span style="color: hsl(0, 100%, 40%);">-               } else if (rc != 0 && plink->state != PHY_LINK_SHUTDOWN) {</span><br><span style="color: hsl(0, 100%, 40%);">-                   trx_sched_clock_stopped(pinst->trx->bts);</span><br><span style="color: hsl(0, 100%, 40%);">-                 phy_link_state_set(plink, PHY_LINK_SHUTDOWN);</span><br><span style="color: hsl(0, 100%, 40%);">-           }</span><br><span style="color: hsl(0, 100%, 40%);">-       } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                if (plink->state != PHY_LINK_SHUTDOWN) {</span><br><span style="color: hsl(0, 100%, 40%);">-                     trx_sched_clock_stopped(pinst->trx->bts);</span><br><span style="color: hsl(0, 100%, 40%);">-                 phy_link_state_set(plink, PHY_LINK_SHUTDOWN);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                   /* Notify TRX close on all TRX associated with this phy */</span><br><span style="color: hsl(0, 100%, 40%);">-                      llist_for_each_entry(pinst, &plink->instances, list) {</span><br><span style="color: hsl(0, 100%, 40%);">-                           bts_model_trx_close_cb(pinst->trx, rc);</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 style="color: hsl(0, 100%, 40%);">-</span><br><span> static void l1if_setpower_att_cb(struct trx_l1h *l1h, int power_att_db, int rc)</span><br><span> {</span><br><span>   struct phy_instance *pinst = l1h->phy_inst;</span><br><span>@@ -257,113 +189,6 @@</span><br><span> }</span><br><span> </span><br><span> /*</span><br><span style="color: hsl(0, 100%, 40%);">- * transceiver provisioning</span><br><span style="color: hsl(0, 100%, 40%);">- */</span><br><span style="color: hsl(0, 100%, 40%);">-int l1if_provision_transceiver_trx(struct trx_l1h *l1h)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-     uint8_t tn;</span><br><span style="color: hsl(0, 100%, 40%);">-     struct phy_instance *pinst = l1h->phy_inst;</span><br><span style="color: hsl(0, 100%, 40%);">-  struct phy_link *plink = pinst->phy_link;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    /* During setup, pinst may still not be associated to a TRX nr */</span><br><span style="color: hsl(0, 100%, 40%);">-       if (!pinst->trx) {</span><br><span style="color: hsl(0, 100%, 40%);">-           LOGPPHI(pinst, DL1C, LOGL_INFO,</span><br><span style="color: hsl(0, 100%, 40%);">-                 "Delaying provision, TRX not yet assigned to phy instance\n");</span><br><span style="color: hsl(0, 100%, 40%);">-                return -EIO;</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%);">-       if (phy_link_state_get(plink) == PHY_LINK_SHUTDOWN) {</span><br><span style="color: hsl(0, 100%, 40%);">-           LOGPPHI(pinst, DL1C, LOGL_INFO,</span><br><span style="color: hsl(0, 100%, 40%);">-                 "Delaying provision, TRX not yet available\n");</span><br><span style="color: hsl(0, 100%, 40%);">-               return -EIO;</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%);">-       if (l1h->config.enabled</span><br><span style="color: hsl(0, 100%, 40%);">-       && l1h->config.tsc_valid</span><br><span style="color: hsl(0, 100%, 40%);">-     && l1h->config.bsic_valid</span><br><span style="color: hsl(0, 100%, 40%);">-    && l1h->config.arfcn_valid) {</span><br><span style="color: hsl(0, 100%, 40%);">-               /* before power on */</span><br><span style="color: hsl(0, 100%, 40%);">-           if (!l1h->config.arfcn_sent) {</span><br><span style="color: hsl(0, 100%, 40%);">-                       trx_if_cmd_rxtune(l1h, l1h->config.arfcn);</span><br><span style="color: hsl(0, 100%, 40%);">-                   trx_if_cmd_txtune(l1h, l1h->config.arfcn);</span><br><span style="color: hsl(0, 100%, 40%);">-                   /* After TXTUNE is sent to TRX, get the tx nominal power</span><br><span style="color: hsl(0, 100%, 40%);">-                         * (which may vary precisly on band/arfcn. Avoid sending</span><br><span style="color: hsl(0, 100%, 40%);">-                         * it if we are forced by VTY to use a specific nominal</span><br><span style="color: hsl(0, 100%, 40%);">-                  * power (because TRX may not support the command or</span><br><span style="color: hsl(0, 100%, 40%);">-                     * provide broken values) */</span><br><span style="color: hsl(0, 100%, 40%);">-                    if (!l1h->config.nominal_power_set_by_vty)</span><br><span style="color: hsl(0, 100%, 40%);">-                           trx_if_cmd_getnompower(l1h, l1if_getnompower_cb);</span><br><span style="color: hsl(0, 100%, 40%);">-                       l1h->config.arfcn_sent = 1;</span><br><span style="color: hsl(0, 100%, 40%);">-          }</span><br><span style="color: hsl(0, 100%, 40%);">-               if (!l1h->config.tsc_sent) {</span><br><span style="color: hsl(0, 100%, 40%);">-                 trx_if_cmd_settsc(l1h, l1h->config.tsc);</span><br><span style="color: hsl(0, 100%, 40%);">-                     l1h->config.tsc_sent = 1;</span><br><span style="color: hsl(0, 100%, 40%);">-            }</span><br><span style="color: hsl(0, 100%, 40%);">-               if (!l1h->config.bsic_sent) {</span><br><span style="color: hsl(0, 100%, 40%);">-                        trx_if_cmd_setbsic(l1h, l1h->config.bsic);</span><br><span style="color: hsl(0, 100%, 40%);">-                   l1h->config.bsic_sent = 1;</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%);">-               /* Ask transceiver to use the newest TRXD header version if not using it yet */</span><br><span style="color: hsl(0, 100%, 40%);">-         if (!l1h->config.setformat_sent) {</span><br><span style="color: hsl(0, 100%, 40%);">-                   if (l1h->config.trxd_hdr_ver_use != plink->u.osmotrx.trxd_hdr_ver_max) {</span><br><span style="color: hsl(0, 100%, 40%);">-                          trx_if_cmd_setformat(l1h, plink->u.osmotrx.trxd_hdr_ver_max);</span><br><span style="color: hsl(0, 100%, 40%);">-                                l1h->config.trxd_hdr_ver_req = plink->u.osmotrx.trxd_hdr_ver_max;</span><br><span style="color: hsl(0, 100%, 40%);">-                 } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                                LOGPPHI(pinst, DL1C, LOGL_INFO,</span><br><span style="color: hsl(0, 100%, 40%);">-                                 "No need to negotiate TRXD version, "</span><br><span style="color: hsl(0, 100%, 40%);">-                                 "already using maximum configured one: %" PRIu8 "\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                                       l1h->config.trxd_hdr_ver_use);</span><br><span style="color: hsl(0, 100%, 40%);">-                       }</span><br><span style="color: hsl(0, 100%, 40%);">-                       l1h->config.setformat_sent = 1;</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%);">-               if (pinst->num == 0 && !plink->u.osmotrx.powered && !plink->u.osmotrx.poweronoff_sent) {</span><br><span style="color: hsl(0, 100%, 40%);">-                       trx_if_cmd_poweron(l1h, l1if_poweronoff_cb);</span><br><span style="color: hsl(0, 100%, 40%);">-                    plink->u.osmotrx.poweronoff_sent = true;</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%);">-               /* after power on */</span><br><span style="color: hsl(0, 100%, 40%);">-            if (l1h->config.rxgain_valid && !l1h->config.rxgain_sent) {</span><br><span style="color: hsl(0, 100%, 40%);">-                       trx_if_cmd_setrxgain(l1h, l1h->config.rxgain);</span><br><span style="color: hsl(0, 100%, 40%);">-                       l1h->config.rxgain_sent = 1;</span><br><span style="color: hsl(0, 100%, 40%);">-         }</span><br><span style="color: hsl(0, 100%, 40%);">-               if (l1h->config.maxdly_valid && !l1h->config.maxdly_sent) {</span><br><span style="color: hsl(0, 100%, 40%);">-                       trx_if_cmd_setmaxdly(l1h, l1h->config.maxdly);</span><br><span style="color: hsl(0, 100%, 40%);">-                       l1h->config.maxdly_sent = 1;</span><br><span style="color: hsl(0, 100%, 40%);">-         }</span><br><span style="color: hsl(0, 100%, 40%);">-               if (l1h->config.maxdlynb_valid && !l1h->config.maxdlynb_sent) {</span><br><span style="color: hsl(0, 100%, 40%);">-                   trx_if_cmd_setmaxdlynb(l1h, l1h->config.maxdlynb);</span><br><span style="color: hsl(0, 100%, 40%);">-                   l1h->config.maxdlynb_sent = 1;</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%);">-               for (tn = 0; tn < TRX_NR_TS; tn++) {</span><br><span style="color: hsl(0, 100%, 40%);">-                 if (l1h->config.slottype_valid[tn]</span><br><span style="color: hsl(0, 100%, 40%);">-                    && !l1h->config.slottype_sent[tn]) {</span><br><span style="color: hsl(0, 100%, 40%);">-                                trx_if_cmd_setslot(l1h, tn,</span><br><span style="color: hsl(0, 100%, 40%);">-                                     l1h->config.slottype[tn], l1if_setslot_cb);</span><br><span style="color: hsl(0, 100%, 40%);">-                          l1h->config.slottype_sent[tn] = 1;</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%);">-               return 0;</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%);">-       if (!l1h->config.enabled) {</span><br><span style="color: hsl(0, 100%, 40%);">-          if (pinst->num == 0 && plink->u.osmotrx.powered && !plink->u.osmotrx.poweronoff_sent) {</span><br><span style="color: hsl(0, 100%, 40%);">-                        trx_if_cmd_poweroff(l1h, l1if_poweronoff_cb);</span><br><span style="color: hsl(0, 100%, 40%);">-                   plink->u.osmotrx.poweronoff_sent = true;</span><br><span style="color: hsl(0, 100%, 40%);">-             }</span><br><span style="color: hsl(0, 100%, 40%);">-               l1h->config.rxgain_sent = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-         l1h->config.maxdly_sent = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-         l1h->config.maxdlynb_sent = 0;</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%);">-                   l1h->config.slottype_sent[tn] = 0;</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%);">-       return 0;</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>  * activation/configuration/deactivation of transceiver's TRX</span><br><span>  */</span><br><span> </span><br><span>@@ -373,11 +198,7 @@</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> </span><br><span style="color: hsl(0, 100%, 40%);">-      /* power on transceiver, if not already */</span><br><span style="color: hsl(0, 100%, 40%);">-      if (!l1h->config.enabled) {</span><br><span style="color: hsl(0, 100%, 40%);">-          l1h->config.enabled = true;</span><br><span style="color: hsl(0, 100%, 40%);">-          l1if_provision_transceiver_trx(l1h);</span><br><span style="color: hsl(0, 100%, 40%);">-    }</span><br><span style="color: hsl(120, 100%, 40%);">+     osmo_fsm_inst_dispatch(l1h->provision_fi, TRX_PROV_EV_CFG_ENABLE, (void*)(intptr_t)true);</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>@@ -411,13 +232,7 @@</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> </span><br><span style="color: hsl(0, 100%, 40%);">-      /* power off transceiver, if not already */</span><br><span style="color: hsl(0, 100%, 40%);">-     if (l1h->config.enabled) {</span><br><span style="color: hsl(0, 100%, 40%);">-           l1h->config.enabled = false;</span><br><span style="color: hsl(0, 100%, 40%);">-         l1if_provision_transceiver_trx(l1h);</span><br><span style="color: hsl(0, 100%, 40%);">-    } else if (!pinst->phy_link->u.osmotrx.poweronoff_sent) {</span><br><span style="color: hsl(0, 100%, 40%);">-         bts_model_trx_close_cb(trx, 0);</span><br><span style="color: hsl(0, 100%, 40%);">- } /* else: poweroff in progress, cb will be called upon TRXC RSP */</span><br><span style="color: hsl(120, 100%, 40%);">+   osmo_fsm_inst_dispatch(l1h->provision_fi, TRX_PROV_EV_POWEROFF, NULL);</span><br><span> </span><br><span>        /* Set to Operational State: Disabled */</span><br><span>     check_transceiver_availability_trx(l1h, 0);</span><br><span>@@ -446,12 +261,7 @@</span><br><span>           struct phy_instance *pinst = trx_phy_instance(trx);</span><br><span>          struct phy_link *plink = pinst->phy_link;</span><br><span>                 struct trx_l1h *l1h = pinst->u.osmotrx.hdl;</span><br><span style="color: hsl(0, 100%, 40%);">-          if (l1h->config.bsic != bsic || !l1h->config.bsic_valid) {</span><br><span style="color: hsl(0, 100%, 40%);">-                        l1h->config.bsic = bsic;</span><br><span style="color: hsl(0, 100%, 40%);">-                     l1h->config.bsic_valid = 1;</span><br><span style="color: hsl(0, 100%, 40%);">-                  l1h->config.bsic_sent = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-                   l1if_provision_transceiver_trx(l1h);</span><br><span style="color: hsl(0, 100%, 40%);">-            }</span><br><span style="color: hsl(120, 100%, 40%);">+             osmo_fsm_inst_dispatch(l1h->provision_fi, TRX_PROV_EV_CFG_BSIC, (void*)(intptr_t)bsic);</span><br><span>           check_transceiver_availability_trx(l1h, phy_link_state_get(plink) != PHY_LINK_SHUTDOWN);</span><br><span>     }</span><br><span> </span><br><span>@@ -466,12 +276,7 @@</span><br><span>         struct phy_link *plink = pinst->phy_link;</span><br><span>         uint16_t arfcn = trx->arfcn;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     if (l1h->config.arfcn != arfcn || !l1h->config.arfcn_valid) {</span><br><span style="color: hsl(0, 100%, 40%);">-             l1h->config.arfcn = arfcn;</span><br><span style="color: hsl(0, 100%, 40%);">-           l1h->config.arfcn_valid = 1;</span><br><span style="color: hsl(0, 100%, 40%);">-         l1h->config.arfcn_sent = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-          l1if_provision_transceiver_trx(l1h);</span><br><span style="color: hsl(0, 100%, 40%);">-    }</span><br><span style="color: hsl(120, 100%, 40%);">+     osmo_fsm_inst_dispatch(l1h->provision_fi, TRX_PROV_EV_CFG_ARFCN, (void*)(intptr_t)arfcn);</span><br><span> </span><br><span>     /* Begin to ramp up the power if power reduction is set by OML and TRX</span><br><span>          is already running. Otherwise skip, power ramping will be started</span><br><span>@@ -497,12 +302,7 @@</span><br><span>  /* all TSC of all timeslots must be equal, because transceiver only</span><br><span>   * supports one TSC per TRX */</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      if (l1h->config.tsc != tsc || !l1h->config.tsc_valid) {</span><br><span style="color: hsl(0, 100%, 40%);">-           l1h->config.tsc = tsc;</span><br><span style="color: hsl(0, 100%, 40%);">-               l1h->config.tsc_valid = 1;</span><br><span style="color: hsl(0, 100%, 40%);">-           l1h->config.tsc_sent = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-            l1if_provision_transceiver_trx(l1h);</span><br><span style="color: hsl(0, 100%, 40%);">-    }</span><br><span style="color: hsl(120, 100%, 40%);">+     osmo_fsm_inst_dispatch(l1h->provision_fi, TRX_PROV_EV_CFG_TSC, (void*)(intptr_t)tsc);</span><br><span> </span><br><span>         /* ignore disabled slots */</span><br><span>  if (!(l1h->config.slotmask & (1 << tn)))</span><br><span>@@ -525,13 +325,9 @@</span><br><span> </span><br><span>     slottype = transceiver_chan_types[pchan];</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   if (l1h->config.slottype[tn] != slottype</span><br><span style="color: hsl(0, 100%, 40%);">-      || !l1h->config.slottype_valid[tn]) {</span><br><span style="color: hsl(0, 100%, 40%);">-               l1h->config.slottype[tn] = slottype;</span><br><span style="color: hsl(0, 100%, 40%);">-         l1h->config.slottype_valid[tn] = 1;</span><br><span style="color: hsl(0, 100%, 40%);">-          l1h->config.slottype_sent[tn] = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-           l1if_provision_transceiver_trx(l1h);</span><br><span style="color: hsl(0, 100%, 40%);">-    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   struct trx_prov_ev_cfg_ts_data data = { .tn = tn, .slottype = slottype };</span><br><span style="color: hsl(120, 100%, 40%);">+     osmo_fsm_inst_dispatch(l1h->provision_fi, TRX_PROV_EV_CFG_TS, &data);</span><br><span> </span><br><span>     return 0;</span><br><span> }</span><br><span>diff --git a/src/osmo-bts-trx/l1_if.h b/src/osmo-bts-trx/l1_if.h</span><br><span>index d2fdf06..07751f2 100644</span><br><span>--- a/src/osmo-bts-trx/l1_if.h</span><br><span>+++ b/src/osmo-bts-trx/l1_if.h</span><br><span>@@ -114,6 +114,7 @@</span><br><span> </span><br><span>        /* transceiver config */</span><br><span>     struct trx_config       config;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct osmo_fsm_inst    *provision_fi;</span><br><span> </span><br><span>   struct l1sched_trx      l1s;</span><br><span> };</span><br><span>@@ -122,6 +123,8 @@</span><br><span> int l1if_provision_transceiver_trx(struct trx_l1h *l1h);</span><br><span> int l1if_mph_time_ind(struct gsm_bts *bts, uint32_t fn);</span><br><span> void l1if_trx_set_nominal_power(struct gsm_bts_trx *trx, int nominal_power);</span><br><span style="color: hsl(120, 100%, 40%);">+int l1if_trx_start_power_ramp(struct gsm_bts_trx *trx, ramp_compl_cb_t ramp_compl_cb);</span><br><span style="color: hsl(120, 100%, 40%);">+enum gsm_phys_chan_config transceiver_chan_type_2_pchan(uint8_t type);</span><br><span> </span><br><span> static inline struct l1sched_trx *trx_l1sched_hdl(struct gsm_bts_trx *trx)</span><br><span> {</span><br><span>diff --git a/src/osmo-bts-trx/trx_if.c b/src/osmo-bts-trx/trx_if.c</span><br><span>index 7508606..e650d79 100644</span><br><span>--- a/src/osmo-bts-trx/trx_if.c</span><br><span>+++ b/src/osmo-bts-trx/trx_if.c</span><br><span>@@ -39,6 +39,7 @@</span><br><span> #include <osmocom/core/timer.h></span><br><span> #include <osmocom/core/talloc.h></span><br><span> #include <osmocom/core/bits.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/fsm.h></span><br><span> </span><br><span> #include <osmo-bts/phy_link.h></span><br><span> #include <osmo-bts/logging.h></span><br><span>@@ -47,6 +48,7 @@</span><br><span> </span><br><span> #include "l1_if.h"</span><br><span> #include "trx_if.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "trx_provision_fsm.h"</span><br><span> </span><br><span> /*</span><br><span>  * socket helper functions</span><br><span>@@ -1231,12 +1233,6 @@</span><br><span>  if (rc < 0)</span><br><span>               goto err;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   /* enable all slots */</span><br><span style="color: hsl(0, 100%, 40%);">-  l1h->config.slotmask = 0xff;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (pinst->num == 0)</span><br><span style="color: hsl(0, 100%, 40%);">-         trx_if_cmd_poweroff(l1h, NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>      return 0;</span><br><span> </span><br><span> err:</span><br><span>@@ -1301,8 +1297,10 @@</span><br><span> </span><br><span>   /* open the individual instances with their ctrl+data sockets */</span><br><span>     llist_for_each_entry(pinst, &plink->instances, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+         struct trx_l1h *l1h = pinst->u.osmotrx.hdl;</span><br><span>               if (trx_phy_inst_open(pinst) < 0)</span><br><span>                         goto cleanup;</span><br><span style="color: hsl(120, 100%, 40%);">+         osmo_fsm_inst_dispatch(l1h->provision_fi, TRX_PROV_EV_OPEN, NULL);</span><br><span>        }</span><br><span> </span><br><span>        return 0;</span><br><span>diff --git a/src/osmo-bts-trx/trx_provision_fsm.c b/src/osmo-bts-trx/trx_provision_fsm.c</span><br><span>new file mode 100644</span><br><span>index 0000000..c3b266d</span><br><span>--- /dev/null</span><br><span>+++ b/src/osmo-bts-trx/trx_provision_fsm.c</span><br><span>@@ -0,0 +1,459 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* BTS shutdown 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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "l1_if.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "trx_provision_fsm.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 trx_prov_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%);">+static void l1if_poweronoff_cb(struct trx_l1h *l1h, bool poweronoff, int rc)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct phy_instance *pinst = l1h->phy_inst;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct phy_link *plink = pinst->phy_link;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        plink->u.osmotrx.powered = poweronoff;</span><br><span style="color: hsl(120, 100%, 40%);">+     plink->u.osmotrx.poweronoff_sent = false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (poweronoff)</span><br><span style="color: hsl(120, 100%, 40%);">+               osmo_fsm_inst_dispatch(l1h->provision_fi, TRX_PROV_EV_POWERON_CNF, (void*)(intptr_t)rc);</span><br><span style="color: hsl(120, 100%, 40%);">+   else</span><br><span style="color: hsl(120, 100%, 40%);">+          osmo_fsm_inst_dispatch(l1h->provision_fi, TRX_PROV_EV_POWEROFF_CNF, (void*)(intptr_t)rc);</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 l1if_getnompower_cb(struct trx_l1h *l1h, int nominal_power, int rc)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct phy_instance *pinst = l1h->phy_inst;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct gsm_bts_trx *trx = pinst->trx;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    LOGPPHI(pinst, DL1C, LOGL_DEBUG, "l1if_getnompower_cb(nominal_power=%d, rc=%d)\n", nominal_power, rc);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    l1if_trx_set_nominal_power(trx, nominal_power);</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%);">+ * transceiver provisioning</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int l1if_provision_transceiver_trx(struct trx_l1h *l1h)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct phy_instance *pinst = l1h->phy_inst;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct phy_link *plink = pinst->phy_link;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* During setup, pinst may still not be associated to a TRX nr */</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!pinst->trx) {</span><br><span style="color: hsl(120, 100%, 40%);">+         LOGPPHI(pinst, DL1C, LOGL_INFO,</span><br><span style="color: hsl(120, 100%, 40%);">+                       "Delaying provision, TRX not yet assigned to phy instance\n");</span><br><span style="color: hsl(120, 100%, 40%);">+              return -EIO;</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 (phy_link_state_get(plink) == PHY_LINK_SHUTDOWN) {</span><br><span style="color: hsl(120, 100%, 40%);">+         LOGPPHI(pinst, DL1C, LOGL_INFO,</span><br><span style="color: hsl(120, 100%, 40%);">+                       "Delaying provision, TRX not yet available\n");</span><br><span style="color: hsl(120, 100%, 40%);">+             return -EIO;</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 (l1h->config.enabled</span><br><span style="color: hsl(120, 100%, 40%);">+     && l1h->config.tsc_valid</span><br><span style="color: hsl(120, 100%, 40%);">+   && l1h->config.bsic_valid</span><br><span style="color: hsl(120, 100%, 40%);">+  && l1h->config.arfcn_valid) {</span><br><span style="color: hsl(120, 100%, 40%);">+             /* before power on */</span><br><span style="color: hsl(120, 100%, 40%);">+         if (!l1h->config.arfcn_sent) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     trx_if_cmd_rxtune(l1h, l1h->config.arfcn);</span><br><span style="color: hsl(120, 100%, 40%);">+                 trx_if_cmd_txtune(l1h, l1h->config.arfcn);</span><br><span style="color: hsl(120, 100%, 40%);">+                 /* After TXTUNE is sent to TRX, get the tx nominal power</span><br><span style="color: hsl(120, 100%, 40%);">+                       * (which may vary precisly on band/arfcn. Avoid sending</span><br><span style="color: hsl(120, 100%, 40%);">+                       * it if we are forced by VTY to use a specific nominal</span><br><span style="color: hsl(120, 100%, 40%);">+                        * power (because TRX may not support the command or</span><br><span style="color: hsl(120, 100%, 40%);">+                   * provide broken values) */</span><br><span style="color: hsl(120, 100%, 40%);">+                  if (!l1h->config.nominal_power_set_by_vty)</span><br><span style="color: hsl(120, 100%, 40%);">+                         trx_if_cmd_getnompower(l1h, l1if_getnompower_cb);</span><br><span style="color: hsl(120, 100%, 40%);">+                     l1h->config.arfcn_sent = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+             if (!l1h->config.tsc_sent) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       trx_if_cmd_settsc(l1h, l1h->config.tsc);</span><br><span style="color: hsl(120, 100%, 40%);">+                   l1h->config.tsc_sent = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+          }</span><br><span style="color: hsl(120, 100%, 40%);">+             if (!l1h->config.bsic_sent) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      trx_if_cmd_setbsic(l1h, l1h->config.bsic);</span><br><span style="color: hsl(120, 100%, 40%);">+                 l1h->config.bsic_sent = 1;</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%);">+           /* Ask transceiver to use the newest TRXD header version if not using it yet */</span><br><span style="color: hsl(120, 100%, 40%);">+               if (!l1h->config.setformat_sent) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 if (l1h->config.trxd_hdr_ver_use != plink->u.osmotrx.trxd_hdr_ver_max) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                trx_if_cmd_setformat(l1h, plink->u.osmotrx.trxd_hdr_ver_max);</span><br><span style="color: hsl(120, 100%, 40%);">+                              l1h->config.trxd_hdr_ver_req = plink->u.osmotrx.trxd_hdr_ver_max;</span><br><span style="color: hsl(120, 100%, 40%);">+                       } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                              LOGPPHI(pinst, DL1C, LOGL_INFO,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       "No need to negotiate TRXD version, "</span><br><span style="color: hsl(120, 100%, 40%);">+                                       "already using maximum configured one: %" PRIu8 "\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                     l1h->config.trxd_hdr_ver_use);</span><br><span style="color: hsl(120, 100%, 40%);">+                     }</span><br><span style="color: hsl(120, 100%, 40%);">+                     l1h->config.setformat_sent = 1;</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 (pinst->num == 0 && !plink->u.osmotrx.powered && !plink->u.osmotrx.poweronoff_sent) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     trx_if_cmd_poweron(l1h, l1if_poweronoff_cb);</span><br><span style="color: hsl(120, 100%, 40%);">+                  plink->u.osmotrx.poweronoff_sent = 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%);">+           return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     LOGPPHI(pinst, DL1C, LOGL_INFO, "Delaying provision, TRX attributes not yet received from BSC:%s%s%s%s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+          l1h->config.enabled ? "" :" enable",</span><br><span style="color: hsl(120, 100%, 40%);">+           l1h->config.tsc_valid ? "" : " tsc",</span><br><span style="color: hsl(120, 100%, 40%);">+           l1h->config.bsic_valid ? "" : " bsic",</span><br><span style="color: hsl(120, 100%, 40%);">+         l1h->config.arfcn_valid ? "" : " arfcn");</span><br><span style="color: hsl(120, 100%, 40%);">+      return 1;</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 l1if_setslot_cb(struct trx_l1h *l1h, uint8_t tn, uint8_t type, int rc)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct phy_instance *pinst = l1h->phy_inst;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct gsm_bts_trx *trx = pinst->trx;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gsm_bts_trx_ts *ts;</span><br><span style="color: hsl(120, 100%, 40%);">+    enum gsm_phys_chan_config pchan;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (tn >= TRX_NR_TS) {</span><br><span style="color: hsl(120, 100%, 40%);">+             LOGPPHI(pinst, DL1C, LOGL_ERROR, "transceiver SETSLOT invalid param TN (%" PRIu8 ")\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                   tn);</span><br><span style="color: hsl(120, 100%, 40%);">+          return;</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%);">+   pchan = transceiver_chan_type_2_pchan(type);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (pchan == GSM_PCHAN_UNKNOWN) {</span><br><span style="color: hsl(120, 100%, 40%);">+             LOGPPHI(pinst, DL1C, LOGL_ERROR, "transceiver SETSLOT invalid param TS_TYPE (%" PRIu8 ")\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                      type);</span><br><span style="color: hsl(120, 100%, 40%);">+                return;</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%);">+   ts = &trx->ts[tn];</span><br><span style="color: hsl(120, 100%, 40%);">+     LOGPPHI(pinst, DL1C, LOGL_DEBUG, "%s l1if_setslot_cb(as_pchan=%s),"</span><br><span style="color: hsl(120, 100%, 40%);">+      " calling cb_ts_connected(rc=%d)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+        gsm_ts_name(ts), gsm_pchan_name(pchan), rc);</span><br><span style="color: hsl(120, 100%, 40%);">+     cb_ts_connected(ts, rc);</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%);">+/* Returns true if any TS changed, false otherwise */</span><br><span style="color: hsl(120, 100%, 40%);">+static bool update_ts_data(struct trx_l1h *l1h, struct trx_prov_ev_cfg_ts_data* ts_data) {</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (l1h->config.slottype[ts_data->tn] != ts_data->slottype ||</span><br><span style="color: hsl(120, 100%, 40%);">+            !l1h->config.slottype_valid[ts_data->tn]) {</span><br><span style="color: hsl(120, 100%, 40%);">+         l1h->config.slottype[ts_data->tn] = ts_data->slottype;</span><br><span style="color: hsl(120, 100%, 40%);">+               l1h->config.slottype_valid[ts_data->tn] = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+            l1h->config.slottype_sent[ts_data->tn] = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+             return true;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+     return false;</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%);">+// 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_closed(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 trx_l1h *l1h = (struct trx_l1h *)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 TRX_PROV_EV_OPEN:</span><br><span style="color: hsl(120, 100%, 40%);">+                /* enable all slots */</span><br><span style="color: hsl(120, 100%, 40%);">+                l1h->config.slotmask = 0xff;</span><br><span style="color: hsl(120, 100%, 40%);">+               if (l1h->phy_inst->num == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                    trx_if_cmd_poweroff(l1h, NULL); /* TODO: jump to poweroff upon cb received */</span><br><span style="color: hsl(120, 100%, 40%);">+         trx_prov_fsm_state_chg(fi, TRX_PROV_ST_OPEN_POWEROFF);</span><br><span style="color: hsl(120, 100%, 40%);">+                break;</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_open_poweroff(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 trx_l1h *l1h = (struct trx_l1h *)fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+  uint8_t bsic;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint16_t arfcn;</span><br><span style="color: hsl(120, 100%, 40%);">+       uint16_t tsc;</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 TRX_PROV_EV_CFG_ENABLE:</span><br><span style="color: hsl(120, 100%, 40%);">+          l1h->config.enabled =(bool)data;</span><br><span style="color: hsl(120, 100%, 40%);">+           break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case TRX_PROV_EV_CFG_BSIC:</span><br><span style="color: hsl(120, 100%, 40%);">+            bsic = (uint8_t)(intptr_t)data;</span><br><span style="color: hsl(120, 100%, 40%);">+               if (l1h->config.bsic != bsic || !l1h->config.bsic_valid) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      l1h->config.bsic = bsic;</span><br><span style="color: hsl(120, 100%, 40%);">+                   l1h->config.bsic_valid = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+                        l1h->config.bsic_sent = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+         }</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case TRX_PROV_EV_CFG_ARFCN:</span><br><span style="color: hsl(120, 100%, 40%);">+           arfcn = (uint16_t)(intptr_t)data;</span><br><span style="color: hsl(120, 100%, 40%);">+             if (l1h->config.arfcn != arfcn || !l1h->config.arfcn_valid) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   l1h->config.arfcn = arfcn;</span><br><span style="color: hsl(120, 100%, 40%);">+                 l1h->config.arfcn_valid = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+                       l1h->config.arfcn_sent = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case TRX_PROV_EV_CFG_TSC:</span><br><span style="color: hsl(120, 100%, 40%);">+             tsc = (uint16_t)(intptr_t)data;</span><br><span style="color: hsl(120, 100%, 40%);">+               if (l1h->config.tsc != tsc || !l1h->config.tsc_valid) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 l1h->config.tsc = tsc;</span><br><span style="color: hsl(120, 100%, 40%);">+                     l1h->config.tsc_valid = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+                 l1h->config.tsc_sent = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+          }</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case TRX_PROV_EV_CFG_TS:</span><br><span style="color: hsl(120, 100%, 40%);">+              update_ts_data(l1h, (struct trx_prov_ev_cfg_ts_data*)data);</span><br><span style="color: hsl(120, 100%, 40%);">+           break;</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%);">+   /* 0 = if we gathered all date and could go forward :*/</span><br><span style="color: hsl(120, 100%, 40%);">+       if (l1if_provision_transceiver_trx(l1h) == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+               if (l1h->phy_inst->num == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                    trx_prov_fsm_state_chg(fi, TRX_PROV_ST_OPEN_WAIT_POWERON_CNF);</span><br><span style="color: hsl(120, 100%, 40%);">+                else</span><br><span style="color: hsl(120, 100%, 40%);">+                  trx_prov_fsm_state_chg(fi, TRX_PROV_ST_OPEN_POWERON);</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_open_wait_power_cnf(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 trx_l1h *l1h = (struct trx_l1h *)fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct phy_instance *pinst = l1h->phy_inst;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct phy_link *plink = pinst->phy_link;</span><br><span style="color: hsl(120, 100%, 40%);">+  int rc;</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 TRX_PROV_EV_POWERON_CNF:</span><br><span style="color: hsl(120, 100%, 40%);">+         rc = (uint16_t)(intptr_t)data;</span><br><span style="color: hsl(120, 100%, 40%);">+                if (rc == 0 && plink->state != PHY_LINK_CONNECTED) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       trx_sched_clock_started(pinst->trx->bts);</span><br><span style="color: hsl(120, 100%, 40%);">+                       phy_link_state_set(plink, PHY_LINK_CONNECTED);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                      /* Begin to ramp up the power on all TRX associated with this phy */</span><br><span style="color: hsl(120, 100%, 40%);">+                  llist_for_each_entry(pinst, &plink->instances, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+                         if (pinst->trx->mo.nm_state.administrative == NM_STATE_UNLOCKED)</span><br><span style="color: hsl(120, 100%, 40%);">+                                        l1if_trx_start_power_ramp(pinst->trx, NULL);</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%);">+                   trx_prov_fsm_state_chg(fi, TRX_PROV_ST_OPEN_POWERON);</span><br><span style="color: hsl(120, 100%, 40%);">+         } else if (rc != 0 && plink->state != PHY_LINK_SHUTDOWN) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 trx_sched_clock_stopped(pinst->trx->bts);</span><br><span style="color: hsl(120, 100%, 40%);">+                       phy_link_state_set(plink, PHY_LINK_SHUTDOWN);</span><br><span style="color: hsl(120, 100%, 40%);">+         }</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case TRX_PROV_EV_CFG_TS:</span><br><span style="color: hsl(120, 100%, 40%);">+              update_ts_data(l1h, (struct trx_prov_ev_cfg_ts_data*)data);</span><br><span style="color: hsl(120, 100%, 40%);">+           break;</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_open_poweron_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 trx_l1h *l1h = (struct trx_l1h *)fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+  uint8_t tn;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* after power on */</span><br><span style="color: hsl(120, 100%, 40%);">+  if (l1h->config.rxgain_valid && !l1h->config.rxgain_sent) {</span><br><span style="color: hsl(120, 100%, 40%);">+             trx_if_cmd_setrxgain(l1h, l1h->config.rxgain);</span><br><span style="color: hsl(120, 100%, 40%);">+             l1h->config.rxgain_sent = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (l1h->config.maxdly_valid && !l1h->config.maxdly_sent) {</span><br><span style="color: hsl(120, 100%, 40%);">+             trx_if_cmd_setmaxdly(l1h, l1h->config.maxdly);</span><br><span style="color: hsl(120, 100%, 40%);">+             l1h->config.maxdly_sent = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (l1h->config.maxdlynb_valid && !l1h->config.maxdlynb_sent) {</span><br><span style="color: hsl(120, 100%, 40%);">+         trx_if_cmd_setmaxdlynb(l1h, l1h->config.maxdlynb);</span><br><span style="color: hsl(120, 100%, 40%);">+         l1h->config.maxdlynb_sent = 1;</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%);">+   for (tn = 0; tn < TRX_NR_TS; tn++) {</span><br><span style="color: hsl(120, 100%, 40%);">+               if (l1h->config.slottype_valid[tn]</span><br><span style="color: hsl(120, 100%, 40%);">+          && !l1h->config.slottype_sent[tn]) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      trx_if_cmd_setslot(l1h, tn,</span><br><span style="color: hsl(120, 100%, 40%);">+                           l1h->config.slottype[tn], l1if_setslot_cb);</span><br><span style="color: hsl(120, 100%, 40%);">+                        l1h->config.slottype_sent[tn] = 1;</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_open_poweron(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 trx_l1h *l1h = (struct trx_l1h *)fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct phy_instance *pinst = l1h->phy_inst;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct phy_link *plink = pinst->phy_link;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct trx_prov_ev_cfg_ts_data* ts_data;</span><br><span style="color: hsl(120, 100%, 40%);">+      uint8_t tn;</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 TRX_PROV_EV_CLOSE:</span><br><span style="color: hsl(120, 100%, 40%);">+               /* power off transceiver, if not already */</span><br><span style="color: hsl(120, 100%, 40%);">+           if (l1h->config.enabled) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 if (pinst->num == 0 && plink->u.osmotrx.powered && !plink->u.osmotrx.poweronoff_sent) {</span><br><span style="color: hsl(120, 100%, 40%);">+                              trx_if_cmd_poweroff(l1h, l1if_poweronoff_cb);</span><br><span style="color: hsl(120, 100%, 40%);">+                         plink->u.osmotrx.poweronoff_sent = true;</span><br><span style="color: hsl(120, 100%, 40%);">+                   }</span><br><span style="color: hsl(120, 100%, 40%);">+                     l1h->config.rxgain_sent = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                       l1h->config.maxdly_sent = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                       l1h->config.maxdlynb_sent = 0;</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%);">+                         l1h->config.slottype_sent[tn] = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+         } else if (!pinst->phy_link->u.osmotrx.poweronoff_sent) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       bts_model_trx_close_cb(pinst->trx, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+             } /* else: poweroff in progress, cb will be called upon TRXC RSP */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         if (pinst->num == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                       trx_prov_fsm_state_chg(fi, TRX_PROV_ST_OPEN_WAIT_POWEROFF_CNF);</span><br><span style="color: hsl(120, 100%, 40%);">+               else</span><br><span style="color: hsl(120, 100%, 40%);">+                  trx_prov_fsm_state_chg(fi, TRX_PROV_ST_OPEN_POWEROFF);</span><br><span style="color: hsl(120, 100%, 40%);">+                break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case TRX_PROV_EV_CFG_TS:</span><br><span style="color: hsl(120, 100%, 40%);">+              ts_data = (struct trx_prov_ev_cfg_ts_data*)data;</span><br><span style="color: hsl(120, 100%, 40%);">+              if (update_ts_data(l1h, ts_data)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   trx_if_cmd_setslot(l1h, ts_data->tn,</span><br><span style="color: hsl(120, 100%, 40%);">+                               l1h->config.slottype[ ts_data->tn], l1if_setslot_cb);</span><br><span style="color: hsl(120, 100%, 40%);">+                   l1h->config.slottype_sent[ ts_data->tn] = 1;</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%);">+           break;</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_open_wait_poweroff_cnf(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 trx_l1h *l1h = (struct trx_l1h *)fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct phy_instance *pinst = l1h->phy_inst;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct phy_link *plink = pinst->phy_link;</span><br><span style="color: hsl(120, 100%, 40%);">+  int rc;</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 TRX_PROV_EV_POWEROFF_CNF:</span><br><span style="color: hsl(120, 100%, 40%);">+                rc = (uint16_t)(intptr_t)data;</span><br><span style="color: hsl(120, 100%, 40%);">+                if (plink->state != PHY_LINK_SHUTDOWN) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   trx_sched_clock_stopped(pinst->trx->bts);</span><br><span style="color: hsl(120, 100%, 40%);">+                       phy_link_state_set(plink, PHY_LINK_SHUTDOWN);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                       /* Notify TRX close on all TRX associated with this phy */</span><br><span style="color: hsl(120, 100%, 40%);">+                    llist_for_each_entry(pinst, &plink->instances, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+                         bts_model_trx_close_cb(pinst->trx, rc);</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%);">+             break;</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 struct osmo_fsm_state trx_prov_fsm_states[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+        [TRX_PROV_ST_CLOSED] = {</span><br><span style="color: hsl(120, 100%, 40%);">+              .in_event_mask =</span><br><span style="color: hsl(120, 100%, 40%);">+                      X(TRX_PROV_EV_OPEN),</span><br><span style="color: hsl(120, 100%, 40%);">+          .out_state_mask =</span><br><span style="color: hsl(120, 100%, 40%);">+                     X(TRX_PROV_ST_OPEN_POWEROFF),</span><br><span style="color: hsl(120, 100%, 40%);">+         .name = "CLOSED",</span><br><span style="color: hsl(120, 100%, 40%);">+           .action = st_closed,</span><br><span style="color: hsl(120, 100%, 40%);">+  },</span><br><span style="color: hsl(120, 100%, 40%);">+    [TRX_PROV_ST_OPEN_POWEROFF] = {</span><br><span style="color: hsl(120, 100%, 40%);">+               .in_event_mask =</span><br><span style="color: hsl(120, 100%, 40%);">+                      X(TRX_PROV_EV_CFG_ENABLE) |</span><br><span style="color: hsl(120, 100%, 40%);">+                   X(TRX_PROV_EV_CFG_BSIC) |</span><br><span style="color: hsl(120, 100%, 40%);">+                     X(TRX_PROV_EV_CFG_ARFCN) |</span><br><span style="color: hsl(120, 100%, 40%);">+                    X(TRX_PROV_EV_CFG_TSC) |</span><br><span style="color: hsl(120, 100%, 40%);">+                      X(TRX_PROV_EV_CFG_TS),</span><br><span style="color: hsl(120, 100%, 40%);">+                .out_state_mask =</span><br><span style="color: hsl(120, 100%, 40%);">+                     X(TRX_PROV_ST_OPEN_WAIT_POWERON_CNF) |</span><br><span style="color: hsl(120, 100%, 40%);">+                        X(TRX_PROV_ST_OPEN_POWERON),</span><br><span style="color: hsl(120, 100%, 40%);">+          .name = "OPEN_POWEROFF",</span><br><span style="color: hsl(120, 100%, 40%);">+            .action = st_open_poweroff,</span><br><span style="color: hsl(120, 100%, 40%);">+   },</span><br><span style="color: hsl(120, 100%, 40%);">+    [TRX_PROV_ST_OPEN_WAIT_POWERON_CNF] = {</span><br><span style="color: hsl(120, 100%, 40%);">+               .in_event_mask =</span><br><span style="color: hsl(120, 100%, 40%);">+                      X(TRX_PROV_EV_POWERON_CNF) |</span><br><span style="color: hsl(120, 100%, 40%);">+                  X(TRX_PROV_EV_CFG_TS),</span><br><span style="color: hsl(120, 100%, 40%);">+                .out_state_mask =</span><br><span style="color: hsl(120, 100%, 40%);">+                     X(TRX_PROV_ST_OPEN_POWERON),</span><br><span style="color: hsl(120, 100%, 40%);">+          .name = "OPEN_WAIT_POWERON_CNF",</span><br><span style="color: hsl(120, 100%, 40%);">+            .action = st_open_wait_power_cnf,</span><br><span style="color: hsl(120, 100%, 40%);">+     },</span><br><span style="color: hsl(120, 100%, 40%);">+    [TRX_PROV_ST_OPEN_POWERON] = {</span><br><span style="color: hsl(120, 100%, 40%);">+                .in_event_mask =</span><br><span style="color: hsl(120, 100%, 40%);">+                      X(TRX_PROV_EV_POWEROFF) |</span><br><span style="color: hsl(120, 100%, 40%);">+                     X(TRX_PROV_EV_CFG_TS),</span><br><span style="color: hsl(120, 100%, 40%);">+                .out_state_mask =</span><br><span style="color: hsl(120, 100%, 40%);">+                     X(TRX_PROV_ST_OPEN_WAIT_POWEROFF_CNF) |</span><br><span style="color: hsl(120, 100%, 40%);">+                       X(TRX_PROV_ST_OPEN_POWEROFF),</span><br><span style="color: hsl(120, 100%, 40%);">+         .name = "OPEN_POWERON",</span><br><span style="color: hsl(120, 100%, 40%);">+             .onenter = st_open_poweron_on_enter,</span><br><span style="color: hsl(120, 100%, 40%);">+          .action = st_open_poweron,</span><br><span style="color: hsl(120, 100%, 40%);">+    },</span><br><span style="color: hsl(120, 100%, 40%);">+    [TRX_PROV_ST_OPEN_WAIT_POWEROFF_CNF] = {</span><br><span style="color: hsl(120, 100%, 40%);">+              .in_event_mask =</span><br><span style="color: hsl(120, 100%, 40%);">+                      X(TRX_PROV_EV_POWEROFF_CNF),</span><br><span style="color: hsl(120, 100%, 40%);">+          .out_state_mask =</span><br><span style="color: hsl(120, 100%, 40%);">+                     X(TRX_PROV_ST_OPEN_POWEROFF),</span><br><span style="color: hsl(120, 100%, 40%);">+         .name = "OPEN_WAIT_POWEROFF_CNF",</span><br><span style="color: hsl(120, 100%, 40%);">+           .action = st_open_wait_poweroff_cnf,</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%);">+const struct value_string trx_prov_fsm_event_names[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_VALUE_STRING(TRX_PROV_EV_OPEN),</span><br><span style="color: hsl(120, 100%, 40%);">+  OSMO_VALUE_STRING(TRX_PROV_EV_CFG_ENABLE),</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_VALUE_STRING(TRX_PROV_EV_CFG_BSIC),</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_VALUE_STRING(TRX_PROV_EV_CFG_ARFCN),</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_VALUE_STRING(TRX_PROV_EV_CFG_TSC),</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_VALUE_STRING(TRX_PROV_EV_CFG_TS),</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_VALUE_STRING(TRX_PROV_EV_CFG_RXGAIN),</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_VALUE_STRING(TRX_PROV_EV_CFG_SETMAXDLY),</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_VALUE_STRING(TRX_PROV_EV_POWERON_CNF),</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_VALUE_STRING(TRX_PROV_EV_POWEROFF),</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_VALUE_STRING(TRX_PROV_EV_POWEROFF_CNF),</span><br><span style="color: hsl(120, 100%, 40%);">+  OSMO_VALUE_STRING(TRX_PROV_EV_CLOSE),</span><br><span style="color: hsl(120, 100%, 40%);">+ { 0, NULL }</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 trx_prov_fsm = {</span><br><span style="color: hsl(120, 100%, 40%);">+   .name = "TRX_PROV",</span><br><span style="color: hsl(120, 100%, 40%);">+ .states = trx_prov_fsm_states,</span><br><span style="color: hsl(120, 100%, 40%);">+        .num_states = ARRAY_SIZE(trx_prov_fsm_states),</span><br><span style="color: hsl(120, 100%, 40%);">+        .event_names = trx_prov_fsm_event_names,</span><br><span style="color: hsl(120, 100%, 40%);">+      .log_subsys = DL1C,</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 trx_prov_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(&trx_prov_fsm) == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/osmo-bts-trx/trx_provision_fsm.h b/src/osmo-bts-trx/trx_provision_fsm.h</span><br><span>new file mode 100644</span><br><span>index 0000000..7fede35</span><br><span>--- /dev/null</span><br><span>+++ b/src/osmo-bts-trx/trx_provision_fsm.h</span><br><span>@@ -0,0 +1,55 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* Provision TRX over TRXC protocol 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%);">+#pragma once</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum trx_provision_fsm_states {</span><br><span style="color: hsl(120, 100%, 40%);">+        TRX_PROV_ST_CLOSED,</span><br><span style="color: hsl(120, 100%, 40%);">+   TRX_PROV_ST_OPEN_POWEROFF,</span><br><span style="color: hsl(120, 100%, 40%);">+    TRX_PROV_ST_OPEN_WAIT_POWERON_CNF,</span><br><span style="color: hsl(120, 100%, 40%);">+    TRX_PROV_ST_OPEN_POWERON,</span><br><span style="color: hsl(120, 100%, 40%);">+     TRX_PROV_ST_OPEN_WAIT_POWEROFF_CNF,</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 trx_prov_ev_cfg_ts_data {</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t tn;</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t slottype;</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%);">+enum trx_provision_fsm_events {</span><br><span style="color: hsl(120, 100%, 40%);">+      TRX_PROV_EV_OPEN,</span><br><span style="color: hsl(120, 100%, 40%);">+     TRX_PROV_EV_CFG_ENABLE,</span><br><span style="color: hsl(120, 100%, 40%);">+       TRX_PROV_EV_CFG_BSIC,</span><br><span style="color: hsl(120, 100%, 40%);">+ TRX_PROV_EV_CFG_ARFCN,</span><br><span style="color: hsl(120, 100%, 40%);">+        TRX_PROV_EV_CFG_TSC,</span><br><span style="color: hsl(120, 100%, 40%);">+  TRX_PROV_EV_CFG_TS,</span><br><span style="color: hsl(120, 100%, 40%);">+   TRX_PROV_EV_CFG_RXGAIN,</span><br><span style="color: hsl(120, 100%, 40%);">+       TRX_PROV_EV_CFG_SETMAXDLY,</span><br><span style="color: hsl(120, 100%, 40%);">+    TRX_PROV_EV_POWERON_CNF,</span><br><span style="color: hsl(120, 100%, 40%);">+      TRX_PROV_EV_POWEROFF,</span><br><span style="color: hsl(120, 100%, 40%);">+ TRX_PROV_EV_POWEROFF_CNF,</span><br><span style="color: hsl(120, 100%, 40%);">+     TRX_PROV_EV_CLOSE,</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%);">+extern struct osmo_fsm trx_prov_fsm;</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-bts/+/19167">change 19167</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/+/19167"/><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: I2a00c23df15840e33fbb232c9e1dd6db128f63f6 </div>
<div style="display:none"> Gerrit-Change-Number: 19167 </div>
<div style="display:none"> Gerrit-PatchSet: 4 </div>
<div style="display:none"> Gerrit-Owner: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: Hoernchen <ewild@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder </div>
<div style="display:none"> Gerrit-Reviewer: daniel <dwillmann@sysmocom.de> </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>