Change in osmo-bsc[master]: Implement MS Uplink Power Control Loop

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

keith gerrit-no-reply at lists.osmocom.org
Tue Oct 5 04:32:33 UTC 2021


keith has submitted this change. ( https://gerrit.osmocom.org/c/osmo-bsc/+/25654 )

Change subject: Implement MS Uplink Power Control Loop
......................................................................

Implement MS Uplink Power Control Loop

* Adds vty option dyn-bsc for ms-power-control -> mode
* Imports power_control.c from osmo-bts project
  [at commit 2f3cd4b697972d8484f9a9d3b7ef634086f65fa5]
* Removes unused C/I code from osmo-bts's power_control.c

This patch then calls the power loop on receipt of measurement
reports and updates the MS Power Level accordingly.

Change-Id: Ibc307e758697eb5ca3fb86622f35709d6077db9e
---
M include/osmocom/bsc/Makefile.am
M include/osmocom/bsc/debug.h
M include/osmocom/bsc/gsm_data.h
A include/osmocom/bsc/power_control.h
M src/osmo-bsc/Makefile.am
M src/osmo-bsc/abis_rsl.c
M src/osmo-bsc/bsc_vty.c
M src/osmo-bsc/bts_vty.c
M src/osmo-bsc/osmo_bsc_main.c
A src/osmo-bsc/power_control.c
M tests/power_ctrl.vty
11 files changed, 333 insertions(+), 5 deletions(-)

Approvals:
  keith: Looks good to me, approved
  Jenkins Builder: Verified



diff --git a/include/osmocom/bsc/Makefile.am b/include/osmocom/bsc/Makefile.am
index 3accc74..3bccf44 100644
--- a/include/osmocom/bsc/Makefile.am
+++ b/include/osmocom/bsc/Makefile.am
@@ -62,4 +62,5 @@
 	penalty_timers.h \
 	osmo_bsc_lcls.h \
 	smscb.h \
+	power_control.h \
 	$(NULL)
diff --git a/include/osmocom/bsc/debug.h b/include/osmocom/bsc/debug.h
index 4ad61b4..a3cad68 100644
--- a/include/osmocom/bsc/debug.h
+++ b/include/osmocom/bsc/debug.h
@@ -29,6 +29,7 @@
 	DCBS,
 	DLCS,
 	DRESET,
+	DLOOP,
 	Debug_LastEntry,
 };
 
diff --git a/include/osmocom/bsc/gsm_data.h b/include/osmocom/bsc/gsm_data.h
index 21828d4..36d364c 100644
--- a/include/osmocom/bsc/gsm_data.h
+++ b/include/osmocom/bsc/gsm_data.h
@@ -673,6 +673,27 @@
 #define INTERF_DBM_UNKNOWN 0
 #define INTERF_BAND_UNKNOWN 0xff
 
+/* Measurement pre-processing state */
+struct gsm_power_ctrl_meas_proc_state {
+	/* Number of measurements processed */
+	unsigned int meas_num;
+	/* Algorithm specific data */
+	union {
+		struct {
+			/* Scaled up 100 times average value */
+			int Avg100;
+		} ewma;
+	};
+};
+
+struct lchan_power_ctrl_state {
+	/* Measurement pre-processing state (for dynamic mode) */
+	struct gsm_power_ctrl_meas_proc_state rxlev_meas_proc;
+	struct gsm_power_ctrl_meas_proc_state rxqual_meas_proc;
+	/* Number of SACCH blocks to skip (for dynamic mode) */
+	int skip_block_num;
+};
+
 struct gsm_lchan {
 	/* The TS that we're part of */
 	struct gsm_bts_trx_ts *ts;
@@ -820,6 +841,8 @@
 	/* Actual reported interference band index, or INTERF_BAND_UNKNOWN if this lchan was not included in the most
 	 * recent Resource Indication. */
 	uint8_t interf_band;
+	/* MS power control state */
+	struct lchan_power_ctrl_state ms_power_ctrl;
 };
 
 /* One Timeslot in a TRX */
@@ -1342,6 +1365,9 @@
 	GSM_PWR_CTRL_MODE_STATIC,
 	/* Send MS/BS Power [Parameters] IEs (dynamic mode) */
 	GSM_PWR_CTRL_MODE_DYN_BTS,
+	/* Do not send MS/BS Power IEs and use BSC Power Loop */
+	GSM_PWR_CTRL_MODE_DYN_BSC,
+
 };
 
 /* MS/BS Power Control Parameters */
diff --git a/include/osmocom/bsc/power_control.h b/include/osmocom/bsc/power_control.h
new file mode 100644
index 0000000..82cbcb0
--- /dev/null
+++ b/include/osmocom/bsc/power_control.h
@@ -0,0 +1,7 @@
+#pragma once
+
+#include <stdint.h>
+#include <osmocom/bsc/gsm_data.h>
+#include <osmocom/bsc/meas_rep.h>
+
+int lchan_ms_pwr_ctrl(struct gsm_lchan *lchan, const struct gsm_meas_rep *mr);
diff --git a/src/osmo-bsc/Makefile.am b/src/osmo-bsc/Makefile.am
index 8991697..19af569 100644
--- a/src/osmo-bsc/Makefile.am
+++ b/src/osmo-bsc/Makefile.am
@@ -106,6 +106,7 @@
 	smscb.c \
 	cbch_scheduler.c \
 	cbsp_link.c \
+	power_control.c \
 	$(NULL)
 
 libbsc_la_LIBADD = \
diff --git a/src/osmo-bsc/abis_rsl.c b/src/osmo-bsc/abis_rsl.c
index 9882252..a7b267d 100644
--- a/src/osmo-bsc/abis_rsl.c
+++ b/src/osmo-bsc/abis_rsl.c
@@ -55,6 +55,7 @@
 #include <osmocom/bsc/handover_fsm.h>
 #include <osmocom/bsc/smscb.h>
 #include <osmocom/bsc/bts.h>
+#include <osmocom/bsc/power_control.h>
 
 static void send_lchan_signal(int sig_no, struct gsm_lchan *lchan,
 			      struct gsm_meas_rep *resp)
@@ -1341,6 +1342,8 @@
 
 	print_meas_rep(msg->lchan, mr);
 
+	lchan_ms_pwr_ctrl(msg->lchan, mr);
+
 	send_lchan_signal(S_LCHAN_MEAS_REP, msg->lchan, mr);
 
 	return 0;
diff --git a/src/osmo-bsc/bsc_vty.c b/src/osmo-bsc/bsc_vty.c
index 879ae3f..c1a6e44 100644
--- a/src/osmo-bsc/bsc_vty.c
+++ b/src/osmo-bsc/bsc_vty.c
@@ -1363,6 +1363,12 @@
 		return CMD_WARNING;
 	}
 
+	if (bts->ms_power_ctrl.mode != GSM_PWR_CTRL_MODE_DYN_BTS) {
+		vty_out(vty, "%% Not Sending default MS/BS Power control parameters "
+			"because BTS%d is not using dyn-bts mode%s", bts_nr, VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+
 	if (bts->model->power_ctrl_send_def_params == NULL) {
 		vty_out(vty, "%% Sending default MS/BS Power control parameters "
 			"for BTS%d is not implemented%s", bts_nr, VTY_NEWLINE);
diff --git a/src/osmo-bsc/bts_vty.c b/src/osmo-bsc/bts_vty.c
index fb11520..460e14a 100644
--- a/src/osmo-bsc/bts_vty.c
+++ b/src/osmo-bsc/bts_vty.c
@@ -2915,10 +2915,11 @@
 DEFUN_USRATTR(cfg_power_ctrl_mode,
 	      cfg_power_ctrl_mode_cmd,
 	      X(BSC_VTY_ATTR_NEW_LCHAN),
-	      "mode (static|dyn-bts) [reset]",
+	      "mode (static|dyn-bts|dyn-bsc) [reset]",
 	      "Power control mode\n"
 	      "Instruct the MS/BTS to use a static power level\n"
 	      "Power control to be performed dynamically by the BTS itself\n"
+	      "Power control to be performed dynamically at this BSC\n"
 	      "Reset to default parameters for the given mode\n")
 {
 	struct gsm_power_ctrl_params *params = vty->index;
@@ -2935,6 +2936,13 @@
 		params->mode = GSM_PWR_CTRL_MODE_STATIC;
 	else if (strcmp(argv[0], "dyn-bts") == 0)
 		params->mode = GSM_PWR_CTRL_MODE_DYN_BTS;
+	else if (strcmp(argv[0], "dyn-bsc") == 0) {
+		if (params->dir == GSM_PWR_CTRL_DIR_DL) {
+			vty_out(vty, "%% mode dyn-bsc not supported for Downlink.%s", VTY_NEWLINE);
+			return CMD_WARNING;
+		}
+		params->mode = GSM_PWR_CTRL_MODE_DYN_BSC;
+	}
 
 	return CMD_SUCCESS;
 }
@@ -3139,6 +3147,11 @@
 	int upper = atoi(argv[2]);
 	struct gsm_power_ctrl_meas_params *meas_params;
 
+	if (params->mode == GSM_PWR_CTRL_MODE_DYN_BSC) {
+		vty_out(vty, "%% C/I based power loop not possible in dyn-bsc mode!%s", VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+
 	if (params->dir != GSM_PWR_CTRL_DIR_UL) {
 		vty_out(vty, "%% C/I based power loop only possible in Uplink!%s", VTY_NEWLINE);
 		return CMD_WARNING;
@@ -3962,8 +3975,10 @@
 			cfg_out(" bs-power static %u%s", cp->bs_power_val_db, VTY_NEWLINE);
 		break;
 	case GSM_PWR_CTRL_MODE_DYN_BTS:
+	case GSM_PWR_CTRL_MODE_DYN_BSC:
 		cfg_out("%s%s", node_name, VTY_NEWLINE);
-		cfg_out(" mode dyn-bts%s", VTY_NEWLINE);
+		cfg_out(" mode %s%s",
+			cp->mode == GSM_PWR_CTRL_MODE_DYN_BTS ? "dyn-bts" : "dyn-bsc", VTY_NEWLINE);
 		if (cp->dir == GSM_PWR_CTRL_DIR_DL)
 			cfg_out(" bs-power dyn-max %u%s", cp->bs_power_max_db, VTY_NEWLINE);
 
@@ -3975,7 +3990,8 @@
 		/* Measurement processing / averaging parameters */
 		config_write_power_ctrl_meas(vty, indent + 1, &cp->rxlev_meas, "rxlev", "");
 		config_write_power_ctrl_meas(vty, indent + 1, &cp->rxqual_meas, "rxqual", "");
-		if (cp->dir == GSM_PWR_CTRL_DIR_UL && is_osmobts(bts)) {
+		if (cp->dir == GSM_PWR_CTRL_DIR_UL && is_osmobts(bts)
+		    && cp->mode == GSM_PWR_CTRL_MODE_DYN_BTS) {
 			config_write_power_ctrl_meas(vty, indent + 1, &cp->ci_fr_meas, "ci", " fr-efr");
 			config_write_power_ctrl_meas(vty, indent + 1, &cp->ci_hr_meas, "ci", " hr");
 			config_write_power_ctrl_meas(vty, indent + 1, &cp->ci_amr_fr_meas, "ci", " amr-fr");
diff --git a/src/osmo-bsc/osmo_bsc_main.c b/src/osmo-bsc/osmo_bsc_main.c
index 395a60e..0ed0033 100644
--- a/src/osmo-bsc/osmo_bsc_main.c
+++ b/src/osmo-bsc/osmo_bsc_main.c
@@ -855,6 +855,12 @@
 		.description = "RESET/ACK on A and Lb interfaces",
 		.enabled = 1, .loglevel = LOGL_NOTICE,
 	},
+	[DLOOP] = {
+		.name = "DLOOP",
+		.description = "Control loops",
+		.color = "\033[0;34m",
+		.enabled = 1, .loglevel = LOGL_NOTICE,
+	},
 };
 
 static int filter_fn(const struct log_context *ctx, struct log_target *tar)
diff --git a/src/osmo-bsc/power_control.c b/src/osmo-bsc/power_control.c
new file mode 100644
index 0000000..6fe4455
--- /dev/null
+++ b/src/osmo-bsc/power_control.c
@@ -0,0 +1,261 @@
+/* MS Power Control Loop L1 */
+
+/* (C) 2014 by Holger Hans Peter Freyther
+ * (C) 2020-2021 by sysmocom - s.m.f.c. GmbH <info at sysmocom.de>
+ * Author: Vadim Yanitskiy <vyanitskiy at sysmocom.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdint.h>
+#include <unistd.h>
+#include <errno.h>
+#include <inttypes.h>
+
+#include <osmocom/bsc/debug.h>
+#include <osmocom/bsc/bts.h>
+#include <osmocom/bsc/gsm_data.h>
+#include <osmocom/bsc/bsc_subscriber.h>
+#include <osmocom/bsc/abis_rsl.h>
+#include <osmocom/bsc/meas_rep.h>
+#include <osmocom/bsc/power_control.h>
+
+/* We don't want to deal with floating point, so we scale up */
+#define EWMA_SCALE_FACTOR 100
+/* EWMA_SCALE_FACTOR/2 = +50: Round to nearest value when downscaling, otherwise floor() is applied. */
+#define EWMA_ROUND_FACTOR (EWMA_SCALE_FACTOR / 2)
+
+/* Base Low-Pass Single-Pole IIR Filter (EWMA) formula:
+ *
+ *   Avg[n] = a * Val[n] + (1 - a) * Avg[n - 1]
+ *
+ * where parameter 'a' determines how much weight of the latest measurement value
+ * 'Val[n]' carries vs the weight of the accumulated average 'Avg[n - 1]'.  The
+ * value of 'a' is usually a float in range 0 .. 1, so:
+ *
+ *  - value 0.5 gives equal weight to both 'Val[n]' and 'Avg[n - 1]';
+ *  - value 1.0 means no filtering at all (pass through);
+ *  - value 0.0 makes no sense.
+ *
+ * Further optimization:
+ *
+ *   Avg[n] = a * Val[n] + Avg[n - 1] - a * Avg[n - 1]
+ *   ^^^^^^                ^^^^^^^^^^
+ *
+ * a) this can be implemented in C using '+=' operator:
+ *
+ *   Avg += a * Val - a * Avg
+ *   Avg += a * (Val - Avg)
+ *
+ * b) everything is scaled up by 100 to avoid floating point stuff:
+ *
+ *   Avg100 += A * (Val - Avg)
+ *
+ * where 'Avg100' is 'Avg * 100' and 'A' is 'a * 100'.
+ *
+ * For more details, see:
+ *
+ *   https://en.wikipedia.org/wiki/Moving_average
+ *   https://en.wikipedia.org/wiki/Low-pass_filter#Simple_infinite_impulse_response_filter
+ *   https://tomroelandts.com/articles/low-pass-single-pole-iir-filter
+ */
+static int do_pf_ewma(const struct gsm_power_ctrl_meas_params *mp,
+		      struct gsm_power_ctrl_meas_proc_state *mps,
+		      const int Val)
+{
+	const uint8_t A = mp->ewma.alpha;
+	int *Avg100 = &mps->ewma.Avg100;
+
+	/* We don't have 'Avg[n - 1]' if this is the first run */
+	if (mps->meas_num++ == 0) {
+		*Avg100 = Val * EWMA_SCALE_FACTOR;
+		return Val;
+	}
+
+	*Avg100 += A * (Val - (*Avg100 + EWMA_ROUND_FACTOR) / EWMA_SCALE_FACTOR);
+	return (*Avg100 + EWMA_ROUND_FACTOR) / EWMA_SCALE_FACTOR;
+}
+
+/* Calculate target RxLev value from lower/upper thresholds */
+#define CALC_TARGET(mp) \
+	((mp).lower_thresh + (mp).upper_thresh) / 2
+
+static int do_avg_algo(const struct gsm_power_ctrl_meas_params *mp,
+		       struct gsm_power_ctrl_meas_proc_state *mps,
+		       const int val)
+{
+	int val_avg;
+	switch (mp->algo) {
+	case GSM_PWR_CTRL_MEAS_AVG_ALGO_OSMO_EWMA:
+		val_avg = do_pf_ewma(mp, mps, val);
+		break;
+	/* TODO: implement other pre-processing methods */
+	case GSM_PWR_CTRL_MEAS_AVG_ALGO_NONE:
+	default:
+		/* No filtering (pass through) */
+		val_avg = val;
+	}
+	return val_avg;
+}
+/* Calculate a 'delta' value (for the given MS/BS power control parameters)
+ * to be applied to the current Tx power level to approach the target level. */
+static int calc_delta_rxlev(const struct gsm_power_ctrl_params *params, const uint8_t rxlev)
+{
+	int delta;
+
+	/* Check if RxLev is within the threshold window */
+	if (rxlev >= params->rxlev_meas.lower_thresh &&
+	    rxlev <= params->rxlev_meas.upper_thresh)
+		return 0;
+
+	/* How many dBs measured power should be increased (+) or decreased (-)
+	 * to reach expected power. */
+	delta = CALC_TARGET(params->rxlev_meas) - rxlev;
+
+	/* Don't ever change more than PWR_{LOWER,RAISE}_MAX_DBM during one loop
+	 * iteration, i.e. reduce the speed at which the MS transmit power can
+	 * change. A higher value means a lower level (and vice versa) */
+	if (delta > params->inc_step_size_db)
+		delta = params->inc_step_size_db;
+	else if (delta < -params->red_step_size_db)
+		delta = -params->red_step_size_db;
+
+	return delta;
+}
+
+/* Shall we skip current block based on configured interval? */
+static bool ctrl_interval_skip_block(const struct gsm_power_ctrl_params *params,
+				     struct lchan_power_ctrl_state *state)
+{
+	/* Power control interval: how many blocks do we skip? */
+	if (state->skip_block_num-- > 0)
+		return true;
+
+	/* Can we be sure if ONE Report is always going to correspond
+	 * to ONE SACCH block at the BTS? - If not this is as approximation
+	 * but it should not hurt. */
+
+	/* Reset the number of SACCH blocks to be skipped:
+	 *   ctrl_interval=0 => 0 blocks to skip,
+	 *   ctrl_interval=1 => 1 blocks to skip,
+	 *   ctrl_interval=2 => 3 blocks to skip,
+	 *     so basically ctrl_interval * 2 - 1. */
+	state->skip_block_num = params->ctrl_interval * 2 - 1;
+	return false;
+}
+
+int lchan_ms_pwr_ctrl(struct gsm_lchan *lchan, const struct gsm_meas_rep *mr)
+{
+	struct lchan_power_ctrl_state *state = &lchan->ms_power_ctrl;
+	struct gsm_bts_trx *trx = lchan->ts->trx;
+	struct gsm_bts *bts = trx->bts;
+	enum gsm_band band = bts->band;
+	const struct gsm_power_ctrl_params *params = &bts->ms_power_ctrl;
+	int8_t new_power_lvl; /* TS 05.05 power level */
+	int8_t ms_dbm, new_dbm, current_dbm, bsc_max_dbm;
+	uint8_t rxlev_avg;
+	uint8_t ms_power_lvl = ms_pwr_ctl_lvl(band, mr->ms_l1.pwr);
+	int8_t ul_rssi_dbm;
+	bool ignore;
+
+	if (params == NULL)
+		return 0;
+	/* Not doing the power loop here if we are not handling it */
+	if (params->mode != GSM_PWR_CTRL_MODE_DYN_BSC)
+		return 0;
+
+	/* Shall we skip current block based on configured interval? */
+	if (ctrl_interval_skip_block(params, state))
+		return 0;
+
+	/* If DTx is active on Uplink,
+	 * use the '-SUB', otherwise '-FULL': */
+	if (mr->flags & MEAS_REP_F_UL_DTX)
+		ul_rssi_dbm = rxlev2dbm(mr->ul.sub.rx_lev);
+	else
+		ul_rssi_dbm = rxlev2dbm(mr->ul.full.rx_lev);
+
+	ms_dbm = ms_pwr_dbm(band, ms_power_lvl);
+	if (ms_dbm < 0) {
+		LOGPLCHAN(lchan, DLOOP, LOGL_NOTICE,
+			  "Failed to calculate dBm for power ctl level %" PRIu8 " on band %s\n",
+			  ms_power_lvl, gsm_band_name(band));
+		return 0;
+	}
+
+	bsc_max_dbm = bts->ms_max_power;
+	rxlev_avg = do_avg_algo(&params->rxlev_meas, &state->rxlev_meas_proc, dbm2rxlev(ul_rssi_dbm));
+	new_dbm = ms_dbm + calc_delta_rxlev(params, rxlev_avg);
+
+	/* Make sure new_dbm is never negative. ms_pwr_ctl_lvl() can later on
+	   cope with any unsigned dbm value, regardless of band minimal value. */
+	if (new_dbm < 0)
+		new_dbm = 0;
+	/* Don't ask for smaller ms power level than the one set by ms max power for this BTS */
+	if (new_dbm > bsc_max_dbm)
+		new_dbm = bsc_max_dbm;
+
+	new_power_lvl = ms_pwr_ctl_lvl(band, new_dbm);
+	if (new_power_lvl < 0) {
+		LOGPLCHAN(lchan, DLOOP, LOGL_NOTICE,
+			  "Failed to retrieve power level for %" PRId8 " dBm on band %d\n",
+			  new_dbm, band);
+		return 0;
+	}
+
+	current_dbm = ms_pwr_dbm(band, lchan->ms_power);
+
+	/* In this Power Control Loop, we infer a new good MS Power Level based
+	 * on the previous MS Power Level announced by the MS (not the previous
+	 * one we requested!) together with the related computed measurements.
+	 * Hence, and since we allow for several good MS Power Levels falling into our
+	 * thresholds, we could finally converge into an oscillation loop where
+	 * the MS bounces between 2 different correct MS Power levels all the
+	 * time, due to the fact that we "accept" and "request back" whatever
+	 * good MS Power Level we received from the MS, but at that time the MS
+	 * will be transmitting using the previous MS Power Level we
+	 * requested, which we will later "accept" and "request back" on next loop
+	 * iteration. As a result MS effectively bounces between those 2 MS
+	 * Power Levels.
+	 * In order to fix this permanent oscillation, if current MS_PWR used/announced
+	 * by MS is good ("ms_dbm == new_dbm", hence within thresholds and no change
+	 * required) but has higher Tx power than the one we last requested, we ignore
+	 * it and keep requesting for one with lower Tx power. This way we converge to
+	 * the lowest good Tx power avoiding oscillating over values within thresholds.
+	 */
+	ignore = (ms_dbm == new_dbm && ms_dbm > current_dbm);
+
+	if (lchan->ms_power == new_power_lvl || ignore) {
+		LOGPLCHAN(lchan, DLOOP, LOGL_INFO, "Keeping MS power at control level %d (%d dBm): "
+			  "ms-pwr-lvl[curr %" PRIu8 ", max %" PRIu8 "], RSSI[curr %d, avg %d, thresh %d..%d] dBm\n",
+			  new_power_lvl, ms_dbm, ms_power_lvl, bsc_max_dbm, ul_rssi_dbm, rxlev2dbm(rxlev_avg),
+			  rxlev2dbm(params->rxlev_meas.lower_thresh), rxlev2dbm(params->rxlev_meas.upper_thresh));
+		return 0;
+	}
+
+	LOGPLCHAN(lchan, DLOOP, LOGL_INFO, "%s MS power control level %d (%d dBm) => %d (%d dBm): "
+		  "ms-pwr-lvl[curr %" PRIu8 ", max %" PRIu8 "], RSSI[curr %d, avg %d, thresh %d..%d] dBm\n",
+		  (new_dbm > current_dbm) ? "Raising" : "Lowering",
+		  lchan->ms_power, current_dbm, new_power_lvl, new_dbm, ms_power_lvl,
+		  bsc_max_dbm, ul_rssi_dbm, rxlev2dbm(rxlev_avg),
+		  rxlev2dbm(params->rxlev_meas.lower_thresh), rxlev2dbm(params->rxlev_meas.upper_thresh));
+
+	lchan_update_ms_power_ctrl_level(lchan, new_dbm);
+
+	return 1;
+
+}
diff --git a/tests/power_ctrl.vty b/tests/power_ctrl.vty
index 491adca..9747ec2 100644
--- a/tests/power_ctrl.vty
+++ b/tests/power_ctrl.vty
@@ -28,7 +28,7 @@
 OsmoBSC(config-net-bts)# bs-power-control
 OsmoBSC(config-bs-power-ctrl)# list with-flags
 ...
-  . l.  mode (static|dyn-bts) [reset]
+  . l.  mode (static|dyn-bts|dyn-bsc) [reset]
   . l.  bs-power (static|dyn-max) <0-30>
   . lv  ctrl-interval <0-31>
   . lv  step-size inc <2-6> red <2-4>
@@ -109,7 +109,7 @@
 OsmoBSC(config-net-bts)# ms-power-control
 OsmoBSC(config-ms-power-ctrl)# list with-flags
 ...
-  . l.  mode (static|dyn-bts) [reset]
+  . l.  mode (static|dyn-bts|dyn-bsc) [reset]
   . l.  bs-power (static|dyn-max) <0-30>
   . lv  ctrl-interval <0-31>
   . lv  step-size inc <2-6> red <2-4>

-- 
To view, visit https://gerrit.osmocom.org/c/osmo-bsc/+/25654
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings

Gerrit-Project: osmo-bsc
Gerrit-Branch: master
Gerrit-Change-Id: Ibc307e758697eb5ca3fb86622f35709d6077db9e
Gerrit-Change-Number: 25654
Gerrit-PatchSet: 13
Gerrit-Owner: keith <keith at rhizomatica.org>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: fixeria <vyanitskiy at sysmocom.de>
Gerrit-Reviewer: keith <keith at rhizomatica.org>
Gerrit-Reviewer: laforge <laforge at osmocom.org>
Gerrit-Reviewer: pespin <pespin at sysmocom.de>
Gerrit-MessageType: merged
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20211005/b4cd70d0/attachment.htm>


More information about the gerrit-log mailing list