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

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">power_control: implement BS (Downlink) Power Control<br><br>We already have MS Power Control, which according to 3GPP 45.008<br>shall be implemented in the MS to minimize the transmit power in<br>the Uplink direction.  The BS Power Control may optionally be<br>implemented by the network side for the same purpose.<br><br>Using Downlink signal measurements reported by the MS, the BSS<br>(either BSC, or BTS) may control Downlink attenuation in a way<br>that the transmit power remains as low as possible, or remains<br>in a specific range corresponding to good RxLev values on the<br>MS side.  This change implements autonomous BS Power Control,<br>that can optionally be enabled by the BSC.<br><br>BS Power Control re-uses parts of the MS Power Control code,<br>so all parameters can be configured in the same way - via the<br>VTY interface or a configuration file.  This basically means<br>that features like hysteresis and EWMA based filtering are<br>also available for BS Power Control.<br><br>The only difference is that RxQual values higher than 0 would<br>trigger the logic to reduce the current attenuation twice.<br><br>Note that one of the unit tests ('TC_rxlev_max_min') fails,<br>as the power step limitations for raising and lowering look<br>wrong to me, and the related discussion is still ongoing.<br><br>Change-Id: I5b509e71d5f668b6b8b2abf8053c27f2a7c78451<br>Related: SYS#4918<br>---<br>M .gitignore<br>M include/osmo-bts/gsm_data.h<br>M include/osmo-bts/power_control.h<br>M src/common/l1sap.c<br>M src/common/power_control.c<br>M src/common/rsl.c<br>M src/common/scheduler.c<br>M src/common/tx_power.c<br>M src/common/vty.c<br>M tests/power/Makefile.am<br>A tests/power/bs_power_loop_test.c<br>A tests/power/bs_power_loop_test.err<br>A tests/power/bs_power_loop_test.ok<br>M tests/testsuite.at<br>14 files changed, 878 insertions(+), 26 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/.gitignore b/.gitignore</span><br><span>index 22a1bdd..f76bdac 100644</span><br><span>--- a/.gitignore</span><br><span>+++ b/.gitignore</span><br><span>@@ -64,6 +64,7 @@</span><br><span> tests/tx_power/tx_power_test</span><br><span> tests/ta_control/ta_control_test</span><br><span> tests/power/ms_power_loop_test</span><br><span style="color: hsl(120, 100%, 40%);">+tests/power/bs_power_loop_test</span><br><span> tests/testsuite</span><br><span> tests/testsuite.log</span><br><span> </span><br><span>diff --git a/include/osmo-bts/gsm_data.h b/include/osmo-bts/gsm_data.h</span><br><span>index 04c6629..6af96fe 100644</span><br><span>--- a/include/osmo-bts/gsm_data.h</span><br><span>+++ b/include/osmo-bts/gsm_data.h</span><br><span>@@ -316,11 +316,9 @@</span><br><span>  /* RTP header Marker bit to indicate beginning of speech after pause  */</span><br><span>     bool rtp_tx_marker;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- /* MS power control */</span><br><span style="color: hsl(120, 100%, 40%);">+        /* MS/BS power control */</span><br><span>    struct lchan_power_ctrl_state ms_power_ctrl;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    /* BTS power reduction (in dB) */</span><br><span style="color: hsl(0, 100%, 40%);">-       uint8_t bs_power_red;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct lchan_power_ctrl_state bs_power_ctrl;</span><br><span> </span><br><span>     struct msgb *pending_rel_ind_msg;</span><br><span> </span><br><span>diff --git a/include/osmo-bts/power_control.h b/include/osmo-bts/power_control.h</span><br><span>index cb566a8..f2e14cf 100644</span><br><span>--- a/include/osmo-bts/power_control.h</span><br><span>+++ b/include/osmo-bts/power_control.h</span><br><span>@@ -6,3 +6,6 @@</span><br><span> int lchan_ms_pwr_ctrl(struct gsm_lchan *lchan,</span><br><span>                     const uint8_t ms_power_lvl,</span><br><span>                  const int8_t ul_rssi_dbm);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int lchan_bs_pwr_ctrl(struct gsm_lchan *lchan,</span><br><span style="color: hsl(120, 100%, 40%);">+                  const struct gsm48_hdr *gh);</span><br><span>diff --git a/src/common/l1sap.c b/src/common/l1sap.c</span><br><span>index 2038fba..33d10a5 100644</span><br><span>--- a/src/common/l1sap.c</span><br><span>+++ b/src/common/l1sap.c</span><br><span>@@ -1546,6 +1546,7 @@</span><br><span>              lchan->meas.flags |= LC_UL_M_F_L1_VALID;</span><br><span> </span><br><span>              lchan_ms_pwr_ctrl(lchan, data[0] & 0x1f, data_ind->rssi);</span><br><span style="color: hsl(120, 100%, 40%);">+              lchan_bs_pwr_ctrl(lchan, (const struct gsm48_hdr *) &data[5]);</span><br><span>   } else</span><br><span>               le = &lchan->lapdm_ch.lapdm_dcch;</span><br><span> </span><br><span>diff --git a/src/common/power_control.c b/src/common/power_control.c</span><br><span>index 3441439..4c4e283 100644</span><br><span>--- a/src/common/power_control.c</span><br><span>+++ b/src/common/power_control.c</span><br><span>@@ -209,3 +209,105 @@</span><br><span> </span><br><span>        return 1;</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! compute the new Downlink attenuation value for the given logical channel.</span><br><span style="color: hsl(120, 100%, 40%);">+  *  \param lchan logical channel for which to compute (and in which to store) new power value.</span><br><span style="color: hsl(120, 100%, 40%);">+  *  \param[in] gh pointer to the beginning of (presumably) a Measurement Report.</span><br><span style="color: hsl(120, 100%, 40%);">+  */</span><br><span style="color: hsl(120, 100%, 40%);">+int lchan_bs_pwr_ctrl(struct gsm_lchan *lchan,</span><br><span style="color: hsl(120, 100%, 40%);">+                  const struct gsm48_hdr *gh)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct gsm_bts_trx *trx = lchan->ts->trx;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct gsm_bts *bts = trx->bts;</span><br><span style="color: hsl(120, 100%, 40%);">+    uint8_t rxqual_full, rxqual_sub;</span><br><span style="color: hsl(120, 100%, 40%);">+      uint8_t rxlev_full, rxlev_sub;</span><br><span style="color: hsl(120, 100%, 40%);">+        uint8_t rxqual, rxlev;</span><br><span style="color: hsl(120, 100%, 40%);">+        int delta, new;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     const struct bts_power_ctrl_params *params = &bts->dl_power_ctrl;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct lchan_power_ctrl_state *state = &lchan->bs_power_ctrl;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* Check if BS Power Control is enabled */</span><br><span style="color: hsl(120, 100%, 40%);">+    if (state->fixed)</span><br><span style="color: hsl(120, 100%, 40%);">+          return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Check if this is a Measurement Report */</span><br><span style="color: hsl(120, 100%, 40%);">+   if (gh->proto_discr != GSM48_PDISC_RR)</span><br><span style="color: hsl(120, 100%, 40%);">+             return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     if (gh->msg_type != GSM48_MT_RR_MEAS_REP)</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%);">+   /* Check if the measurement results are valid */</span><br><span style="color: hsl(120, 100%, 40%);">+      if ((gh->data[1] & 0x40) == 0x40) {</span><br><span style="color: hsl(120, 100%, 40%);">+            LOGPLCHAN(lchan, DLOOP, LOGL_DEBUG,</span><br><span style="color: hsl(120, 100%, 40%);">+                     "The measurement results are not valid\n");</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* See 3GPP TS 44.018, section 10.5.2.20 */</span><br><span style="color: hsl(120, 100%, 40%);">+   rxqual_full = (gh->data[2] >> 4) & 0x7;</span><br><span style="color: hsl(120, 100%, 40%);">+  rxqual_sub = (gh->data[2] >> 1) & 0x7;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ rxlev_full = gh->data[0] & 0x3f;</span><br><span style="color: hsl(120, 100%, 40%);">+       rxlev_sub = gh->data[1] & 0x3f;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      LOGPLCHAN(lchan, DLOOP, LOGL_DEBUG, "Rx DL Measurement Report: "</span><br><span style="color: hsl(120, 100%, 40%);">+              "RXLEV-FULL(%02u), RXQUAL-FULL(%u), "</span><br><span style="color: hsl(120, 100%, 40%);">+               "RXLEV-SUB(%02u), RXQUAL-SUB(%u), "</span><br><span style="color: hsl(120, 100%, 40%);">+                 "DTx is %s => using %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+               rxlev_full, rxqual_full, rxlev_sub, rxqual_sub,</span><br><span style="color: hsl(120, 100%, 40%);">+               lchan->tch.dtx.dl_active ? "enabled" : "disabled",</span><br><span style="color: hsl(120, 100%, 40%);">+             lchan->tch.dtx.dl_active ? "SUB" : "FULL");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* If DTx is active on Downlink, use the '-SUB' */</span><br><span style="color: hsl(120, 100%, 40%);">+    if (lchan->tch.dtx.dl_active) {</span><br><span style="color: hsl(120, 100%, 40%);">+            rxqual = rxqual_sub;</span><br><span style="color: hsl(120, 100%, 40%);">+          rxlev = rxlev_sub;</span><br><span style="color: hsl(120, 100%, 40%);">+    } else { /* ... otherwise use the '-FULL' */</span><br><span style="color: hsl(120, 100%, 40%);">+          rxqual = rxqual_full;</span><br><span style="color: hsl(120, 100%, 40%);">+         rxlev = rxlev_full;</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%);">+   /* Bit Error Rate > 0 => reduce by 2 */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rxqual > 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+          LOGPLCHAN(lchan, DLOOP, LOGL_INFO, "Reducing Downlink attenuation "</span><br><span style="color: hsl(120, 100%, 40%);">+                   "by half: %u -> %u dB due to RXQUAL %u > 0\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                        state->current, state->current / 2, rxqual);</span><br><span style="color: hsl(120, 100%, 40%);">+          state->current /= 2;</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%);">+   /* Calculate a 'delta' for the current attenuation level */</span><br><span style="color: hsl(120, 100%, 40%);">+   delta = calc_delta(params, state, rxlev2dbm(rxlev));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* Basic signal transmission / reception formula:</span><br><span style="color: hsl(120, 100%, 40%);">+      *</span><br><span style="color: hsl(120, 100%, 40%);">+     *   RxLev = TxPwr - (PathLoss + TxAtt)</span><br><span style="color: hsl(120, 100%, 40%);">+        *</span><br><span style="color: hsl(120, 100%, 40%);">+     * Here we want to change RxLev at the MS side, so:</span><br><span style="color: hsl(120, 100%, 40%);">+    *</span><br><span style="color: hsl(120, 100%, 40%);">+     *   RxLev + Delta = TxPwr - (PathLoss + TxAtt) + Delta</span><br><span style="color: hsl(120, 100%, 40%);">+        *</span><br><span style="color: hsl(120, 100%, 40%);">+     * The only parameter we can change here is TxAtt, so:</span><br><span style="color: hsl(120, 100%, 40%);">+         *</span><br><span style="color: hsl(120, 100%, 40%);">+     *   RxLev + Delta = TxPwr - PathLoss -  TxAtt + Delta</span><br><span style="color: hsl(120, 100%, 40%);">+         *   RxLev + Delta = TxPwr - PathLoss - (TxAtt - Delta)</span><br><span style="color: hsl(120, 100%, 40%);">+        */</span><br><span style="color: hsl(120, 100%, 40%);">+   new = state->current - delta;</span><br><span style="color: hsl(120, 100%, 40%);">+      if (new > state->max)</span><br><span style="color: hsl(120, 100%, 40%);">+           new = state->max;</span><br><span style="color: hsl(120, 100%, 40%);">+  if (new < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+               new = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (state->current != new) {</span><br><span style="color: hsl(120, 100%, 40%);">+               LOGPLCHAN(lchan, DLOOP, LOGL_INFO, "Changing Downlink attenuation: "</span><br><span style="color: hsl(120, 100%, 40%);">+                          "%u -> %u dB (maximum %u dB, target %d dBm, delta %d dB)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                     state->current, new, state->max, params->target, delta);</span><br><span style="color: hsl(120, 100%, 40%);">+           state->current = new;</span><br><span style="color: hsl(120, 100%, 40%);">+              return 1;</span><br><span style="color: hsl(120, 100%, 40%);">+     } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGPLCHAN(lchan, DLOOP, LOGL_INFO, "Keeping Downlink attenuation "</span><br><span style="color: hsl(120, 100%, 40%);">+                    "at %u dB (maximum %u dB, target %d dBm, delta %d dB)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                   state->current, state->max, params->target, delta);</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%);">+}</span><br><span>diff --git a/src/common/rsl.c b/src/common/rsl.c</span><br><span>index 8760c24..2ebfb32 100644</span><br><span>--- a/src/common/rsl.c</span><br><span>+++ b/src/common/rsl.c</span><br><span>@@ -1036,8 +1036,8 @@</span><br><span>    lchan->tch_mode = 0;</span><br><span>      memset(&lchan->encr, 0, sizeof(lchan->encr));</span><br><span>      memset(&lchan->ho, 0, sizeof(lchan->ho));</span><br><span style="color: hsl(0, 100%, 40%);">-     lchan->bs_power_red = 0;</span><br><span>  memset(&lchan->ms_power_ctrl, 0, sizeof(lchan->ms_power_ctrl));</span><br><span style="color: hsl(120, 100%, 40%);">+     memset(&lchan->bs_power_ctrl, 0, sizeof(lchan->bs_power_ctrl));</span><br><span>    lchan->rqd_ta = 0;</span><br><span>        copy_sacch_si_to_lchan(lchan);</span><br><span>       memset(&lchan->tch, 0, sizeof(lchan->tch));</span><br><span>@@ -1153,11 +1153,16 @@</span><br><span>      LOGPLCHAN(lchan, DRSL, LOGL_DEBUG, "rx Channel Activation in state: %s.\n",</span><br><span>                  gsm_lchans_name(lchan->state));</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-        /* Initialize channel defaults */</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Initialize MS Power Control defaults */</span><br><span>   lchan->ms_power_ctrl.max = ms_pwr_ctl_lvl(lchan->ts->trx->bts->band, 0);</span><br><span>      lchan->ms_power_ctrl.current = lchan->ms_power_ctrl.max;</span><br><span>       lchan->ms_power_ctrl.fixed = true;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+     /* Initialize BS Power Control defaults */</span><br><span style="color: hsl(120, 100%, 40%);">+    lchan->bs_power_ctrl.max = 2 * 15;</span><br><span style="color: hsl(120, 100%, 40%);">+ lchan->bs_power_ctrl.current = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+  lchan->bs_power_ctrl.fixed = true;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>      rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg));</span><br><span> </span><br><span>   /* 9.3.3 Activation Type */</span><br><span>@@ -1209,9 +1214,11 @@</span><br><span>                         return rsl_tx_chan_act_nack(lchan, RSL_ERR_SERV_OPT_UNIMPL);</span><br><span>                 }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-           lchan->bs_power_red = BS_POWER2DB(*TLVP_VAL(&tp, RSL_IE_BS_POWER));</span><br><span style="color: hsl(120, 100%, 40%);">+            lchan->bs_power_ctrl.max = BS_POWER2DB(*TLVP_VAL(&tp, RSL_IE_BS_POWER));</span><br><span style="color: hsl(120, 100%, 40%);">+               lchan->bs_power_ctrl.current = lchan->bs_power_ctrl.max;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>             LOGPLCHAN(lchan, DRSL, LOGL_DEBUG, "BS Power attenuation %u dB\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                      lchan->bs_power_red);</span><br><span style="color: hsl(120, 100%, 40%);">+                      lchan->bs_power_ctrl.current);</span><br><span>  }</span><br><span> </span><br><span>        /* 9.3.13 MS Power */</span><br><span>@@ -1224,7 +1231,6 @@</span><br><span>        if (TLVP_PRES_LEN(&tp, RSL_IE_TIMING_ADVANCE, 1))</span><br><span>                lchan->rqd_ta = *TLVP_VAL(&tp, RSL_IE_TIMING_ADVANCE);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       /* 9.3.32 BS Power Parameters */</span><br><span>     /* 9.3.31 MS Power Parameters */</span><br><span>     if (TLVP_PRESENT(&tp, RSL_IE_MS_POWER_PARAM)) {</span><br><span>          /* Spec explicitly states BTS should only perform</span><br><span>@@ -1232,6 +1238,14 @@</span><br><span>           * Parameters' IE is present! */</span><br><span>          lchan->ms_power_ctrl.fixed = false;</span><br><span>       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* 9.3.32 BS Power Parameters */</span><br><span style="color: hsl(120, 100%, 40%);">+      if (TLVP_PRESENT(&tp, RSL_IE_BS_POWER_PARAM)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           /* NOTE: it's safer to start from 0 */</span><br><span style="color: hsl(120, 100%, 40%);">+            lchan->bs_power_ctrl.current = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+          lchan->bs_power_ctrl.fixed = false;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  /* 9.3.16 Physical Context */</span><br><span> </span><br><span>    /* 9.3.29 SACCH Information */</span><br><span>@@ -1753,7 +1767,7 @@</span><br><span>       struct abis_rsl_dchan_hdr *dch = msgb_l2(msg);</span><br><span>       struct gsm_lchan *lchan = msg->lchan;</span><br><span>     struct tlv_parsed tp;</span><br><span style="color: hsl(0, 100%, 40%);">-   uint8_t old_bs_power_red;</span><br><span style="color: hsl(120, 100%, 40%);">+     uint8_t old, new;</span><br><span> </span><br><span>        rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg));</span><br><span> </span><br><span>@@ -1766,18 +1780,24 @@</span><br><span>                 return rsl_tx_error_report(msg->trx, RSL_ERR_SERV_OPT_UNIMPL, &dch->chan_nr, NULL, msg);</span><br><span>   }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   old_bs_power_red = lchan->bs_power_red;</span><br><span style="color: hsl(0, 100%, 40%);">-      lchan->bs_power_red = BS_POWER2DB(*TLVP_VAL(&tp, RSL_IE_BS_POWER));</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      LOGPLCHAN(lchan, DRSL, LOGL_INFO, "BS POWER CONTROL Attenuation %d -> %d dB\n",</span><br><span style="color: hsl(0, 100%, 40%);">-              old_bs_power_red, lchan->bs_power_red);</span><br><span style="color: hsl(120, 100%, 40%);">+  new = BS_POWER2DB(*TLVP_VAL(&tp, RSL_IE_BS_POWER));</span><br><span style="color: hsl(120, 100%, 40%);">+       old = lchan->bs_power_ctrl.current;</span><br><span> </span><br><span>   /* 9.3.31 MS Power Parameters (O) */</span><br><span>         if (TLVP_PRESENT(&tp, RSL_IE_BS_POWER_PARAM)) {</span><br><span style="color: hsl(0, 100%, 40%);">-             /* Spec explicitly states BTS should perform autonomous</span><br><span style="color: hsl(0, 100%, 40%);">-          * BS power control loop in BTS if 'BS Power Parameters'</span><br><span style="color: hsl(0, 100%, 40%);">-                 * IE is present!  WE don't support that. */</span><br><span style="color: hsl(0, 100%, 40%);">-                return rsl_tx_error_report(msg->trx, RSL_ERR_OPT_IE_ERROR, &dch->chan_nr, NULL, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+               /* NOTE: it's safer to start from 0 */</span><br><span style="color: hsl(120, 100%, 40%);">+            lchan->bs_power_ctrl.current = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+          lchan->bs_power_ctrl.max = new;</span><br><span style="color: hsl(120, 100%, 40%);">+            lchan->bs_power_ctrl.fixed = false;</span><br><span style="color: hsl(120, 100%, 40%);">+        } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              lchan->bs_power_ctrl.current = new;</span><br><span style="color: hsl(120, 100%, 40%);">+                lchan->bs_power_ctrl.fixed = 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 (lchan->bs_power_ctrl.current != old) {</span><br><span style="color: hsl(120, 100%, 40%);">+         LOGPLCHAN(lchan, DRSL, LOGL_INFO, "BS POWER CONTROL: "</span><br><span style="color: hsl(120, 100%, 40%);">+                        "attenuation change %u -> %u dB\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                      old, lchan->bs_power_ctrl.current);</span><br><span>     }</span><br><span> </span><br><span>        return 0;</span><br><span>@@ -2975,7 +2995,7 @@</span><br><span>            msgb_tlv_put(msg, RSL_IE_UPLINK_MEAS, ie_len, meas_res);</span><br><span>             lchan->meas.flags &= ~LC_UL_M_F_RES_VALID;</span><br><span>    }</span><br><span style="color: hsl(0, 100%, 40%);">-       msgb_tv_put(msg, RSL_IE_BS_POWER, lchan->bs_power_red / 2);</span><br><span style="color: hsl(120, 100%, 40%);">+        msgb_tv_put(msg, RSL_IE_BS_POWER, lchan->bs_power_ctrl.current / 2);</span><br><span>      if (lchan->meas.flags & LC_UL_M_F_L1_VALID) {</span><br><span>                 msgb_tv_fixed_put(msg, RSL_IE_L1_INFO, 2, lchan->meas.l1_info);</span><br><span>           lchan->meas.flags &= ~LC_UL_M_F_L1_VALID;</span><br><span>diff --git a/src/common/scheduler.c b/src/common/scheduler.c</span><br><span>index 84918e3..3d780fd 100644</span><br><span>--- a/src/common/scheduler.c</span><br><span>+++ b/src/common/scheduler.c</span><br><span>@@ -1237,7 +1237,7 @@</span><br><span> </span><br><span>    /* BS Power reduction (in dB) per logical channel */</span><br><span>         if (l1cs->lchan != NULL)</span><br><span style="color: hsl(0, 100%, 40%);">-             br->att = l1cs->lchan->bs_power_red;</span><br><span style="color: hsl(120, 100%, 40%);">+         br->att = l1cs->lchan->bs_power_ctrl.current;</span><br><span> </span><br><span>   /* encrypt */</span><br><span>        if (br->burst_len && l1cs->dl_encr_algo) {</span><br><span>diff --git a/src/common/tx_power.c b/src/common/tx_power.c</span><br><span>index 0741429..348aba5 100644</span><br><span>--- a/src/common/tx_power.c</span><br><span>+++ b/src/common/tx_power.c</span><br><span>@@ -68,7 +68,7 @@</span><br><span> }</span><br><span> int get_p_target_mdBm_lchan(const struct gsm_lchan *lchan)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-   return get_p_target_mdBm(lchan->ts->trx, lchan->bs_power_red);</span><br><span style="color: hsl(120, 100%, 40%);">+       return get_p_target_mdBm(lchan->ts->trx, lchan->bs_power_ctrl.current);</span><br><span> }</span><br><span> </span><br><span> /* calculate the actual total output power required, taking into account the</span><br><span>@@ -134,7 +134,7 @@</span><br><span> }</span><br><span> int get_p_trxout_target_mdBm_lchan(const struct gsm_lchan *lchan)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-  return get_p_trxout_target_mdBm(lchan->ts->trx, lchan->bs_power_red);</span><br><span style="color: hsl(120, 100%, 40%);">+        return get_p_trxout_target_mdBm(lchan->ts->trx, lchan->bs_power_ctrl.current);</span><br><span> }</span><br><span> </span><br><span> </span><br><span>diff --git a/src/common/vty.c b/src/common/vty.c</span><br><span>index f32f6cd..5d21e58 100644</span><br><span>--- a/src/common/vty.c</span><br><span>+++ b/src/common/vty.c</span><br><span>@@ -1335,10 +1335,13 @@</span><br><span>          lchan->state == LCHAN_S_BROKEN ? " Error reason: " : "",</span><br><span>              lchan->state == LCHAN_S_BROKEN ? lchan->broken_reason : "",</span><br><span>          VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+#if 0</span><br><span style="color: hsl(120, 100%, 40%);">+  /* TODO: print more info about MS/BS Power Control */</span><br><span>        vty_out(vty, "  BS Power: %d dBm, MS Power: %u dBm%s",</span><br><span>             lchan->ts->trx->nominal_power - (lchan->ts->trx->max_power_red + lchan->bs_power_red),</span><br><span>          ms_pwr_dbm(lchan->ts->trx->bts->band, lchan->ms_power_ctrl.max),</span><br><span>              VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span>        vty_out(vty, "  Channel Mode / Codec: %s%s",</span><br><span>               gsm48_chan_mode_name(lchan->tch_mode),</span><br><span>            VTY_NEWLINE);</span><br><span>@@ -1380,7 +1383,6 @@</span><br><span>        if (lchan->loopback)</span><br><span>              vty_out(vty, "  RTP/PDCH Loopback Enabled%s", VTY_NEWLINE);</span><br><span>        vty_out(vty, "  Radio Link Failure Counter 'S': %d%s", lchan->s, VTY_NEWLINE);</span><br><span style="color: hsl(0, 100%, 40%);">-     /* TODO: MS Power Control */</span><br><span> }</span><br><span> </span><br><span> static void lchan_dump_short_vty(struct vty *vty, const struct gsm_lchan *lchan)</span><br><span>diff --git a/tests/power/Makefile.am b/tests/power/Makefile.am</span><br><span>index d6e1a6b..e428178 100644</span><br><span>--- a/tests/power/Makefile.am</span><br><span>+++ b/tests/power/Makefile.am</span><br><span>@@ -2,8 +2,12 @@</span><br><span> AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOCODEC_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LIBOSMOTRAU_CFLAGS)</span><br><span> LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOCODEC_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOTRAU_LIBS)</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-noinst_PROGRAMS = ms_power_loop_test</span><br><span style="color: hsl(0, 100%, 40%);">-EXTRA_DIST = ms_power_loop_test.ok ms_power_loop_test.err</span><br><span style="color: hsl(120, 100%, 40%);">+noinst_PROGRAMS = ms_power_loop_test bs_power_loop_test</span><br><span style="color: hsl(120, 100%, 40%);">+EXTRA_DIST = ms_power_loop_test.ok ms_power_loop_test.err \</span><br><span style="color: hsl(120, 100%, 40%);">+       bs_power_loop_test.ok bs_power_loop_test.err</span><br><span> </span><br><span> ms_power_loop_test_SOURCES = ms_power_loop_test.c $(srcdir)/../stubs.c</span><br><span> ms_power_loop_test_LDADD = $(top_builddir)/src/common/libbts.a $(LIBOSMOABIS_LIBS) $(LDADD)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+bs_power_loop_test_SOURCES = bs_power_loop_test.c $(srcdir)/../stubs.c</span><br><span style="color: hsl(120, 100%, 40%);">+bs_power_loop_test_LDADD = $(top_builddir)/src/common/libbts.a $(LIBOSMOABIS_LIBS) $(LDADD)</span><br><span>diff --git a/tests/power/bs_power_loop_test.c b/tests/power/bs_power_loop_test.c</span><br><span>new file mode 100644</span><br><span>index 0000000..bc6b815</span><br><span>--- /dev/null</span><br><span>+++ b/tests/power/bs_power_loop_test.c</span><br><span>@@ -0,0 +1,398 @@</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: Vadim Yanitskiy <vyanitskiy@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%);">+#include <stdio.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/talloc.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/application.h></span><br><span style="color: hsl(120, 100%, 40%);">+</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/l1sap.h></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/power_control.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define PWR_TEST_RXLEV_TARGET      30</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define DL_MEAS_FULL(rxqual, rxlev) \</span><br><span style="color: hsl(120, 100%, 40%);">+   .rxqual_full = rxqual, \</span><br><span style="color: hsl(120, 100%, 40%);">+      .rxlev_full = rxlev</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define DL_MEAS_SUB(rxqual, rxlev) \</span><br><span style="color: hsl(120, 100%, 40%);">+   .rxqual_sub = rxqual, \</span><br><span style="color: hsl(120, 100%, 40%);">+       .rxlev_sub = rxlev</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define DL_MEAS_FULL_SUB(rxqual, rxlev) \</span><br><span style="color: hsl(120, 100%, 40%);">+       { DL_MEAS_FULL(rxqual, rxlev), \</span><br><span style="color: hsl(120, 100%, 40%);">+        DL_MEAS_SUB(rxqual, rxlev) }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define DL_MEAS_FULL_SUB_INV(rxqual, rxlev) \</span><br><span style="color: hsl(120, 100%, 40%);">+       { DL_MEAS_FULL(rxqual, rxlev), \</span><br><span style="color: hsl(120, 100%, 40%);">+        DL_MEAS_SUB(rxqual, rxlev), \</span><br><span style="color: hsl(120, 100%, 40%);">+         .invalid = true }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum power_test_step_type {</span><br><span style="color: hsl(120, 100%, 40%);">+    PWR_TEST_ST_IND_MEAS = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+     PWR_TEST_ST_IND_DUMMY,</span><br><span style="color: hsl(120, 100%, 40%);">+        PWR_TEST_ST_SET_STATE,</span><br><span style="color: hsl(120, 100%, 40%);">+        PWR_TEST_ST_SET_PARAMS,</span><br><span style="color: hsl(120, 100%, 40%);">+       PWR_TEST_ST_ENABLE_DTXD,</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 power_test_step {</span><br><span style="color: hsl(120, 100%, 40%);">+      /* Instruction to be performed */</span><br><span style="color: hsl(120, 100%, 40%);">+     enum power_test_step_type type;</span><br><span style="color: hsl(120, 100%, 40%);">+       /* Instruction parameters */</span><br><span style="color: hsl(120, 100%, 40%);">+  union {</span><br><span style="color: hsl(120, 100%, 40%);">+               /* Power Control state */</span><br><span style="color: hsl(120, 100%, 40%);">+             struct lchan_power_ctrl_state state;</span><br><span style="color: hsl(120, 100%, 40%);">+          /* Power Control parameters */</span><br><span style="color: hsl(120, 100%, 40%);">+                struct bts_power_ctrl_params params;</span><br><span style="color: hsl(120, 100%, 40%);">+          /* Indicated DL measurements */</span><br><span style="color: hsl(120, 100%, 40%);">+               struct {</span><br><span style="color: hsl(120, 100%, 40%);">+                      uint8_t rxqual_full;</span><br><span style="color: hsl(120, 100%, 40%);">+                  uint8_t rxqual_sub;</span><br><span style="color: hsl(120, 100%, 40%);">+                   uint8_t rxlev_full;</span><br><span style="color: hsl(120, 100%, 40%);">+                   uint8_t rxlev_sub;</span><br><span style="color: hsl(120, 100%, 40%);">+                    bool invalid;</span><br><span style="color: hsl(120, 100%, 40%);">+         } meas;</span><br><span style="color: hsl(120, 100%, 40%);">+       };</span><br><span style="color: hsl(120, 100%, 40%);">+    /* Expected Tx power reduction */</span><br><span style="color: hsl(120, 100%, 40%);">+     uint8_t exp_txred;</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 gsm_bts *g_bts = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+static struct gsm_bts_trx *g_trx = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void init_test(const char *name)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        if (g_trx != NULL)</span><br><span style="color: hsl(120, 100%, 40%);">+            talloc_free(g_trx);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (g_bts != NULL)</span><br><span style="color: hsl(120, 100%, 40%);">+            talloc_free(g_bts);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ g_bts = talloc_zero(tall_bts_ctx, struct gsm_bts);</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(g_bts != NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ INIT_LLIST_HEAD(&g_bts->trx_list);</span><br><span style="color: hsl(120, 100%, 40%);">+     g_trx = gsm_bts_trx_alloc(g_bts);</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(g_trx != NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ g_bts->dl_power_ctrl.target = rxlev2dbm(PWR_TEST_RXLEV_TARGET);</span><br><span style="color: hsl(120, 100%, 40%);">+    g_bts->band = GSM_BAND_900;</span><br><span style="color: hsl(120, 100%, 40%);">+        g_bts->c0 = g_trx;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       printf("\nStarting test case '%s'\n", name);</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 enc_meas_rep(struct gsm48_hdr *gh,</span><br><span style="color: hsl(120, 100%, 40%);">+                    const unsigned int n,</span><br><span style="color: hsl(120, 100%, 40%);">+                         const struct power_test_step *step)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct gsm48_meas_res *mr = (struct gsm48_meas_res *) gh->data;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  gh->proto_discr = GSM48_PDISC_RR;</span><br><span style="color: hsl(120, 100%, 40%);">+  gh->msg_type = GSM48_MT_RR_MEAS_REP;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     *mr = (struct gsm48_meas_res) {</span><br><span style="color: hsl(120, 100%, 40%);">+               .rxlev_full = step->meas.rxlev_full,</span><br><span style="color: hsl(120, 100%, 40%);">+               .rxlev_sub = step->meas.rxlev_sub,</span><br><span style="color: hsl(120, 100%, 40%);">+         .rxqual_full = step->meas.rxqual_full,</span><br><span style="color: hsl(120, 100%, 40%);">+             .rxqual_sub = step->meas.rxqual_sub,</span><br><span style="color: hsl(120, 100%, 40%);">+               /* NOTE: inversed logic (1 means invalid) */</span><br><span style="color: hsl(120, 100%, 40%);">+          .meas_valid = step->meas.invalid,</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%);">+  printf("#%02u %s() -> Measurement Results (%svalid): "</span><br><span style="color: hsl(120, 100%, 40%);">+          "RXLEV-FULL(%02u), RXQUAL-FULL(%u), "</span><br><span style="color: hsl(120, 100%, 40%);">+               "RXLEV-SUB(%02u), RXQUAL-SUB(%u)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+        n, __func__, step->meas.invalid ? "in" : "",</span><br><span style="color: hsl(120, 100%, 40%);">+           mr->rxlev_full, mr->rxqual_full,</span><br><span style="color: hsl(120, 100%, 40%);">+        mr->rxlev_sub, mr->rxqual_sub);</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 int exec_power_step(struct gsm_lchan *lchan,</span><br><span style="color: hsl(120, 100%, 40%);">+                           const unsigned int n,</span><br><span style="color: hsl(120, 100%, 40%);">+                         const struct power_test_step *step)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct gsm48_hdr *gh;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t old, new;</span><br><span style="color: hsl(120, 100%, 40%);">+     uint8_t buf[18];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    gh = (struct gsm48_hdr *) buf;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      switch (step->type) {</span><br><span style="color: hsl(120, 100%, 40%);">+      case PWR_TEST_ST_SET_STATE:</span><br><span style="color: hsl(120, 100%, 40%);">+           printf("#%02u %s() <- State (re)set (current %u dB, max %u dB)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                      n, __func__, step->state.current, step->state.max);</span><br><span style="color: hsl(120, 100%, 40%);">+              lchan->bs_power_ctrl = step->state;</span><br><span style="color: hsl(120, 100%, 40%);">+             return 0; /* we're done */</span><br><span style="color: hsl(120, 100%, 40%);">+        case PWR_TEST_ST_SET_PARAMS:</span><br><span style="color: hsl(120, 100%, 40%);">+          printf("#%02u %s() <- Param (re)set (target %d dBm, hysteresis %u dB, "</span><br><span style="color: hsl(120, 100%, 40%);">+                                              "filtering is %sabled)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                     n, __func__, step->params.target, step->params.hysteresis,</span><br><span style="color: hsl(120, 100%, 40%);">+                      step->params.pf_algo != BTS_PF_ALGO_NONE ? "en" : "dis");</span><br><span style="color: hsl(120, 100%, 40%);">+               g_bts->dl_power_ctrl = step->params;</span><br><span style="color: hsl(120, 100%, 40%);">+            return 0; /* we're done */</span><br><span style="color: hsl(120, 100%, 40%);">+        case PWR_TEST_ST_ENABLE_DTXD:</span><br><span style="color: hsl(120, 100%, 40%);">+         printf("#%02u %s() <- Enable DTXd\n", n, __func__);</span><br><span style="color: hsl(120, 100%, 40%);">+              lchan->tch.dtx.dl_active = true;</span><br><span style="color: hsl(120, 100%, 40%);">+           return 0; /* we're done */</span><br><span style="color: hsl(120, 100%, 40%);">+        case PWR_TEST_ST_IND_DUMMY:</span><br><span style="color: hsl(120, 100%, 40%);">+           printf("#%02u %s() <- Dummy block\n", n, __func__);</span><br><span style="color: hsl(120, 100%, 40%);">+              memset(buf, 0x2b, sizeof(buf));</span><br><span style="color: hsl(120, 100%, 40%);">+               break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case PWR_TEST_ST_IND_MEAS:</span><br><span style="color: hsl(120, 100%, 40%);">+            enc_meas_rep(gh, n, step);</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%);">+   printf("#%02u lchan_bs_pwr_ctrl() <- UL SACCH: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+           n, osmo_hexdump(buf, sizeof(buf)));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  old = lchan->bs_power_ctrl.current;</span><br><span style="color: hsl(120, 100%, 40%);">+        lchan_bs_pwr_ctrl(lchan, gh);</span><br><span style="color: hsl(120, 100%, 40%);">+ new = lchan->bs_power_ctrl.current;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      printf("#%02u lchan_bs_pwr_ctrl() -> BS power reduction: "</span><br><span style="color: hsl(120, 100%, 40%);">+              "%u -> %u (expected %u)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+              n, old, new, step->exp_txred);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    return new != step->exp_txred;</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 exec_power_test(const struct power_test_step *steps,</span><br><span style="color: hsl(120, 100%, 40%);">+                          unsigned int num_steps,</span><br><span style="color: hsl(120, 100%, 40%);">+                       const char *name)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      unsigned int n;</span><br><span style="color: hsl(120, 100%, 40%);">+       int rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ init_test(name);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    struct gsm_lchan *lchan = &g_trx->ts[0].lchan[0];</span><br><span style="color: hsl(120, 100%, 40%);">+      for (n = 0; n < num_steps; n++)</span><br><span style="color: hsl(120, 100%, 40%);">+            rc |= exec_power_step(lchan, n, &steps[n]);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     printf("Test case verdict: %s\n", rc ? "FAIL" : "SUCCESS");</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%);">+/* Verify that the power remains constant in fixed mode. */</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct power_test_step TC_fixed_mode[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+  /* Initial state: 10 dB, up to 20 dB */</span><br><span style="color: hsl(120, 100%, 40%);">+       { .type = PWR_TEST_ST_SET_STATE,</span><br><span style="color: hsl(120, 100%, 40%);">+        .state = { .current = 10, .max = 2 * 10, .fixed = true } },</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /* MS indicates random RxQual/RxLev values, which must be ignored */</span><br><span style="color: hsl(120, 100%, 40%);">+  { .meas = DL_MEAS_FULL_SUB(0, 63),      .exp_txred = 10 },</span><br><span style="color: hsl(120, 100%, 40%);">+    { .meas = DL_MEAS_FULL_SUB(7, 0),       .exp_txred = 10 },</span><br><span style="color: hsl(120, 100%, 40%);">+    { .meas = DL_MEAS_FULL_SUB(0, 30),      .exp_txred = 10 },</span><br><span style="color: hsl(120, 100%, 40%);">+    { .meas = DL_MEAS_FULL_SUB(1, 30),      .exp_txred = 10 },</span><br><span style="color: hsl(120, 100%, 40%);">+    { .meas = DL_MEAS_FULL_SUB(1, 50),      .exp_txred = 10 },</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%);">+/* Verify that the power remains constant if RxLev equals the target level. */</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct power_test_step TC_rxlev_target[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Initial state: 0 dB, up to 20 dB */</span><br><span style="color: hsl(120, 100%, 40%);">+        { .type = PWR_TEST_ST_SET_STATE,</span><br><span style="color: hsl(120, 100%, 40%);">+        .state = { .current = 0, .max = 2 * 10 } },</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /* MS indicates RxLev values that match the target level */</span><br><span style="color: hsl(120, 100%, 40%);">+   { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET) },</span><br><span style="color: hsl(120, 100%, 40%);">+       { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET) },</span><br><span style="color: hsl(120, 100%, 40%);">+       { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET) },</span><br><span style="color: hsl(120, 100%, 40%);">+       { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET) },</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%);">+/* Verify that the power is gradually reduced/increased to the</span><br><span style="color: hsl(120, 100%, 40%);">+ * minimum/maximum if the MS reports high/low RxLev values. */</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct power_test_step TC_rxlev_max_min[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Initial state: 0 dB, up to 20 dB */</span><br><span style="color: hsl(120, 100%, 40%);">+        { .type = PWR_TEST_ST_SET_STATE,</span><br><span style="color: hsl(120, 100%, 40%);">+        .state = { .current = 0, .max = 2 * 10 } },</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /* MS indicates high RxLev values (-50 dBm) */</span><br><span style="color: hsl(120, 100%, 40%);">+        { .meas = DL_MEAS_FULL_SUB(0, 60),      .exp_txred =  4 },</span><br><span style="color: hsl(120, 100%, 40%);">+    { .meas = DL_MEAS_FULL_SUB(0, 60),      .exp_txred =  8 },</span><br><span style="color: hsl(120, 100%, 40%);">+    { .meas = DL_MEAS_FULL_SUB(0, 60),      .exp_txred = 12 },</span><br><span style="color: hsl(120, 100%, 40%);">+    { .meas = DL_MEAS_FULL_SUB(0, 60),      .exp_txred = 16 },</span><br><span style="color: hsl(120, 100%, 40%);">+    { .meas = DL_MEAS_FULL_SUB(0, 60),      .exp_txred = 20 }, /* max */</span><br><span style="color: hsl(120, 100%, 40%);">+  { .meas = DL_MEAS_FULL_SUB(0, 60),      .exp_txred = 20 }, /* max */</span><br><span style="color: hsl(120, 100%, 40%);">+  { .meas = DL_MEAS_FULL_SUB(0, 60),      .exp_txred = 20 }, /* max */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* MS indicates low RxLev values (-100 dBm) */</span><br><span style="color: hsl(120, 100%, 40%);">+        { .meas = DL_MEAS_FULL_SUB(0, 10),      .exp_txred = 12 },</span><br><span style="color: hsl(120, 100%, 40%);">+    { .meas = DL_MEAS_FULL_SUB(0, 10),      .exp_txred =  4 },</span><br><span style="color: hsl(120, 100%, 40%);">+    { .meas = DL_MEAS_FULL_SUB(0, 10),      .exp_txred =  0 }, /* min */</span><br><span style="color: hsl(120, 100%, 40%);">+  { .meas = DL_MEAS_FULL_SUB(0, 10),      .exp_txred =  0 }, /* min */</span><br><span style="color: hsl(120, 100%, 40%);">+  { .meas = DL_MEAS_FULL_SUB(0, 10),      .exp_txred =  0 }, /* min */</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%);">+/* Verify that the logic picks the 'SUB' values in DTXd mode. */</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct power_test_step TC_dtxd_mode[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+  /* Initial state: 0 dB, up to 20 dB */</span><br><span style="color: hsl(120, 100%, 40%);">+        { .type = PWR_TEST_ST_SET_STATE,</span><br><span style="color: hsl(120, 100%, 40%);">+        .state = { .current = 0, .max = 2 * 10 } },</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET) },</span><br><span style="color: hsl(120, 100%, 40%);">+       { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET) },</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     { .type = PWR_TEST_ST_ENABLE_DTXD }, /* DTXd mode */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* MS indicates target RxLev values as 'SUB', and random as 'FULL' */</span><br><span style="color: hsl(120, 100%, 40%);">+ { .meas = { DL_MEAS_FULL(7,  0), DL_MEAS_SUB(0, PWR_TEST_RXLEV_TARGET) } },</span><br><span style="color: hsl(120, 100%, 40%);">+   { .meas = { DL_MEAS_FULL(3, 30), DL_MEAS_SUB(0, PWR_TEST_RXLEV_TARGET) } },</span><br><span style="color: hsl(120, 100%, 40%);">+   { .meas = { DL_MEAS_FULL(0, 63), DL_MEAS_SUB(0, PWR_TEST_RXLEV_TARGET) } },</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%);">+/* Verify that RxQual > 0 reduces the current attenuation value. */</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct power_test_step TC_rxqual_ber[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+    /* Initial state: 16 dB, up to 20 dB */</span><br><span style="color: hsl(120, 100%, 40%);">+       { .type = PWR_TEST_ST_SET_STATE,</span><br><span style="color: hsl(120, 100%, 40%);">+        .state = { .current = 16, .max = 2 * 10 } },</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* MS indicates target RxLev, and no bit errors */</span><br><span style="color: hsl(120, 100%, 40%);">+    { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET),   .exp_txred = 16 },</span><br><span style="color: hsl(120, 100%, 40%);">+    { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET),   .exp_txred = 16 },</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* MS indicates target RxLev, but RxQual values > 0 */</span><br><span style="color: hsl(120, 100%, 40%);">+     { .meas = DL_MEAS_FULL_SUB(7, PWR_TEST_RXLEV_TARGET),   .exp_txred = 16 / 2 },</span><br><span style="color: hsl(120, 100%, 40%);">+        { .meas = DL_MEAS_FULL_SUB(4, PWR_TEST_RXLEV_TARGET),   .exp_txred = 16 / 4 },</span><br><span style="color: hsl(120, 100%, 40%);">+        { .meas = DL_MEAS_FULL_SUB(1, PWR_TEST_RXLEV_TARGET),   .exp_txred = 16 / 8 },</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* MS indicates target RxLev, and no bit errors anymore */</span><br><span style="color: hsl(120, 100%, 40%);">+    { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET),   .exp_txred = 16 / 8 },</span><br><span style="color: hsl(120, 100%, 40%);">+        { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET),   .exp_txred = 16 / 8 },</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* Reset state: 16 dB, up to 20 dB */</span><br><span style="color: hsl(120, 100%, 40%);">+ { .type = PWR_TEST_ST_SET_STATE,</span><br><span style="color: hsl(120, 100%, 40%);">+        .state = { .current = 16, .max = 2 * 10 } },</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* MS indicates target RxLev, but RxQual values > 0 again */</span><br><span style="color: hsl(120, 100%, 40%);">+       { .meas = DL_MEAS_FULL_SUB(7, PWR_TEST_RXLEV_TARGET),   .exp_txred = 16 /  2 },</span><br><span style="color: hsl(120, 100%, 40%);">+       { .meas = DL_MEAS_FULL_SUB(7, PWR_TEST_RXLEV_TARGET),   .exp_txred = 16 /  4 },</span><br><span style="color: hsl(120, 100%, 40%);">+       { .meas = DL_MEAS_FULL_SUB(7, PWR_TEST_RXLEV_TARGET),   .exp_txred = 16 /  8 },</span><br><span style="color: hsl(120, 100%, 40%);">+       { .meas = DL_MEAS_FULL_SUB(7, PWR_TEST_RXLEV_TARGET),   .exp_txred = 16 / 16 },</span><br><span style="color: hsl(120, 100%, 40%);">+       { .meas = DL_MEAS_FULL_SUB(7, PWR_TEST_RXLEV_TARGET),   .exp_txred = 16 / 32 },</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%);">+/* Verify that invalid and dummy SACCH blocks are ignored. */</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct power_test_step TC_inval_dummy[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+        /* Initial state: 16 dB, up to 20 dB */</span><br><span style="color: hsl(120, 100%, 40%);">+       { .type = PWR_TEST_ST_SET_STATE,</span><br><span style="color: hsl(120, 100%, 40%);">+        .state = { .current = 16, .max = 2 * 10 } },</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* MS sends invalid measurement results which must be ignored */</span><br><span style="color: hsl(120, 100%, 40%);">+      { .meas = DL_MEAS_FULL_SUB_INV(7, 63),                  .exp_txred = 16 },</span><br><span style="color: hsl(120, 100%, 40%);">+    { .meas = DL_MEAS_FULL_SUB_INV(0, 0),                   .exp_txred = 16 },</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* Let's say SMS (SAPI=3) blocks substitute some of the reports */</span><br><span style="color: hsl(120, 100%, 40%);">+        { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET),   .exp_txred = 16 },</span><br><span style="color: hsl(120, 100%, 40%);">+    { .type = PWR_TEST_ST_IND_DUMMY, /* not a report */     .exp_txred = 16 },</span><br><span style="color: hsl(120, 100%, 40%);">+    { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET),   .exp_txred = 16 },</span><br><span style="color: hsl(120, 100%, 40%);">+    { .type = PWR_TEST_ST_IND_DUMMY, /* not a report */     .exp_txred = 16 },</span><br><span style="color: hsl(120, 100%, 40%);">+    { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET),   .exp_txred = 16 },</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%);">+/* Verify that small deviations from the target do not trigger any changes. */</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct power_test_step TC_rxlev_hyst[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Initial state: 16 dB, up to 20 dB */</span><br><span style="color: hsl(120, 100%, 40%);">+       { .type = PWR_TEST_ST_SET_STATE,</span><br><span style="color: hsl(120, 100%, 40%);">+        .state = { .current = 12, .max = 2 * 8 } },</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /* Hysteresis is not enabled, so small deviations trigger oscillations */</span><br><span style="color: hsl(120, 100%, 40%);">+     { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET + 1),       .exp_txred = 13 },</span><br><span style="color: hsl(120, 100%, 40%);">+    { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET - 2),       .exp_txred = 11 },</span><br><span style="color: hsl(120, 100%, 40%);">+    { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET + 3),       .exp_txred = 14 },</span><br><span style="color: hsl(120, 100%, 40%);">+    { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET - 2),       .exp_txred = 12 },</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* Enable hysteresis */</span><br><span style="color: hsl(120, 100%, 40%);">+       { .type = PWR_TEST_ST_SET_PARAMS,</span><br><span style="color: hsl(120, 100%, 40%);">+       .params = {</span><br><span style="color: hsl(120, 100%, 40%);">+         .target = -110 + PWR_TEST_RXLEV_TARGET,</span><br><span style="color: hsl(120, 100%, 40%);">+               .hysteresis = 3,</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%);">+  /* Hysteresis is enabled, so small deviations do not trigger any changes */</span><br><span style="color: hsl(120, 100%, 40%);">+   { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET + 1),       .exp_txred = 12 },</span><br><span style="color: hsl(120, 100%, 40%);">+    { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET - 2),       .exp_txred = 12 },</span><br><span style="color: hsl(120, 100%, 40%);">+    { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET + 3),       .exp_txred = 12 },</span><br><span style="color: hsl(120, 100%, 40%);">+    { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET - 2),       .exp_txred = 12 },</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%);">+/* Verify EWMA based power filtering. */</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct power_test_step TC_rxlev_pf_ewma[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+        /* Initial state: 20 dB, up to 30 dB */</span><br><span style="color: hsl(120, 100%, 40%);">+       { .type = PWR_TEST_ST_SET_STATE,</span><br><span style="color: hsl(120, 100%, 40%);">+        .state = { .current = 16, .max = 2 * 15 } },</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* Enable EWMA based power filtering */</span><br><span style="color: hsl(120, 100%, 40%);">+       { .type = PWR_TEST_ST_SET_PARAMS,</span><br><span style="color: hsl(120, 100%, 40%);">+       .params = {</span><br><span style="color: hsl(120, 100%, 40%);">+         .target = -110 + PWR_TEST_RXLEV_TARGET, /* RxLev 30 */</span><br><span style="color: hsl(120, 100%, 40%);">+                .pf_algo = BTS_PF_ALGO_EWMA,</span><br><span style="color: hsl(120, 100%, 40%);">+          .pf.ewma.alpha = 50,</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%);">+  /* MS indicates target RxLev, power level remains constant */</span><br><span style="color: hsl(120, 100%, 40%);">+ { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET),           .exp_txred = 16 },</span><br><span style="color: hsl(120, 100%, 40%);">+    { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET),           .exp_txred = 16 },</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* Avg[t] = (0.5 * 26) + (0.5 * 30) = 28, so delta is 2 */</span><br><span style="color: hsl(120, 100%, 40%);">+    { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET - 4),       .exp_txred = 14 },</span><br><span style="color: hsl(120, 100%, 40%);">+    /* Avg[t] = (0.5 * 26) + (0.5 * 28) = 27, so delta is 3 */</span><br><span style="color: hsl(120, 100%, 40%);">+    { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET - 4),       .exp_txred = 11 },</span><br><span style="color: hsl(120, 100%, 40%);">+    /* Avg[t] = (0.5 * 35) + (0.5 * 27) = 31, so delta is 1 */</span><br><span style="color: hsl(120, 100%, 40%);">+    { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET + 5),       .exp_txred = 12 },</span><br><span style="color: hsl(120, 100%, 40%);">+    /* Avg[t] = (0.5 * 35) + (0.5 * 31) = 33, so delta is 3 */</span><br><span style="color: hsl(120, 100%, 40%);">+    { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET + 5),       .exp_txred = 15 },</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%);">+int main(int argc, char **argv)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  printf("Testing BS Power loop...\n");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     tall_bts_ctx = talloc_named_const(NULL, 1, "OsmoBTS context");</span><br><span style="color: hsl(120, 100%, 40%);">+      msgb_talloc_ctx_init(tall_bts_ctx, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      osmo_init_logging2(tall_bts_ctx, &bts_log_info);</span><br><span style="color: hsl(120, 100%, 40%);">+  osmo_stderr_target->categories[DLOOP].loglevel = LOGL_DEBUG;</span><br><span style="color: hsl(120, 100%, 40%);">+       osmo_stderr_target->categories[DL1C].loglevel = LOGL_DEBUG;</span><br><span style="color: hsl(120, 100%, 40%);">+        log_set_print_filename(osmo_stderr_target, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+        log_set_use_color(osmo_stderr_target, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define exec_test(test) \</span><br><span style="color: hsl(120, 100%, 40%);">+        exec_power_test(test, ARRAY_SIZE(test), #test)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      exec_test(TC_fixed_mode);</span><br><span style="color: hsl(120, 100%, 40%);">+     exec_test(TC_rxlev_target);</span><br><span style="color: hsl(120, 100%, 40%);">+   exec_test(TC_rxlev_max_min); /* FIXME */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    exec_test(TC_dtxd_mode);</span><br><span style="color: hsl(120, 100%, 40%);">+      exec_test(TC_rxqual_ber);</span><br><span style="color: hsl(120, 100%, 40%);">+     exec_test(TC_inval_dummy);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  exec_test(TC_rxlev_hyst);</span><br><span style="color: hsl(120, 100%, 40%);">+     exec_test(TC_rxlev_pf_ewma);</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>diff --git a/tests/power/bs_power_loop_test.err b/tests/power/bs_power_loop_test.err</span><br><span>new file mode 100644</span><br><span>index 0000000..44d996e</span><br><span>--- /dev/null</span><br><span>+++ b/tests/power/bs_power_loop_test.err</span><br><span>@@ -0,0 +1,102 @@</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0), DTx is disabled => using FULL</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Keeping Downlink attenuation at 0 dB (maximum 20 dB, target -80 dBm, delta 0 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0), DTx is disabled => using FULL</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Keeping Downlink attenuation at 0 dB (maximum 20 dB, target -80 dBm, delta 0 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0), DTx is disabled => using FULL</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Keeping Downlink attenuation at 0 dB (maximum 20 dB, target -80 dBm, delta 0 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0), DTx is disabled => using FULL</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Keeping Downlink attenuation at 0 dB (maximum 20 dB, target -80 dBm, delta 0 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0), DTx is disabled => using FULL</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Changing Downlink attenuation: 0 -> 8 dB (maximum 20 dB, target -80 dBm, delta -8 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0), DTx is disabled => using FULL</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Changing Downlink attenuation: 8 -> 16 dB (maximum 20 dB, target -80 dBm, delta -8 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0), DTx is disabled => using FULL</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Changing Downlink attenuation: 16 -> 20 dB (maximum 20 dB, target -80 dBm, delta -8 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0), DTx is disabled => using FULL</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Keeping Downlink attenuation at 20 dB (maximum 20 dB, target -80 dBm, delta -8 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0), DTx is disabled => using FULL</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Keeping Downlink attenuation at 20 dB (maximum 20 dB, target -80 dBm, delta -8 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0), DTx is disabled => using FULL</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Keeping Downlink attenuation at 20 dB (maximum 20 dB, target -80 dBm, delta -8 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0), DTx is disabled => using FULL</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Keeping Downlink attenuation at 20 dB (maximum 20 dB, target -80 dBm, delta -8 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(10), RXQUAL-FULL(0), RXLEV-SUB(10), RXQUAL-SUB(0), DTx is disabled => using FULL</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Changing Downlink attenuation: 20 -> 16 dB (maximum 20 dB, target -80 dBm, delta 4 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(10), RXQUAL-FULL(0), RXLEV-SUB(10), RXQUAL-SUB(0), DTx is disabled => using FULL</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Changing Downlink attenuation: 16 -> 12 dB (maximum 20 dB, target -80 dBm, delta 4 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(10), RXQUAL-FULL(0), RXLEV-SUB(10), RXQUAL-SUB(0), DTx is disabled => using FULL</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Changing Downlink attenuation: 12 -> 8 dB (maximum 20 dB, target -80 dBm, delta 4 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(10), RXQUAL-FULL(0), RXLEV-SUB(10), RXQUAL-SUB(0), DTx is disabled => using FULL</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Changing Downlink attenuation: 8 -> 4 dB (maximum 20 dB, target -80 dBm, delta 4 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(10), RXQUAL-FULL(0), RXLEV-SUB(10), RXQUAL-SUB(0), DTx is disabled => using FULL</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Changing Downlink attenuation: 4 -> 0 dB (maximum 20 dB, target -80 dBm, delta 4 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0), DTx is disabled => using FULL</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Keeping Downlink attenuation at 0 dB (maximum 20 dB, target -80 dBm, delta 0 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0), DTx is disabled => using FULL</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Keeping Downlink attenuation at 0 dB (maximum 20 dB, target -80 dBm, delta 0 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(00), RXQUAL-FULL(7), RXLEV-SUB(30), RXQUAL-SUB(0), DTx is enabled => using SUB</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Keeping Downlink attenuation at 0 dB (maximum 20 dB, target -80 dBm, delta 0 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(30), RXQUAL-FULL(3), RXLEV-SUB(30), RXQUAL-SUB(0), DTx is enabled => using SUB</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Keeping Downlink attenuation at 0 dB (maximum 20 dB, target -80 dBm, delta 0 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(63), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0), DTx is enabled => using SUB</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Keeping Downlink attenuation at 0 dB (maximum 20 dB, target -80 dBm, delta 0 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0), DTx is disabled => using FULL</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Keeping Downlink attenuation at 16 dB (maximum 20 dB, target -80 dBm, delta 0 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0), DTx is disabled => using FULL</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Keeping Downlink attenuation at 16 dB (maximum 20 dB, target -80 dBm, delta 0 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(30), RXQUAL-FULL(7), RXLEV-SUB(30), RXQUAL-SUB(7), DTx is disabled => using FULL</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Reducing Downlink attenuation by half: 16 -> 8 dB due to RXQUAL 7 > 0</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(30), RXQUAL-FULL(4), RXLEV-SUB(30), RXQUAL-SUB(4), DTx is disabled => using FULL</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Reducing Downlink attenuation by half: 8 -> 4 dB due to RXQUAL 4 > 0</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(30), RXQUAL-FULL(1), RXLEV-SUB(30), RXQUAL-SUB(1), DTx is disabled => using FULL</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Reducing Downlink attenuation by half: 4 -> 2 dB due to RXQUAL 1 > 0</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0), DTx is disabled => using FULL</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Keeping Downlink attenuation at 2 dB (maximum 20 dB, target -80 dBm, delta 0 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0), DTx is disabled => using FULL</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Keeping Downlink attenuation at 2 dB (maximum 20 dB, target -80 dBm, delta 0 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(30), RXQUAL-FULL(7), RXLEV-SUB(30), RXQUAL-SUB(7), DTx is disabled => using FULL</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Reducing Downlink attenuation by half: 16 -> 8 dB due to RXQUAL 7 > 0</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(30), RXQUAL-FULL(7), RXLEV-SUB(30), RXQUAL-SUB(7), DTx is disabled => using FULL</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Reducing Downlink attenuation by half: 8 -> 4 dB due to RXQUAL 7 > 0</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(30), RXQUAL-FULL(7), RXLEV-SUB(30), RXQUAL-SUB(7), DTx is disabled => using FULL</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Reducing Downlink attenuation by half: 4 -> 2 dB due to RXQUAL 7 > 0</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(30), RXQUAL-FULL(7), RXLEV-SUB(30), RXQUAL-SUB(7), DTx is disabled => using FULL</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Reducing Downlink attenuation by half: 2 -> 1 dB due to RXQUAL 7 > 0</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(30), RXQUAL-FULL(7), RXLEV-SUB(30), RXQUAL-SUB(7), DTx is disabled => using FULL</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Reducing Downlink attenuation by half: 1 -> 0 dB due to RXQUAL 7 > 0</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) The measurement results are not valid</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) The measurement results are not valid</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0), DTx is disabled => using FULL</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Keeping Downlink attenuation at 16 dB (maximum 20 dB, target -80 dBm, delta 0 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0), DTx is disabled => using FULL</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Keeping Downlink attenuation at 16 dB (maximum 20 dB, target -80 dBm, delta 0 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0), DTx is disabled => using FULL</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Keeping Downlink attenuation at 16 dB (maximum 20 dB, target -80 dBm, delta 0 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(31), RXQUAL-FULL(0), RXLEV-SUB(31), RXQUAL-SUB(0), DTx is disabled => using FULL</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Changing Downlink attenuation: 12 -> 13 dB (maximum 16 dB, target -80 dBm, delta -1 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(28), RXQUAL-FULL(0), RXLEV-SUB(28), RXQUAL-SUB(0), DTx is disabled => using FULL</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Changing Downlink attenuation: 13 -> 11 dB (maximum 16 dB, target -80 dBm, delta 2 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(33), RXQUAL-FULL(0), RXLEV-SUB(33), RXQUAL-SUB(0), DTx is disabled => using FULL</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Changing Downlink attenuation: 11 -> 14 dB (maximum 16 dB, target -80 dBm, delta -3 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(28), RXQUAL-FULL(0), RXLEV-SUB(28), RXQUAL-SUB(0), DTx is disabled => using FULL</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Changing Downlink attenuation: 14 -> 12 dB (maximum 16 dB, target -80 dBm, delta 2 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(31), RXQUAL-FULL(0), RXLEV-SUB(31), RXQUAL-SUB(0), DTx is disabled => using FULL</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Keeping Downlink attenuation at 12 dB (maximum 16 dB, target -80 dBm, delta 0 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(28), RXQUAL-FULL(0), RXLEV-SUB(28), RXQUAL-SUB(0), DTx is disabled => using FULL</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Keeping Downlink attenuation at 12 dB (maximum 16 dB, target -80 dBm, delta 0 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(33), RXQUAL-FULL(0), RXLEV-SUB(33), RXQUAL-SUB(0), DTx is disabled => using FULL</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Keeping Downlink attenuation at 12 dB (maximum 16 dB, target -80 dBm, delta 0 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(28), RXQUAL-FULL(0), RXLEV-SUB(28), RXQUAL-SUB(0), DTx is disabled => using FULL</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Keeping Downlink attenuation at 12 dB (maximum 16 dB, target -80 dBm, delta 0 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0), DTx is disabled => using FULL</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Keeping Downlink attenuation at 16 dB (maximum 30 dB, target -80 dBm, delta 0 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0), DTx is disabled => using FULL</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Keeping Downlink attenuation at 16 dB (maximum 30 dB, target -80 dBm, delta 0 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(26), RXQUAL-FULL(0), RXLEV-SUB(26), RXQUAL-SUB(0), DTx is disabled => using FULL</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Changing Downlink attenuation: 16 -> 14 dB (maximum 30 dB, target -80 dBm, delta 2 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(26), RXQUAL-FULL(0), RXLEV-SUB(26), RXQUAL-SUB(0), DTx is disabled => using FULL</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Changing Downlink attenuation: 14 -> 11 dB (maximum 30 dB, target -80 dBm, delta 3 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(35), RXQUAL-FULL(0), RXLEV-SUB(35), RXQUAL-SUB(0), DTx is disabled => using FULL</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Changing Downlink attenuation: 11 -> 12 dB (maximum 30 dB, target -80 dBm, delta -1 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Rx DL Measurement Report: RXLEV-FULL(35), RXQUAL-FULL(0), RXLEV-SUB(35), RXQUAL-SUB(0), DTx is disabled => using FULL</span><br><span style="color: hsl(120, 100%, 40%);">+(bts=0,trx=0,ts=0,ss=0) Changing Downlink attenuation: 12 -> 15 dB (maximum 30 dB, target -80 dBm, delta -3 dB)</span><br><span>diff --git a/tests/power/bs_power_loop_test.ok b/tests/power/bs_power_loop_test.ok</span><br><span>new file mode 100644</span><br><span>index 0000000..fe2eb78</span><br><span>--- /dev/null</span><br><span>+++ b/tests/power/bs_power_loop_test.ok</span><br><span>@@ -0,0 +1,214 @@</span><br><span style="color: hsl(120, 100%, 40%);">+Testing BS Power loop...</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Starting test case 'TC_fixed_mode'</span><br><span style="color: hsl(120, 100%, 40%);">+#00 exec_power_step() <- State (re)set (current 10 dB, max 20 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+#01 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(63), RXQUAL-FULL(0), RXLEV-SUB(63), RXQUAL-SUB(0)</span><br><span style="color: hsl(120, 100%, 40%);">+#01 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 3f 3f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#01 lchan_bs_pwr_ctrl() -> BS power reduction: 10 -> 10 (expected 10)</span><br><span style="color: hsl(120, 100%, 40%);">+#02 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(00), RXQUAL-FULL(7), RXLEV-SUB(00), RXQUAL-SUB(7)</span><br><span style="color: hsl(120, 100%, 40%);">+#02 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 00 00 7e 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#02 lchan_bs_pwr_ctrl() -> BS power reduction: 10 -> 10 (expected 10)</span><br><span style="color: hsl(120, 100%, 40%);">+#03 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0)</span><br><span style="color: hsl(120, 100%, 40%);">+#03 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#03 lchan_bs_pwr_ctrl() -> BS power reduction: 10 -> 10 (expected 10)</span><br><span style="color: hsl(120, 100%, 40%);">+#04 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(1), RXLEV-SUB(30), RXQUAL-SUB(1)</span><br><span style="color: hsl(120, 100%, 40%);">+#04 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 12 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#04 lchan_bs_pwr_ctrl() -> BS power reduction: 10 -> 10 (expected 10)</span><br><span style="color: hsl(120, 100%, 40%);">+#05 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(50), RXQUAL-FULL(1), RXLEV-SUB(50), RXQUAL-SUB(1)</span><br><span style="color: hsl(120, 100%, 40%);">+#05 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 32 32 12 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#05 lchan_bs_pwr_ctrl() -> BS power reduction: 10 -> 10 (expected 10)</span><br><span style="color: hsl(120, 100%, 40%);">+Test case verdict: SUCCESS</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Starting test case 'TC_rxlev_target'</span><br><span style="color: hsl(120, 100%, 40%);">+#00 exec_power_step() <- State (re)set (current 0 dB, max 20 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+#01 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0)</span><br><span style="color: hsl(120, 100%, 40%);">+#01 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#01 lchan_bs_pwr_ctrl() -> BS power reduction: 0 -> 0 (expected 0)</span><br><span style="color: hsl(120, 100%, 40%);">+#02 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0)</span><br><span style="color: hsl(120, 100%, 40%);">+#02 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#02 lchan_bs_pwr_ctrl() -> BS power reduction: 0 -> 0 (expected 0)</span><br><span style="color: hsl(120, 100%, 40%);">+#03 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0)</span><br><span style="color: hsl(120, 100%, 40%);">+#03 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#03 lchan_bs_pwr_ctrl() -> BS power reduction: 0 -> 0 (expected 0)</span><br><span style="color: hsl(120, 100%, 40%);">+#04 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0)</span><br><span style="color: hsl(120, 100%, 40%);">+#04 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#04 lchan_bs_pwr_ctrl() -> BS power reduction: 0 -> 0 (expected 0)</span><br><span style="color: hsl(120, 100%, 40%);">+Test case verdict: SUCCESS</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Starting test case 'TC_rxlev_max_min'</span><br><span style="color: hsl(120, 100%, 40%);">+#00 exec_power_step() <- State (re)set (current 0 dB, max 20 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+#01 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0)</span><br><span style="color: hsl(120, 100%, 40%);">+#01 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 3c 3c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#01 lchan_bs_pwr_ctrl() -> BS power reduction: 0 -> 8 (expected 4)</span><br><span style="color: hsl(120, 100%, 40%);">+#02 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0)</span><br><span style="color: hsl(120, 100%, 40%);">+#02 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 3c 3c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#02 lchan_bs_pwr_ctrl() -> BS power reduction: 8 -> 16 (expected 8)</span><br><span style="color: hsl(120, 100%, 40%);">+#03 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0)</span><br><span style="color: hsl(120, 100%, 40%);">+#03 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 3c 3c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#03 lchan_bs_pwr_ctrl() -> BS power reduction: 16 -> 20 (expected 12)</span><br><span style="color: hsl(120, 100%, 40%);">+#04 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0)</span><br><span style="color: hsl(120, 100%, 40%);">+#04 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 3c 3c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#04 lchan_bs_pwr_ctrl() -> BS power reduction: 20 -> 20 (expected 16)</span><br><span style="color: hsl(120, 100%, 40%);">+#05 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0)</span><br><span style="color: hsl(120, 100%, 40%);">+#05 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 3c 3c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#05 lchan_bs_pwr_ctrl() -> BS power reduction: 20 -> 20 (expected 20)</span><br><span style="color: hsl(120, 100%, 40%);">+#06 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0)</span><br><span style="color: hsl(120, 100%, 40%);">+#06 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 3c 3c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#06 lchan_bs_pwr_ctrl() -> BS power reduction: 20 -> 20 (expected 20)</span><br><span style="color: hsl(120, 100%, 40%);">+#07 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(60), RXQUAL-FULL(0), RXLEV-SUB(60), RXQUAL-SUB(0)</span><br><span style="color: hsl(120, 100%, 40%);">+#07 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 3c 3c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#07 lchan_bs_pwr_ctrl() -> BS power reduction: 20 -> 20 (expected 20)</span><br><span style="color: hsl(120, 100%, 40%);">+#08 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(10), RXQUAL-FULL(0), RXLEV-SUB(10), RXQUAL-SUB(0)</span><br><span style="color: hsl(120, 100%, 40%);">+#08 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 0a 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#08 lchan_bs_pwr_ctrl() -> BS power reduction: 20 -> 16 (expected 12)</span><br><span style="color: hsl(120, 100%, 40%);">+#09 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(10), RXQUAL-FULL(0), RXLEV-SUB(10), RXQUAL-SUB(0)</span><br><span style="color: hsl(120, 100%, 40%);">+#09 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 0a 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#09 lchan_bs_pwr_ctrl() -> BS power reduction: 16 -> 12 (expected 4)</span><br><span style="color: hsl(120, 100%, 40%);">+#10 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(10), RXQUAL-FULL(0), RXLEV-SUB(10), RXQUAL-SUB(0)</span><br><span style="color: hsl(120, 100%, 40%);">+#10 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 0a 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#10 lchan_bs_pwr_ctrl() -> BS power reduction: 12 -> 8 (expected 0)</span><br><span style="color: hsl(120, 100%, 40%);">+#11 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(10), RXQUAL-FULL(0), RXLEV-SUB(10), RXQUAL-SUB(0)</span><br><span style="color: hsl(120, 100%, 40%);">+#11 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 0a 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#11 lchan_bs_pwr_ctrl() -> BS power reduction: 8 -> 4 (expected 0)</span><br><span style="color: hsl(120, 100%, 40%);">+#12 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(10), RXQUAL-FULL(0), RXLEV-SUB(10), RXQUAL-SUB(0)</span><br><span style="color: hsl(120, 100%, 40%);">+#12 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 0a 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#12 lchan_bs_pwr_ctrl() -> BS power reduction: 4 -> 0 (expected 0)</span><br><span style="color: hsl(120, 100%, 40%);">+Test case verdict: FAIL</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Starting test case 'TC_dtxd_mode'</span><br><span style="color: hsl(120, 100%, 40%);">+#00 exec_power_step() <- State (re)set (current 0 dB, max 20 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+#01 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0)</span><br><span style="color: hsl(120, 100%, 40%);">+#01 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#01 lchan_bs_pwr_ctrl() -> BS power reduction: 0 -> 0 (expected 0)</span><br><span style="color: hsl(120, 100%, 40%);">+#02 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0)</span><br><span style="color: hsl(120, 100%, 40%);">+#02 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#02 lchan_bs_pwr_ctrl() -> BS power reduction: 0 -> 0 (expected 0)</span><br><span style="color: hsl(120, 100%, 40%);">+#03 exec_power_step() <- Enable DTXd</span><br><span style="color: hsl(120, 100%, 40%);">+#04 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(00), RXQUAL-FULL(7), RXLEV-SUB(30), RXQUAL-SUB(0)</span><br><span style="color: hsl(120, 100%, 40%);">+#04 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 00 1e 70 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#04 lchan_bs_pwr_ctrl() -> BS power reduction: 0 -> 0 (expected 0)</span><br><span style="color: hsl(120, 100%, 40%);">+#05 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(3), RXLEV-SUB(30), RXQUAL-SUB(0)</span><br><span style="color: hsl(120, 100%, 40%);">+#05 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 30 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#05 lchan_bs_pwr_ctrl() -> BS power reduction: 0 -> 0 (expected 0)</span><br><span style="color: hsl(120, 100%, 40%);">+#06 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(63), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0)</span><br><span style="color: hsl(120, 100%, 40%);">+#06 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 3f 1e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#06 lchan_bs_pwr_ctrl() -> BS power reduction: 0 -> 0 (expected 0)</span><br><span style="color: hsl(120, 100%, 40%);">+Test case verdict: SUCCESS</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Starting test case 'TC_rxqual_ber'</span><br><span style="color: hsl(120, 100%, 40%);">+#00 exec_power_step() <- State (re)set (current 16 dB, max 20 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+#01 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0)</span><br><span style="color: hsl(120, 100%, 40%);">+#01 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#01 lchan_bs_pwr_ctrl() -> BS power reduction: 16 -> 16 (expected 16)</span><br><span style="color: hsl(120, 100%, 40%);">+#02 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0)</span><br><span style="color: hsl(120, 100%, 40%);">+#02 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#02 lchan_bs_pwr_ctrl() -> BS power reduction: 16 -> 16 (expected 16)</span><br><span style="color: hsl(120, 100%, 40%);">+#03 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(7), RXLEV-SUB(30), RXQUAL-SUB(7)</span><br><span style="color: hsl(120, 100%, 40%);">+#03 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 7e 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#03 lchan_bs_pwr_ctrl() -> BS power reduction: 16 -> 8 (expected 8)</span><br><span style="color: hsl(120, 100%, 40%);">+#04 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(4), RXLEV-SUB(30), RXQUAL-SUB(4)</span><br><span style="color: hsl(120, 100%, 40%);">+#04 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 48 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#04 lchan_bs_pwr_ctrl() -> BS power reduction: 8 -> 4 (expected 4)</span><br><span style="color: hsl(120, 100%, 40%);">+#05 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(1), RXLEV-SUB(30), RXQUAL-SUB(1)</span><br><span style="color: hsl(120, 100%, 40%);">+#05 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 12 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#05 lchan_bs_pwr_ctrl() -> BS power reduction: 4 -> 2 (expected 2)</span><br><span style="color: hsl(120, 100%, 40%);">+#06 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0)</span><br><span style="color: hsl(120, 100%, 40%);">+#06 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#06 lchan_bs_pwr_ctrl() -> BS power reduction: 2 -> 2 (expected 2)</span><br><span style="color: hsl(120, 100%, 40%);">+#07 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0)</span><br><span style="color: hsl(120, 100%, 40%);">+#07 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#07 lchan_bs_pwr_ctrl() -> BS power reduction: 2 -> 2 (expected 2)</span><br><span style="color: hsl(120, 100%, 40%);">+#08 exec_power_step() <- State (re)set (current 16 dB, max 20 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+#09 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(7), RXLEV-SUB(30), RXQUAL-SUB(7)</span><br><span style="color: hsl(120, 100%, 40%);">+#09 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 7e 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#09 lchan_bs_pwr_ctrl() -> BS power reduction: 16 -> 8 (expected 8)</span><br><span style="color: hsl(120, 100%, 40%);">+#10 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(7), RXLEV-SUB(30), RXQUAL-SUB(7)</span><br><span style="color: hsl(120, 100%, 40%);">+#10 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 7e 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#10 lchan_bs_pwr_ctrl() -> BS power reduction: 8 -> 4 (expected 4)</span><br><span style="color: hsl(120, 100%, 40%);">+#11 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(7), RXLEV-SUB(30), RXQUAL-SUB(7)</span><br><span style="color: hsl(120, 100%, 40%);">+#11 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 7e 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#11 lchan_bs_pwr_ctrl() -> BS power reduction: 4 -> 2 (expected 2)</span><br><span style="color: hsl(120, 100%, 40%);">+#12 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(7), RXLEV-SUB(30), RXQUAL-SUB(7)</span><br><span style="color: hsl(120, 100%, 40%);">+#12 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 7e 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#12 lchan_bs_pwr_ctrl() -> BS power reduction: 2 -> 1 (expected 1)</span><br><span style="color: hsl(120, 100%, 40%);">+#13 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(7), RXLEV-SUB(30), RXQUAL-SUB(7)</span><br><span style="color: hsl(120, 100%, 40%);">+#13 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 7e 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#13 lchan_bs_pwr_ctrl() -> BS power reduction: 1 -> 0 (expected 0)</span><br><span style="color: hsl(120, 100%, 40%);">+Test case verdict: SUCCESS</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Starting test case 'TC_inval_dummy'</span><br><span style="color: hsl(120, 100%, 40%);">+#00 exec_power_step() <- State (re)set (current 16 dB, max 20 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+#01 enc_meas_rep() -> Measurement Results (invalid): RXLEV-FULL(63), RXQUAL-FULL(7), RXLEV-SUB(63), RXQUAL-SUB(7)</span><br><span style="color: hsl(120, 100%, 40%);">+#01 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 3f 7f 7e 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#01 lchan_bs_pwr_ctrl() -> BS power reduction: 16 -> 16 (expected 16)</span><br><span style="color: hsl(120, 100%, 40%);">+#02 enc_meas_rep() -> Measurement Results (invalid): RXLEV-FULL(00), RXQUAL-FULL(0), RXLEV-SUB(00), RXQUAL-SUB(0)</span><br><span style="color: hsl(120, 100%, 40%);">+#02 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#02 lchan_bs_pwr_ctrl() -> BS power reduction: 16 -> 16 (expected 16)</span><br><span style="color: hsl(120, 100%, 40%);">+#03 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0)</span><br><span style="color: hsl(120, 100%, 40%);">+#03 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#03 lchan_bs_pwr_ctrl() -> BS power reduction: 16 -> 16 (expected 16)</span><br><span style="color: hsl(120, 100%, 40%);">+#04 exec_power_step() <- Dummy block</span><br><span style="color: hsl(120, 100%, 40%);">+#04 lchan_bs_pwr_ctrl() <- UL SACCH: 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b </span><br><span style="color: hsl(120, 100%, 40%);">+#04 lchan_bs_pwr_ctrl() -> BS power reduction: 16 -> 16 (expected 16)</span><br><span style="color: hsl(120, 100%, 40%);">+#05 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0)</span><br><span style="color: hsl(120, 100%, 40%);">+#05 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#05 lchan_bs_pwr_ctrl() -> BS power reduction: 16 -> 16 (expected 16)</span><br><span style="color: hsl(120, 100%, 40%);">+#06 exec_power_step() <- Dummy block</span><br><span style="color: hsl(120, 100%, 40%);">+#06 lchan_bs_pwr_ctrl() <- UL SACCH: 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b </span><br><span style="color: hsl(120, 100%, 40%);">+#06 lchan_bs_pwr_ctrl() -> BS power reduction: 16 -> 16 (expected 16)</span><br><span style="color: hsl(120, 100%, 40%);">+#07 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0)</span><br><span style="color: hsl(120, 100%, 40%);">+#07 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#07 lchan_bs_pwr_ctrl() -> BS power reduction: 16 -> 16 (expected 16)</span><br><span style="color: hsl(120, 100%, 40%);">+Test case verdict: SUCCESS</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Starting test case 'TC_rxlev_hyst'</span><br><span style="color: hsl(120, 100%, 40%);">+#00 exec_power_step() <- State (re)set (current 12 dB, max 16 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+#01 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(31), RXQUAL-FULL(0), RXLEV-SUB(31), RXQUAL-SUB(0)</span><br><span style="color: hsl(120, 100%, 40%);">+#01 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1f 1f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#01 lchan_bs_pwr_ctrl() -> BS power reduction: 12 -> 13 (expected 13)</span><br><span style="color: hsl(120, 100%, 40%);">+#02 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(28), RXQUAL-FULL(0), RXLEV-SUB(28), RXQUAL-SUB(0)</span><br><span style="color: hsl(120, 100%, 40%);">+#02 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1c 1c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#02 lchan_bs_pwr_ctrl() -> BS power reduction: 13 -> 11 (expected 11)</span><br><span style="color: hsl(120, 100%, 40%);">+#03 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(33), RXQUAL-FULL(0), RXLEV-SUB(33), RXQUAL-SUB(0)</span><br><span style="color: hsl(120, 100%, 40%);">+#03 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 21 21 00 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#03 lchan_bs_pwr_ctrl() -> BS power reduction: 11 -> 14 (expected 14)</span><br><span style="color: hsl(120, 100%, 40%);">+#04 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(28), RXQUAL-FULL(0), RXLEV-SUB(28), RXQUAL-SUB(0)</span><br><span style="color: hsl(120, 100%, 40%);">+#04 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1c 1c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#04 lchan_bs_pwr_ctrl() -> BS power reduction: 14 -> 12 (expected 12)</span><br><span style="color: hsl(120, 100%, 40%);">+#05 exec_power_step() <- Param (re)set (target -80 dBm, hysteresis 3 dB, filtering is disabled)</span><br><span style="color: hsl(120, 100%, 40%);">+#06 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(31), RXQUAL-FULL(0), RXLEV-SUB(31), RXQUAL-SUB(0)</span><br><span style="color: hsl(120, 100%, 40%);">+#06 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1f 1f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#06 lchan_bs_pwr_ctrl() -> BS power reduction: 12 -> 12 (expected 12)</span><br><span style="color: hsl(120, 100%, 40%);">+#07 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(28), RXQUAL-FULL(0), RXLEV-SUB(28), RXQUAL-SUB(0)</span><br><span style="color: hsl(120, 100%, 40%);">+#07 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1c 1c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#07 lchan_bs_pwr_ctrl() -> BS power reduction: 12 -> 12 (expected 12)</span><br><span style="color: hsl(120, 100%, 40%);">+#08 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(33), RXQUAL-FULL(0), RXLEV-SUB(33), RXQUAL-SUB(0)</span><br><span style="color: hsl(120, 100%, 40%);">+#08 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 21 21 00 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#08 lchan_bs_pwr_ctrl() -> BS power reduction: 12 -> 12 (expected 12)</span><br><span style="color: hsl(120, 100%, 40%);">+#09 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(28), RXQUAL-FULL(0), RXLEV-SUB(28), RXQUAL-SUB(0)</span><br><span style="color: hsl(120, 100%, 40%);">+#09 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1c 1c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#09 lchan_bs_pwr_ctrl() -> BS power reduction: 12 -> 12 (expected 12)</span><br><span style="color: hsl(120, 100%, 40%);">+Test case verdict: SUCCESS</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Starting test case 'TC_rxlev_pf_ewma'</span><br><span style="color: hsl(120, 100%, 40%);">+#00 exec_power_step() <- State (re)set (current 16 dB, max 30 dB)</span><br><span style="color: hsl(120, 100%, 40%);">+#01 exec_power_step() <- Param (re)set (target -80 dBm, hysteresis 0 dB, filtering is enabled)</span><br><span style="color: hsl(120, 100%, 40%);">+#02 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0)</span><br><span style="color: hsl(120, 100%, 40%);">+#02 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#02 lchan_bs_pwr_ctrl() -> BS power reduction: 16 -> 16 (expected 16)</span><br><span style="color: hsl(120, 100%, 40%);">+#03 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0)</span><br><span style="color: hsl(120, 100%, 40%);">+#03 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#03 lchan_bs_pwr_ctrl() -> BS power reduction: 16 -> 16 (expected 16)</span><br><span style="color: hsl(120, 100%, 40%);">+#04 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(26), RXQUAL-FULL(0), RXLEV-SUB(26), RXQUAL-SUB(0)</span><br><span style="color: hsl(120, 100%, 40%);">+#04 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1a 1a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#04 lchan_bs_pwr_ctrl() -> BS power reduction: 16 -> 14 (expected 14)</span><br><span style="color: hsl(120, 100%, 40%);">+#05 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(26), RXQUAL-FULL(0), RXLEV-SUB(26), RXQUAL-SUB(0)</span><br><span style="color: hsl(120, 100%, 40%);">+#05 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1a 1a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#05 lchan_bs_pwr_ctrl() -> BS power reduction: 14 -> 11 (expected 11)</span><br><span style="color: hsl(120, 100%, 40%);">+#06 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(35), RXQUAL-FULL(0), RXLEV-SUB(35), RXQUAL-SUB(0)</span><br><span style="color: hsl(120, 100%, 40%);">+#06 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 23 23 00 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#06 lchan_bs_pwr_ctrl() -> BS power reduction: 11 -> 12 (expected 12)</span><br><span style="color: hsl(120, 100%, 40%);">+#07 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(35), RXQUAL-FULL(0), RXLEV-SUB(35), RXQUAL-SUB(0)</span><br><span style="color: hsl(120, 100%, 40%);">+#07 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 23 23 00 00 00 00 00 00 00 00 00 00 00 00 00 00 </span><br><span style="color: hsl(120, 100%, 40%);">+#07 lchan_bs_pwr_ctrl() -> BS power reduction: 12 -> 15 (expected 15)</span><br><span style="color: hsl(120, 100%, 40%);">+Test case verdict: SUCCESS</span><br><span>diff --git a/tests/testsuite.at b/tests/testsuite.at</span><br><span>index 0590580..ba5a409 100644</span><br><span>--- a/tests/testsuite.at</span><br><span>+++ b/tests/testsuite.at</span><br><span>@@ -38,6 +38,13 @@</span><br><span> AT_CHECK([$abs_top_builddir/tests/power/ms_power_loop_test], [], [expout], [experr])</span><br><span> AT_CLEANUP</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+AT_SETUP([bs_power_loop])</span><br><span style="color: hsl(120, 100%, 40%);">+AT_KEYWORDS([power])</span><br><span style="color: hsl(120, 100%, 40%);">+cat $abs_srcdir/power/bs_power_loop_test.ok > expout</span><br><span style="color: hsl(120, 100%, 40%);">+cat $abs_srcdir/power/bs_power_loop_test.err > experr</span><br><span style="color: hsl(120, 100%, 40%);">+AT_CHECK([$abs_top_builddir/tests/power/bs_power_loop_test], [], [expout], [experr])</span><br><span style="color: hsl(120, 100%, 40%);">+AT_CLEANUP</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> AT_SETUP([tx_power])</span><br><span> AT_KEYWORDS([tx_power])</span><br><span> cat $abs_srcdir/tx_power/tx_power_test.ok > expout</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-bts/+/21447">change 21447</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/+/21447"/><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: I5b509e71d5f668b6b8b2abf8053c27f2a7c78451 </div>
<div style="display:none"> Gerrit-Change-Number: 21447 </div>
<div style="display:none"> Gerrit-PatchSet: 5 </div>
<div style="display:none"> Gerrit-Owner: fixeria <vyanitskiy@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>