pespin has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-bts/+/41807?usp=email )
Change subject: {bs,ms}_power_control: Move params inside lchan_power_ctrl_state ......................................................................
{bs,ms}_power_control: Move params inside lchan_power_ctrl_state
Those fields are also part of the power control state, since they are modified through the lifecycle of the lchan eg. during rx of CHAN (RE)ACT, MS POWER CONTROL, etc. Those should also be reset together with other fields.
Moreover, with this patch we get rid of an extra indirection pointer which could be NULL (under static configuration) and hence create potential problems.
Change-Id: I0e2a6c2c33e0ac9a0bc1734d83eaeafc27f2f4df --- M include/osmo-bts/lchan.h M src/common/power_control.c M src/common/rsl.c M src/common/vty.c M tests/power/bs_power_loop_test.c M tests/power/ms_power_loop_test.c 6 files changed, 76 insertions(+), 87 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-bts refs/changes/07/41807/1
diff --git a/include/osmo-bts/lchan.h b/include/osmo-bts/lchan.h index 42de2f4..2b19c28 100644 --- a/include/osmo-bts/lchan.h +++ b/include/osmo-bts/lchan.h @@ -120,8 +120,9 @@
struct lchan_power_ctrl_state { - /* Dynamic Power Control parameters (NULL in static mode) */ - const struct gsm_power_ctrl_params *dpc_params; + /* Dynamic Power Control parameters (false = static mode) */ + bool dpc_enabled; + struct gsm_power_ctrl_params dpc_params; /* Measurement pre-processing state (for dynamic mode) */ struct gsm_power_ctrl_meas_proc_state rxlev_meas_proc; struct gsm_power_ctrl_meas_proc_state rxqual_meas_proc; @@ -356,10 +357,6 @@ struct lchan_power_ctrl_state ms_power_ctrl; struct lchan_power_ctrl_state bs_power_ctrl;
- /* MS/BS Dynamic Power Control parameters */ - struct gsm_power_ctrl_params ms_dpc_params; - struct gsm_power_ctrl_params bs_dpc_params; - /* Temporary ACCH overpower capabilities and state */ struct abis_rsl_osmo_temp_ovp_acch_cap top_acch_cap; bool top_acch_active; diff --git a/src/common/power_control.c b/src/common/power_control.c index 187c5da..7f66dce 100644 --- a/src/common/power_control.c +++ b/src/common/power_control.c @@ -140,13 +140,17 @@ void lchan_ms_pwr_ctrl_reset(struct gsm_lchan *lchan) { struct lchan_power_ctrl_state *state = &lchan->ms_power_ctrl; + struct gsm_power_ctrl_params *params = &state->dpc_params; + struct gsm_bts_trx *trx = lchan->ts->trx;
/* This below implicitly sets: - * state->dpc_params = NULL (static mode). + * state->dpc_enabled = false (static mode). * state->skip_block_num = 0, so that 1st power input is taken into account. */ memset(state, 0, sizeof(*state));
- state->max = ms_pwr_ctl_lvl(lchan->ts->trx->bts->band, 0); + memcpy(params, trx->ms_dpc_params, sizeof(*params)); + + state->max = ms_pwr_ctl_lvl(trx->bts->band, 0); /* XXX: should we use the maximum power level instead of 0 dBm? */ state->current = state->max; } @@ -170,7 +174,7 @@
static const struct gsm_power_ctrl_meas_params *lchan_get_ci_thresholds(const struct gsm_lchan *lchan) { - const struct gsm_power_ctrl_params *params = lchan->ms_power_ctrl.dpc_params; + const struct gsm_power_ctrl_params *params = &lchan->ms_power_ctrl.dpc_params;
switch (lchan->type) { case GSM_LCHAN_SDCCH: @@ -204,7 +208,7 @@ const int16_t ul_lqual_cb) { struct lchan_power_ctrl_state *state = &lchan->ms_power_ctrl; - const struct gsm_power_ctrl_params *params = state->dpc_params; + const struct gsm_power_ctrl_params *params = &state->dpc_params; struct gsm_bts_trx *trx = lchan->ts->trx; struct gsm_bts *bts = trx->bts; enum gsm_band band = bts->band; @@ -217,7 +221,7 @@
if (!trx_ms_pwr_ctrl_is_osmo(trx)) return 0; - if (params == NULL) + if (!state->dpc_enabled) return 0;
/* Average the input RxLev/RxQual samples (if needed). Do this before @@ -327,13 +331,17 @@ void lchan_bs_pwr_ctrl_reset(struct gsm_lchan *lchan) { struct lchan_power_ctrl_state *state = &lchan->bs_power_ctrl; + struct gsm_power_ctrl_params *params = &state->dpc_params; + struct gsm_bts_trx *trx = lchan->ts->trx;
/* This below implicitly sets: + * state->dpc_enabled = false (static mode). * state->current = 0 (it's safer to start from 0 unless told differently). - * state->dpc_params = NULL (static mode). * state->skip_block_num = 0, so that 1st power input is taken into account. */ memset(state, 0, sizeof(*state));
+ memcpy(params, trx->ms_dpc_params, sizeof(*params)); + state->max = 2 * 15; /* maximum defined in 9.3.4 */ }
@@ -345,12 +353,12 @@ const struct gsm48_meas_res *mr) { struct lchan_power_ctrl_state *state = &lchan->bs_power_ctrl; - const struct gsm_power_ctrl_params *params = state->dpc_params; + const struct gsm_power_ctrl_params *params = &state->dpc_params; uint8_t rxqual, rxqual_avg, rxlev, rxlev_avg; int new_att;
/* Check if dynamic BS Power Control is enabled */ - if (params == NULL) + if (!state->dpc_enabled) return 0;
LOGPLCHAN(lchan, DLOOP, LOGL_DEBUG, "Rx DL Measurement Report: " diff --git a/src/common/rsl.c b/src/common/rsl.c index 3a52167..aadce84 100644 --- a/src/common/rsl.c +++ b/src/common/rsl.c @@ -2062,35 +2062,25 @@
/* 9.3.31 (TLV) MS Power Parameters IE (vendor specific) */ if ((ie = TLVP_GET(&tp, RSL_IE_MS_POWER_PARAM)) != NULL) { - struct gsm_power_ctrl_params *params = &lchan->ms_dpc_params; - /* Parsed parameters will override per-TRX defaults */ - memcpy(params, ts->trx->ms_dpc_params, sizeof(*params)); - - if (ie->len && parse_power_ctrl_params(params, ie->val, ie->len) != 0) { + if (ie->len && parse_power_ctrl_params(&lchan->ms_power_ctrl.dpc_params, ie->val, ie->len) != 0) { LOGPLCHAN(lchan, DRSL, LOGL_ERROR, "Failed to parse MS Power Parameters IE\n"); return rsl_tx_chan_act_nack(lchan, RSL_ERR_IE_CONTENT); } - /* Spec explicitly states BTS should only perform * autonomous MS power control loop in BTS if 'MS Power * Parameters' IE is present! */ - lchan->ms_power_ctrl.dpc_params = params; + lchan->ms_power_ctrl.dpc_enabled = true; }
/* 9.3.32 (TLV) BS Power Parameters IE (vendor specific) */ if ((ie = TLVP_GET(&tp, RSL_IE_BS_POWER_PARAM)) != NULL) { - struct gsm_power_ctrl_params *params = &lchan->bs_dpc_params; - /* Parsed parameters will override per-TRX defaults */ - memcpy(params, ts->trx->bs_dpc_params, sizeof(*params)); - - /* Parsed parameters will override per-TRX defaults */ - if (ie->len && parse_power_ctrl_params(params, ie->val, ie->len) != 0) { + if (ie->len && parse_power_ctrl_params(&lchan->bs_power_ctrl.dpc_params, ie->val, ie->len) != 0) { LOGPLCHAN(lchan, DRSL, LOGL_ERROR, "Failed to parse BS Power Parameters IE\n"); return rsl_tx_chan_act_nack(lchan, RSL_ERR_IE_CONTENT); } - lchan->bs_power_ctrl.dpc_params = params; + lchan->ms_power_ctrl.dpc_enabled = true; }
/* 9.3.16 Physical Context */ @@ -2561,29 +2551,24 @@
/* Spec explicitly states BTS should only perform autonomous MS Power * control loop in BTS if 'MS Power Parameters' IE is present! */ - lchan->ms_power_ctrl.dpc_params = NULL; + lchan->ms_power_ctrl.dpc_enabled = false;
/* 9.3.31 (TLV) MS Power Parameters IE (vendor specific) */ if ((ie = TLVP_GET(&tp, RSL_IE_MS_POWER_PARAM)) != NULL) { - struct gsm_power_ctrl_params *params = &lchan->ms_dpc_params; - + struct gsm_power_ctrl_params *params = &lchan->ms_power_ctrl.dpc_params; /* Parsed parameters will override per-TRX defaults */ memcpy(params, msg->trx->ms_dpc_params, sizeof(*params)); - /* Parsed parameters will override per-TRX defaults */ if (ie->len && parse_power_ctrl_params(params, ie->val, ie->len) != 0) { LOGPLCHAN(lchan, DRSL, LOGL_ERROR, "Failed to parse MS Power Parameters IE\n"); return rsl_tx_chan_act_nack(lchan, RSL_ERR_IE_CONTENT); } - - lchan->ms_power_ctrl.dpc_params = params; + lchan->ms_power_ctrl.dpc_enabled = true; }
/* Only set current to max if actual value of current in dBm > value in dBm from max, or if fixed. */ - if (lchan->ms_power_ctrl.dpc_params == NULL) { - lchan->ms_power_ctrl.current = lchan->ms_power_ctrl.max; - } else { + if (lchan->ms_power_ctrl.dpc_enabled) { max_pwr = ms_pwr_dbm(bts->band, lchan->ms_power_ctrl.max); curr_pwr = ms_pwr_dbm(bts->band, lchan->ms_power_ctrl.current); if (max_pwr < 0 || curr_pwr < 0) { @@ -2594,6 +2579,8 @@ } else if (curr_pwr > max_pwr) { lchan->ms_power_ctrl.current = lchan->ms_power_ctrl.max; } + } else { + lchan->ms_power_ctrl.current = lchan->ms_power_ctrl.max; }
bts_model_adjst_ms_pwr(lchan); @@ -2648,23 +2635,20 @@
/* 9.3.32 (TLV) BS Power Parameters IE (vendor specific) */ if ((ie = TLVP_GET(&tp, RSL_IE_BS_POWER_PARAM)) != NULL) { - struct gsm_power_ctrl_params *params = &lchan->bs_dpc_params; - + struct gsm_power_ctrl_params *params = &lchan->bs_power_ctrl.dpc_params; /* Parsed parameters will override per-TRX defaults */ memcpy(params, trx->bs_dpc_params, sizeof(*params)); - /* Parsed parameters will override per-TRX defaults */ if (ie->len && parse_power_ctrl_params(params, ie->val, ie->len) != 0) { LOGPLCHAN(lchan, DRSL, LOGL_ERROR, "Failed to parse BS Power Parameters IE\n"); return rsl_tx_chan_act_nack(lchan, RSL_ERR_IE_CONTENT); } - /* NOTE: it's safer to start from 0 */ lchan->bs_power_ctrl.current = 0; lchan->bs_power_ctrl.max = new; - lchan->bs_power_ctrl.dpc_params = params; + lchan->bs_power_ctrl.dpc_enabled = true; } else { - lchan->bs_power_ctrl.dpc_params = NULL; + lchan->bs_power_ctrl.dpc_enabled = false; lchan->bs_power_ctrl.current = new; }
diff --git a/src/common/vty.c b/src/common/vty.c index ca7947b..2b18e33 100644 --- a/src/common/vty.c +++ b/src/common/vty.c @@ -1832,11 +1832,11 @@ const struct gsm_bts_trx *trx = lchan->ts->trx;
cfg_out(vty, "BS (Downlink) Power Control (%s mode):%s", - st->dpc_params ? "dynamic" : "static", VTY_NEWLINE); + st->dpc_enabled ? "dynamic" : "static", VTY_NEWLINE); indent += 2;
cfg_out(vty, "Channel reduction: %u dB", st->current); - if (st->dpc_params != NULL) + if (st->dpc_enabled) vty_out(vty, " (max %u dB)", st->max); vty_out(vty, "%s", VTY_NEWLINE);
@@ -1847,11 +1847,11 @@ cfg_out(vty, "Actual / Nominal power: %d dBm / %d dBm%s", actual, trx->nominal_power, VTY_NEWLINE);
- if (st->dpc_params == NULL) + if (!st->dpc_enabled) return;
cfg_out(vty, "Power Control parameters:%s", VTY_NEWLINE); - dump_dpc_params(vty, indent + 2, st->dpc_params, false); + dump_dpc_params(vty, indent + 2, &st->dpc_params, false); }
static void lchan_ms_power_ctrl_state_dump(struct vty *vty, unsigned int indent, @@ -1861,7 +1861,7 @@ const struct gsm_bts_trx *trx = lchan->ts->trx;
cfg_out(vty, "MS (Uplink) Power Control (%s):%s", - st->dpc_params ? "dynamic" : "static", VTY_NEWLINE); + st->dpc_enabled ? "dynamic" : "static", VTY_NEWLINE); indent += 2;
int current_dbm = ms_pwr_dbm(trx->bts->band, st->current); @@ -1869,15 +1869,15 @@
cfg_out(vty, "Current power level: %u, %d dBm", st->current, current_dbm); - if (st->dpc_params != NULL) + if (st->dpc_enabled) vty_out(vty, " (max %u, %d dBm)", st->max, max_dbm); vty_out(vty, "%s", VTY_NEWLINE);
- if (st->dpc_params == NULL) + if (!st->dpc_enabled) return;
cfg_out(vty, "Power Control parameters:%s", VTY_NEWLINE); - dump_dpc_params(vty, indent + 2, st->dpc_params, true); + dump_dpc_params(vty, indent + 2, &st->dpc_params, true); }
static void lchan_acch_rep_state_dump(struct vty *vty, unsigned int indent, @@ -2603,7 +2603,6 @@ "Enable the power control loop\n", CMD_ATTR_HIDDEN) { - const struct gsm_power_ctrl_params *params; struct lchan_power_ctrl_state *state; const char **args = argv + 4; struct gsm_lchan *lchan; @@ -2614,18 +2613,15 @@ return CMD_WARNING; }
- if (strcmp(args[0], "bs-power-ctrl") == 0) { - params = &lchan->bs_dpc_params; + if (strcmp(args[0], "bs-power-ctrl") == 0) state = &lchan->bs_power_ctrl; - } else { /* ms-power-ctrl */ - params = &lchan->ms_dpc_params; + else/* ms-power-ctrl */ state = &lchan->ms_power_ctrl; - }
if (strcmp(args[1], "dynamic") == 0) - state->dpc_params = params; + state->dpc_enabled = true; else - state->dpc_params = NULL; + state->dpc_enabled = false;
return CMD_SUCCESS; } diff --git a/tests/power/bs_power_loop_test.c b/tests/power/bs_power_loop_test.c index 8fbdcee..3f591ca 100644 --- a/tests/power/bs_power_loop_test.c +++ b/tests/power/bs_power_loop_test.c @@ -106,9 +106,9 @@ g_bts->c0 = g_trx;
/* Init defaultBS power control parameters, enable dynamic power control */ - struct gsm_power_ctrl_params *params = &g_trx->ts[0].lchan[0].bs_dpc_params; - g_trx->ts[0].lchan[0].bs_power_ctrl.dpc_params = params; + struct gsm_power_ctrl_params *params = &g_trx->ts[0].lchan[0].bs_power_ctrl.dpc_params; *params = power_ctrl_params_def; + g_trx->ts[0].lchan[0].bs_power_ctrl.dpc_enabled = true;
/* Disable loop SACCH block skip by default: */ params->ctrl_interval = 0; @@ -141,35 +141,39 @@ { struct gsm48_meas_res mr; uint8_t old, new; + struct gsm_power_ctrl_params tmp_params;
switch (step->type) { case PWR_TEST_ST_SET_STATE: printf("#%02u %s() <- State (re)set (current %u dB, max %u dB)\n", n, __func__, step->state.current, step->state.max); + /* Retain default Dynamic Power Control Parameters, only interested in changing the state here: */ + memcpy(&tmp_params, &lchan->bs_power_ctrl.dpc_params, sizeof(tmp_params)); lchan->bs_power_ctrl = step->state; - lchan->bs_power_ctrl.dpc_params = &lchan->bs_dpc_params; + memcpy(&lchan->bs_power_ctrl.dpc_params, &tmp_params, sizeof(tmp_params)); + lchan->bs_power_ctrl.dpc_enabled = true; return 0; /* we're done */ case PWR_TEST_ST_DISABLE_DPC: printf("#%02u %s() <- Dynamic power control is disabled\n", n, __func__); - lchan->bs_power_ctrl.dpc_params = NULL; + lchan->bs_power_ctrl.dpc_enabled = false; return 0; /* we're done */ case PWR_TEST_ST_SET_CTRL_INTERVAL: printf("#%02u %s() <- (Re)set power control interval: %u -> %u\n", - n, __func__, lchan->bs_dpc_params.ctrl_interval, step->ctrl_interval); - lchan->bs_dpc_params.ctrl_interval = step->ctrl_interval; + n, __func__, lchan->bs_power_ctrl.dpc_params.ctrl_interval, step->ctrl_interval); + lchan->bs_power_ctrl.dpc_params.ctrl_interval = step->ctrl_interval; return 0; /* we're done */ case PWR_TEST_ST_SET_STEP_SIZE: printf("#%02u %s() <- Set step size: inc %u dB, red %u dB\n", n, __func__, step->step_size.inc, step->step_size.red); - lchan->bs_dpc_params.inc_step_size_db = step->step_size.inc; - lchan->bs_dpc_params.red_step_size_db = step->step_size.red; + lchan->bs_power_ctrl.dpc_params.inc_step_size_db = step->step_size.inc; + lchan->bs_power_ctrl.dpc_params.red_step_size_db = step->step_size.red; return 0; /* we're done */ case PWR_TEST_ST_SET_RXLEV_PARAMS: printf("#%02u %s() <- (Re)set RxLev params (thresh %u .. %u, " "averaging is %sabled)\n", n, __func__, step->mp.lower_thresh, step->mp.upper_thresh, step->mp.algo != GSM_PWR_CTRL_MEAS_AVG_ALGO_NONE ? "en" : "dis"); - lchan->bs_dpc_params.rxlev_meas = step->mp; + lchan->bs_power_ctrl.dpc_params.rxlev_meas = step->mp; return 0; /* we're done */ case PWR_TEST_ST_ENABLE_DTXD: printf("#%02u %s() <- Enable DTXd\n", n, __func__); @@ -204,7 +208,7 @@ init_test(name);
struct gsm_lchan *lchan = &g_trx->ts[0].lchan[0]; - struct gsm_power_ctrl_params *params = &lchan->bs_dpc_params; + struct gsm_power_ctrl_params *params = &lchan->bs_power_ctrl.dpc_params;
/* No RxLev hysteresis: lower == upper */ params->rxlev_meas.lower_thresh = PWR_TEST_RXLEV_TARGET; diff --git a/tests/power/ms_power_loop_test.c b/tests/power/ms_power_loop_test.c index 47df68e..55a70ed 100644 --- a/tests/power/ms_power_loop_test.c +++ b/tests/power/ms_power_loop_test.c @@ -55,9 +55,9 @@ g_bts->c0 = g_trx;
/* Init default MS power control parameters, enable dynamic power control */ - struct gsm_power_ctrl_params *params = &g_trx->ts[0].lchan[0].ms_dpc_params; - g_trx->ts[0].lchan[0].ms_power_ctrl.dpc_params = params; + struct gsm_power_ctrl_params *params = &g_trx->ts[0].lchan[0].ms_power_ctrl.dpc_params; *params = power_ctrl_params_def; + g_trx->ts[0].lchan[0].ms_power_ctrl.dpc_enabled = true;
/* Disable loop SACCH block skip by default: */ params->ctrl_interval = 0; @@ -98,7 +98,7 @@
init_test(__func__); lchan = &g_trx->ts[0].lchan[0]; - params = lchan->ms_power_ctrl.dpc_params; + params = &lchan->ms_power_ctrl.dpc_params; lchan->type = GSM_LCHAN_SDCCH; good_lqual = (params->ci_sdcch_meas.lower_thresh + 2) * 10;
@@ -160,11 +160,11 @@ OSMO_ASSERT(lchan->ms_power_ctrl.max == 0);
/* Disable dynamic power control and jump down */ - lchan->ms_power_ctrl.dpc_params = NULL; + lchan->ms_power_ctrl.dpc_enabled = false; apply_power_test(lchan, -60, good_lqual, 0, 14);
/* Enable and leave it again */ - lchan->ms_power_ctrl.dpc_params = &lchan->ms_dpc_params; + lchan->ms_power_ctrl.dpc_enabled = true; apply_power_test(lchan, -40, good_lqual, 1, 15); }
@@ -178,11 +178,11 @@ init_test(__func__); lchan = &g_trx->ts[0].lchan[0]; lchan->type = GSM_LCHAN_SDCCH; - params = lchan->ms_power_ctrl.dpc_params; + params = &lchan->ms_power_ctrl.dpc_params; good_lqual = (params->ci_sdcch_meas.lower_thresh + 2) * 10; avg100 = &lchan->ms_power_ctrl.rxlev_meas_proc.ewma.Avg100;
- struct gsm_power_ctrl_meas_params *mp = &lchan->ms_dpc_params.rxlev_meas; + struct gsm_power_ctrl_meas_params *mp = &lchan->ms_power_ctrl.dpc_params.rxlev_meas; mp->algo = GSM_PWR_CTRL_MEAS_AVG_ALGO_OSMO_EWMA; mp->ewma.alpha = 20; /* 80% smoothing */
@@ -238,18 +238,18 @@ static void test_power_hysteresis(void) { struct gsm_lchan *lchan; - const struct gsm_power_ctrl_params *params; + struct gsm_power_ctrl_params *params; int16_t good_lqual;
init_test(__func__); lchan = &g_trx->ts[0].lchan[0]; lchan->type = GSM_LCHAN_SDCCH; - params = lchan->ms_power_ctrl.dpc_params; + params = &lchan->ms_power_ctrl.dpc_params; good_lqual = (params->ci_sdcch_meas.lower_thresh + 2) * 10;
/* Tolerate power deviations in range -80 .. -70 */ - lchan->ms_dpc_params.rxlev_meas.lower_thresh = 30; - lchan->ms_dpc_params.rxlev_meas.upper_thresh = 40; + params->rxlev_meas.lower_thresh = 30; + params->rxlev_meas.upper_thresh = 40;
lchan->ms_power_ctrl.current = ms_pwr_ctl_lvl(GSM_BAND_1800, 0); OSMO_ASSERT(lchan->ms_power_ctrl.current == 15); @@ -277,7 +277,7 @@ init_test(__func__); lchan = &g_trx->ts[0].lchan[0]; lchan->type = GSM_LCHAN_SDCCH; - params = lchan->ms_power_ctrl.dpc_params; + params = &lchan->ms_power_ctrl.dpc_params; good_lqual = (params->ci_sdcch_meas.lower_thresh + 2) * 10;
lchan->ms_power_ctrl.max = ms_pwr_ctl_lvl(GSM_BAND_1800, 26); @@ -325,7 +325,7 @@
/* Set the corresponding power control interval */ printf("%s(): power control interval is now %u\n", __func__, i); - lchan->ms_dpc_params.ctrl_interval = i; + lchan->ms_power_ctrl.dpc_params.ctrl_interval = i;
for (j = 0; j < ARRAY_SIZE(script[i]); j++) { apply_power_test(lchan, script[i][j][0], /* UL RxLev */ @@ -346,7 +346,7 @@
init_test(__func__); lchan = &g_trx->ts[0].lchan[0]; - params = lchan->ms_power_ctrl.dpc_params; + params = &lchan->ms_power_ctrl.dpc_params; lchan->type = GSM_LCHAN_SDCCH; good_lqual = (params->ci_sdcch_meas.lower_thresh + 2) * 10; too_low_lqual = (params->ci_sdcch_meas.lower_thresh - 1) * 10; @@ -383,14 +383,14 @@ static void test_good_threshold_convergence(void) { struct gsm_lchan *lchan; - const struct gsm_power_ctrl_params *params; + struct gsm_power_ctrl_params *params; int16_t good_lqual, good_rxlev;
init_test(__func__); lchan = &g_trx->ts[0].lchan[0]; - params = lchan->ms_power_ctrl.dpc_params; - lchan->ms_dpc_params.rxlev_meas.upper_thresh = 37; - lchan->ms_dpc_params.rxlev_meas.lower_thresh = 30; + params = &lchan->ms_power_ctrl.dpc_params; + params->rxlev_meas.upper_thresh = 37; + params->rxlev_meas.lower_thresh = 30; lchan->type = GSM_LCHAN_SDCCH; good_lqual = (params->ci_sdcch_meas.lower_thresh + 2) * 10; good_rxlev = rxlev2dbm(params->rxlev_meas.lower_thresh + 2);