fixeria has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-bts/+/21447 )
Change subject: power_control: implement Downlink power control ...................................................................... power_control: implement Downlink power control Change-Id: I5b509e71d5f668b6b8b2abf8053c27f2a7c78451 Related: SYS#4918 --- M include/osmo-bts/gsm_data.h M include/osmo-bts/power_control.h M src/common/l1sap.c M src/common/power_control.c M src/common/rsl.c M src/common/scheduler.c M src/common/vty.c 7 files changed, 148 insertions(+), 22 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-bts refs/changes/47/21447/1 diff --git a/include/osmo-bts/gsm_data.h b/include/osmo-bts/gsm_data.h index 04c6629..6af96fe 100644 --- a/include/osmo-bts/gsm_data.h +++ b/include/osmo-bts/gsm_data.h @@ -316,11 +316,9 @@ /* RTP header Marker bit to indicate beginning of speech after pause */ bool rtp_tx_marker; - /* MS power control */ + /* MS/BS power control */ struct lchan_power_ctrl_state ms_power_ctrl; - - /* BTS power reduction (in dB) */ - uint8_t bs_power_red; + struct lchan_power_ctrl_state bs_power_ctrl; struct msgb *pending_rel_ind_msg; diff --git a/include/osmo-bts/power_control.h b/include/osmo-bts/power_control.h index cb566a8..f2e14cf 100644 --- a/include/osmo-bts/power_control.h +++ b/include/osmo-bts/power_control.h @@ -6,3 +6,6 @@ int lchan_ms_pwr_ctrl(struct gsm_lchan *lchan, const uint8_t ms_power_lvl, const int8_t ul_rssi_dbm); + +int lchan_bs_pwr_ctrl(struct gsm_lchan *lchan, + const struct gsm48_hdr *gh); diff --git a/src/common/l1sap.c b/src/common/l1sap.c index 2038fba..33d10a5 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -1546,6 +1546,7 @@ lchan->meas.flags |= LC_UL_M_F_L1_VALID; lchan_ms_pwr_ctrl(lchan, data[0] & 0x1f, data_ind->rssi); + lchan_bs_pwr_ctrl(lchan, (const struct gsm48_hdr *) &data[5]); } else le = &lchan->lapdm_ch.lapdm_dcch; diff --git a/src/common/power_control.c b/src/common/power_control.c index 592e4f6..71808c8 100644 --- a/src/common/power_control.c +++ b/src/common/power_control.c @@ -219,3 +219,105 @@ return 1; } + + /*! compute the new Downlink attenuation value for the given logical channel. + * \param lchan logical channel for which to compute (and in which to store) new power value. + * \param[in] gh pointer to the beginning of (presumably) a Measurement Report. + */ +int lchan_bs_pwr_ctrl(struct gsm_lchan *lchan, + const struct gsm48_hdr *gh) +{ + struct gsm_bts_trx *trx = lchan->ts->trx; + struct gsm_bts *bts = trx->bts; + uint8_t rxqual_full, rxqual_sub; + uint8_t rxlev_full, rxlev_sub; + uint8_t rxqual, rxlev; + int delta, new; + + const struct bts_power_ctrl_params *params = &bts->dl_power_ctrl; + struct lchan_power_ctrl_state *state = &lchan->bs_power_ctrl; + + /* Check if BS Power Control is enabled */ + if (state->fixed) + return 0; + /* Check if this is a Measurement Report */ + if (gh->proto_discr != GSM48_PDISC_RR) + return 0; + if (gh->msg_type != GSM48_MT_RR_MEAS_REP) + return 0; + + /* Check if the measurement results are valid */ + if ((gh->data[1] & 0x40) == 0x40) { + LOGPLCHAN(lchan, DLOOP, LOGL_DEBUG, + "The measurement results are not valid\n"); + return 0; + } + + /* See 3GPP TS 44.018, section 10.5.2.20 */ + rxqual_full = (gh->data[2] >> 4) & 0x7; + rxqual_sub = (gh->data[2] >> 1) & 0x7; + + rxlev_full = gh->data[0] & 0x3f; + rxlev_sub = gh->data[1] & 0x3f; + + LOGPLCHAN(lchan, DLOOP, LOGL_DEBUG, "Rx DL Measurement Report: " + "RXLEV-FULL(%02u), RXQUAL-FULL(%u), " + "RXLEV-SUB(%02u), RXQUAL-SUB(%u), " + "DTx is %s => using %s\n", + rxqual_full, rxqual_sub, rxlev_full, rxlev_sub, + lchan->tch.dtx.dl_active ? "enabled" : "disabled", + lchan->tch.dtx.dl_active ? "SUB" : "FULL"); + + /* If DTx is active on Downlink, use the '-SUB' */ + if (lchan->tch.dtx.dl_active) { + rxqual = rxqual_sub; + rxlev = rxlev_sub; + } else { /* ... otherwise use the '-FULL' */ + rxqual = rxqual_full; + rxlev = rxlev_full; + } + + /* Bit Error Rate > 0 => reduce by 2 */ + if (rxqual > 0) { + LOGPLCHAN(lchan, DLOOP, LOGL_INFO, "Reducing Downlink attenuation " + "by half: %u -> %u dB due to RXQUAL %u > 0\n", + state->current, state->current / 2, rxqual); + state->current /= 2; + return 1; + } + + /* Calculate a 'delta' for the current attenuation level */ + delta = calc_delta(params, state, rxlev2dbm(rxlev)); + + /* Basic signal transmission / reception formula: + * + * RxLev = TxPwr - (PathLoss + TxAtt) + * + * Here we want to change RxLev at the MS side, so: + * + * RxLev + Delta = TxPwr - (PathLoss + TxAtt) + Delta + * + * The only parameter we can change here is TxAtt, so: + * + * RxLev + Delta = TxPwr - PathLoss - TxAtt + Delta + * RxLev + Delta = TxPwr - PathLoss - (TxAtt - Delta) + */ + new = state->current - delta; + if (new > state->max) + new = state->max; + if (new < 0) + new = 0; + + if (state->current != new) { + LOGPLCHAN(lchan, DLOOP, LOGL_INFO, "Changing Downlink attenuation: " + "%u -> %u dB (maximum %u dB, target %d dBm, delta %d dB)\n", + state->current, new, state->max, params->target, delta); + state->current = new; + return 1; + } else { + LOGPLCHAN(lchan, DLOOP, LOGL_INFO, "Keeping Downlink attenuation " + "at %u dB (maximum %u dB, target %d dBm, delta %d dB)\n", + state->current, state->max, params->target, delta); + return 0; + } +} diff --git a/src/common/rsl.c b/src/common/rsl.c index 8760c24..2ebfb32 100644 --- a/src/common/rsl.c +++ b/src/common/rsl.c @@ -1036,8 +1036,8 @@ lchan->tch_mode = 0; memset(&lchan->encr, 0, sizeof(lchan->encr)); memset(&lchan->ho, 0, sizeof(lchan->ho)); - lchan->bs_power_red = 0; memset(&lchan->ms_power_ctrl, 0, sizeof(lchan->ms_power_ctrl)); + memset(&lchan->bs_power_ctrl, 0, sizeof(lchan->bs_power_ctrl)); lchan->rqd_ta = 0; copy_sacch_si_to_lchan(lchan); memset(&lchan->tch, 0, sizeof(lchan->tch)); @@ -1153,11 +1153,16 @@ LOGPLCHAN(lchan, DRSL, LOGL_DEBUG, "rx Channel Activation in state: %s.\n", gsm_lchans_name(lchan->state)); - /* Initialize channel defaults */ + /* Initialize MS Power Control defaults */ lchan->ms_power_ctrl.max = ms_pwr_ctl_lvl(lchan->ts->trx->bts->band, 0); lchan->ms_power_ctrl.current = lchan->ms_power_ctrl.max; lchan->ms_power_ctrl.fixed = true; + /* Initialize BS Power Control defaults */ + lchan->bs_power_ctrl.max = 2 * 15; + lchan->bs_power_ctrl.current = 0; + lchan->bs_power_ctrl.fixed = true; + rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg)); /* 9.3.3 Activation Type */ @@ -1209,9 +1214,11 @@ return rsl_tx_chan_act_nack(lchan, RSL_ERR_SERV_OPT_UNIMPL); } - lchan->bs_power_red = BS_POWER2DB(*TLVP_VAL(&tp, RSL_IE_BS_POWER)); + lchan->bs_power_ctrl.max = BS_POWER2DB(*TLVP_VAL(&tp, RSL_IE_BS_POWER)); + lchan->bs_power_ctrl.current = lchan->bs_power_ctrl.max; + LOGPLCHAN(lchan, DRSL, LOGL_DEBUG, "BS Power attenuation %u dB\n", - lchan->bs_power_red); + lchan->bs_power_ctrl.current); } /* 9.3.13 MS Power */ @@ -1224,7 +1231,6 @@ if (TLVP_PRES_LEN(&tp, RSL_IE_TIMING_ADVANCE, 1)) lchan->rqd_ta = *TLVP_VAL(&tp, RSL_IE_TIMING_ADVANCE); - /* 9.3.32 BS Power Parameters */ /* 9.3.31 MS Power Parameters */ if (TLVP_PRESENT(&tp, RSL_IE_MS_POWER_PARAM)) { /* Spec explicitly states BTS should only perform @@ -1232,6 +1238,14 @@ * Parameters' IE is present! */ lchan->ms_power_ctrl.fixed = false; } + + /* 9.3.32 BS Power Parameters */ + if (TLVP_PRESENT(&tp, RSL_IE_BS_POWER_PARAM)) { + /* NOTE: it's safer to start from 0 */ + lchan->bs_power_ctrl.current = 0; + lchan->bs_power_ctrl.fixed = false; + } + /* 9.3.16 Physical Context */ /* 9.3.29 SACCH Information */ @@ -1753,7 +1767,7 @@ struct abis_rsl_dchan_hdr *dch = msgb_l2(msg); struct gsm_lchan *lchan = msg->lchan; struct tlv_parsed tp; - uint8_t old_bs_power_red; + uint8_t old, new; rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg)); @@ -1766,18 +1780,24 @@ return rsl_tx_error_report(msg->trx, RSL_ERR_SERV_OPT_UNIMPL, &dch->chan_nr, NULL, msg); } - old_bs_power_red = lchan->bs_power_red; - lchan->bs_power_red = BS_POWER2DB(*TLVP_VAL(&tp, RSL_IE_BS_POWER)); - - LOGPLCHAN(lchan, DRSL, LOGL_INFO, "BS POWER CONTROL Attenuation %d -> %d dB\n", - old_bs_power_red, lchan->bs_power_red); + new = BS_POWER2DB(*TLVP_VAL(&tp, RSL_IE_BS_POWER)); + old = lchan->bs_power_ctrl.current; /* 9.3.31 MS Power Parameters (O) */ if (TLVP_PRESENT(&tp, RSL_IE_BS_POWER_PARAM)) { - /* Spec explicitly states BTS should perform autonomous - * BS power control loop in BTS if 'BS Power Parameters' - * IE is present! WE don't support that. */ - return rsl_tx_error_report(msg->trx, RSL_ERR_OPT_IE_ERROR, &dch->chan_nr, NULL, msg); + /* NOTE: it's safer to start from 0 */ + lchan->bs_power_ctrl.current = 0; + lchan->bs_power_ctrl.max = new; + lchan->bs_power_ctrl.fixed = false; + } else { + lchan->bs_power_ctrl.current = new; + lchan->bs_power_ctrl.fixed = true; + } + + if (lchan->bs_power_ctrl.current != old) { + LOGPLCHAN(lchan, DRSL, LOGL_INFO, "BS POWER CONTROL: " + "attenuation change %u -> %u dB\n", + old, lchan->bs_power_ctrl.current); } return 0; @@ -2975,7 +2995,7 @@ msgb_tlv_put(msg, RSL_IE_UPLINK_MEAS, ie_len, meas_res); lchan->meas.flags &= ~LC_UL_M_F_RES_VALID; } - msgb_tv_put(msg, RSL_IE_BS_POWER, lchan->bs_power_red / 2); + msgb_tv_put(msg, RSL_IE_BS_POWER, lchan->bs_power_ctrl.current / 2); if (lchan->meas.flags & LC_UL_M_F_L1_VALID) { msgb_tv_fixed_put(msg, RSL_IE_L1_INFO, 2, lchan->meas.l1_info); lchan->meas.flags &= ~LC_UL_M_F_L1_VALID; diff --git a/src/common/scheduler.c b/src/common/scheduler.c index 84918e3..3d780fd 100644 --- a/src/common/scheduler.c +++ b/src/common/scheduler.c @@ -1237,7 +1237,7 @@ /* BS Power reduction (in dB) per logical channel */ if (l1cs->lchan != NULL) - br->att = l1cs->lchan->bs_power_red; + br->att = l1cs->lchan->bs_power_ctrl.current; /* encrypt */ if (br->burst_len && l1cs->dl_encr_algo) { diff --git a/src/common/vty.c b/src/common/vty.c index 0e78ad3..f366956 100644 --- a/src/common/vty.c +++ b/src/common/vty.c @@ -1381,10 +1381,13 @@ lchan->state == LCHAN_S_BROKEN ? " Error reason: " : "", lchan->state == LCHAN_S_BROKEN ? lchan->broken_reason : "", VTY_NEWLINE); +#if 0 + /* TODO: print more info about MS/BS Power Control */ vty_out(vty, " BS Power: %d dBm, MS Power: %u dBm%s", lchan->ts->trx->nominal_power - (lchan->ts->trx->max_power_red + lchan->bs_power_red), ms_pwr_dbm(lchan->ts->trx->bts->band, lchan->ms_power_ctrl.max), VTY_NEWLINE); +#endif vty_out(vty, " Channel Mode / Codec: %s%s", gsm48_chan_mode_name(lchan->tch_mode), VTY_NEWLINE); @@ -1426,7 +1429,6 @@ if (lchan->loopback) vty_out(vty, " RTP/PDCH Loopback Enabled%s", VTY_NEWLINE); vty_out(vty, " Radio Link Failure Counter 'S': %d%s", lchan->s, VTY_NEWLINE); - /* TODO: MS Power Control */ } static void lchan_dump_short_vty(struct vty *vty, const struct gsm_lchan *lchan) -- To view, visit https://gerrit.osmocom.org/c/osmo-bts/+/21447 To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Change-Id: I5b509e71d5f668b6b8b2abf8053c27f2a7c78451 Gerrit-Change-Number: 21447 Gerrit-PatchSet: 1 Gerrit-Owner: fixeria <vyanits...@sysmocom.de> Gerrit-MessageType: newchange