aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHolger Hans Peter Freyther <holger@moiji-mobile.com>2014-12-06 20:30:52 +0100
committerHolger Hans Peter Freyther <holger@moiji-mobile.com>2015-02-05 23:02:42 +0100
commit35f49065f59053364b73f4343103d463ed6ec058 (patch)
tree6c62a503e3795049159662d785391cee61d65bc3
parentbc24955e91f050e904851f589400eac4c3443917 (diff)
power/sysmobts: Add a manual ms power level control
Currently the DSP is instructed to achieve a given uplink power target but there are circumstances (e.g. EMV testing) where we need more control over it. The "manual/software/osmo" power control can only be implemented per TRX and not per lchan. Add a very very basic control that checks the MS Power used by the phone, the actual receive level and then adjust the power. The code doesn't take the history into account, if the phone can not reach the requested power level the code will be stuck (e.g. no timeout based on multiframes). It has a mode for a fixed power control but no way to set it yet. The change of the mode requires a restart of the software. Conflicts: include/osmo-bts/bts_model.h src/common/vty.c src/osmo-bts-sysmo/l1_if.c src/osmo-bts-sysmo/l1_if.h src/osmo-bts-sysmo/oml.c tests/sysmobts/sysmobts_test.c
-rw-r--r--include/osmo-bts/bts.h3
-rw-r--r--include/osmo-bts/bts_model.h1
-rw-r--r--src/common/bts.c5
-rw-r--r--src/common/rsl.c10
-rw-r--r--src/common/vty.c14
-rw-r--r--src/osmo-bts-sysmo/l1_if.c84
-rw-r--r--src/osmo-bts-sysmo/l1_if.h2
-rw-r--r--src/osmo-bts-sysmo/oml.c39
-rw-r--r--tests/sysmobts/Makefile.am12
-rw-r--r--tests/sysmobts/sysmobts_test.c65
-rw-r--r--tests/sysmobts/sysmobts_test.ok1
11 files changed, 219 insertions, 17 deletions
diff --git a/include/osmo-bts/bts.h b/include/osmo-bts/bts.h
index e489973..bfa2dc3 100644
--- a/include/osmo-bts/bts.h
+++ b/include/osmo-bts/bts.h
@@ -39,5 +39,8 @@ void load_timer_start(struct gsm_bts *bts);
void bts_update_status(enum bts_global_status which, int on);
+int trx_ms_pwr_ctrl_is_osmo(struct gsm_bts_trx *trx);
+
+
#endif /* _BTS_H */
diff --git a/include/osmo-bts/bts_model.h b/include/osmo-bts/bts_model.h
index 2641db7..3d4a88e 100644
--- a/include/osmo-bts/bts_model.h
+++ b/include/osmo-bts/bts_model.h
@@ -46,4 +46,5 @@ void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx);
int bts_model_oml_estab(struct gsm_bts *bts);
+int bts_model_adjst_ms_pwr(struct gsm_lchan *lchan);
#endif
diff --git a/src/common/bts.c b/src/common/bts.c
index 878770a..4c9d04a 100644
--- a/src/common/bts.c
+++ b/src/common/bts.c
@@ -595,3 +595,8 @@ int bts_supports_cipher(struct gsm_bts_role_bts *bts, int rsl_cipher)
sup = (1 << (rsl_cipher - 2)) & bts->support.ciphers;
return sup > 0;
}
+
+int trx_ms_pwr_ctrl_is_osmo(struct gsm_bts_trx *trx)
+{
+ return trx->ms_power_control == 1;
+}
diff --git a/src/common/rsl.c b/src/common/rsl.c
index bc7fddb..5082f2a 100644
--- a/src/common/rsl.c
+++ b/src/common/rsl.c
@@ -709,6 +709,11 @@ static int rsl_rx_chan_activ(struct msgb *msg)
return rsl_tx_chan_act_nack(lchan, RSL_ERR_EQUIPMENT_FAIL);
}
+ /* Initialize channel defaults */
+ lchan->ms_power = ms_pwr_ctl_lvl(lchan->ts->trx->bts->band, 0);
+ lchan->ms_power_ctrl.current = lchan->ms_power;
+ lchan->ms_power_ctrl.fixed = 0;
+
rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg));
/* 9.3.3 Activation Type */
@@ -748,8 +753,11 @@ static int rsl_rx_chan_activ(struct msgb *msg)
if (TLVP_PRESENT(&tp, RSL_IE_BS_POWER))
lchan->bs_power = *TLVP_VAL(&tp, RSL_IE_BS_POWER);
/* 9.3.13 MS Power */
- if (TLVP_PRESENT(&tp, RSL_IE_MS_POWER))
+ if (TLVP_PRESENT(&tp, RSL_IE_MS_POWER)) {
lchan->ms_power = *TLVP_VAL(&tp, RSL_IE_MS_POWER);
+ lchan->ms_power_ctrl.current = lchan->ms_power;
+ lchan->ms_power_ctrl.fixed = 0;
+ }
/* 9.3.24 Timing Advance */
if (TLVP_PRESENT(&tp, RSL_IE_TIMING_ADVANCE))
lchan->rqd_ta = *TLVP_VAL(&tp, RSL_IE_TIMING_ADVANCE);
diff --git a/src/common/vty.c b/src/common/vty.c
index 3af697c..0056b1b 100644
--- a/src/common/vty.c
+++ b/src/common/vty.c
@@ -202,6 +202,9 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
llist_for_each_entry(trx, &bts->trx_list, list) {
vty_out(vty, " trx %u%s", trx->nr, VTY_NEWLINE);
+ vty_out(vty, " ms-power-control %s%s",
+ trx->ms_power_control == 0 ? "dsp" : "osmo",
+ VTY_NEWLINE);
bts_model_config_write_trx(vty, trx);
}
}
@@ -399,6 +402,16 @@ DEFUN(cfg_bts_agch_queue_mgmt_default,
return CMD_SUCCESS;
}
+DEFUN(cfg_trx_ms_power_control, cfg_trx_ms_power_control_cmd,
+ "ms-power-control (dsp|osmo)",
+ "Mobile Station Power Level Control (change requires restart)\n"
+ "Handled by DSP\n" "Handled by OsmoBTS\n")
+{
+ struct gsm_bts_trx *trx = vty->index;
+
+ trx->ms_power_control = argv[0][0] == 'd' ? 0 : 1;
+ return CMD_SUCCESS;
+}
/* ======================================================================
* SHOW
@@ -578,6 +591,7 @@ int bts_vty_init(const struct log_info *cat)
install_node(&trx_node, config_write_dummy);
install_default(TRX_NODE);
+ install_element(TRX_NODE, &cfg_trx_ms_power_control_cmd);
install_element(ENABLE_NODE, &bts_t_t_l_jitter_buf_cmd);
return 0;
diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c
index 5bda73f..9440f92 100644
--- a/src/osmo-bts-sysmo/l1_if.c
+++ b/src/osmo-bts-sysmo/l1_if.c
@@ -49,6 +49,7 @@
#include <osmo-bts/measurement.h>
#include <osmo-bts/pcu_if.h>
#include <osmo-bts/handover.h>
+#include <osmo-bts/bts_model.h>
#include <sysmocom/femtobts/superfemto.h>
#include <sysmocom/femtobts/gsml1prim.h>
@@ -476,10 +477,11 @@ static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1,
/* resolve the L2 entity using rts_ind->hLayer2 */
lchan = l1if_hLayer_to_lchan(trx, rts_ind->hLayer2);
le = &lchan->lapdm_ch.lapdm_acch;
- /* if the DSP is taking care of power control
- * (ul_power_target==0), then this value will be
- * overridden. */
- msu_param->u8Buffer[0] = lchan->ms_power;
+ /*
+ * if the DSP is taking care of power control,
+ * then this value will be overridden.
+ */
+ msu_param->u8Buffer[0] = lchan->ms_power_ctrl.current;
msu_param->u8Buffer[1] = lchan->rqd_ta;
rc = lapdm_phsap_dequeue_prim(le, &pp);
if (rc < 0) {
@@ -724,6 +726,14 @@ static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_i
data_ind->msgUnitParam.u8Size);
break;
}
+
+ /*
+ * Handle power control
+ */
+ l1if_ms_pwr_ctrl(lchan, fl1->ul_power_target,
+ data_ind->msgUnitParam.u8Buffer[0] & 0x1f,
+ data_ind->measParam.fRssi);
+
/* Some brilliant engineer decided that the ordering of
* fields on the Um interface is different from the
* order of fields in RLS. See TS 04.04 (Chapter 7.2)
@@ -1640,3 +1650,69 @@ int l1if_rf_clock_info_correct(struct femtol1_hdl *fl1h)
return l1if_req_compl(fl1h, msg, clock_correct_info_cb);
}
#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 1168aea..7c7a978 100644
--- a/src/osmo-bts-sysmo/l1_if.h
+++ b/src/osmo-bts-sysmo/l1_if.h
@@ -124,4 +124,6 @@ int calib_load(struct femtol1_hdl *fl1h);
int l1if_rf_clock_info_reset(struct femtol1_hdl *fl1h);
int l1if_rf_clock_info_correct(struct femtol1_hdl *fl1h);
+inline int l1if_ms_pwr_ctrl(struct gsm_lchan *lchan, const int uplink_target,
+ const uint8_t ms_power, const float rxLevel);
#endif /* _FEMTO_L1_H */
diff --git a/src/osmo-bts-sysmo/oml.c b/src/osmo-bts-sysmo/oml.c
index 4ebf664..cc3f23b 100644
--- a/src/osmo-bts-sysmo/oml.c
+++ b/src/osmo-bts-sysmo/oml.c
@@ -322,7 +322,8 @@ static int trx_init(struct gsm_bts_trx *trx)
dev_par->u16Arfcn = trx->arfcn;
dev_par->u16BcchArfcn = trx->bts->c0->arfcn;
dev_par->u8NbTsc = trx->bts->bsic & 7;
- dev_par->fRxPowerLevel = fl1h->ul_power_target;
+ dev_par->fRxPowerLevel = trx_ms_pwr_ctrl_is_osmo(trx)
+ ? 0.0 : fl1h->ul_power_target;
dev_par->fTxPowerLevel = sysmobts_get_power_trx(trx);
LOGP(DL1C, LOGL_NOTICE, "Init TRX (ARFCN %u, TSC %u, RxPower % 2f dBm, "
"TxPower % 2.2f dBm\n", dev_par->u16Arfcn, dev_par->u8NbTsc,
@@ -894,12 +895,16 @@ static int mph_send_activate_req(struct gsm_lchan *lchan, struct sapi_cmd *cmd)
case GsmL1_Sapi_Prach:
lch_par->prach.u8Bsic = lchan->ts->trx->bts->bsic;
break;
- case GsmL1_Sapi_Pdtch:
- case GsmL1_Sapi_Pacch:
case GsmL1_Sapi_Sacch:
/*
- * TODO: For the SACCH we need to set the u8MsPowerLevel when
- * doing manual MS power control. */
+ * For the SACCH we need to set the u8MsPowerLevel when
+ * doing manual MS power control.
+ */
+ if (trx_ms_pwr_ctrl_is_osmo(lchan->ts->trx))
+ lch_par->sacch.u8MsPowerLevel = lchan->ms_power_ctrl.current;
+ /* fall through */
+ case GsmL1_Sapi_Pdtch:
+ case GsmL1_Sapi_Pacch:
/*
* Be sure that every packet is received, even if it
* fails. In this case the length might be lower or 0.
@@ -1136,7 +1141,8 @@ err:
static int mph_send_config_logchpar(struct gsm_lchan *lchan, struct sapi_cmd *cmd)
{
- struct femtol1_hdl *fl1h = trx_femtol1_hdl(lchan->ts->trx);
+ struct gsm_bts_trx *trx = lchan->ts->trx;
+ struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx);
struct msgb *msg = l1p_msgb_alloc();
GsmL1_MphConfigReq_t *conf_req;
GsmL1_LogChParam_t *lch_par;
@@ -1146,7 +1152,7 @@ static int mph_send_config_logchpar(struct gsm_lchan *lchan, struct sapi_cmd *cm
/* update multi-rate config */
conf_req = prim_init(msgb_l1prim(msg), GsmL1_PrimId_MphConfigReq, fl1h);
conf_req->cfgParamId = GsmL1_ConfigParamId_SetLogChParams;
- conf_req->cfgParams.setLogChParams.sapi = lchan_to_GsmL1_Sapi_t(lchan);
+ conf_req->cfgParams.setLogChParams.sapi = cmd->sapi;
conf_req->cfgParams.setLogChParams.u8Tn = lchan->ts->nr;
conf_req->cfgParams.setLogChParams.subCh = lchan_to_GsmL1_SubCh_t(lchan);
conf_req->cfgParams.setLogChParams.dir = cmd->dir;
@@ -1155,6 +1161,10 @@ static int mph_send_config_logchpar(struct gsm_lchan *lchan, struct sapi_cmd *cm
lch_par = &conf_req->cfgParams.setLogChParams.logChParams;
lchan2lch_par(lch_par, lchan);
+ /* Update the MS Power Level */
+ if (cmd->sapi == GsmL1_Sapi_Sacch && trx_ms_pwr_ctrl_is_osmo(trx))
+ lch_par->sacch.u8MsPowerLevel = lchan->ms_power_ctrl.current;
+
/* FIXME: update encryption */
LOGP(DL1C, LOGL_INFO, "%s MPH-CONFIG.req (%s) ",
@@ -1172,19 +1182,19 @@ static int mph_send_config_logchpar(struct gsm_lchan *lchan, struct sapi_cmd *cm
return l1if_gsm_req_compl(fl1h, msg, chmod_modif_compl_cb);
}
-static void enqueue_sapi_logchpar_cmd(struct gsm_lchan *lchan, int dir)
+static void enqueue_sapi_logchpar_cmd(struct gsm_lchan *lchan, int dir, GsmL1_Sapi_t sapi)
{
struct sapi_cmd *cmd = talloc_zero(lchan->ts->trx, struct sapi_cmd);
cmd->dir = dir;
+ cmd->sapi = sapi;
cmd->type = SAPI_CMD_CONFIG_LOGCH_PARAM;
queue_sapi_command(lchan, cmd);
}
static int tx_confreq_logchpar(struct gsm_lchan *lchan, uint8_t direction)
{
- enqueue_sapi_logchpar_cmd(lchan, direction);
-
+ enqueue_sapi_logchpar_cmd(lchan, direction, lchan_to_GsmL1_Sapi_t(lchan));
return 0;
}
@@ -1267,6 +1277,15 @@ int l1if_set_ciphering(struct femtol1_hdl *fl1h,
return 0;
}
+int bts_model_adjst_ms_pwr(struct gsm_lchan *lchan)
+{
+ if (lchan->state != LCHAN_S_ACTIVE)
+ return -1;
+
+ enqueue_sapi_logchpar_cmd(lchan, GsmL1_Dir_RxUplink, GsmL1_Sapi_Sacch);
+ return 0;
+}
+
int bts_model_rsl_mode_modify(struct gsm_lchan *lchan)
{
if (lchan->state != LCHAN_S_ACTIVE)
diff --git a/tests/sysmobts/Makefile.am b/tests/sysmobts/Makefile.am
index d884237..79d13a1 100644
--- a/tests/sysmobts/Makefile.am
+++ b/tests/sysmobts/Makefile.am
@@ -5,5 +5,13 @@ LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOTRAU_
noinst_PROGRAMS = sysmobts_test
EXTRA_DIST = sysmobts_test.ok
-sysmobts_test_SOURCES = sysmobts_test.c $(top_srcdir)/src/osmo-bts-sysmo/utils.c
-sysmobts_test_LDADD = $(LDADD)
+sysmobts_test_SOURCES = sysmobts_test.c $(top_srcdir)/src/osmo-bts-sysmo/utils.c \
+ $(top_srcdir)/src/osmo-bts-sysmo/l1_if.c \
+ $(top_srcdir)/src/osmo-bts-sysmo/oml.c \
+ $(top_srcdir)/src/osmo-bts-sysmo/l1_transp_hw.c \
+ $(top_srcdir)/src/osmo-bts-sysmo/tch.c \
+ $(top_srcdir)/src/osmo-bts-sysmo/calib_file.c \
+ $(top_srcdir)/src/osmo-bts-sysmo/calib_fixup.c \
+ $(top_srcdir)/src/osmo-bts-sysmo/misc/sysmobts_par.c \
+ $(top_srcdir)/src/osmo-bts-sysmo/eeprom.c
+sysmobts_test_LDADD = $(top_builddir)/src/common/libbts.a $(LIBOSMOABIS_LIBS) $(LDADD)
diff --git a/tests/sysmobts/sysmobts_test.c b/tests/sysmobts/sysmobts_test.c
index 291f6da..5f8d713 100644
--- a/tests/sysmobts/sysmobts_test.c
+++ b/tests/sysmobts/sysmobts_test.c
@@ -125,9 +125,74 @@ static void test_sysmobts_auto_band(void)
}
}
+static void test_sysmobts_loop(void)
+{
+ struct gsm_bts bts;
+ struct gsm_bts_trx trx;
+ struct gsm_bts_trx_ts ts;
+ struct gsm_lchan *lchan;
+ int ret;
+
+ memset(&bts, 0, sizeof(bts));
+ memset(&trx, 0, sizeof(trx));
+ memset(&ts, 0, sizeof(ts));
+
+ lchan = &ts.lchan[0];
+ lchan->ts = &ts;
+ ts.trx = &trx;
+ trx.bts = &bts;
+ bts.band = GSM_BAND_1800;
+ trx.ms_power_control = 1;
+
+ printf("Testing sysmobts power control\n");
+
+ /* Simply clamping */
+ 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);
+ OSMO_ASSERT(ret == 0);
+ OSMO_ASSERT(lchan->ms_power_ctrl.current == 15);
+
+
+ /*
+ * 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);
+ 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);
+ 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);
+ 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);
+ OSMO_ASSERT(ret == 1);
+ OSMO_ASSERT(lchan->ms_power_ctrl.current == 15);
+}
+
int main(int argc, char **argv)
{
printf("Testing sysmobts routines\n");
test_sysmobts_auto_band();
+ test_sysmobts_loop();
return 0;
}
+
+int pcu_direct = 0;
+int bts_model_init(struct gsm_bts *bts)
+{ return 0; }
+void bts_update_status(enum bts_global_status which, int on)
+{ }
+int bts_model_oml_estab(struct gsm_bts *bts)
+{ return 0; }
diff --git a/tests/sysmobts/sysmobts_test.ok b/tests/sysmobts/sysmobts_test.ok
index 1f53417..07d79fd 100644
--- a/tests/sysmobts/sysmobts_test.ok
+++ b/tests/sysmobts/sysmobts_test.ok
@@ -17,3 +17,4 @@ Checking PCS to PCS
PCS to PCS band(1) arfcn(512) want(3) got(3)
PCS to PCS band(8) arfcn(128) want(0) got(0)
PCS to PCS band(2) arfcn(438) want(-1) got(-1)
+Testing sysmobts power control