aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--configure.ac4
-rw-r--r--include/osmo-bts/Makefile.am2
-rw-r--r--include/osmo-bts/bts_model.h2
-rw-r--r--include/osmo-bts/gsm_data.h1
-rw-r--r--include/osmo-bts/tx_power.h74
-rw-r--r--src/common/Makefile.am4
-rw-r--r--src/common/bts.c6
-rw-r--r--src/common/tx_power.c273
-rw-r--r--src/common/vty.c82
-rw-r--r--src/osmo-bts-sysmo/main.c6
-rw-r--r--src/osmo-bts-sysmo/oml.c21
-rw-r--r--src/osmo-bts-sysmo/sysmobts_vty.c48
-rw-r--r--src/osmo-bts-sysmo/utils.c84
13 files changed, 455 insertions, 152 deletions
diff --git a/configure.ac b/configure.ac
index 2d08b87..8708548 100644
--- a/configure.ac
+++ b/configure.ac
@@ -45,10 +45,10 @@ AC_ARG_WITH([openbsc],
AC_SUBST([OPENBSC_INCDIR], $openbsc_incdir)
oldCPPFLAGS=$CPPFLAGS
-CPPFLAGS="$CPPFLAGS -I$OPENBSC_INCDIR $LIBOSMOCORE_CFLAGS"
+CPPFLAGS="$CPPFLAGS -I$OPENBSC_INCDIR -I$srcdir/include $LIBOSMOCORE_CFLAGS"
AC_CHECK_HEADER([openbsc/gsm_data_shared.h],[],
[AC_MSG_ERROR([openbsc/gsm_data_shared.h can not be found in $openbsc_incdir])],
- [])
+ [#include <osmo-bts/tx_power.h>])
CPPFLAGS=$oldCPPFLAGS
# Check for the sbts2050_header.h that was added after the 3.6 release
diff --git a/include/osmo-bts/Makefile.am b/include/osmo-bts/Makefile.am
index 68d63e0..b294144 100644
--- a/include/osmo-bts/Makefile.am
+++ b/include/osmo-bts/Makefile.am
@@ -1,3 +1,3 @@
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
+ handover.h msg_utils.h tx_power.h
diff --git a/include/osmo-bts/bts_model.h b/include/osmo-bts/bts_model.h
index 2641db7..200d02d 100644
--- a/include/osmo-bts/bts_model.h
+++ b/include/osmo-bts/bts_model.h
@@ -46,4 +46,6 @@ 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_change_power(struct gsm_bts_trx *trx, int p_trxout_mdBm);
+
#endif
diff --git a/include/osmo-bts/gsm_data.h b/include/osmo-bts/gsm_data.h
index c7a0fc6..5e0af77 100644
--- a/include/osmo-bts/gsm_data.h
+++ b/include/osmo-bts/gsm_data.h
@@ -6,6 +6,7 @@
#include <osmocom/gsm/lapdm.h>
#include <osmo-bts/paging.h>
+#include <osmo-bts/tx_power.h>
#define GSM_BTS_AGCH_QUEUE_THRESH_LEVEL_DEFAULT 41
#define GSM_BTS_AGCH_QUEUE_THRESH_LEVEL_DISABLE 999999
diff --git a/include/osmo-bts/tx_power.h b/include/osmo-bts/tx_power.h
new file mode 100644
index 0000000..c5d6f2b
--- /dev/null
+++ b/include/osmo-bts/tx_power.h
@@ -0,0 +1,74 @@
+#pragma once
+
+#include <stdint.h>
+#include <osmocom/core/timer.h>
+
+/* our unit is 'milli dB" or "milli dBm", i.e. 1/1000 of a dB(m) */
+#define to_mdB(x) (x * 1000)
+
+/* PA calibration table */
+struct pa_calibration {
+ int gain_mdB[1024]; /* gain provided at given ARFCN */
+ /* FIXME: thermal calibration */
+};
+
+/* representation of a RF power amplifier */
+struct power_amp {
+ /* nominal gain of the PA */
+ int nominal_gain_mdB;
+ /* table with calibrated actual gain for each ARFCN */
+ struct pa_calibration calib;
+};
+
+/* Transmit power related parameters of a transceiver */
+struct trx_power_params {
+ /* specified maximum output of TRX at full power, has to be
+ * initialized by BTS model at startup*/
+ int trx_p_max_out_mdBm;
+
+ /* intended current total system output power */
+ int p_total_tgt_mdBm;
+
+ /* actual current total system output power, filled in by tx_power code */
+ int p_total_cur_mdBm;
+
+ /* current temporary attenuation due to thermal management,
+ * set by thermal management code via control interface */
+ int thermal_attenuation_mdB;
+
+ /* external gain (+) or attenuation (-) added by the user, configured
+ * by the user via VTY */
+ int user_gain_mdB;
+
+ /* calibration table of internal PA */
+ struct power_amp pa;
+
+ /* calibration table of user PA */
+ struct power_amp user_pa;
+
+ /* power ramping related data */
+ struct {
+ /* maximum initial Pout including all PAs */
+ int max_initial_pout_mdBm;
+ /* temporary attenuation due to power ramping */
+ int attenuation_mdB;
+ unsigned int step_size_mdB;
+ unsigned int step_interval_sec;
+ struct osmo_timer_list step_timer;
+ } ramp;
+};
+
+int get_p_max_out_mdBm(struct gsm_bts_trx *trx);
+
+int get_p_nominal_mdBm(struct gsm_bts_trx *trx);
+
+int get_p_target_mdBm(struct gsm_bts_trx *trx, uint8_t bs_power_ie);
+int get_p_target_mdBm_lchan(struct gsm_lchan *lchan);
+
+int get_p_trxout_target_mdBm(struct gsm_bts_trx *trx, uint8_t bs_power_ie);
+int get_p_trxout_target_mdBm_lchan(struct gsm_lchan *lchan);
+
+int get_p_trxout_actual_mdBm(struct gsm_bts_trx *trx, uint8_t bs_power_ie);
+int get_p_trxout_actual_mdBm_lchan(struct gsm_lchan *lchan);
+
+int power_ramp_start(struct gsm_bts_trx *trx, int p_total_tgt_mdBm, int bypass);
diff --git a/src/common/Makefile.am b/src/common/Makefile.am
index ea2a742..77f73b4 100644
--- a/src/common/Makefile.am
+++ b/src/common/Makefile.am
@@ -5,4 +5,6 @@ LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOTRAU_LIBS)
noinst_LIBRARIES = libbts.a
libbts_a_SOURCES = gsm_data_shared.c sysinfo.c logging.c abis.c oml.c bts.c \
rsl.c vty.c paging.c measurement.c amr.c lchan.c \
- load_indication.c pcu_sock.c handover.c msg_utils.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
diff --git a/src/common/bts.c b/src/common/bts.c
index 878770a..6cbafd1 100644
--- a/src/common/bts.c
+++ b/src/common/bts.c
@@ -120,7 +120,9 @@ int bts_init(struct gsm_bts *bts)
/* initialize bts data structure */
llist_for_each_entry(trx, &bts->trx_list, list) {
+ struct trx_power_params *tpp = &trx->power_params;
int i;
+
for (i = 0; i < ARRAY_SIZE(trx->ts); i++) {
struct gsm_bts_trx_ts *ts = &trx->ts[i];
int k;
@@ -130,6 +132,10 @@ int bts_init(struct gsm_bts *bts)
INIT_LLIST_HEAD(&lchan->dl_tch_queue);
}
}
+ /* Default values for the power adjustments */
+ tpp->ramp.max_initial_pout_mdBm = to_mdB(23);
+ tpp->ramp.step_size_mdB = to_mdB(2);
+ tpp->ramp.step_interval_sec = 1;
}
osmo_rtp_init(tall_bts_ctx);
diff --git a/src/common/tx_power.c b/src/common/tx_power.c
new file mode 100644
index 0000000..e2bb9ed
--- /dev/null
+++ b/src/common/tx_power.c
@@ -0,0 +1,273 @@
+/* Transmit Power computation */
+
+/* (C) 2014 by Harald Welte <laforge@gnumonks.org>
+ *
+ * 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 <limits.h>
+#include <errno.h>
+
+#include <osmocom/core/utils.h>
+
+#include <osmo-bts/logging.h>
+#include <osmo-bts/gsm_data.h>
+#include <osmo-bts/bts_model.h>
+#include <osmo-bts/tx_power.h>
+
+static int get_pa_drive_level_mdBm(const struct power_amp *pa,
+ int desired_p_out_mdBm, unsigned int arfcn)
+{
+ if (arfcn > ARRAY_SIZE(pa->calib.gain_mdB))
+ return INT_MIN;
+
+ /* FIXME: temperature compensation */
+
+ return desired_p_out_mdBm - pa->calib.gain_mdB[arfcn];
+}
+
+/* maximum output power of the system */
+int get_p_max_out_mdBm(struct gsm_bts_trx *trx)
+{
+ struct trx_power_params *tpp = &trx->power_params;
+ /* Add user gain, internal and external PA gain to TRX output power */
+ return tpp->trx_p_max_out_mdBm + tpp->user_gain_mdB +
+ tpp->pa.nominal_gain_mdB + tpp->user_pa.nominal_gain_mdB;
+}
+
+/* nominal output power, i.e. OML-reduced maximum output power */
+int get_p_nominal_mdBm(struct gsm_bts_trx *trx)
+{
+ /* P_max_out subtracted by OML maximum power reduction IE */
+ return get_p_max_out_mdBm(trx) - to_mdB(trx->max_power_red);
+}
+
+/* calculate the target total output power required, reduced by both
+ * OML and RSL, but ignoring the attenutation required for power ramping and
+ * thermal management */
+int get_p_target_mdBm(struct gsm_bts_trx *trx, uint8_t bs_power_ie)
+{
+ /* Pn subtracted by RSL BS Power IE (in 2 dB steps) */
+ return get_p_nominal_mdBm(trx) - to_mdB(bs_power_ie * 2);
+}
+int get_p_target_mdBm_lchan(struct gsm_lchan *lchan)
+{
+ return get_p_target_mdBm(lchan->ts->trx, lchan->bs_power);
+}
+
+/* calculate the actual total output power required, taking into account the
+ * attenutation required for power ramping but not thermal management */
+int get_p_actual_mdBm(struct gsm_bts_trx *trx, int p_target_mdBm)
+{
+ struct trx_power_params *tpp = &trx->power_params;
+
+ /* P_target subtracted by ramp attenuation */
+ return p_target_mdBm - tpp->ramp.attenuation_mdB;
+}
+
+/* calculate the effective total output power required, taking into account the
+ * attenutation required for power ramping and thermal management */
+int get_p_eff_mdBm(struct gsm_bts_trx *trx, int p_target_mdBm)
+{
+ struct trx_power_params *tpp = &trx->power_params;
+
+ /* P_target subtracted by ramp attenuation */
+ return p_target_mdBm - tpp->ramp.attenuation_mdB - tpp->thermal_attenuation_mdB;
+}
+
+/* calculate effect TRX output power required, taking into account the
+ * attenuations required for power ramping and thermal management */
+int get_p_trxout_eff_mdBm(struct gsm_bts_trx *trx, int p_target_mdBm)
+{
+ struct trx_power_params *tpp = &trx->power_params;
+ int p_actual_mdBm, user_pa_drvlvl_mdBm, pa_drvlvl_mdBm;
+ unsigned int arfcn = trx->arfcn;
+
+ /* P_actual subtracted by any bulk gaion added by the user */
+ p_actual_mdBm = get_p_eff_mdBm(trx, p_target_mdBm) - tpp->user_gain_mdB;
+
+ /* determine input drive level required at input to user PA */
+ user_pa_drvlvl_mdBm = get_pa_drive_level_mdBm(&tpp->user_pa, p_actual_mdBm, arfcn);
+
+ /* determine input drive level required at input to internal PA */
+ pa_drvlvl_mdBm = get_pa_drive_level_mdBm(&tpp->pa, user_pa_drvlvl_mdBm, arfcn);
+
+ /* internal PA input drive level is TRX output power */
+ return pa_drvlvl_mdBm;
+}
+
+/* calculate target TRX output power required, ignoring the
+ * attenuations required for power ramping but not thermal management */
+int get_p_trxout_target_mdBm(struct gsm_bts_trx *trx, uint8_t bs_power_ie)
+{
+ struct trx_power_params *tpp = &trx->power_params;
+ int p_target_mdBm, user_pa_drvlvl_mdBm, pa_drvlvl_mdBm;
+ unsigned int arfcn = trx->arfcn;
+
+ /* P_target subtracted by any bulk gaion added by the user */
+ p_target_mdBm = get_p_target_mdBm(trx, bs_power_ie) - tpp->user_gain_mdB;
+
+ /* determine input drive level required at input to user PA */
+ user_pa_drvlvl_mdBm = get_pa_drive_level_mdBm(&tpp->user_pa, p_target_mdBm, arfcn);
+
+ /* determine input drive level required at input to internal PA */
+ pa_drvlvl_mdBm = get_pa_drive_level_mdBm(&tpp->pa, user_pa_drvlvl_mdBm, arfcn);
+
+ /* internal PA input drive level is TRX output power */
+ return pa_drvlvl_mdBm;
+}
+int get_p_trxout_target_mdBm_lchan(struct gsm_lchan *lchan)
+{
+ return get_p_trxout_target_mdBm(lchan->ts->trx, lchan->bs_power);
+}
+
+
+/* output power ramping code */
+
+/* The idea here is to avoid a hard switch from 0 to 100, but to actually
+ * slowly and gradually ramp up or down the power. This is needed on the
+ * one hand side to avoid very fast dynamic load changes towards the PA power
+ * supply, but is also needed in order to avoid a DoS by too many subscriber
+ * attempting to register at the same time. Rather, grow the cell slowly in
+ * radius than start with the full raduis at once. */
+
+static int we_are_ramping_up(struct gsm_bts_trx *trx)
+{
+ struct trx_power_params *tpp = &trx->power_params;
+
+ if (tpp->p_total_tgt_mdBm > tpp->p_total_cur_mdBm)
+ return 1;
+ else
+ return 0;
+}
+
+static void power_ramp_do_step(struct gsm_bts_trx *trx, int first);
+
+/* timer call-back for the ramp tumer */
+static void power_ramp_timer_cb(void *_trx)
+{
+ struct gsm_bts_trx *trx = _trx;
+ struct trx_power_params *tpp = &trx->power_params;
+ int p_trxout_eff_mdBm;
+
+ /* compute new actual total output power (= minus ramp attenuation) */
+ tpp->p_total_cur_mdBm = get_p_actual_mdBm(trx, tpp->p_total_tgt_mdBm);
+
+ /* compute new effective (= minus ramp and thermal attenuation) TRX output required */
+ p_trxout_eff_mdBm = get_p_trxout_eff_mdBm(trx, tpp->p_total_tgt_mdBm);
+
+ LOGP(DL1C, LOGL_DEBUG, "ramp_timer_cb(cur_pout=%d, tgt_pout=%d, "
+ "ramp_att=%d, therm_att=%d, user_gain=%d)\n",
+ tpp->p_total_cur_mdBm, tpp->p_total_tgt_mdBm,
+ tpp->ramp.attenuation_mdB, tpp->thermal_attenuation_mdB,
+ tpp->user_gain_mdB);
+
+ LOGP(DL1C, LOGL_INFO,
+ "ramping TRX board output power to %d mdBm.\n", p_trxout_eff_mdBm);
+
+ /* Instruct L1 to apply new effective TRX output power required */
+ bts_model_change_power(trx, p_trxout_eff_mdBm);
+
+ /* and do another step... */
+ power_ramp_do_step(trx, 0);
+}
+
+static void power_ramp_do_step(struct gsm_bts_trx *trx, int first)
+{
+ struct trx_power_params *tpp = &trx->power_params;
+
+ /* we had finished in last loop iteration */
+ if (!first && tpp->ramp.attenuation_mdB == 0)
+ return;
+
+ if (we_are_ramping_up(trx)) {
+ /* ramp up power -> ramp down attenuation */
+ tpp->ramp.attenuation_mdB -= tpp->ramp.step_size_mdB;
+ if (tpp->ramp.attenuation_mdB <= 0) {
+ /* we are done */
+ tpp->ramp.attenuation_mdB = 0;
+ }
+ } else {
+ /* ramp down power -> ramp up attenuation */
+ tpp->ramp.attenuation_mdB += tpp->ramp.step_size_mdB;
+ if (tpp->ramp.attenuation_mdB >= 0) {
+ /* we are done */
+ tpp->ramp.attenuation_mdB = 0;
+ }
+ }
+
+ /* schedule timer for the next step */
+ tpp->ramp.step_timer.data = trx;
+ tpp->ramp.step_timer.cb = power_ramp_timer_cb;
+ osmo_timer_schedule(&tpp->ramp.step_timer, tpp->ramp.step_interval_sec, 0);
+}
+
+
+int power_ramp_start(struct gsm_bts_trx *trx, int p_total_tgt_mdBm, int bypass)
+{
+ struct trx_power_params *tpp = &trx->power_params;
+
+ /* The input to this function is the actual desired output power, i.e.
+ * the maximum total system power subtracted by OML as well as RSL
+ * reductions */
+
+ LOGP(DL1C, LOGL_INFO, "power_ramp_start(cur=%d, tgt=%d)\n",
+ tpp->p_total_cur_mdBm, p_total_tgt_mdBm);
+
+ if (!bypass && (p_total_tgt_mdBm > get_p_nominal_mdBm(trx))) {
+ LOGP(DL1C, LOGL_ERROR, "Asked to ramp power up to "
+ "%d mdBm, which exceeds P_max_out (%d)\n",
+ p_total_tgt_mdBm, get_p_nominal_mdBm(trx));
+ return -ERANGE;
+ }
+
+ /* Cancel any pending request */
+ osmo_timer_del(&tpp->ramp.step_timer);
+
+ /* set the new target */
+ tpp->p_total_tgt_mdBm = p_total_tgt_mdBm;
+
+ if (we_are_ramping_up(trx)) {
+ if (tpp->p_total_tgt_mdBm <= tpp->ramp.max_initial_pout_mdBm) {
+ LOGP(DL1C, LOGL_INFO,
+ "target_power(%d) is below max.initial power\n",
+ tpp->p_total_tgt_mdBm);
+ /* new setting is below the maximum initial output
+ * power, so we can directly jump to this level */
+ tpp->p_total_cur_mdBm = tpp->p_total_tgt_mdBm;
+ tpp->ramp.attenuation_mdB = 0;
+ power_ramp_timer_cb(trx);
+ } else {
+ /* We need to step it up. Start from the current value */
+ /* Set attenuation to cause no power change right now */
+ tpp->ramp.attenuation_mdB = tpp->p_total_tgt_mdBm - tpp->p_total_cur_mdBm;
+
+ /* start with the firsrt step */
+ power_ramp_do_step(trx, 1);
+ }
+ } else {
+ /* Set ramp attenuation to negative value, and increse that by
+ * steps until it reaches 0 */
+ tpp->ramp.attenuation_mdB = tpp->p_total_tgt_mdBm - tpp->p_total_cur_mdBm;
+
+ /* start with the firsrt step */
+ power_ramp_do_step(trx, 1);
+ }
+
+ return 0;
+}
diff --git a/src/common/vty.c b/src/common/vty.c
index ea38ac9..a2f2fb3 100644
--- a/src/common/vty.c
+++ b/src/common/vty.c
@@ -186,7 +186,19 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
bts_model_config_write_bts(vty, bts);
llist_for_each_entry(trx, &bts->trx_list, list) {
+ struct trx_power_params *tpp = &trx->power_params;
vty_out(vty, " trx %u%s", trx->nr, VTY_NEWLINE);
+
+ if (trx->power_params.user_gain_mdB)
+ vty_out(vty, " user-gain %u mdB%s",
+ tpp->user_gain_mdB, VTY_NEWLINE);
+ vty_out(vty, " power-ramp max-initinal-pout %d mdBm%s",
+ tpp->ramp.max_initial_pout_mdBm, VTY_NEWLINE);
+ vty_out(vty, " power-ramp step-size %d mdBm%s",
+ tpp->ramp.step_size_mdB, VTY_NEWLINE);
+ vty_out(vty, " power-ramp step-interval %d%s",
+ tpp->ramp.step_interval_sec, VTY_NEWLINE);
+
bts_model_config_write_trx(vty, trx);
}
}
@@ -384,6 +396,71 @@ DEFUN(cfg_bts_agch_queue_mgmt_default,
return CMD_SUCCESS;
}
+#define DB_DBM_STR \
+ "Unit is dB (decibels)\n" \
+ "Unit is mdB (milli-decibels, or rather 1/10000 bel)\n"
+
+static int parse_mdbm(const char *valstr, const char *unit)
+{
+ int val = atoi(valstr);
+
+ if (!strcmp(unit, "dB") || !strcmp(unit, "dBm"))
+ return val * 1000;
+ else
+ return val;
+}
+
+DEFUN(cfg_trx_user_gain,
+ cfg_trx_user_gain_cmd,
+ "user-gain <-100000-100000> (dB|mdB)",
+ "Inform BTS about additional, user-provided gain or attenuation at TRX output\n"
+ "Value of user-provided external gain(+)/attenuation(-)\n" DB_DBM_STR)
+{
+ struct gsm_bts_trx *trx = vty->index;
+
+ trx->power_params.user_gain_mdB = parse_mdbm(argv[0], argv[1]);
+
+ return CMD_SUCCESS;
+}
+
+#define PR_STR "Power-Ramp settings"
+DEFUN(cfg_trx_pr_max_initial, cfg_trx_pr_max_initial_cmd,
+ "power-ramp max-initial <0-100000> (dBm|mdBm)",
+ PR_STR "Maximum initial power\n"
+ "Value\n" DB_DBM_STR)
+{
+ struct gsm_bts_trx *trx = vty->index;
+
+ trx->power_params.ramp.max_initial_pout_mdBm =
+ parse_mdbm(argv[0], argv[1]);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_trx_pr_step_size, cfg_trx_pr_step_size_cmd,
+ "power-ramp step-size <1-100000> (dB|mdB)",
+ PR_STR "Power increase by step\n"
+ "Step size\n" DB_DBM_STR)
+{
+ struct gsm_bts_trx *trx = vty->index;
+
+ trx->power_params.ramp.step_size_mdB =
+ parse_mdbm(argv[0], argv[1]);
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_trx_pr_step_interval, cfg_trx_pr_step_interval_cmd,
+ "power-ramp step-interval <1-100>",
+ PR_STR "Power increase by step\n"
+ "Step time in seconds\n")
+{
+ struct gsm_bts_trx *trx = vty->index;
+
+ trx->power_params.ramp.step_interval_sec = atoi(argv[0]);
+ return CMD_SUCCESS;
+}
+
+
/* ======================================================================
* SHOW
@@ -563,6 +640,11 @@ 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_user_gain_cmd);
+ install_element(TRX_NODE, &cfg_trx_pr_max_initial_cmd);
+ install_element(TRX_NODE, &cfg_trx_pr_step_size_cmd);
+ install_element(TRX_NODE, &cfg_trx_pr_step_interval_cmd);
+
install_element(ENABLE_NODE, &bts_t_t_l_jitter_buf_cmd);
return 0;
diff --git a/src/osmo-bts-sysmo/main.c b/src/osmo-bts-sysmo/main.c
index 5a86407..d12421d 100644
--- a/src/osmo-bts-sysmo/main.c
+++ b/src/osmo-bts-sysmo/main.c
@@ -84,11 +84,7 @@ int bts_model_init(struct gsm_bts *bts)
rc = 23;
}
bts->c0->nominal_power = rc;
-
- /* Initial values for the power adjustments */
- bts->c0->pa.max_initial_power = 23;
- bts->c0->pa.step_size = 2;
- bts->c0->pa.step_interval = 1;
+ bts->c0->power_params.trx_p_max_out_mdBm = to_mdB(rc);
bts_model_vty_init(bts);
diff --git a/src/osmo-bts-sysmo/oml.c b/src/osmo-bts-sysmo/oml.c
index e5f9260..207cae8 100644
--- a/src/osmo-bts-sysmo/oml.c
+++ b/src/osmo-bts-sysmo/oml.c
@@ -272,7 +272,7 @@ static int trx_init_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg)
#endif
/* Begin to ramp up the power */
- sysmobts_pa_maybe_step(trx);
+ power_ramp_start(trx, get_p_target_mdBm(trx, 0), 0);
return opstart_compl(&trx->mo, l1_msg);
}
@@ -327,9 +327,7 @@ static int trx_init(struct gsm_bts_trx *trx)
dev_par->u8NbTsc = trx->bts->bsic & 7;
dev_par->fRxPowerLevel = fl1h->ul_power_target;
- /* initialize the power */
- sysmobts_pa_pwr_init(trx);
- dev_par->fTxPowerLevel = trx->pa.current_power;
+ dev_par->fTxPowerLevel = 0.0;
LOGP(DL1C, LOGL_NOTICE, "Init TRX (ARFCN %u, TSC %u, RxPower % 2f dBm, "
"TxPower % 2.2f dBm\n", dev_par->u16Arfcn, dev_par->u8NbTsc,
dev_par->fRxPowerLevel, dev_par->fTxPowerLevel);
@@ -1074,12 +1072,8 @@ static int chmod_txpower_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg)
LOGPC(DL1C, LOGL_INFO, "setTxPower %f dBm\n",
cc->cfgParams.setTxPowerLevel.fTxPowerLevel);
- trx->pa.current_power = cc->cfgParams.setTxPowerLevel.fTxPowerLevel;
msgb_free(l1_msg);
- /* Schedule the next step up */
- sysmobts_pa_maybe_step(trx);
-
return 0;
}
@@ -1553,10 +1547,8 @@ int bts_model_apply_oml(struct gsm_bts *bts, struct msgb *msg,
struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx);
/* Did we go through MphInit yet? If yes fire and forget */
- if (fl1h->hLayer1) {
- sysmobts_pa_pwr_init(trx);
- l1if_set_txpower(fl1h, (float) trx->pa.current_power);
- }
+ if (fl1h->hLayer1)
+ power_ramp_start(trx, get_p_target_mdBm(trx, 0), 0);
}
/* FIXME: we actaully need to send a ACK or NACK for the OML message */
@@ -1722,3 +1714,8 @@ int bts_model_trx_deact_rf(struct gsm_bts_trx *trx)
return l1if_activate_rf(fl1, 0);
}
+
+int bts_model_change_power(struct gsm_bts_trx *trx, int p_trxout_mdBm)
+{
+ return l1if_set_txpower(trx_femtol1_hdl(trx), ((float) p_trxout_mdBm)/1000.0);
+}
diff --git a/src/osmo-bts-sysmo/sysmobts_vty.c b/src/osmo-bts-sysmo/sysmobts_vty.c
index ed90a23..8b617d7 100644
--- a/src/osmo-bts-sysmo/sysmobts_vty.c
+++ b/src/osmo-bts-sysmo/sysmobts_vty.c
@@ -254,40 +254,6 @@ DEFUN(cfg_trx_nominal_power, cfg_trx_nominal_power_cmd,
return CMD_SUCCESS;
}
-#define PA_STR "Power-Amplifier settings"
-DEFUN(cfg_trx_pa_max_initial, cfg_trx_pa_max_initial_cmd,
- "power-amplifier max-initial <0-100>",
- PA_STR "Maximum initial power\n"
- "Value in dBm\n")
-{
- struct gsm_bts_trx *trx = vty->index;
-
- trx->pa.max_initial_power = atoi(argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_trx_pa_step_size, cfg_trx_pa_step_size_cmd,
- "power-amplifier step-size <1-100>",
- PA_STR "Power increase by step\n"
- "Step size in dB\n")
-{
- struct gsm_bts_trx *trx = vty->index;
-
- trx->pa.step_size = atoi(argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_trx_pa_step_interval, cfg_trx_pa_step_interval_cmd,
- "power-amplifier step-interval <1-100>",
- PA_STR "Power increase by step\n"
- "Step time in seconds\n")
-{
- struct gsm_bts_trx *trx = vty->index;
-
- trx->pa.step_interval = atoi(argv[0]);
- return CMD_SUCCESS;
-}
-
/* runtime */
DEFUN(show_trx_clksrc, show_trx_clksrc_cmd,
@@ -452,11 +418,8 @@ DEFUN(set_tx_power, set_tx_power_cmd,
int trx_nr = atoi(argv[0]);
int power = atoi(argv[1]);
struct gsm_bts_trx *trx = gsm_bts_trx_num(vty_bts, trx_nr);
- struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx);
- trx->pa.current_power = power;
- osmo_timer_del(&trx->pa.step_timer);
- l1if_set_txpower(fl1h, (float) trx->pa.current_power);
+ power_ramp_start(trx, to_mdB(power), 1);
return CMD_SUCCESS;
}
@@ -586,12 +549,6 @@ void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx)
if (trx->nominal_power != sysmobts_get_nominal_power(trx))
vty_out(vty, " nominal-tx-power %d%s", trx->nominal_power,
VTY_NEWLINE);
- vty_out(vty, " power-amplifier max-initial %d%s",
- trx->pa.max_initial_power, VTY_NEWLINE);
- vty_out(vty, " power-amplifier step-size %d%s",
- trx->pa.step_size, VTY_NEWLINE);
- vty_out(vty, " power-amplifier step-interval %d%s",
- trx->pa.step_interval, VTY_NEWLINE);
for (i = 0; i < 32; i++) {
if (fl1h->gsmtap_sapi_mask & (1 << i)) {
@@ -663,9 +620,6 @@ int bts_model_vty_init(struct gsm_bts *bts)
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);
- install_element(TRX_NODE, &cfg_trx_pa_max_initial_cmd);
- install_element(TRX_NODE, &cfg_trx_pa_step_size_cmd);
- install_element(TRX_NODE, &cfg_trx_pa_step_interval_cmd);
return 0;
}
diff --git a/src/osmo-bts-sysmo/utils.c b/src/osmo-bts-sysmo/utils.c
index afca773..a636ae1 100644
--- a/src/osmo-bts-sysmo/utils.c
+++ b/src/osmo-bts-sysmo/utils.c
@@ -137,88 +137,4 @@ int sysmobts_get_nominal_power(struct gsm_bts_trx *trx)
return -1;
}
-int sysmobts_get_target_power(struct gsm_bts_trx *trx)
-{
- int target_power = trx->nominal_power - trx->max_power_red;
- target_power -= trx->power_reduce;
-
- if (target_power < 0)
- target_power = 0;
-
- return target_power;
-}
-
-void sysmobts_pa_pwr_init(struct gsm_bts_trx *trx)
-{
- int target_power = sysmobts_get_target_power(trx);
-
- /* Cancel any pending request */
- osmo_timer_del(&trx->pa.step_timer);
-
- /* is this below our initial target */
- if (target_power <= trx->pa.max_initial_power) {
- LOGP(DL1C, LOGL_NOTICE,
- "PA target_power(%d) is below initial power.\n",
- target_power);
- trx->pa.current_power = target_power;
- return;
- }
-
- /* is this below our current value? */
- if (target_power <= trx->pa.current_power) {
- LOGP(DL1C, LOGL_NOTICE,
- "PA target_power(%d) is below current_power.\n",
- target_power);
- trx->pa.current_power = target_power;
- return;
- }
- if (trx->pa.current_power > trx->pa.max_initial_power) {
- LOGP(DL1C, LOGL_NOTICE,
- "PA target_power(%d) starting from current_power.\n",
- target_power);
- return;
- }
-
- /* We need to step it up. Start from the initial value */
- trx->pa.current_power = trx->pa.max_initial_power;
- LOGP(DL1C, LOGL_NOTICE,
- "PA target_power(%d) starting with %d dBm.\n",
- target_power, trx->pa.current_power);
-}
-
-static void pa_trx_cb(void *_trx)
-{
- struct gsm_bts_trx *trx = _trx;
-
- LOGP(DL1C, LOGL_NOTICE,
- "PA raising power to %d dBm.\n", trx->pa.current_power);
- l1if_set_txpower(trx_femtol1_hdl(trx), (float) trx->pa.current_power);
-}
-
-void sysmobts_pa_maybe_step(struct gsm_bts_trx *trx)
-{
- /* it can not have changed */
- int target_power = sysmobts_get_target_power(trx);
-
- /* We are done */
- if (trx->pa.current_power >= target_power) {
- LOGP(DL1C, LOGL_NOTICE,
- "PA have reached target power: %d dBm.\n",
- target_power);
- return;
- }
-
- /* Step up the current power but clamp it */
- trx->pa.current_power += trx->pa.step_size;
- if (trx->pa.current_power > target_power)
- trx->pa.current_power = target_power;
-
- LOGP(DL1C, LOGL_NOTICE,
- "PA scheduling to step to %d dBm.\n",
- trx->pa.current_power);
-
- trx->pa.step_timer.data = trx;
- trx->pa.step_timer.cb = pa_trx_cb;
- osmo_timer_schedule(&trx->pa.step_timer, trx->pa.step_interval, 0);
-}