<p>fixeria has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/osmo-bts/+/21993">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">power_control: migrate MS/BS control loops to the new params<br><br>In change [1] the new power control structures and default params<br>were introduced.  In change [2], the existing VTY commands for MS<br>power control in the BTS were deprecated and changed to use the<br>new structures as storage.  Finally, in change [3], handling of<br>the power control parameters on the A-bis/RSL was implemented.<br><br>This change is the final logical step in the mentioned chain: it<br>makes both MS/BS power control loops use the new parameters, and<br>removes the old structures.  The actual implementation of both<br>power control loops remains the same, however the expected output<br>of some unit tests for the Downlink loop needs to be changed:<br><br>  - TC_fixed_mode: disabling dynamic power control becomes a separate<br>    step of the test script since the field 'fixed' is removed;<br><br>  - TC_rxlev_target: RxLev thresholds are printed 'as-is'.<br><br>Not all of the new parameters are used by the power control loops<br>yet.  Further improvements to be done in the follow up commits.<br><br>[1] I6d41eb238aa6d4f5b77596c5477c2ecbe86de2a8<br>[2] Icbd9a7d31ce6723294130a31a179a002fccb4612<br>[3] I5a901eca5a78a0335a6954064e602e65cda85390<br><br>Change-Id: Ib18f84c40227841d95a36063a6789bf63054fc2e<br>Related: SYS#4918<br>---<br>M include/osmo-bts/bts.h<br>M include/osmo-bts/gsm_data.h<br>M src/common/bts.c<br>M src/common/power_control.c<br>M src/common/rsl.c<br>M src/common/vty.c<br>M src/osmo-bts-trx/trx_vty.c<br>M tests/power/bs_power_loop_test.c<br>M tests/power/bs_power_loop_test.ok<br>M tests/power/ms_power_loop_test.c<br>10 files changed, 140 insertions(+), 144 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/osmo-bts refs/changes/93/21993/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/osmo-bts/bts.h b/include/osmo-bts/bts.h</span><br><span>index 0b224be..f6389ad 100644</span><br><span>--- a/include/osmo-bts/bts.h</span><br><span>+++ b/include/osmo-bts/bts.h</span><br><span>@@ -321,10 +321,6 @@</span><br><span>              bool vty_override;      /* OML value overridden by VTY */</span><br><span>    } radio_link_timeout;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       /* Uplink/Downlink power control (legacy parameters) */</span><br><span style="color: hsl(0, 100%, 40%);">- struct bts_power_ctrl_params ul_power_ctrl;</span><br><span style="color: hsl(0, 100%, 40%);">-     struct bts_power_ctrl_params dl_power_ctrl;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>  /* Default (fall-back) Dynamic Power Control parameters for all transceivers */</span><br><span>      struct gsm_power_ctrl_params bs_dpc_params; /* BS Dynamic Power Control */</span><br><span>   struct gsm_power_ctrl_params ms_dpc_params; /* MS Dynamic Power Control */</span><br><span>diff --git a/include/osmo-bts/gsm_data.h b/include/osmo-bts/gsm_data.h</span><br><span>index b9e0e88..6efc717 100644</span><br><span>--- a/include/osmo-bts/gsm_data.h</span><br><span>+++ b/include/osmo-bts/gsm_data.h</span><br><span>@@ -222,7 +222,6 @@</span><br><span>     * (attenuation, in dB). */</span><br><span>  uint8_t current;</span><br><span>     uint8_t max;</span><br><span style="color: hsl(0, 100%, 40%);">-    bool fixed;</span><br><span> </span><br><span>      /* Scaled up (100 times) average UL/DL RxLev (in dBm) */</span><br><span>     int avg100_rxlev_dbm;</span><br><span>diff --git a/src/common/bts.c b/src/common/bts.c</span><br><span>index de07957..06a5ccb 100644</span><br><span>--- a/src/common/bts.c</span><br><span>+++ b/src/common/bts.c</span><br><span>@@ -330,22 +330,6 @@</span><br><span>    bts->rtp_port_range_next = bts->rtp_port_range_start;</span><br><span>  bts->rtp_ip_dscp = -1;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   /* Default UL/DL power control parameters (legacy) */</span><br><span style="color: hsl(0, 100%, 40%);">-   bts->ul_power_ctrl = bts->dl_power_ctrl = \</span><br><span style="color: hsl(0, 100%, 40%);">-       (struct bts_power_ctrl_params) {</span><br><span style="color: hsl(0, 100%, 40%);">-                .target_dbm = -75,</span><br><span style="color: hsl(0, 100%, 40%);">-              .hysteresis_db = 3,     /* -78 .. -72 dBm */</span><br><span style="color: hsl(0, 100%, 40%);">-            .raise_step_max_db = PWR_RAISE_MAX_DB,</span><br><span style="color: hsl(0, 100%, 40%);">-          .lower_step_max_db = PWR_LOWER_MAX_DB,</span><br><span style="color: hsl(0, 100%, 40%);">-          .pf_algo = BTS_PF_ALGO_EWMA,</span><br><span style="color: hsl(0, 100%, 40%);">-            .pf = {</span><br><span style="color: hsl(0, 100%, 40%);">-                 .ewma = {</span><br><span style="color: hsl(0, 100%, 40%);">-                               /* 50% smoothing */</span><br><span style="color: hsl(0, 100%, 40%);">-                             .alpha = 50</span><br><span style="color: hsl(0, 100%, 40%);">-                     }</span><br><span style="color: hsl(0, 100%, 40%);">-               }</span><br><span style="color: hsl(0, 100%, 40%);">-       };</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>   /* Default (fall-back) MS/BS Power control parameters */</span><br><span>     bts->bs_dpc_params = power_ctrl_params_def;</span><br><span>       bts->ms_dpc_params = power_ctrl_params_def;</span><br><span>diff --git a/src/common/power_control.c b/src/common/power_control.c</span><br><span>index 44a8046..45d06cc 100644</span><br><span>--- a/src/common/power_control.c</span><br><span>+++ b/src/common/power_control.c</span><br><span>@@ -82,42 +82,52 @@</span><br><span>    return *Avg100 / EWMA_SCALE_FACTOR;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* Calculate target RxLev value from lower/upper thresholds */</span><br><span style="color: hsl(120, 100%, 40%);">+#define CALC_TARGET(mp) \</span><br><span style="color: hsl(120, 100%, 40%);">+       (mp.lower_thresh + mp.upper_thresh) / 2</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* Calculate a 'delta' value (for the given MS/BS power control state and parameters)</span><br><span>  * to be applied to the current Tx power level to approach the target level. */</span><br><span style="color: hsl(0, 100%, 40%);">-static int calc_delta(const struct bts_power_ctrl_params *params,</span><br><span style="color: hsl(120, 100%, 40%);">+static int calc_delta(const struct gsm_power_ctrl_params *params,</span><br><span>                  struct lchan_power_ctrl_state *state,</span><br><span>                const int rxlev_dbm)</span><br><span> {</span><br><span>      int rxlev_dbm_avg;</span><br><span style="color: hsl(120, 100%, 40%);">+    uint8_t rxlev_avg;</span><br><span>   int delta;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  /* Filter input value(s) to reduce unnecessary Tx power oscillations */</span><br><span style="color: hsl(0, 100%, 40%);">- switch (params->pf_algo) {</span><br><span style="color: hsl(0, 100%, 40%);">-   case BTS_PF_ALGO_EWMA:</span><br><span style="color: hsl(120, 100%, 40%);">+        /* Filter RxLev value to reduce unnecessary Tx power oscillations */</span><br><span style="color: hsl(120, 100%, 40%);">+  switch (params->rxlev_meas.algo) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case GSM_PWR_CTRL_MEAS_AVG_ALGO_OSMO_EWMA:</span><br><span>           rxlev_dbm_avg = do_pf_ewma(&state->avg100_rxlev_dbm, rxlev_dbm,</span><br><span style="color: hsl(0, 100%, 40%);">-                                     params->pf.ewma.alpha);</span><br><span style="color: hsl(120, 100%, 40%);">+                                    params->rxlev_meas.ewma.alpha);</span><br><span>                break;</span><br><span style="color: hsl(0, 100%, 40%);">-  case BTS_PF_ALGO_NONE:</span><br><span style="color: hsl(120, 100%, 40%);">+        /* TODO: implement other pre-processing methods */</span><br><span style="color: hsl(120, 100%, 40%);">+    case GSM_PWR_CTRL_MEAS_AVG_ALGO_NONE:</span><br><span>        default:</span><br><span>             /* No filtering (pass through) */</span><br><span>            rxlev_dbm_avg = rxlev_dbm;</span><br><span>   }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* FIXME: avoid this conversion, accept RxLev as-is */</span><br><span style="color: hsl(120, 100%, 40%);">+        rxlev_avg = dbm2rxlev(rxlev_dbm_avg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /* Check if RxLev is within the threshold window */</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rxlev_avg >= params->rxlev_meas.lower_thresh &&</span><br><span style="color: hsl(120, 100%, 40%);">+         rxlev_avg <= params->rxlev_meas.upper_thresh)</span><br><span style="color: hsl(120, 100%, 40%);">+               return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  /* How many dBs measured power should be increased (+) or decreased (-)</span><br><span>       * to reach expected power. */</span><br><span style="color: hsl(0, 100%, 40%);">-  delta = params->target_dbm - rxlev_dbm_avg;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  /* Tolerate small deviations from 'rx-target' */</span><br><span style="color: hsl(0, 100%, 40%);">-        if (abs(delta) <= params->hysteresis_db)</span><br><span style="color: hsl(0, 100%, 40%);">-          return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     delta = CALC_TARGET(params->rxlev_meas) - rxlev_avg;</span><br><span> </span><br><span>  /* Don't ever change more than PWR_{LOWER,RAISE}_MAX_DBM during one loop</span><br><span>          * iteration, i.e. reduce the speed at which the MS transmit power can</span><br><span>        * change. A higher value means a lower level (and vice versa) */</span><br><span style="color: hsl(0, 100%, 40%);">-       if (delta > params->raise_step_max_db)</span><br><span style="color: hsl(0, 100%, 40%);">-            delta = params->raise_step_max_db;</span><br><span style="color: hsl(0, 100%, 40%);">-   else if (delta < -params->lower_step_max_db)</span><br><span style="color: hsl(0, 100%, 40%);">-              delta = -params->lower_step_max_db;</span><br><span style="color: hsl(120, 100%, 40%);">+        if (delta > params->inc_step_size_db)</span><br><span style="color: hsl(120, 100%, 40%);">+           delta = params->inc_step_size_db;</span><br><span style="color: hsl(120, 100%, 40%);">+  else if (delta < -params->red_step_size_db)</span><br><span style="color: hsl(120, 100%, 40%);">+             delta = -params->red_step_size_db;</span><br><span> </span><br><span>    return delta;</span><br><span> }</span><br><span>@@ -131,18 +141,17 @@</span><br><span>                 const uint8_t ms_power_lvl,</span><br><span>                  const int8_t ul_rssi_dbm)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+  struct lchan_power_ctrl_state *state = &lchan->ms_power_ctrl;</span><br><span style="color: hsl(120, 100%, 40%);">+  const struct gsm_power_ctrl_params *params = state->dpc_params;</span><br><span>   struct gsm_bts_trx *trx = lchan->ts->trx;</span><br><span>      struct gsm_bts *bts = trx->bts;</span><br><span>   enum gsm_band band = bts->band;</span><br><span>   int8_t new_power_lvl; /* TS 05.05 power level */</span><br><span>     int8_t ms_dbm, new_dbm, current_dbm, bsc_max_dbm;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   const struct bts_power_ctrl_params *params = &bts->ul_power_ctrl;</span><br><span style="color: hsl(0, 100%, 40%);">-        struct lchan_power_ctrl_state *state = &lchan->ms_power_ctrl;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>         if (!trx_ms_pwr_ctrl_is_osmo(trx))</span><br><span>           return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-       if (state->fixed)</span><br><span style="color: hsl(120, 100%, 40%);">+  if (params == NULL)</span><br><span>          return 0;</span><br><span> </span><br><span>        ms_dbm = ms_pwr_dbm(band, ms_power_lvl);</span><br><span>@@ -180,11 +189,14 @@</span><br><span>             return 0;</span><br><span>    }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* FIXME: this is only needed for logging, print thresholds instead */</span><br><span style="color: hsl(120, 100%, 40%);">+        int target_dbm = rxlev2dbm(CALC_TARGET(params->rxlev_meas));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>    if (state->current == new_power_lvl) {</span><br><span>            LOGPLCHAN(lchan, DLOOP, LOGL_INFO, "Keeping MS power at control level %d, %d dBm "</span><br><span>                           "(rx-ms-pwr-lvl %" PRIu8 ", max-ms-pwr-lvl %" PRIu8 ", rx-current %d dBm, rx-target %d dBm)\n",</span><br><span>                        new_power_lvl, new_dbm, ms_power_lvl, state->max,</span><br><span style="color: hsl(0, 100%, 40%);">-                    ul_rssi_dbm, params->target_dbm);</span><br><span style="color: hsl(120, 100%, 40%);">+                          ul_rssi_dbm, target_dbm);</span><br><span>          return 0;</span><br><span>    }</span><br><span> </span><br><span>@@ -193,7 +205,7 @@</span><br><span>            "(rx-ms-pwr-lvl %" PRIu8 ", max-ms-pwr-lvl %" PRIu8 ", rx-current %d dBm, rx-target %d dBm)\n",</span><br><span>                (new_dbm > current_dbm) ? "Raising" : "Lowering",</span><br><span>             state->current, current_dbm, new_power_lvl, new_dbm,</span><br><span style="color: hsl(0, 100%, 40%);">-                 ms_power_lvl, state->max, ul_rssi_dbm, params->target_dbm);</span><br><span style="color: hsl(120, 100%, 40%);">+             ms_power_lvl, state->max, ul_rssi_dbm, target_dbm);</span><br><span> </span><br><span>         /* store the resulting new MS power level in the lchan */</span><br><span>    state->current = new_power_lvl;</span><br><span>@@ -209,18 +221,15 @@</span><br><span> int lchan_bs_pwr_ctrl(struct gsm_lchan *lchan,</span><br><span>                       const struct gsm48_hdr *gh)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-  struct gsm_bts_trx *trx = lchan->ts->trx;</span><br><span style="color: hsl(0, 100%, 40%);">- struct gsm_bts *bts = trx->bts;</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%);">+  const struct gsm_power_ctrl_params *params = state->dpc_params;</span><br><span>   uint8_t rxqual_full, rxqual_sub;</span><br><span>     uint8_t rxlev_full, rxlev_sub;</span><br><span>       uint8_t rxqual, rxlev;</span><br><span>       int delta, new;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     const struct bts_power_ctrl_params *params = &bts->dl_power_ctrl;</span><br><span style="color: hsl(0, 100%, 40%);">-        struct lchan_power_ctrl_state *state = &lchan->bs_power_ctrl;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    /* Check if BS Power Control is enabled */</span><br><span style="color: hsl(0, 100%, 40%);">-      if (state->fixed)</span><br><span style="color: hsl(120, 100%, 40%);">+  /* Check if dynamic BS Power Control is enabled */</span><br><span style="color: hsl(120, 100%, 40%);">+    if (params == NULL)</span><br><span>          return 0;</span><br><span>    /* Check if this is a Measurement Report */</span><br><span>  if (gh->proto_discr != GSM48_PDISC_RR)</span><br><span>@@ -260,7 +269,7 @@</span><br><span>      }</span><br><span> </span><br><span>        /* Bit Error Rate > 0 => reduce by 2 */</span><br><span style="color: hsl(0, 100%, 40%);">-   if (rxqual > 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+  if (rxqual > 0) { /* FIXME: take RxQual threshold into account */</span><br><span>                 LOGPLCHAN(lchan, DLOOP, LOGL_INFO, "Reducing Downlink attenuation "</span><br><span>                          "by half: %u -> %u dB due to RXQUAL %u > 0\n",</span><br><span>                       state->current, state->current / 2, rxqual);</span><br><span>@@ -290,16 +299,19 @@</span><br><span>         if (new < 0)</span><br><span>              new = 0;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+  /* FIXME: this is only needed for logging, print thresholds instead */</span><br><span style="color: hsl(120, 100%, 40%);">+        int target_dbm = rxlev2dbm(CALC_TARGET(params->rxlev_meas));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>    if (state->current != new) {</span><br><span>              LOGPLCHAN(lchan, DLOOP, LOGL_INFO, "Changing Downlink attenuation: "</span><br><span>                         "%u -> %u dB (maximum %u dB, target %d dBm, delta %d dB)\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                       state->current, new, state->max, params->target_dbm, delta);</span><br><span style="color: hsl(120, 100%, 40%);">+                         state->current, new, state->max, target_dbm, delta);</span><br><span>                 state->current = new;</span><br><span>             return 1;</span><br><span>    } else {</span><br><span>             LOGPLCHAN(lchan, DLOOP, LOGL_INFO, "Keeping Downlink attenuation "</span><br><span>                           "at %u dB (maximum %u dB, target %d dBm, delta %d dB)\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                     state->current, state->max, params->target_dbm, delta);</span><br><span style="color: hsl(120, 100%, 40%);">+                      state->current, state->max, target_dbm, delta);</span><br><span>              return 0;</span><br><span>    }</span><br><span> }</span><br><span>diff --git a/src/common/rsl.c b/src/common/rsl.c</span><br><span>index bca365e..b4df22c 100644</span><br><span>--- a/src/common/rsl.c</span><br><span>+++ b/src/common/rsl.c</span><br><span>@@ -1322,14 +1322,12 @@</span><br><span>        lchan->ms_power_ctrl = (struct lchan_power_ctrl_state) {</span><br><span>          .max = ms_pwr_ctl_lvl(lchan->ts->trx->bts->band, 0),</span><br><span>             .current = lchan->ms_power_ctrl.max,</span><br><span style="color: hsl(0, 100%, 40%);">-         .fixed = true,</span><br><span>       };</span><br><span> </span><br><span>       /* Initialize BS Power Control defaults */</span><br><span>   lchan->bs_power_ctrl = (struct lchan_power_ctrl_state) {</span><br><span>          .max = 2 * 15, /* maximum defined in 9.3.4 */</span><br><span>                .current = 0,</span><br><span style="color: hsl(0, 100%, 40%);">-           .fixed = true,</span><br><span>       };</span><br><span> </span><br><span>       rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg));</span><br><span>@@ -1414,7 +1412,6 @@</span><br><span>               /* Spec explicitly states BTS should only perform</span><br><span>            * autonomous MS power control loop in BTS if 'MS Power</span><br><span>           * Parameters' IE is present! */</span><br><span style="color: hsl(0, 100%, 40%);">-             lchan->ms_power_ctrl.fixed = false;</span><br><span>               lchan->ms_power_ctrl.dpc_params = params;</span><br><span>         }</span><br><span> </span><br><span>@@ -1433,7 +1430,6 @@</span><br><span> </span><br><span>            /* NOTE: it's safer to start from 0 */</span><br><span>           lchan->bs_power_ctrl.current = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-            lchan->bs_power_ctrl.fixed = false;</span><br><span>               lchan->bs_power_ctrl.dpc_params = params;</span><br><span>         }</span><br><span> </span><br><span>@@ -1925,7 +1921,6 @@</span><br><span> </span><br><span>    /* Spec explicitly states BTS should only perform autonomous MS Power</span><br><span>         * control loop in BTS if 'MS Power Parameters' IE is present! */</span><br><span style="color: hsl(0, 100%, 40%);">-       lchan->ms_power_ctrl.fixed = !TLVP_PRESENT(&tp, RSL_IE_MS_POWER_PARAM);</span><br><span>       lchan->ms_power_ctrl.dpc_params = NULL;</span><br><span> </span><br><span>       /* 9.3.31 (TLV) MS Power Parameters IE (vendor specific) */</span><br><span>@@ -1946,7 +1941,7 @@</span><br><span> </span><br><span>      /* Only set current to max if actual value of current</span><br><span>           in dBm > value in dBm from max, or if fixed. */</span><br><span style="color: hsl(0, 100%, 40%);">-   if (lchan->ms_power_ctrl.fixed) {</span><br><span style="color: hsl(120, 100%, 40%);">+  if (lchan->ms_power_ctrl.dpc_params == NULL) {</span><br><span>            lchan->ms_power_ctrl.current = lchan->ms_power_ctrl.max;</span><br><span>       } else {</span><br><span>             max_pwr = ms_pwr_dbm(bts->band, lchan->ms_power_ctrl.max);</span><br><span>@@ -2005,12 +2000,10 @@</span><br><span>           /* NOTE: it's safer to start from 0 */</span><br><span>           lchan->bs_power_ctrl.current = 0;</span><br><span>                 lchan->bs_power_ctrl.max = new;</span><br><span style="color: hsl(0, 100%, 40%);">-              lchan->bs_power_ctrl.fixed = false;</span><br><span>               lchan->bs_power_ctrl.dpc_params = params;</span><br><span>         } else {</span><br><span>             lchan->bs_power_ctrl.dpc_params = NULL;</span><br><span>           lchan->bs_power_ctrl.current = new;</span><br><span style="color: hsl(0, 100%, 40%);">-          lchan->bs_power_ctrl.fixed = true;</span><br><span>        }</span><br><span> </span><br><span>        if (lchan->bs_power_ctrl.current != old) {</span><br><span>diff --git a/src/common/vty.c b/src/common/vty.c</span><br><span>index 326e332..4dff5cb 100644</span><br><span>--- a/src/common/vty.c</span><br><span>+++ b/src/common/vty.c</span><br><span>@@ -1421,13 +1421,12 @@</span><br><span>         const struct lchan_power_ctrl_state *st = &lchan->bs_power_ctrl;</span><br><span>      const struct gsm_bts_trx *trx = lchan->ts->trx;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       cfg_out(vty, "BS (Downlink) Power Control (%s):%s",</span><br><span style="color: hsl(0, 100%, 40%);">-           st->fixed ? "fixed" : "autonomous",</span><br><span style="color: hsl(0, 100%, 40%);">-              VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+ cfg_out(vty, "BS (Downlink) Power Control (%s mode):%s",</span><br><span style="color: hsl(120, 100%, 40%);">+            st->dpc_params ? "dynamic" : "static", VTY_NEWLINE);</span><br><span>  indent += 2;</span><br><span> </span><br><span>     cfg_out(vty, "Channel reduction: %u dB", st->current);</span><br><span style="color: hsl(0, 100%, 40%);">-     if (!st->fixed)</span><br><span style="color: hsl(120, 100%, 40%);">+    if (st->dpc_params != NULL)</span><br><span>               vty_out(vty, " (max %u dB)", st->max);</span><br><span>  vty_out(vty, "%s", VTY_NEWLINE);</span><br><span> </span><br><span>@@ -1452,8 +1451,7 @@</span><br><span>       const struct gsm_bts_trx *trx = lchan->ts->trx;</span><br><span> </span><br><span>    cfg_out(vty, "MS (Uplink) Power Control (%s):%s",</span><br><span style="color: hsl(0, 100%, 40%);">-             st->fixed ? "fixed" : "autonomous",</span><br><span style="color: hsl(0, 100%, 40%);">-              VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+         st->dpc_params ? "dynamic" : "static", VTY_NEWLINE);</span><br><span>  indent += 2;</span><br><span> </span><br><span>     int current_dbm = ms_pwr_dbm(trx->bts->band, st->current);</span><br><span>@@ -1461,7 +1459,7 @@</span><br><span> </span><br><span>      cfg_out(vty, "Current power level: %u, -%d dBm",</span><br><span>           st->current, current_dbm);</span><br><span style="color: hsl(0, 100%, 40%);">-   if (!st->fixed)</span><br><span style="color: hsl(120, 100%, 40%);">+    if (st->dpc_params != NULL)</span><br><span>               vty_out(vty, " (max %u, -%d dBm)", st->max, max_dbm);</span><br><span>   vty_out(vty, "%s", VTY_NEWLINE);</span><br><span> </span><br><span>diff --git a/src/osmo-bts-trx/trx_vty.c b/src/osmo-bts-trx/trx_vty.c</span><br><span>index 49403d4..8e701ea 100644</span><br><span>--- a/src/osmo-bts-trx/trx_vty.c</span><br><span>+++ b/src/osmo-bts-trx/trx_vty.c</span><br><span>@@ -199,7 +199,9 @@</span><br><span>    vty_out(vty, "'%s' is deprecated, MS Power Control is now managed by BSC%s",</span><br><span>               self->string, VTY_NEWLINE);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      g_bts->ul_power_ctrl.target_dbm = atoi(argv[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t rxlev = dbm2rxlev(atoi(argv[0]));</span><br><span style="color: hsl(120, 100%, 40%);">+     g_bts->ms_dpc_params.rxlev_meas.lower_thresh = rxlev;</span><br><span style="color: hsl(120, 100%, 40%);">+      g_bts->ms_dpc_params.rxlev_meas.upper_thresh = rxlev;</span><br><span> </span><br><span>         return CMD_SUCCESS;</span><br><span> }</span><br><span>diff --git a/tests/power/bs_power_loop_test.c b/tests/power/bs_power_loop_test.c</span><br><span>index fd93183..ecd83e7 100644</span><br><span>--- a/tests/power/bs_power_loop_test.c</span><br><span>+++ b/tests/power/bs_power_loop_test.c</span><br><span>@@ -31,14 +31,9 @@</span><br><span> </span><br><span> #define PWR_TEST_RXLEV_TARGET 30</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-#define PWR_TEST_CFG_RXLEV_TARGET \</span><br><span style="color: hsl(0, 100%, 40%);">-       .target_dbm = -110 + PWR_TEST_RXLEV_TARGET</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/* NOTE: raise/lower values are intentionally swapped here,</span><br><span style="color: hsl(0, 100%, 40%);">- * as it makes more sense in the context of BS Power Control. */</span><br><span style="color: hsl(0, 100%, 40%);">-#define PWR_TEST_CFG_RAISE_LOWER_MAX \</span><br><span style="color: hsl(0, 100%, 40%);">-     .raise_step_max_db = PWR_LOWER_MAX_DB, \</span><br><span style="color: hsl(0, 100%, 40%);">-        .lower_step_max_db = PWR_RAISE_MAX_DB</span><br><span style="color: hsl(120, 100%, 40%);">+#define PWR_TEST_CFG_RXLEV_THRESH(hyst) \</span><br><span style="color: hsl(120, 100%, 40%);">+      .lower_thresh = PWR_TEST_RXLEV_TARGET - hyst, \</span><br><span style="color: hsl(120, 100%, 40%);">+       .upper_thresh = PWR_TEST_RXLEV_TARGET + hyst</span><br><span> </span><br><span> #define DL_MEAS_FULL(rxqual, rxlev) \</span><br><span>    .rxqual_full = rxqual, \</span><br><span>@@ -61,8 +56,9 @@</span><br><span>         PWR_TEST_ST_IND_MEAS = 0,</span><br><span>    PWR_TEST_ST_IND_DUMMY,</span><br><span>       PWR_TEST_ST_SET_STATE,</span><br><span style="color: hsl(0, 100%, 40%);">-  PWR_TEST_ST_SET_PARAMS,</span><br><span style="color: hsl(120, 100%, 40%);">+       PWR_TEST_ST_SET_RXLEV_PARAMS,</span><br><span>        PWR_TEST_ST_ENABLE_DTXD,</span><br><span style="color: hsl(120, 100%, 40%);">+      PWR_TEST_ST_DISABLE_DPC,</span><br><span> };</span><br><span> </span><br><span> struct power_test_step {</span><br><span>@@ -72,8 +68,8 @@</span><br><span>   union {</span><br><span>              /* Power Control state */</span><br><span>            struct lchan_power_ctrl_state state;</span><br><span style="color: hsl(0, 100%, 40%);">-            /* Power Control parameters */</span><br><span style="color: hsl(0, 100%, 40%);">-          struct bts_power_ctrl_params params;</span><br><span style="color: hsl(120, 100%, 40%);">+          /* Measurement pre-processing parameters */</span><br><span style="color: hsl(120, 100%, 40%);">+           struct gsm_power_ctrl_meas_params mp;</span><br><span>                /* Indicated DL measurements */</span><br><span>              struct {</span><br><span>                     uint8_t rxqual_full;</span><br><span>@@ -107,12 +103,6 @@</span><br><span>  g_bts->band = GSM_BAND_900;</span><br><span>       g_bts->c0 = g_trx;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       g_bts->dl_power_ctrl = g_bts->ul_power_ctrl = \</span><br><span style="color: hsl(0, 100%, 40%);">-   (struct bts_power_ctrl_params) {</span><br><span style="color: hsl(0, 100%, 40%);">-                PWR_TEST_CFG_RXLEV_TARGET,</span><br><span style="color: hsl(0, 100%, 40%);">-              PWR_TEST_CFG_RAISE_LOWER_MAX,</span><br><span style="color: hsl(0, 100%, 40%);">-   };</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>   printf("\nStarting test case '%s'\n", name);</span><br><span> }</span><br><span> </span><br><span>@@ -157,13 +147,18 @@</span><br><span>              printf("#%02u %s() <- State (re)set (current %u dB, max %u dB)\n",</span><br><span>                     n, __func__, step->state.current, step->state.max);</span><br><span>             lchan->bs_power_ctrl = step->state;</span><br><span style="color: hsl(120, 100%, 40%);">+             lchan->bs_power_ctrl.dpc_params = &lchan->bs_dpc_params;</span><br><span>           return 0; /* we're done */</span><br><span style="color: hsl(0, 100%, 40%);">-  case PWR_TEST_ST_SET_PARAMS:</span><br><span style="color: hsl(0, 100%, 40%);">-            printf("#%02u %s() <- Param (re)set (target %d dBm, hysteresis %u dB, "</span><br><span style="color: hsl(0, 100%, 40%);">-                                                "filtering is %sabled)\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                       n, __func__, step->params.target_dbm, step->params.hysteresis_db,</span><br><span style="color: hsl(0, 100%, 40%);">-                 step->params.pf_algo != BTS_PF_ALGO_NONE ? "en" : "dis");</span><br><span style="color: hsl(0, 100%, 40%);">-         g_bts->dl_power_ctrl = step->params;</span><br><span style="color: hsl(120, 100%, 40%);">+    case PWR_TEST_ST_DISABLE_DPC:</span><br><span style="color: hsl(120, 100%, 40%);">+         printf("#%02u %s() <- Dynamic power control is disabled\n", n, __func__);</span><br><span style="color: hsl(120, 100%, 40%);">+                lchan->bs_power_ctrl.dpc_params = NULL;</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_RXLEV_PARAMS:</span><br><span style="color: hsl(120, 100%, 40%);">+            printf("#%02u %s() <- (Re)set RxLev params (thresh %u .. %u, "</span><br><span style="color: hsl(120, 100%, 40%);">+                                                      "averaging is %sabled)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                      n, __func__, step->mp.lower_thresh, step->mp.upper_thresh,</span><br><span style="color: hsl(120, 100%, 40%);">+                      step->mp.algo != GSM_PWR_CTRL_MEAS_AVG_ALGO_NONE ? "en" : "dis");</span><br><span style="color: hsl(120, 100%, 40%);">+               lchan->bs_dpc_params.rxlev_meas = step->mp;</span><br><span>            return 0; /* we're done */</span><br><span>       case PWR_TEST_ST_ENABLE_DTXD:</span><br><span>                printf("#%02u %s() <- Enable DTXd\n", n, __func__);</span><br><span>@@ -202,6 +197,17 @@</span><br><span>      init_test(name);</span><br><span> </span><br><span>         struct gsm_lchan *lchan = &g_trx->ts[0].lchan[0];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    lchan->bs_dpc_params = (struct gsm_power_ctrl_params) {</span><br><span style="color: hsl(120, 100%, 40%);">+            /* NOTE: raise/lower values are intentionally swapped here,</span><br><span style="color: hsl(120, 100%, 40%);">+            * as it makes more sense in the context of BS Power Control. */</span><br><span style="color: hsl(120, 100%, 40%);">+              .inc_step_size_db = PWR_LOWER_MAX_DB,</span><br><span style="color: hsl(120, 100%, 40%);">+         .red_step_size_db = PWR_RAISE_MAX_DB,</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               /* RxLev pre-processing parameters */</span><br><span style="color: hsl(120, 100%, 40%);">+         .rxlev_meas = { PWR_TEST_CFG_RXLEV_THRESH(0) },</span><br><span style="color: hsl(120, 100%, 40%);">+       };</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         for (n = 0; n < num_steps; n++)</span><br><span>           rc |= exec_power_step(lchan, n, &steps[n]);</span><br><span> </span><br><span>@@ -212,7 +218,8 @@</span><br><span> static const struct power_test_step TC_fixed_mode[] = {</span><br><span>         /* Initial state: 10 dB, up to 20 dB */</span><br><span>      { .type = PWR_TEST_ST_SET_STATE,</span><br><span style="color: hsl(0, 100%, 40%);">-          .state = { .current = 10, .max = 2 * 10, .fixed = true } },</span><br><span style="color: hsl(120, 100%, 40%);">+   .state = { .current = 10, .max = 2 * 10 } },</span><br><span style="color: hsl(120, 100%, 40%);">+        { .type = PWR_TEST_ST_DISABLE_DPC },</span><br><span> </span><br><span>     /* MS indicates random RxQual/RxLev values, which must be ignored */</span><br><span>         { .meas = DL_MEAS_FULL_SUB(0, 63),      .exp_txred = 10 },</span><br><span>@@ -338,12 +345,8 @@</span><br><span>    { .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET - 2),       .exp_txred = 12 },</span><br><span> </span><br><span>       /* Enable hysteresis */</span><br><span style="color: hsl(0, 100%, 40%);">- { .type = PWR_TEST_ST_SET_PARAMS,</span><br><span style="color: hsl(0, 100%, 40%);">-         .params = {</span><br><span style="color: hsl(0, 100%, 40%);">-           PWR_TEST_CFG_RXLEV_TARGET,</span><br><span style="color: hsl(0, 100%, 40%);">-              PWR_TEST_CFG_RAISE_LOWER_MAX,</span><br><span style="color: hsl(0, 100%, 40%);">-           .hysteresis_db = 3,</span><br><span style="color: hsl(0, 100%, 40%);">-       }</span><br><span style="color: hsl(120, 100%, 40%);">+   { .type = PWR_TEST_ST_SET_RXLEV_PARAMS,</span><br><span style="color: hsl(120, 100%, 40%);">+         .mp = { PWR_TEST_CFG_RXLEV_THRESH(3) }</span><br><span>     },</span><br><span> </span><br><span>       /* Hysteresis is enabled, so small deviations do not trigger any changes */</span><br><span>@@ -359,13 +362,12 @@</span><br><span>  { .type = PWR_TEST_ST_SET_STATE,</span><br><span>       .state = { .current = 16, .max = 2 * 15 } },</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      /* Enable EWMA based power filtering */</span><br><span style="color: hsl(0, 100%, 40%);">- { .type = PWR_TEST_ST_SET_PARAMS,</span><br><span style="color: hsl(0, 100%, 40%);">-         .params = {</span><br><span style="color: hsl(0, 100%, 40%);">-           PWR_TEST_CFG_RXLEV_TARGET,</span><br><span style="color: hsl(0, 100%, 40%);">-              PWR_TEST_CFG_RAISE_LOWER_MAX,</span><br><span style="color: hsl(0, 100%, 40%);">-           .pf_algo = BTS_PF_ALGO_EWMA,</span><br><span style="color: hsl(0, 100%, 40%);">-            .pf.ewma.alpha = 50,</span><br><span style="color: hsl(120, 100%, 40%);">+  /* Enable EWMA based pre-processing for RxLev */</span><br><span style="color: hsl(120, 100%, 40%);">+      { .type = PWR_TEST_ST_SET_RXLEV_PARAMS,</span><br><span style="color: hsl(120, 100%, 40%);">+         .mp = {</span><br><span style="color: hsl(120, 100%, 40%);">+             PWR_TEST_CFG_RXLEV_THRESH(0),</span><br><span style="color: hsl(120, 100%, 40%);">+         .algo = GSM_PWR_CTRL_MEAS_AVG_ALGO_OSMO_EWMA,</span><br><span style="color: hsl(120, 100%, 40%);">+         .ewma.alpha = 50,</span><br><span>      }</span><br><span>  },</span><br><span> </span><br><span>diff --git a/tests/power/bs_power_loop_test.ok b/tests/power/bs_power_loop_test.ok</span><br><span>index acaad82..814f7e2 100644</span><br><span>--- a/tests/power/bs_power_loop_test.ok</span><br><span>+++ b/tests/power/bs_power_loop_test.ok</span><br><span>@@ -2,21 +2,22 @@</span><br><span> </span><br><span> Starting test case 'TC_fixed_mode'</span><br><span> #00 exec_power_step() <- State (re)set (current 10 dB, max 20 dB)</span><br><span style="color: hsl(0, 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(0, 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(0, 100%, 40%);">-#01 lchan_bs_pwr_ctrl() -> BS power reduction: 10 -> 10 (expected 10)</span><br><span style="color: hsl(0, 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(0, 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%);">+#01 exec_power_step() <- Dynamic power control is disabled</span><br><span style="color: hsl(120, 100%, 40%);">+#02 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%);">+#02 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> #02 lchan_bs_pwr_ctrl() -> BS power reduction: 10 -> 10 (expected 10)</span><br><span style="color: hsl(0, 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(0, 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 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%);">+#03 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> #03 lchan_bs_pwr_ctrl() -> BS power reduction: 10 -> 10 (expected 10)</span><br><span style="color: hsl(0, 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(0, 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 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> #04 lchan_bs_pwr_ctrl() -> BS power reduction: 10 -> 10 (expected 10)</span><br><span style="color: hsl(0, 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(0, 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 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> #05 lchan_bs_pwr_ctrl() -> BS power reduction: 10 -> 10 (expected 10)</span><br><span style="color: hsl(120, 100%, 40%);">+#06 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%);">+#06 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%);">+#06 lchan_bs_pwr_ctrl() -> BS power reduction: 10 -> 10 (expected 10)</span><br><span> Test case verdict: SUCCESS</span><br><span> </span><br><span> Starting test case 'TC_rxlev_target'</span><br><span>@@ -175,7 +176,7 @@</span><br><span> #04 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(28), RXQUAL-FULL(0), RXLEV-SUB(28), RXQUAL-SUB(0)</span><br><span> #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> #04 lchan_bs_pwr_ctrl() -> BS power reduction: 14 -> 12 (expected 12)</span><br><span style="color: hsl(0, 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%);">+#05 exec_power_step() <- (Re)set RxLev params (thresh 27 .. 33, averaging is disabled)</span><br><span> #06 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(31), RXQUAL-FULL(0), RXLEV-SUB(31), RXQUAL-SUB(0)</span><br><span> #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> #06 lchan_bs_pwr_ctrl() -> BS power reduction: 12 -> 12 (expected 12)</span><br><span>@@ -192,7 +193,7 @@</span><br><span> </span><br><span> Starting test case 'TC_rxlev_pf_ewma'</span><br><span> #00 exec_power_step() <- State (re)set (current 16 dB, max 30 dB)</span><br><span style="color: hsl(0, 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%);">+#01 exec_power_step() <- (Re)set RxLev params (thresh 30 .. 30, averaging is enabled)</span><br><span> #02 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0)</span><br><span> #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> #02 lchan_bs_pwr_ctrl() -> BS power reduction: 16 -> 16 (expected 16)</span><br><span>diff --git a/tests/power/ms_power_loop_test.c b/tests/power/ms_power_loop_test.c</span><br><span>index ea3c249..e93a2ef 100644</span><br><span>--- a/tests/power/ms_power_loop_test.c</span><br><span>+++ b/tests/power/ms_power_loop_test.c</span><br><span>@@ -28,6 +28,10 @@</span><br><span> </span><br><span> #include <stdio.h></span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#define PWR_TEST_RXLEV_TARGET_DBM   -75</span><br><span style="color: hsl(120, 100%, 40%);">+#define PWR_TEST_RXLEV_TARGET \</span><br><span style="color: hsl(120, 100%, 40%);">+  dbm2rxlev(PWR_TEST_RXLEV_TARGET_DBM)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static struct gsm_bts *g_bts = NULL;</span><br><span> static struct gsm_bts_trx *g_trx = NULL;</span><br><span> </span><br><span>@@ -50,12 +54,15 @@</span><br><span>         g_bts->band = GSM_BAND_1800;</span><br><span>      g_bts->c0 = g_trx;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       g_bts->ul_power_ctrl = g_bts->dl_power_ctrl = \</span><br><span style="color: hsl(0, 100%, 40%);">-   (struct bts_power_ctrl_params) {</span><br><span style="color: hsl(0, 100%, 40%);">-                .target_dbm = -75,</span><br><span style="color: hsl(0, 100%, 40%);">-              .raise_step_max_db = PWR_RAISE_MAX_DB,</span><br><span style="color: hsl(0, 100%, 40%);">-          .lower_step_max_db = PWR_LOWER_MAX_DB,</span><br><span style="color: hsl(0, 100%, 40%);">-  };</span><br><span style="color: hsl(120, 100%, 40%);">+    /* Init default MS power control parameters, enable dynamic power control */</span><br><span style="color: hsl(120, 100%, 40%);">+  struct gsm_power_ctrl_params *params = &g_trx->ts[0].lchan[0].ms_dpc_params;</span><br><span style="color: hsl(120, 100%, 40%);">+   g_trx->ts[0].lchan[0].ms_power_ctrl.dpc_params = params;</span><br><span style="color: hsl(120, 100%, 40%);">+   *params = power_ctrl_params_def;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* Disable RxLev pre-processing and hysteresis by default */</span><br><span style="color: hsl(120, 100%, 40%);">+  struct gsm_power_ctrl_meas_params *mp = &params->rxlev_meas;</span><br><span style="color: hsl(120, 100%, 40%);">+   mp->lower_thresh = mp->upper_thresh = PWR_TEST_RXLEV_TARGET;</span><br><span style="color: hsl(120, 100%, 40%);">+    mp->algo = GSM_PWR_CTRL_MEAS_AVG_ALGO_NONE;</span><br><span> </span><br><span>   printf("\nStarting test case '%s'\n", name);</span><br><span> }</span><br><span>@@ -104,7 +111,7 @@</span><br><span>    apply_power_test(lchan, -90, 1, 5);</span><br><span> </span><br><span>      /* Check good RSSI value keeps it at same power level: */</span><br><span style="color: hsl(0, 100%, 40%);">-       apply_power_test(lchan, g_bts->ul_power_ctrl.target_dbm, 0, 5);</span><br><span style="color: hsl(120, 100%, 40%);">+    apply_power_test(lchan, PWR_TEST_RXLEV_TARGET_DBM, 0, 5);</span><br><span> </span><br><span>        apply_power_test(lchan, -90, 1, 3);</span><br><span>  apply_power_test(lchan, -90, 1, 2); /* .max is pwr lvl 2 */</span><br><span>@@ -122,7 +129,7 @@</span><br><span>    apply_power_test(lchan, -90, 0, 29);</span><br><span> </span><br><span>     /* Check good RSSI value keeps it at same power level: */</span><br><span style="color: hsl(0, 100%, 40%);">-       apply_power_test(lchan, g_bts->ul_power_ctrl.target_dbm, 0, 29);</span><br><span style="color: hsl(120, 100%, 40%);">+   apply_power_test(lchan, PWR_TEST_RXLEV_TARGET_DBM, 0, 29);</span><br><span> </span><br><span>       /* Now go down, steps are double size in this direction: */</span><br><span>  apply_power_test(lchan, -45, 1, 1);</span><br><span>@@ -130,23 +137,23 @@</span><br><span>  apply_power_test(lchan, -45, 1, 9);</span><br><span> </span><br><span>      /* Go down only one level down and up: */</span><br><span style="color: hsl(0, 100%, 40%);">-       apply_power_test(lchan, g_bts->ul_power_ctrl.target_dbm + 2, 1, 10);</span><br><span style="color: hsl(0, 100%, 40%);">- apply_power_test(lchan, g_bts->ul_power_ctrl.target_dbm - 2, 1, 9);</span><br><span style="color: hsl(120, 100%, 40%);">+        apply_power_test(lchan, PWR_TEST_RXLEV_TARGET_DBM + 2, 1, 10);</span><br><span style="color: hsl(120, 100%, 40%);">+        apply_power_test(lchan, PWR_TEST_RXLEV_TARGET_DBM - 2, 1, 9);</span><br><span> </span><br><span>    /* Check if BSC requesting a low max power is applied after loop calculation: */</span><br><span>     lchan->ms_power_ctrl.max = ms_pwr_ctl_lvl(GSM_BAND_1800, 2);</span><br><span>      OSMO_ASSERT(lchan->ms_power_ctrl.max == 14);</span><br><span style="color: hsl(0, 100%, 40%);">- apply_power_test(lchan, g_bts->ul_power_ctrl.target_dbm + 2, 1, 14);</span><br><span style="color: hsl(120, 100%, 40%);">+       apply_power_test(lchan, PWR_TEST_RXLEV_TARGET_DBM + 2, 1, 14);</span><br><span>       /* Set back a more normal max: */</span><br><span>    lchan->ms_power_ctrl.max = ms_pwr_ctl_lvl(GSM_BAND_1800, 30);</span><br><span>     OSMO_ASSERT(lchan->ms_power_ctrl.max == 0);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      /* Fix it and jump down */</span><br><span style="color: hsl(0, 100%, 40%);">-      lchan->ms_power_ctrl.fixed = true;</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Disable dynamic power control and jump down */</span><br><span style="color: hsl(120, 100%, 40%);">+     lchan->ms_power_ctrl.dpc_params = NULL;</span><br><span>   apply_power_test(lchan, -60, 0, 14);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-        /* And leave it again */</span><br><span style="color: hsl(0, 100%, 40%);">-        lchan->ms_power_ctrl.fixed = false;</span><br><span style="color: hsl(120, 100%, 40%);">+        /* Enable and leave it again */</span><br><span style="color: hsl(120, 100%, 40%);">+       lchan->ms_power_ctrl.dpc_params = &lchan->ms_dpc_params;</span><br><span>   apply_power_test(lchan, -40, 1, 15);</span><br><span> }</span><br><span> </span><br><span>@@ -159,8 +166,9 @@</span><br><span>  lchan = &g_trx->ts[0].lchan[0];</span><br><span>       avg100 = &lchan->ms_power_ctrl.avg100_rxlev_dbm;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     g_bts->ul_power_ctrl.pf_algo = BTS_PF_ALGO_EWMA;</span><br><span style="color: hsl(0, 100%, 40%);">-     g_bts->ul_power_ctrl.pf.ewma.alpha = 20; /* 80% smoothing */</span><br><span style="color: hsl(120, 100%, 40%);">+       struct gsm_power_ctrl_meas_params *mp = &lchan->ms_dpc_params.rxlev_meas;</span><br><span style="color: hsl(120, 100%, 40%);">+      mp->algo = GSM_PWR_CTRL_MEAS_AVG_ALGO_OSMO_EWMA;</span><br><span style="color: hsl(120, 100%, 40%);">+   mp->ewma.alpha = 20; /* 80% smoothing */</span><br><span> </span><br><span>      lchan->ms_power_ctrl.current = ms_pwr_ctl_lvl(GSM_BAND_1800, 0);</span><br><span>  OSMO_ASSERT(lchan->ms_power_ctrl.current == 15);</span><br><span>@@ -194,7 +202,7 @@</span><br><span>    apply_power_test(lchan, -70, 1, 9);</span><br><span>  CHECK_UL_RSSI_AVG100(-78.40);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       g_bts->ul_power_ctrl.pf.ewma.alpha = 70; /* 30% smoothing */</span><br><span style="color: hsl(120, 100%, 40%);">+       mp->ewma.alpha = 70; /* 30% smoothing */</span><br><span>  lchan->ms_power_ctrl.current = 15;</span><br><span>        lchan->ms_power_ctrl.avg100_rxlev_dbm = 0;</span><br><span> </span><br><span>@@ -220,22 +228,23 @@</span><br><span>    lchan = &g_trx->ts[0].lchan[0];</span><br><span> </span><br><span>   /* Tolerate power deviations in range -80 .. -70 */</span><br><span style="color: hsl(0, 100%, 40%);">-     g_bts->ul_power_ctrl.hysteresis_db = 5;</span><br><span style="color: hsl(120, 100%, 40%);">+    lchan->ms_dpc_params.rxlev_meas.lower_thresh = 30;</span><br><span style="color: hsl(120, 100%, 40%);">+ lchan->ms_dpc_params.rxlev_meas.upper_thresh = 40;</span><br><span> </span><br><span>    lchan->ms_power_ctrl.current = ms_pwr_ctl_lvl(GSM_BAND_1800, 0);</span><br><span>  OSMO_ASSERT(lchan->ms_power_ctrl.current == 15);</span><br><span>  lchan->ms_power_ctrl.max = ms_pwr_ctl_lvl(GSM_BAND_1800, 26);</span><br><span>     OSMO_ASSERT(lchan->ms_power_ctrl.max == 2);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      apply_power_test(lchan, g_bts->ul_power_ctrl.target_dbm, 0, 15);</span><br><span style="color: hsl(0, 100%, 40%);">-     apply_power_test(lchan, g_bts->ul_power_ctrl.target_dbm + 3, 0, 15);</span><br><span style="color: hsl(0, 100%, 40%);">- apply_power_test(lchan, g_bts->ul_power_ctrl.target_dbm - 3, 0, 15);</span><br><span style="color: hsl(120, 100%, 40%);">+       apply_power_test(lchan, PWR_TEST_RXLEV_TARGET_DBM, 0, 15);</span><br><span style="color: hsl(120, 100%, 40%);">+    apply_power_test(lchan, PWR_TEST_RXLEV_TARGET_DBM + 3, 0, 15);</span><br><span style="color: hsl(120, 100%, 40%);">+        apply_power_test(lchan, PWR_TEST_RXLEV_TARGET_DBM - 3, 0, 15);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      apply_power_test(lchan, g_bts->ul_power_ctrl.target_dbm, 0, 15);</span><br><span style="color: hsl(0, 100%, 40%);">-     apply_power_test(lchan, g_bts->ul_power_ctrl.target_dbm + 5, 0, 15);</span><br><span style="color: hsl(0, 100%, 40%);">- apply_power_test(lchan, g_bts->ul_power_ctrl.target_dbm - 5, 0, 15);</span><br><span style="color: hsl(120, 100%, 40%);">+       apply_power_test(lchan, PWR_TEST_RXLEV_TARGET_DBM, 0, 15);</span><br><span style="color: hsl(120, 100%, 40%);">+    apply_power_test(lchan, PWR_TEST_RXLEV_TARGET_DBM + 5, 0, 15);</span><br><span style="color: hsl(120, 100%, 40%);">+        apply_power_test(lchan, PWR_TEST_RXLEV_TARGET_DBM - 5, 0, 15);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      apply_power_test(lchan, g_bts->ul_power_ctrl.target_dbm - 10, 1, 13);</span><br><span style="color: hsl(120, 100%, 40%);">+      apply_power_test(lchan, PWR_TEST_RXLEV_TARGET_DBM - 10, 1, 13);</span><br><span> }</span><br><span> </span><br><span> int main(int argc, char **argv)</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-bts/+/21993">change 21993</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/+/21993"/><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: Ib18f84c40227841d95a36063a6789bf63054fc2e </div>
<div style="display:none"> Gerrit-Change-Number: 21993 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: fixeria <vyanitskiy@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>