From 819b50e1a7b506a0a394cc71a795f0a9ce4083c1 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 6 Sep 2015 12:33:16 +0200 Subject: 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. --- include/osmo-bts/Makefile.am | 3 +- include/osmo-bts/gsm_data.h | 2 + include/osmo-bts/power_control.h | 7 +++ src/common/Makefile.am | 2 +- src/common/bts.c | 1 + src/common/l1sap.c | 2 + src/common/power_control.c | 99 +++++++++++++++++++++++++++++++++++++++ src/common/vty.c | 15 ++++++ src/osmo-bts-sysmo/l1_if.c | 80 +------------------------------ src/osmo-bts-sysmo/l1_if.h | 1 - src/osmo-bts-sysmo/oml.c | 3 +- src/osmo-bts-sysmo/sysmobts_vty.c | 11 ++--- tests/sysmobts/sysmobts_test.c | 15 ++++-- 13 files changed, 146 insertions(+), 95 deletions(-) create mode 100644 include/osmo-bts/power_control.h create mode 100644 src/common/power_control.c 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 +#include + +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 . + * + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/* + * 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 #include +#include #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); } -- cgit v1.2.3