aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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);
}