<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 = ¶ms->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>