aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2015-09-06 12:33:16 +0200
committerHarald Welte <laforge@gnumonks.org>2015-09-22 16:39:05 +0200
commit819b50e1a7b506a0a394cc71a795f0a9ce4083c1 (patch)
tree290806d3a1bc7f64a0e7a8e1cc5b48bfd6578164
parentf449842053d333f6f9f41d3123262e8e05375acb (diff)
move MS power control handling from sysmobts to common part
MS uplink power control is required in pretty much any BTS, and we cannot assume that they PHY / L1 will always take care of it by itself. So the correspondign code is moved to common/power_control.c and called from the generic part of L1SAP. The corresponding VTY paramter has been moved from the sysmobts-specific trx VTY node to the common BTS VTY node.
-rw-r--r--include/osmo-bts/Makefile.am3
-rw-r--r--include/osmo-bts/gsm_data.h2
-rw-r--r--include/osmo-bts/power_control.h7
-rw-r--r--src/common/Makefile.am2
-rw-r--r--src/common/bts.c1
-rw-r--r--src/common/l1sap.c2
-rw-r--r--src/common/power_control.c99
-rw-r--r--src/common/vty.c15
-rw-r--r--src/osmo-bts-sysmo/l1_if.c80
-rw-r--r--src/osmo-bts-sysmo/l1_if.h1
-rw-r--r--src/osmo-bts-sysmo/oml.c3
-rw-r--r--src/osmo-bts-sysmo/sysmobts_vty.c11
-rw-r--r--tests/sysmobts/sysmobts_test.c15
13 files changed, 146 insertions, 95 deletions
diff --git a/include/osmo-bts/Makefile.am b/include/osmo-bts/Makefile.am
index cd3d8c04..bf037ae3 100644
--- a/include/osmo-bts/Makefile.am
+++ b/include/osmo-bts/Makefile.am
@@ -1,3 +1,4 @@
noinst_HEADERS = abis.h bts.h bts_model.h gsm_data.h logging.h measurement.h \
oml.h paging.h rsl.h signal.h vty.h amr.h pcu_if.h pcuif_proto.h \
- handover.h msg_utils.h tx_power.h control_if.h cbch.h l1sap.h
+ handover.h msg_utils.h tx_power.h control_if.h cbch.h l1sap.h \
+ power_control.h
diff --git a/include/osmo-bts/gsm_data.h b/include/osmo-bts/gsm_data.h
index b5dc25fa..bfa5285b 100644
--- a/include/osmo-bts/gsm_data.h
+++ b/include/osmo-bts/gsm_data.h
@@ -84,6 +84,8 @@ struct gsm_bts_role_bts {
struct gsm_time gsm_time;
uint8_t radio_link_timeout;
+ int ul_power_target; /* Uplink Rx power target */
+
/* used by the sysmoBTS to adjust band */
uint8_t auto_band;
diff --git a/include/osmo-bts/power_control.h b/include/osmo-bts/power_control.h
new file mode 100644
index 00000000..43d4b591
--- /dev/null
+++ b/include/osmo-bts/power_control.h
@@ -0,0 +1,7 @@
+#pragma once
+
+#include <stdint.h>
+#include <osmo-bts/gsm_data.h>
+
+int lchan_ms_pwr_ctrl(struct gsm_lchan *lchan,
+ const uint8_t ms_power, const int rxLevel);
diff --git a/src/common/Makefile.am b/src/common/Makefile.am
index 56648b14..d2580f93 100644
--- a/src/common/Makefile.am
+++ b/src/common/Makefile.am
@@ -8,4 +8,4 @@ libbts_a_SOURCES = gsm_data_shared.c sysinfo.c logging.c abis.c oml.c bts.c \
load_indication.c pcu_sock.c handover.c msg_utils.c \
load_indication.c pcu_sock.c handover.c msg_utils.c \
tx_power.c bts_ctrl_commands.c bts_ctrl_lookup.c \
- l1sap.c cbch.c
+ l1sap.c cbch.c power_control.c
diff --git a/src/common/bts.c b/src/common/bts.c
index 9abbe121..77302e2f 100644
--- a/src/common/bts.c
+++ b/src/common/bts.c
@@ -99,6 +99,7 @@ int bts_init(struct gsm_bts *bts)
/* configurable via VTY */
btsb->paging_state = paging_init(btsb, 200, 0);
+ btsb->ul_power_target = -75; /* dBm default */
/* configurable via OML */
btsb->load.ccch.load_ind_period = 112;
diff --git a/src/common/l1sap.c b/src/common/l1sap.c
index ca785fe4..1cb752e3 100644
--- a/src/common/l1sap.c
+++ b/src/common/l1sap.c
@@ -783,6 +783,8 @@ static int l1sap_ph_data_ind(struct gsm_bts_trx *trx,
lchan->meas.l1_info[0] |= ((data[0] >> 5) & 1) << 2;
lchan->meas.l1_info[1] = data[1];
lchan->meas.flags |= LC_UL_M_F_L1_VALID;
+
+ lchan_ms_pwr_ctrl(lchan, data[0] & 0x1f, data_ind->rssi);
} else
le = &lchan->lapdm_ch.lapdm_dcch;
diff --git a/src/common/power_control.c b/src/common/power_control.c
new file mode 100644
index 00000000..78d2702b
--- /dev/null
+++ b/src/common/power_control.c
@@ -0,0 +1,99 @@
+/* MS Power Control Loop L1 */
+
+/* (C) 2014 by Holger Hans Peter Freyther
+ *
+ * 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 <osmo-bts/logging.h>
+#include <osmo-bts/bts.h>
+#include <osmo-bts/gsm_data.h>
+#include <osmo-bts/measurement.h>
+#include <osmo-bts/bts_model.h>
+#include <osmo-bts/l1sap.h>
+
+/*
+ * Check if manual power control is needed
+ * Check if fixed power was selected
+ * Check if the MS is already using our level if not
+ * the value is bogus..
+ * TODO: Add a timeout.. e.g. if the ms is not capable of reaching
+ * the value we have set.
+ */
+int lchan_ms_pwr_ctrl(struct gsm_lchan *lchan,
+ const uint8_t ms_power, const int rxLevel)
+{
+ int rx;
+ int cur_dBm, new_dBm, new_pwr;
+ struct gsm_bts *bts = lchan->ts->trx->bts;
+ struct gsm_bts_role_bts *btsb = bts_role_bts(bts);
+ const enum gsm_band band = bts->band;
+
+ if (!trx_ms_pwr_ctrl_is_osmo(lchan->ts->trx))
+ return 0;
+ if (lchan->ms_power_ctrl.fixed)
+ return 0;
+
+ /* The phone hasn't reached the power level yet */
+ if (lchan->ms_power_ctrl.current != ms_power)
+ return 0;
+
+ /*
+ * What is the difference between what we want and received?
+ * Ignore a margin that is within the range of measurement
+ * and MS output issues.
+ */
+ rx = btsb->ul_power_target - rxLevel;
+ if (rx >= 0 && rx < 1)
+ return 0;
+ if (rx < 0 && rx > -1)
+ return 0;
+
+ /* We don't really care about the truncation of int + float */
+ cur_dBm = ms_pwr_dbm(band, ms_power);
+ new_dBm = cur_dBm + rx;
+
+ /* Clamp negative values and do it depending on the band */
+ if (new_dBm < 0)
+ new_dBm = 0;
+
+ switch (band) {
+ case GSM_BAND_1800:
+ /* If MS_TX_PWR_MAX_CCH is set the values 29,
+ * 30, 31 are not used. Avoid specifying a dBm
+ * that would lead to these power levels. The
+ * phone might not be able to reach them. */
+ if (new_dBm > 30)
+ new_dBm = 30;
+ break;
+ default:
+ break;
+ }
+
+ new_pwr = ms_pwr_ctl_lvl(band, new_dBm);
+ if (lchan->ms_power_ctrl.current != new_pwr) {
+ lchan->ms_power_ctrl.current = new_pwr;
+ bts_model_adjst_ms_pwr(lchan);
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/src/common/vty.c b/src/common/vty.c
index 8479e5a0..e3fd57df 100644
--- a/src/common/vty.c
+++ b/src/common/vty.c
@@ -207,6 +207,7 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
VTY_NEWLINE);
vty_out(vty, " paging lifetime %u%s", paging_get_lifetime(btsb->paging_state),
VTY_NEWLINE);
+ vty_out(vty, " uplink-power-target %d%s", btsb->ul_power_target, VTY_NEWLINE);
if (btsb->agch_queue_thresh_level != GSM_BTS_AGCH_QUEUE_THRESH_LEVEL_DEFAULT
|| btsb->agch_queue_low_level != GSM_BTS_AGCH_QUEUE_LOW_LEVEL_DEFAULT
|| btsb->agch_queue_high_level != GSM_BTS_AGCH_QUEUE_HIGH_LEVEL_DEFAULT)
@@ -441,6 +442,19 @@ DEFUN(cfg_bts_agch_queue_mgmt_default,
return CMD_SUCCESS;
}
+DEFUN(cfg_bts_ul_power_target, cfg_bts_ul_power_target_cmd,
+ "uplink-power-target <-110-0>",
+ "Set the nominal target Rx Level for uplink power control loop\n"
+ "Target uplink Rx level in dBm\n")
+{
+ struct gsm_bts *bts = vty->index;
+ struct gsm_bts_role_bts *btsb = bts_role_bts(bts);
+
+ btsb->ul_power_target = atoi(argv[0]);
+
+ return CMD_SUCCESS;
+}
+
#define DB_DBM_STR \
"Unit is dB (decibels)\n" \
"Unit is mdB (milli-decibels, or rather 1/10000 bel)\n"
@@ -782,6 +796,7 @@ int bts_vty_init(struct gsm_bts *bts, const struct log_info *cat)
install_element(BTS_NODE, &cfg_bts_paging_lifetime_cmd);
install_element(BTS_NODE, &cfg_bts_agch_queue_mgmt_default_cmd);
install_element(BTS_NODE, &cfg_bts_agch_queue_mgmt_params_cmd);
+ install_element(BTS_NODE, &cfg_bts_ul_power_target_cmd);
install_element(BTS_NODE, &cfg_trx_gsmtap_sapi_cmd);
install_element(BTS_NODE, &cfg_trx_no_gsmtap_sapi_cmd);
diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c
index e4e5d204..e2ad500f 100644
--- a/src/osmo-bts-sysmo/l1_if.c
+++ b/src/osmo-bts-sysmo/l1_if.c
@@ -868,18 +868,6 @@ static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_i
data_ind->msgUnitParam.u8Size));
dump_meas_res(LOGL_DEBUG, &data_ind->measParam);
- switch (data_ind->sapi) {
- case GsmL1_Sapi_Sacch:
- /*
- * Handle power control
- */
- l1if_ms_pwr_ctrl(lchan, fl1->ul_power_target,
- data_ind->msgUnitParam.u8Buffer[0] & 0x1f,
- data_ind->measParam.fRssi);
-
- break;
- }
-
/* check for TCH */
if (data_ind->sapi == GsmL1_Sapi_TchF
|| data_ind->sapi == GsmL1_Sapi_TchH) {
@@ -905,6 +893,7 @@ static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_i
l1sap = msgb_l1sap_prim(l1p_msg);
osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_PH_DATA,
PRIM_OP_INDICATION, l1p_msg);
+ l1sap->u.data.rssi = data_ind->measParam.fRssi;
l1sap->u.data.link_id = link_id;
l1sap->u.data.chan_nr = chan_nr;
l1sap->u.data.fn = fn;
@@ -1515,7 +1504,6 @@ struct femtol1_hdl *l1if_open(void *priv)
fl1h->priv = priv;
fl1h->clk_cal = 0;
fl1h->clk_use_eeprom = 1;
- fl1h->ul_power_target = -75; /* dBm default */
fl1h->min_qual_rach = MIN_QUAL_RACH;
fl1h->min_qual_norm = MIN_QUAL_NORM;
get_hwinfo_eeprom(fl1h);
@@ -1675,69 +1663,3 @@ int l1if_rf_clock_info_correct(struct femtol1_hdl *fl1h)
}
#endif
-
-/*
- * Check if manual power control is needed
- * Check if fixed power was selected
- * Check if the MS is already using our level if not
- * the value is bogus..
- * TODO: Add a timeout.. e.g. if the ms is not capable of reaching
- * the value we have set.
- */
-inline int l1if_ms_pwr_ctrl(struct gsm_lchan *lchan, const int ul_power_target,
- const uint8_t ms_power, const float rxLevel)
-{
- float rx;
- int cur_dBm, new_dBm, new_pwr;
- const enum gsm_band band = lchan->ts->trx->bts->band;
-
- if (!trx_ms_pwr_ctrl_is_osmo(lchan->ts->trx))
- return 0;
- if (lchan->ms_power_ctrl.fixed)
- return 0;
-
- /* The phone hasn't reached the power level yet */
- if (lchan->ms_power_ctrl.current != ms_power)
- return 0;
-
- /*
- * What is the difference between what we want and received?
- * Ignore a margin that is within the range of measurement
- * and MS output issues.
- */
- rx = ul_power_target - rxLevel;
- if (rx >= 0 && rx < 1.5f)
- return 0;
- if (rx < 0 && rx > -1.5f)
- return 0;
-
- /* We don't really care about the truncation of int + float */
- cur_dBm = ms_pwr_dbm(band, ms_power);
- new_dBm = cur_dBm + rx;
-
- /* Clamp negative values and do it depending on the band */
- if (new_dBm < 0)
- new_dBm = 0;
-
- switch (band) {
- case GSM_BAND_1800:
- /* If MS_TX_PWR_MAX_CCH is set the values 29,
- * 30, 31 are not used. Avoid specifying a dBm
- * that would lead to these power levels. The
- * phone might not be able to reach them. */
- if (new_dBm > 30)
- new_dBm = 30;
- break;
- default:
- break;
- }
-
- new_pwr = ms_pwr_ctl_lvl(band, new_dBm);
- if (lchan->ms_power_ctrl.current != new_pwr) {
- lchan->ms_power_ctrl.current = new_pwr;
- bts_model_adjst_ms_pwr(lchan);
- return 1;
- }
-
- return 0;
-}
diff --git a/src/osmo-bts-sysmo/l1_if.h b/src/osmo-bts-sysmo/l1_if.h
index d057c37d..d258f43b 100644
--- a/src/osmo-bts-sysmo/l1_if.h
+++ b/src/osmo-bts-sysmo/l1_if.h
@@ -46,7 +46,6 @@ struct femtol1_hdl {
uint32_t dsp_trace_f;
uint8_t clk_use_eeprom;
int clk_cal;
- int ul_power_target;
uint8_t clk_src;
float min_qual_rach;
float min_qual_norm;
diff --git a/src/osmo-bts-sysmo/oml.c b/src/osmo-bts-sysmo/oml.c
index c5810898..4c9ac497 100644
--- a/src/osmo-bts-sysmo/oml.c
+++ b/src/osmo-bts-sysmo/oml.c
@@ -324,6 +324,7 @@ static const uint8_t trx_rqd_attr[] = { NM_ATT_RF_MAXPOWR_R };
static int trx_init(struct gsm_bts_trx *trx)
{
struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx);
+ struct gsm_bts_role_bts *btsb = bts_role_bts(trx->bts);
struct msgb *msg;
GsmL1_MphInitReq_t *mi_req;
GsmL1_DeviceParam_t *dev_par;
@@ -352,7 +353,7 @@ static int trx_init(struct gsm_bts_trx *trx)
dev_par->u16BcchArfcn = trx->bts->c0->arfcn;
dev_par->u8NbTsc = trx->bts->bsic & 7;
dev_par->fRxPowerLevel = trx_ms_pwr_ctrl_is_osmo(trx)
- ? 0.0 : fl1h->ul_power_target;
+ ? 0.0 : btsb->ul_power_target;
dev_par->fTxPowerLevel = 0.0;
LOGP(DL1C, LOGL_NOTICE, "Init TRX (ARFCN %u, TSC %u, RxPower % 2f dBm, "
diff --git a/src/osmo-bts-sysmo/sysmobts_vty.c b/src/osmo-bts-sysmo/sysmobts_vty.c
index cad29f5a..3c1dafa4 100644
--- a/src/osmo-bts-sysmo/sysmobts_vty.c
+++ b/src/osmo-bts-sysmo/sysmobts_vty.c
@@ -175,15 +175,15 @@ DEFUN(cfg_trx_cal_path, cfg_trx_cal_path_cmd,
return CMD_SUCCESS;
}
-DEFUN(cfg_trx_ul_power_target, cfg_trx_ul_power_target_cmd,
+DEFUN_DEPRECATED(cfg_trx_ul_power_target, cfg_trx_ul_power_target_cmd,
"uplink-power-target <-110-0>",
- "Set the nominal target Rx Level for uplink power control loop\n"
+ "Obsolete alias for bts uplink-power-target\n"
"Target uplink Rx level in dBm\n")
{
struct gsm_bts_trx *trx = vty->index;
- struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx);
+ struct gsm_bts_role_bts *btsb = bts_role_bts(trx->bts);
- fl1h->ul_power_target = atoi(argv[0]);
+ btsb->ul_power_target = atoi(argv[0]);
return CMD_SUCCESS;
}
@@ -484,8 +484,6 @@ void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx)
vty_out(vty, " clock-source %s%s",
get_value_string(femtobts_clksrc_names, fl1h->clk_src),
VTY_NEWLINE);
- vty_out(vty, " uplink-power-target %d%s", fl1h->ul_power_target,
- VTY_NEWLINE);
vty_out(vty, " min-qual-rach %.0f%s", fl1h->min_qual_rach * 10.0f,
VTY_NEWLINE);
vty_out(vty, " min-qual-norm %.0f%s", fl1h->min_qual_norm * 10.0f,
@@ -536,7 +534,6 @@ int bts_model_vty_init(struct gsm_bts *bts)
install_element(TRX_NODE, &cfg_trx_clkcal_def_cmd);
install_element(TRX_NODE, &cfg_trx_clksrc_cmd);
install_element(TRX_NODE, &cfg_trx_cal_path_cmd);
- install_element(TRX_NODE, &cfg_trx_ul_power_target_cmd);
install_element(TRX_NODE, &cfg_trx_min_qual_rach_cmd);
install_element(TRX_NODE, &cfg_trx_min_qual_norm_cmd);
install_element(TRX_NODE, &cfg_trx_nominal_power_cmd);
diff --git a/tests/sysmobts/sysmobts_test.c b/tests/sysmobts/sysmobts_test.c
index 47c351c0..99fd4c7d 100644
--- a/tests/sysmobts/sysmobts_test.c
+++ b/tests/sysmobts/sysmobts_test.c
@@ -19,6 +19,7 @@
#include <osmo-bts/bts.h>
#include <osmo-bts/l1sap.h>
+#include <osmo-bts/power_control.h>
#include "femtobts.h"
#include "l1_if.h"
@@ -186,12 +187,14 @@ static void test_sysmobts_cipher(void)
static void test_sysmobts_loop(void)
{
struct gsm_bts bts;
+ struct gsm_bts_role_bts btsb;
struct gsm_bts_trx trx;
struct gsm_bts_trx_ts ts;
struct gsm_lchan *lchan;
int ret;
memset(&bts, 0, sizeof(bts));
+ memset(&btsb, 0, sizeof(btsb));
memset(&trx, 0, sizeof(trx));
memset(&ts, 0, sizeof(ts));
@@ -199,8 +202,10 @@ static void test_sysmobts_loop(void)
lchan->ts = &ts;
ts.trx = &trx;
trx.bts = &bts;
+ bts.role = &btsb;
bts.band = GSM_BAND_1800;
trx.ms_power_control = 1;
+ btsb.ul_power_target = -75;
printf("Testing sysmobts power control\n");
@@ -208,7 +213,7 @@ static void test_sysmobts_loop(void)
lchan->state = LCHAN_S_NONE;
lchan->ms_power_ctrl.current = ms_pwr_ctl_lvl(GSM_BAND_1800, 0);
OSMO_ASSERT(lchan->ms_power_ctrl.current == 15);
- ret = l1if_ms_pwr_ctrl(lchan, -75, lchan->ms_power_ctrl.current, -60);
+ ret = lchan_ms_pwr_ctrl(lchan, lchan->ms_power_ctrl.current, -60);
OSMO_ASSERT(ret == 0);
OSMO_ASSERT(lchan->ms_power_ctrl.current == 15);
@@ -217,24 +222,24 @@ static void test_sysmobts_loop(void)
* Now 15 dB too little and we should power it up. Could be a
* power level of 7 or 8 for 15 dBm
*/
- ret = l1if_ms_pwr_ctrl(lchan, -75, lchan->ms_power_ctrl.current, -90);
+ ret = lchan_ms_pwr_ctrl(lchan, lchan->ms_power_ctrl.current, -90);
OSMO_ASSERT(ret == 1);
OSMO_ASSERT(lchan->ms_power_ctrl.current == 7);
/* It should be clamped to level 0 and 30 dBm */
- ret = l1if_ms_pwr_ctrl(lchan, -75, lchan->ms_power_ctrl.current, -100);
+ ret = lchan_ms_pwr_ctrl(lchan, lchan->ms_power_ctrl.current, -100);
OSMO_ASSERT(ret == 1);
OSMO_ASSERT(lchan->ms_power_ctrl.current == 0);
/* Fix it and jump down */
lchan->ms_power_ctrl.fixed = 1;
- ret = l1if_ms_pwr_ctrl(lchan, -75, lchan->ms_power_ctrl.current, -60);
+ ret = lchan_ms_pwr_ctrl(lchan, lchan->ms_power_ctrl.current, -60);
OSMO_ASSERT(ret == 0);
OSMO_ASSERT(lchan->ms_power_ctrl.current == 0);
/* And leave it again */
lchan->ms_power_ctrl.fixed = 0;
- ret = l1if_ms_pwr_ctrl(lchan, -75, lchan->ms_power_ctrl.current, -40);
+ ret = lchan_ms_pwr_ctrl(lchan, lchan->ms_power_ctrl.current, -40);
OSMO_ASSERT(ret == 1);
OSMO_ASSERT(lchan->ms_power_ctrl.current == 15);
}