aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPau Espin Pedrol <pespin@sysmocom.de>2021-10-06 18:06:39 +0200
committerpespin <pespin@sysmocom.de>2021-10-07 12:11:52 +0000
commit36bbf1c328b8876aa640f541b6fa8b7ded16ef2e (patch)
tree5326bb3856fee78ac25b72dae9414df69e75c0f9
parente525584f3ad8f937c8d5c04b11e6855195e2038e (diff)
Move lchan,power_control related code from gsm_data.c to their own files
We already have similar classification in osmo-bsc. Change-Id: I1493f40d99f88a565f15d3e0943a512fb9b8719a
-rw-r--r--src/common/gsm_data.c405
-rw-r--r--src/common/lchan.c230
-rw-r--r--src/common/power_control.c172
3 files changed, 404 insertions, 403 deletions
diff --git a/src/common/gsm_data.c b/src/common/gsm_data.c
index 89a740dd..2edeb4dc 100644
--- a/src/common/gsm_data.c
+++ b/src/common/gsm_data.c
@@ -90,21 +90,6 @@ const char *gsm_lchant_name(enum gsm_chan_t c)
return get_value_string(gsm_chan_t_names, c);
}
-static const struct value_string lchan_s_names[] = {
- { LCHAN_S_NONE, "NONE" },
- { LCHAN_S_ACT_REQ, "ACTIVATION REQUESTED" },
- { LCHAN_S_ACTIVE, "ACTIVE" },
- { LCHAN_S_REL_REQ, "RELEASE REQUESTED" },
- { LCHAN_S_REL_ERR, "RELEASE DUE ERROR" },
- { LCHAN_S_BROKEN, "BROKEN UNUSABLE" },
- { 0, NULL }
-};
-
-const char *gsm_lchans_name(enum gsm_lchan_state s)
-{
- return get_value_string(lchan_s_names, s);
-}
-
static char ts2str[255];
char *gsm_ts_name(const struct gsm_bts_trx_ts *ts)
@@ -162,187 +147,6 @@ char *gsm_ts_and_pchan_name(const struct gsm_bts_trx_ts *ts)
return ts2str;
}
-void gsm_lchan_name_update(struct gsm_lchan *lchan)
-{
- const struct gsm_bts_trx_ts *ts = lchan->ts;
- const struct gsm_bts_trx *trx = ts->trx;
- char *name;
-
- name = talloc_asprintf(trx, "(" GSM_TS_NAME_FMT ",ss=%u)",
- GSM_TS_NAME_ARGS(ts), lchan->nr);
- if (lchan->name != NULL)
- talloc_free(lchan->name);
- lchan->name = name;
-}
-
-/* See Table 10.5.25 of GSM04.08 */
-static uint8_t gsm_pchan2chan_nr(enum gsm_phys_chan_config pchan,
- uint8_t ts_nr, uint8_t lchan_nr)
-{
- uint8_t cbits, chan_nr;
-
- OSMO_ASSERT(pchan != GSM_PCHAN_OSMO_DYN);
- OSMO_ASSERT(pchan != GSM_PCHAN_TCH_F_PDCH);
-
- switch (pchan) {
- case GSM_PCHAN_TCH_F:
- OSMO_ASSERT(lchan_nr == 0);
- cbits = ABIS_RSL_CHAN_NR_CBITS_Bm_ACCHs;
- break;
- case GSM_PCHAN_PDCH:
- OSMO_ASSERT(lchan_nr == 0);
- cbits = ABIS_RSL_CHAN_NR_CBITS_OSMO_PDCH;
- break;
- case GSM_PCHAN_TCH_H:
- OSMO_ASSERT(lchan_nr < 2);
- cbits = ABIS_RSL_CHAN_NR_CBITS_Lm_ACCHs(lchan_nr);
- break;
- case GSM_PCHAN_CCCH_SDCCH4:
- case GSM_PCHAN_CCCH_SDCCH4_CBCH:
- /*
- * As a special hack for BCCH, lchan_nr == 4 may be passed
- * here. This should never be sent in an RSL message.
- * See osmo-bts-xxx/oml.c:opstart_compl().
- */
- if (lchan_nr == CCCH_LCHAN)
- cbits = ABIS_RSL_CHAN_NR_CBITS_BCCH;
- else {
- OSMO_ASSERT(lchan_nr < 4);
- cbits = ABIS_RSL_CHAN_NR_CBITS_SDCCH4_ACCH(lchan_nr);
- }
- break;
- case GSM_PCHAN_SDCCH8_SACCH8C:
- case GSM_PCHAN_SDCCH8_SACCH8C_CBCH:
- OSMO_ASSERT(lchan_nr < 8);
- cbits = ABIS_RSL_CHAN_NR_CBITS_SDCCH8_ACCH(lchan_nr);
- break;
- case GSM_PCHAN_CCCH:
- cbits = ABIS_RSL_CHAN_NR_CBITS_BCCH;
- break;
- case GSM_PCHAN_NONE:
- LOGP(DRSL, LOGL_ERROR, "Physical channel %s not expected!\n",
- gsm_pchan_name(pchan));
- cbits = 0x00;
- break;
- default:
- LOGP(DRSL, LOGL_ERROR, "Physical channel %s (0x%02x) not expected!\n",
- gsm_pchan_name(pchan), (int)pchan);
- /* OSMO_ASSERT(lchan_nr == 0);
- * FIXME: On octphy and litecell, we hit above assertion (see
- * Max's comment at https://gerrit.osmocom.org/589 ); disabled
- * for BTS until this is clarified; remove the #ifdef when it
- * is fixed. Tracked in OS#2906.
- */
-#pragma message "fix caller that passes lchan_nr != 0"
- cbits = 0x10;
- break;
- }
-
- chan_nr = (cbits << 3) | (ts_nr & 0x7);
-
- return chan_nr;
-}
-
-static uint8_t _gsm_lchan2chan_nr(const struct gsm_lchan *lchan, bool rsl)
-{
- uint8_t chan_nr;
-
- switch (lchan->ts->pchan) {
- case GSM_PCHAN_OSMO_DYN:
- /* Return chan_nr reflecting the current TS pchan, either a standard TCH kind, or the
- * nonstandard value reflecting PDCH for Osmocom style dyn TS. */
- chan_nr = gsm_lchan_as_pchan2chan_nr(lchan, lchan->ts->dyn.pchan_is);
- break;
- case GSM_PCHAN_TCH_F_PDCH:
- /* For ip.access style dyn TS, on RSL we want to use the chan_nr as if it was TCH/F.
- * We're using custom PDCH ACT and DEACT messages that use the usual chan_nr values. */
- if (rsl)
- chan_nr = gsm_lchan_as_pchan2chan_nr(lchan, GSM_PCHAN_TCH_F);
- else if (~lchan->ts->flags & TS_F_PDCH_ACTIVE)
- chan_nr = gsm_lchan_as_pchan2chan_nr(lchan, GSM_PCHAN_TCH_F);
- else
- chan_nr = gsm_lchan_as_pchan2chan_nr(lchan, GSM_PCHAN_PDCH);
- break;
- default:
- chan_nr = gsm_pchan2chan_nr(lchan->ts->pchan, lchan->ts->nr, lchan->nr);
- break;
- }
-
- /* VAMOS: if this lchan belongs to a shadow timeslot, we must reflect
- * this in the channel number. Convert it to Osmocom specific value. */
- if (lchan->ts->vamos.is_shadow)
- chan_nr |= RSL_CHAN_OSMO_VAMOS_MASK;
-
- return chan_nr;
-}
-
-uint8_t gsm_lchan2chan_nr(const struct gsm_lchan *lchan)
-{
- return _gsm_lchan2chan_nr(lchan, false);
-}
-
-uint8_t gsm_lchan2chan_nr_rsl(const struct gsm_lchan *lchan)
-{
- return _gsm_lchan2chan_nr(lchan, true);
-}
-
-uint8_t gsm_lchan_as_pchan2chan_nr(const struct gsm_lchan *lchan,
- enum gsm_phys_chan_config as_pchan)
-{
- if (lchan->ts->pchan == GSM_PCHAN_OSMO_DYN
- && as_pchan == GSM_PCHAN_PDCH)
- return RSL_CHAN_OSMO_PDCH | (lchan->ts->nr & ~RSL_CHAN_NR_MASK);
- return gsm_pchan2chan_nr(as_pchan, lchan->ts->nr, lchan->nr);
-}
-
-/* Called by the model specific code every 104 TDMA frames (SACCH period) */
-void gsm_lchan_interf_meas_push(struct gsm_lchan *lchan, int dbm)
-{
- const uint8_t meas_num = lchan->meas.interf_meas_num;
-
- if (meas_num >= ARRAY_SIZE(lchan->meas.interf_meas_dbm)) {
- LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "Not enough room "
- "to store interference report (%ddBm)\n", dbm);
- return;
- }
-
- lchan->meas.interf_meas_dbm[meas_num] = dbm;
- lchan->meas.interf_meas_num++;
-}
-
-/* Called by the higher layers every Intave * 104 TDMA frames */
-int gsm_lchan_interf_meas_calc_band(struct gsm_lchan *lchan)
-{
- const uint8_t meas_num = lchan->meas.interf_meas_num;
- const struct gsm_bts *bts = lchan->ts->trx->bts;
- int b, meas_avg, meas_sum = 0;
-
- /* There must be at least one sample */
- if (meas_num == 0)
- return -EAGAIN;
-
- /* Calculate the sum of all collected samples (in -x dBm) */
- while (lchan->meas.interf_meas_num) {
- uint8_t i = --lchan->meas.interf_meas_num;
- meas_sum += lchan->meas.interf_meas_dbm[i];
- }
-
- /* Calculate the average of all collected samples */
- meas_avg = meas_sum / (int) meas_num;
-
- /* Determine the band using interference boundaries from BSC */
- for (b = 0; b < ARRAY_SIZE(bts->interference.boundary); b++) {
- if (meas_avg >= bts->interference.boundary[b])
- break; /* Current 'b' is the band value */
- }
-
- LOGPLCHAN(lchan, DL1C, LOGL_DEBUG,
- "Interference AVG: %ddBm (band %d, samples %u)\n",
- meas_avg, b, meas_num);
-
- return b;
-}
-
/* determine logical channel based on TRX and channel number IE */
struct gsm_lchan *rsl_lchan_lookup(struct gsm_bts_trx *trx, uint8_t chan_nr,
int *rc)
@@ -486,205 +290,18 @@ bool ts_is_tch(const struct gsm_bts_trx_ts *ts)
return pchan_is_tch(ts_pchan(ts));
}
-const struct value_string lchan_ciph_state_names[] = {
- { LCHAN_CIPH_NONE, "NONE" },
- { LCHAN_CIPH_RX_REQ, "RX_REQ" },
- { LCHAN_CIPH_RX_CONF, "RX_CONF" },
- { LCHAN_CIPH_RXTX_REQ, "RXTX_REQ" },
- { LCHAN_CIPH_RX_CONF_TX_REQ, "RX_CONF_TX_REQ" },
- { LCHAN_CIPH_RXTX_CONF, "RXTX_CONF" },
- { 0, NULL }
-};
-
-/* determine the ECU codec constant for the codec used by given lchan */
-int lchan2ecu_codec(const struct gsm_lchan *lchan)
+bool ts_is_pdch(const struct gsm_bts_trx_ts *ts)
{
- const struct gsm_bts_trx_ts *ts = lchan->ts;
-
- switch (lchan->tch_mode) {
- case GSM48_CMODE_SPEECH_V1:
- if (ts_pchan(ts) == GSM_PCHAN_TCH_H)
- return OSMO_ECU_CODEC_HR;
- else
- return OSMO_ECU_CODEC_FR;
- break;
- case GSM48_CMODE_SPEECH_EFR:
- return OSMO_ECU_CODEC_EFR;
- case GSM48_CMODE_SPEECH_AMR:
- return OSMO_ECU_CODEC_AMR;
+ switch (ts->pchan) {
+ case GSM_PCHAN_PDCH:
+ return true;
+ case GSM_PCHAN_TCH_F_PDCH:
+ return (ts->flags & TS_F_PDCH_ACTIVE)
+ && !(ts->flags & TS_F_PDCH_PENDING_MASK);
+ case GSM_PCHAN_OSMO_DYN:
+ return ts->dyn.pchan_is == GSM_PCHAN_PDCH
+ && ts->dyn.pchan_want == ts->dyn.pchan_is;
default:
- return -1;
+ return false;
}
}
-
-/* Default MS/BS Power Control parameters (see 3GPP TS 45.008, table A.1) */
-const struct gsm_power_ctrl_params power_ctrl_params_def = {
-
- .ctrl_interval = 1, /* Trigger loop every second SACCH block. TS 45.008 sec 4.7.1 */
-
- /* Power increasing/reducing step size (optimal defaults) */
- .inc_step_size_db = 4, /* quickly increase MS/BS power */
- .red_step_size_db = 2, /* slowly decrease MS/BS power */
-
- /* RxLev measurement parameters */
- .rxlev_meas = {
- /* Thresholds for RxLev (see 3GPP TS 45.008, A.3.2.1) */
- .lower_thresh = 32, /* L_RXLEV_XX_P (-78 dBm) */
- .upper_thresh = 38, /* U_RXLEV_XX_P (-72 dBm) */
-
- /* NOTE: only Osmocom specific EWMA is supported */
- .algo = GSM_PWR_CTRL_MEAS_AVG_ALGO_OSMO_EWMA,
- .ewma.alpha = 50, /* Smoothing factor 50% */
- },
-
- /* RxQual measurement parameters */
- .rxqual_meas = {
- /* Thresholds for RxQual (see 3GPP TS 45.008, A.3.2.1) */
- .lower_thresh = 3, /* L_RXQUAL_XX_P (0.8% <= BER < 1.6%) */
- .upper_thresh = 0, /* U_RXQUAL_XX_P (BER < 0.2%) */
-
- /* No averaging (filtering) by default.
- * NOTE: only Osmocom specific EWMA is supported */
- .algo = GSM_PWR_CTRL_MEAS_AVG_ALGO_NONE,
- },
-
- /* C/I measurement parameters.
- * Target C/I retrieved from "GSM/EDGE: Evolution and Performance" Table 10.3.
- * Set lower and upper so that (lower + upper) / 2 is equal or slightly
- * above the target.
- */
- .ci_fr_meas = { /* FR: Target C/I = 15 dB, Soft blocking threshold = 10 dB */
- .lower_thresh = 13,
- .upper_thresh = 17,
-
- /* Increase {UL,DL}_TXPWR if at least LOWER_CMP_P averages
- * out of LOWER_CMP_N averages are lower than L_CI_FR_XX_P */
- .lower_cmp_p = 5, /* P3 as in 3GPP TS 45.008, A.3.2.1 (case c) */
- .lower_cmp_n = 7, /* N3 as in 3GPP TS 45.008, A.3.2.1 (case c) */
- /* Decrease {UL,DL}_TXPWR if at least UPPER_CMP_P averages
- * out of UPPER_CMP_N averages are greater than L_CI_FR_XX_P */
- .upper_cmp_p = 15, /* P4 as in 3GPP TS 45.008, A.3.2.1 (case d) */
- .upper_cmp_n = 18, /* N4 as in 3GPP TS 45.008, A.3.2.1 (case d) */
-
- /* No averaging (filtering) by default */
- .algo = GSM_PWR_CTRL_MEAS_AVG_ALGO_NONE,
-
- /* Hreqave: the period over which an average is produced */
- .h_reqave = 4, /* TODO: investigate a reasonable default value */
- /* Hreqt: the number of averaged results maintained */
- .h_reqt = 6, /* TODO: investigate a reasonable default value */
- },
- .ci_hr_meas = { /* HR: Target C/I = 18 dB, Soft blocking threshold = 13 dB */
- .lower_thresh = 16,
- .upper_thresh = 21,
-
- /* Increase {UL,DL}_TXPWR if at least LOWER_CMP_P averages
- * out of LOWER_CMP_N averages are lower than L_CI_HR_XX_P */
- .lower_cmp_p = 5, /* P3 as in 3GPP TS 45.008, A.3.2.1 (case c) */
- .lower_cmp_n = 7, /* N3 as in 3GPP TS 45.008, A.3.2.1 (case c) */
- /* Decrease {UL,DL}_TXPWR if at least UPPER_CMP_P averages
- * out of UPPER_CMP_N averages are greater than L_CI_HR_XX_P */
- .upper_cmp_p = 15, /* P4 as in 3GPP TS 45.008, A.3.2.1 (case d) */
- .upper_cmp_n = 18, /* N4 as in 3GPP TS 45.008, A.3.2.1 (case d) */
-
- /* No averaging (filtering) by default */
- .algo = GSM_PWR_CTRL_MEAS_AVG_ALGO_NONE,
-
- /* Hreqave: the period over which an average is produced */
- .h_reqave = 4, /* TODO: investigate a reasonable default value */
- /* Hreqt: the number of averaged results maintained */
- .h_reqt = 6, /* TODO: investigate a reasonable default value */
- },
- .ci_amr_fr_meas = { /* AMR-FR: Target C/I = 9 dB, Soft blocking threshold = 4 dB */
- .lower_thresh = 7,
- .upper_thresh = 11,
-
- /* Increase {UL,DL}_TXPWR if at least LOWER_CMP_P averages
- * out of LOWER_CMP_N averages are lower than L_CI_AMR_FR_XX_P */
- .lower_cmp_p = 5, /* P3 as in 3GPP TS 45.008, A.3.2.1 (case c) */
- .lower_cmp_n = 7, /* N3 as in 3GPP TS 45.008, A.3.2.1 (case c) */
- /* Decrease {UL,DL}_TXPWR if at least UPPER_CMP_P averages
- * out of UPPER_CMP_N averages are greater than L_CI_AMR_FR_XX_P */
- .upper_cmp_p = 15, /* P4 as in 3GPP TS 45.008, A.3.2.1 (case d) */
- .upper_cmp_n = 18, /* N4 as in 3GPP TS 45.008, A.3.2.1 (case d) */
-
- /* No averaging (filtering) by default */
- .algo = GSM_PWR_CTRL_MEAS_AVG_ALGO_NONE,
-
- /* Hreqave: the period over which an average is produced */
- .h_reqave = 4, /* TODO: investigate a reasonable default value */
- /* Hreqt: the number of averaged results maintained */
- .h_reqt = 6, /* TODO: investigate a reasonable default value */
- },
- .ci_amr_hr_meas = { /* AMR-HR: Target C/I = 15 dB, Soft blocking threshold = 10 dB */
- .lower_thresh = 13,
- .upper_thresh = 17,
-
- /* Increase {UL,DL}_TXPWR if at least LOWER_CMP_P averages
- * out of LOWER_CMP_N averages are lower than L_CI_AMR_HR_XX_P */
- .lower_cmp_p = 5, /* P3 as in 3GPP TS 45.008, A.3.2.1 (case c) */
- .lower_cmp_n = 7, /* N3 as in 3GPP TS 45.008, A.3.2.1 (case c) */
- /* Decrease {UL,DL}_TXPWR if at least UPPER_CMP_P averages
- * out of UPPER_CMP_N averages are greater than L_CI_AMR_HR_XX_P */
- .upper_cmp_p = 15, /* P4 as in 3GPP TS 45.008, A.3.2.1 (case d) */
- .upper_cmp_n = 18, /* N4 as in 3GPP TS 45.008, A.3.2.1 (case d) */
-
- /* No averaging (filtering) by default */
- .algo = GSM_PWR_CTRL_MEAS_AVG_ALGO_NONE,
-
- /* Hreqave: the period over which an average is produced */
- .h_reqave = 4, /* TODO: investigate a reasonable default value */
- /* Hreqt: the number of averaged results maintained */
- .h_reqt = 6, /* TODO: investigate a reasonable default value */
- },
- .ci_sdcch_meas = { /* SDCCH: Target C/I = 14 dB, Soft blocking threshold = 9 dB */
- .lower_thresh = 12,
- .upper_thresh = 16,
-
- /* Increase {UL,DL}_TXPWR if at least LOWER_CMP_P averages
- * out of LOWER_CMP_N averages are lower than L_CI_SDCCH_XX_P */
- .lower_cmp_p = 5, /* P3 as in 3GPP TS 45.008, A.3.2.1 (case c) */
- .lower_cmp_n = 7, /* N3 as in 3GPP TS 45.008, A.3.2.1 (case c) */
- /* Decrease {UL,DL}_TXPWR if at least UPPER_CMP_P averages
- * out of UPPER_CMP_N averages are greater than L_CI_SDCCH_XX_P */
- .upper_cmp_p = 15, /* P4 as in 3GPP TS 45.008, A.3.2.1 (case d) */
- .upper_cmp_n = 18, /* N4 as in 3GPP TS 45.008, A.3.2.1 (case d) */
-
- /* No averaging (filtering) by default */
- .algo = GSM_PWR_CTRL_MEAS_AVG_ALGO_NONE,
-
- /* Hreqave: the period over which an average is produced */
- .h_reqave = 4, /* TODO: investigate a reasonable default value */
- /* Hreqt: the number of averaged results maintained */
- .h_reqt = 6, /* TODO: investigate a reasonable default value */
- },
- .ci_gprs_meas = { /* GPRS: Target C/I = 20 dB, Soft blocking threshold = 15 dB */
- .lower_thresh = 18,
- .upper_thresh = 24,
-
- /* Increase {UL,DL}_TXPWR if at least LOWER_CMP_P averages
- * out of LOWER_CMP_N averages are lower than L_CI_GPRS_XX_P */
- .lower_cmp_p = 5, /* P3 as in 3GPP TS 45.008, A.3.2.1 (case c) */
- .lower_cmp_n = 7, /* N3 as in 3GPP TS 45.008, A.3.2.1 (case c) */
- /* Decrease {UL,DL}_TXPWR if at least UPPER_CMP_P averages
- * out of UPPER_CMP_N averages are greater than L_CI_GPRS_XX_P */
- .upper_cmp_p = 15, /* P4 as in 3GPP TS 45.008, A.3.2.1 (case d) */
- .upper_cmp_n = 18, /* N4 as in 3GPP TS 45.008, A.3.2.1 (case d) */
-
- /* No averaging (filtering) by default */
- .algo = GSM_PWR_CTRL_MEAS_AVG_ALGO_NONE,
-
- /* Hreqave: the period over which an average is produced */
- .h_reqave = 4, /* TODO: investigate a reasonable default value */
- /* Hreqt: the number of averaged results maintained */
- .h_reqt = 6, /* TODO: investigate a reasonable default value */
- },
-};
-
-void power_ctrl_params_def_reset(struct gsm_power_ctrl_params *params, bool is_bs_pwr)
-{
- *params = power_ctrl_params_def;
- if (!is_bs_pwr)
- /* Trigger loop every fourth SACCH block (1.92s). TS 45.008 sec 4.7.1: */
- params->ctrl_interval = 2;
-}
diff --git a/src/common/lchan.c b/src/common/lchan.c
index cd99be72..afcb2c3e 100644
--- a/src/common/lchan.c
+++ b/src/common/lchan.c
@@ -24,6 +24,27 @@
#include <osmo-bts/lchan.h>
#include <osmo-bts/bts.h>
#include <osmo-bts/rsl.h>
+#include <errno.h>
+
+static const struct value_string lchan_s_names[] = {
+ { LCHAN_S_NONE, "NONE" },
+ { LCHAN_S_ACT_REQ, "ACTIVATION REQUESTED" },
+ { LCHAN_S_ACTIVE, "ACTIVE" },
+ { LCHAN_S_REL_REQ, "RELEASE REQUESTED" },
+ { LCHAN_S_REL_ERR, "RELEASE DUE ERROR" },
+ { LCHAN_S_BROKEN, "BROKEN UNUSABLE" },
+ { 0, NULL }
+};
+
+const struct value_string lchan_ciph_state_names[] = {
+ { LCHAN_CIPH_NONE, "NONE" },
+ { LCHAN_CIPH_RX_REQ, "RX_REQ" },
+ { LCHAN_CIPH_RX_CONF, "RX_CONF" },
+ { LCHAN_CIPH_RXTX_REQ, "RXTX_REQ" },
+ { LCHAN_CIPH_RX_CONF_TX_REQ, "RX_CONF_TX_REQ" },
+ { LCHAN_CIPH_RXTX_CONF, "RXTX_CONF" },
+ { 0, NULL }
+};
void gsm_lchan_init(struct gsm_lchan *lchan, struct gsm_bts_trx_ts *ts, unsigned int lchan_nr)
{
@@ -36,6 +57,24 @@ void gsm_lchan_init(struct gsm_lchan *lchan, struct gsm_bts_trx_ts *ts, unsigned
INIT_LLIST_HEAD(&lchan->dl_tch_queue);
}
+void gsm_lchan_name_update(struct gsm_lchan *lchan)
+{
+ const struct gsm_bts_trx_ts *ts = lchan->ts;
+ const struct gsm_bts_trx *trx = ts->trx;
+ char *name;
+
+ name = talloc_asprintf(trx, "(" GSM_TS_NAME_FMT ",ss=%u)",
+ GSM_TS_NAME_ARGS(ts), lchan->nr);
+ if (lchan->name != NULL)
+ talloc_free(lchan->name);
+ lchan->name = name;
+}
+
+const char *gsm_lchans_name(enum gsm_lchan_state s)
+{
+ return get_value_string(lchan_s_names, s);
+}
+
void early_rr_ia_delay_cb(void *data)
{
struct gsm_lchan *lchan = data;
@@ -98,18 +137,191 @@ void lchan_set_state(struct gsm_lchan *lchan, enum gsm_lchan_state state)
}
}
-bool ts_is_pdch(const struct gsm_bts_trx_ts *ts)
+/* See Table 10.5.25 of GSM04.08 */
+static uint8_t gsm_pchan2chan_nr(enum gsm_phys_chan_config pchan,
+ uint8_t ts_nr, uint8_t lchan_nr)
{
- switch (ts->pchan) {
+ uint8_t cbits, chan_nr;
+
+ OSMO_ASSERT(pchan != GSM_PCHAN_OSMO_DYN);
+ OSMO_ASSERT(pchan != GSM_PCHAN_TCH_F_PDCH);
+
+ switch (pchan) {
+ case GSM_PCHAN_TCH_F:
+ OSMO_ASSERT(lchan_nr == 0);
+ cbits = ABIS_RSL_CHAN_NR_CBITS_Bm_ACCHs;
+ break;
case GSM_PCHAN_PDCH:
- return true;
- case GSM_PCHAN_TCH_F_PDCH:
- return (ts->flags & TS_F_PDCH_ACTIVE)
- && !(ts->flags & TS_F_PDCH_PENDING_MASK);
+ OSMO_ASSERT(lchan_nr == 0);
+ cbits = ABIS_RSL_CHAN_NR_CBITS_OSMO_PDCH;
+ break;
+ case GSM_PCHAN_TCH_H:
+ OSMO_ASSERT(lchan_nr < 2);
+ cbits = ABIS_RSL_CHAN_NR_CBITS_Lm_ACCHs(lchan_nr);
+ break;
+ case GSM_PCHAN_CCCH_SDCCH4:
+ case GSM_PCHAN_CCCH_SDCCH4_CBCH:
+ /*
+ * As a special hack for BCCH, lchan_nr == 4 may be passed
+ * here. This should never be sent in an RSL message.
+ * See osmo-bts-xxx/oml.c:opstart_compl().
+ */
+ if (lchan_nr == CCCH_LCHAN)
+ cbits = ABIS_RSL_CHAN_NR_CBITS_BCCH;
+ else {
+ OSMO_ASSERT(lchan_nr < 4);
+ cbits = ABIS_RSL_CHAN_NR_CBITS_SDCCH4_ACCH(lchan_nr);
+ }
+ break;
+ case GSM_PCHAN_SDCCH8_SACCH8C:
+ case GSM_PCHAN_SDCCH8_SACCH8C_CBCH:
+ OSMO_ASSERT(lchan_nr < 8);
+ cbits = ABIS_RSL_CHAN_NR_CBITS_SDCCH8_ACCH(lchan_nr);
+ break;
+ case GSM_PCHAN_CCCH:
+ cbits = ABIS_RSL_CHAN_NR_CBITS_BCCH;
+ break;
+ case GSM_PCHAN_NONE:
+ LOGP(DRSL, LOGL_ERROR, "Physical channel %s not expected!\n",
+ gsm_pchan_name(pchan));
+ cbits = 0x00;
+ break;
+ default:
+ LOGP(DRSL, LOGL_ERROR, "Physical channel %s (0x%02x) not expected!\n",
+ gsm_pchan_name(pchan), (int)pchan);
+ /* OSMO_ASSERT(lchan_nr == 0);
+ * FIXME: On octphy and litecell, we hit above assertion (see
+ * Max's comment at https://gerrit.osmocom.org/589 ); disabled
+ * for BTS until this is clarified; remove the #ifdef when it
+ * is fixed. Tracked in OS#2906.
+ */
+#pragma message "fix caller that passes lchan_nr != 0"
+ cbits = 0x10;
+ break;
+ }
+
+ chan_nr = (cbits << 3) | (ts_nr & 0x7);
+
+ return chan_nr;
+}
+
+static uint8_t _gsm_lchan2chan_nr(const struct gsm_lchan *lchan, bool rsl)
+{
+ uint8_t chan_nr;
+
+ switch (lchan->ts->pchan) {
case GSM_PCHAN_OSMO_DYN:
- return ts->dyn.pchan_is == GSM_PCHAN_PDCH
- && ts->dyn.pchan_want == ts->dyn.pchan_is;
+ /* Return chan_nr reflecting the current TS pchan, either a standard TCH kind, or the
+ * nonstandard value reflecting PDCH for Osmocom style dyn TS. */
+ chan_nr = gsm_lchan_as_pchan2chan_nr(lchan, lchan->ts->dyn.pchan_is);
+ break;
+ case GSM_PCHAN_TCH_F_PDCH:
+ /* For ip.access style dyn TS, on RSL we want to use the chan_nr as if it was TCH/F.
+ * We're using custom PDCH ACT and DEACT messages that use the usual chan_nr values. */
+ if (rsl)
+ chan_nr = gsm_lchan_as_pchan2chan_nr(lchan, GSM_PCHAN_TCH_F);
+ else if (~lchan->ts->flags & TS_F_PDCH_ACTIVE)
+ chan_nr = gsm_lchan_as_pchan2chan_nr(lchan, GSM_PCHAN_TCH_F);
+ else
+ chan_nr = gsm_lchan_as_pchan2chan_nr(lchan, GSM_PCHAN_PDCH);
+ break;
+ default:
+ chan_nr = gsm_pchan2chan_nr(lchan->ts->pchan, lchan->ts->nr, lchan->nr);
+ break;
+ }
+
+ /* VAMOS: if this lchan belongs to a shadow timeslot, we must reflect
+ * this in the channel number. Convert it to Osmocom specific value. */
+ if (lchan->ts->vamos.is_shadow)
+ chan_nr |= RSL_CHAN_OSMO_VAMOS_MASK;
+
+ return chan_nr;
+}
+
+uint8_t gsm_lchan2chan_nr(const struct gsm_lchan *lchan)
+{
+ return _gsm_lchan2chan_nr(lchan, false);
+}
+
+uint8_t gsm_lchan2chan_nr_rsl(const struct gsm_lchan *lchan)
+{
+ return _gsm_lchan2chan_nr(lchan, true);
+}
+
+uint8_t gsm_lchan_as_pchan2chan_nr(const struct gsm_lchan *lchan,
+ enum gsm_phys_chan_config as_pchan)
+{
+ if (lchan->ts->pchan == GSM_PCHAN_OSMO_DYN
+ && as_pchan == GSM_PCHAN_PDCH)
+ return RSL_CHAN_OSMO_PDCH | (lchan->ts->nr & ~RSL_CHAN_NR_MASK);
+ return gsm_pchan2chan_nr(as_pchan, lchan->ts->nr, lchan->nr);
+}
+
+/* Called by the model specific code every 104 TDMA frames (SACCH period) */
+void gsm_lchan_interf_meas_push(struct gsm_lchan *lchan, int dbm)
+{
+ const uint8_t meas_num = lchan->meas.interf_meas_num;
+
+ if (meas_num >= ARRAY_SIZE(lchan->meas.interf_meas_dbm)) {
+ LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "Not enough room "
+ "to store interference report (%ddBm)\n", dbm);
+ return;
+ }
+
+ lchan->meas.interf_meas_dbm[meas_num] = dbm;
+ lchan->meas.interf_meas_num++;
+}
+
+/* Called by the higher layers every Intave * 104 TDMA frames */
+int gsm_lchan_interf_meas_calc_band(struct gsm_lchan *lchan)
+{
+ const uint8_t meas_num = lchan->meas.interf_meas_num;
+ const struct gsm_bts *bts = lchan->ts->trx->bts;
+ int b, meas_avg, meas_sum = 0;
+
+ /* There must be at least one sample */
+ if (meas_num == 0)
+ return -EAGAIN;
+
+ /* Calculate the sum of all collected samples (in -x dBm) */
+ while (lchan->meas.interf_meas_num) {
+ uint8_t i = --lchan->meas.interf_meas_num;
+ meas_sum += lchan->meas.interf_meas_dbm[i];
+ }
+
+ /* Calculate the average of all collected samples */
+ meas_avg = meas_sum / (int) meas_num;
+
+ /* Determine the band using interference boundaries from BSC */
+ for (b = 0; b < ARRAY_SIZE(bts->interference.boundary); b++) {
+ if (meas_avg >= bts->interference.boundary[b])
+ break; /* Current 'b' is the band value */
+ }
+
+ LOGPLCHAN(lchan, DL1C, LOGL_DEBUG,
+ "Interference AVG: %ddBm (band %d, samples %u)\n",
+ meas_avg, b, meas_num);
+
+ return b;
+}
+
+/* determine the ECU codec constant for the codec used by given lchan */
+int lchan2ecu_codec(const struct gsm_lchan *lchan)
+{
+ const struct gsm_bts_trx_ts *ts = lchan->ts;
+
+ switch (lchan->tch_mode) {
+ case GSM48_CMODE_SPEECH_V1:
+ if (ts_pchan(ts) == GSM_PCHAN_TCH_H)
+ return OSMO_ECU_CODEC_HR;
+ else
+ return OSMO_ECU_CODEC_FR;
+ break;
+ case GSM48_CMODE_SPEECH_EFR:
+ return OSMO_ECU_CODEC_EFR;
+ case GSM48_CMODE_SPEECH_AMR:
+ return OSMO_ECU_CODEC_AMR;
default:
- return false;
+ return -1;
}
}
diff --git a/src/common/power_control.c b/src/common/power_control.c
index 8f5ce370..a81000ed 100644
--- a/src/common/power_control.c
+++ b/src/common/power_control.c
@@ -421,3 +421,175 @@ int lchan_bs_pwr_ctrl(struct gsm_lchan *lchan,
state->current = new_att;
return 1;
}
+
+/* Default MS/BS Power Control parameters (see 3GPP TS 45.008, table A.1) */
+const struct gsm_power_ctrl_params power_ctrl_params_def = {
+
+ .ctrl_interval = 1, /* Trigger loop every second SACCH block. TS 45.008 sec 4.7.1 */
+
+ /* Power increasing/reducing step size (optimal defaults) */
+ .inc_step_size_db = 4, /* quickly increase MS/BS power */
+ .red_step_size_db = 2, /* slowly decrease MS/BS power */
+
+ /* RxLev measurement parameters */
+ .rxlev_meas = {
+ /* Thresholds for RxLev (see 3GPP TS 45.008, A.3.2.1) */
+ .lower_thresh = 32, /* L_RXLEV_XX_P (-78 dBm) */
+ .upper_thresh = 38, /* U_RXLEV_XX_P (-72 dBm) */
+
+ /* NOTE: only Osmocom specific EWMA is supported */
+ .algo = GSM_PWR_CTRL_MEAS_AVG_ALGO_OSMO_EWMA,
+ .ewma.alpha = 50, /* Smoothing factor 50% */
+ },
+
+ /* RxQual measurement parameters */
+ .rxqual_meas = {
+ /* Thresholds for RxQual (see 3GPP TS 45.008, A.3.2.1) */
+ .lower_thresh = 3, /* L_RXQUAL_XX_P (0.8% <= BER < 1.6%) */
+ .upper_thresh = 0, /* U_RXQUAL_XX_P (BER < 0.2%) */
+
+ /* No averaging (filtering) by default.
+ * NOTE: only Osmocom specific EWMA is supported */
+ .algo = GSM_PWR_CTRL_MEAS_AVG_ALGO_NONE,
+ },
+
+ /* C/I measurement parameters.
+ * Target C/I retrieved from "GSM/EDGE: Evolution and Performance" Table 10.3.
+ * Set lower and upper so that (lower + upper) / 2 is equal or slightly
+ * above the target.
+ */
+ .ci_fr_meas = { /* FR: Target C/I = 15 dB, Soft blocking threshold = 10 dB */
+ .lower_thresh = 13,
+ .upper_thresh = 17,
+
+ /* Increase {UL,DL}_TXPWR if at least LOWER_CMP_P averages
+ * out of LOWER_CMP_N averages are lower than L_CI_FR_XX_P */
+ .lower_cmp_p = 5, /* P3 as in 3GPP TS 45.008, A.3.2.1 (case c) */
+ .lower_cmp_n = 7, /* N3 as in 3GPP TS 45.008, A.3.2.1 (case c) */
+ /* Decrease {UL,DL}_TXPWR if at least UPPER_CMP_P averages
+ * out of UPPER_CMP_N averages are greater than L_CI_FR_XX_P */
+ .upper_cmp_p = 15, /* P4 as in 3GPP TS 45.008, A.3.2.1 (case d) */
+ .upper_cmp_n = 18, /* N4 as in 3GPP TS 45.008, A.3.2.1 (case d) */
+
+ /* No averaging (filtering) by default */
+ .algo = GSM_PWR_CTRL_MEAS_AVG_ALGO_NONE,
+
+ /* Hreqave: the period over which an average is produced */
+ .h_reqave = 4, /* TODO: investigate a reasonable default value */
+ /* Hreqt: the number of averaged results maintained */
+ .h_reqt = 6, /* TODO: investigate a reasonable default value */
+ },
+ .ci_hr_meas = { /* HR: Target C/I = 18 dB, Soft blocking threshold = 13 dB */
+ .lower_thresh = 16,
+ .upper_thresh = 21,
+
+ /* Increase {UL,DL}_TXPWR if at least LOWER_CMP_P averages
+ * out of LOWER_CMP_N averages are lower than L_CI_HR_XX_P */
+ .lower_cmp_p = 5, /* P3 as in 3GPP TS 45.008, A.3.2.1 (case c) */
+ .lower_cmp_n = 7, /* N3 as in 3GPP TS 45.008, A.3.2.1 (case c) */
+ /* Decrease {UL,DL}_TXPWR if at least UPPER_CMP_P averages
+ * out of UPPER_CMP_N averages are greater than L_CI_HR_XX_P */
+ .upper_cmp_p = 15, /* P4 as in 3GPP TS 45.008, A.3.2.1 (case d) */
+ .upper_cmp_n = 18, /* N4 as in 3GPP TS 45.008, A.3.2.1 (case d) */
+
+ /* No averaging (filtering) by default */
+ .algo = GSM_PWR_CTRL_MEAS_AVG_ALGO_NONE,
+
+ /* Hreqave: the period over which an average is produced */
+ .h_reqave = 4, /* TODO: investigate a reasonable default value */
+ /* Hreqt: the number of averaged results maintained */
+ .h_reqt = 6, /* TODO: investigate a reasonable default value */
+ },
+ .ci_amr_fr_meas = { /* AMR-FR: Target C/I = 9 dB, Soft blocking threshold = 4 dB */
+ .lower_thresh = 7,
+ .upper_thresh = 11,
+
+ /* Increase {UL,DL}_TXPWR if at least LOWER_CMP_P averages
+ * out of LOWER_CMP_N averages are lower than L_CI_AMR_FR_XX_P */
+ .lower_cmp_p = 5, /* P3 as in 3GPP TS 45.008, A.3.2.1 (case c) */
+ .lower_cmp_n = 7, /* N3 as in 3GPP TS 45.008, A.3.2.1 (case c) */
+ /* Decrease {UL,DL}_TXPWR if at least UPPER_CMP_P averages
+ * out of UPPER_CMP_N averages are greater than L_CI_AMR_FR_XX_P */
+ .upper_cmp_p = 15, /* P4 as in 3GPP TS 45.008, A.3.2.1 (case d) */
+ .upper_cmp_n = 18, /* N4 as in 3GPP TS 45.008, A.3.2.1 (case d) */
+
+ /* No averaging (filtering) by default */
+ .algo = GSM_PWR_CTRL_MEAS_AVG_ALGO_NONE,
+
+ /* Hreqave: the period over which an average is produced */
+ .h_reqave = 4, /* TODO: investigate a reasonable default value */
+ /* Hreqt: the number of averaged results maintained */
+ .h_reqt = 6, /* TODO: investigate a reasonable default value */
+ },
+ .ci_amr_hr_meas = { /* AMR-HR: Target C/I = 15 dB, Soft blocking threshold = 10 dB */
+ .lower_thresh = 13,
+ .upper_thresh = 17,
+
+ /* Increase {UL,DL}_TXPWR if at least LOWER_CMP_P averages
+ * out of LOWER_CMP_N averages are lower than L_CI_AMR_HR_XX_P */
+ .lower_cmp_p = 5, /* P3 as in 3GPP TS 45.008, A.3.2.1 (case c) */
+ .lower_cmp_n = 7, /* N3 as in 3GPP TS 45.008, A.3.2.1 (case c) */
+ /* Decrease {UL,DL}_TXPWR if at least UPPER_CMP_P averages
+ * out of UPPER_CMP_N averages are greater than L_CI_AMR_HR_XX_P */
+ .upper_cmp_p = 15, /* P4 as in 3GPP TS 45.008, A.3.2.1 (case d) */
+ .upper_cmp_n = 18, /* N4 as in 3GPP TS 45.008, A.3.2.1 (case d) */
+
+ /* No averaging (filtering) by default */
+ .algo = GSM_PWR_CTRL_MEAS_AVG_ALGO_NONE,
+
+ /* Hreqave: the period over which an average is produced */
+ .h_reqave = 4, /* TODO: investigate a reasonable default value */
+ /* Hreqt: the number of averaged results maintained */
+ .h_reqt = 6, /* TODO: investigate a reasonable default value */
+ },
+ .ci_sdcch_meas = { /* SDCCH: Target C/I = 14 dB, Soft blocking threshold = 9 dB */
+ .lower_thresh = 12,
+ .upper_thresh = 16,
+
+ /* Increase {UL,DL}_TXPWR if at least LOWER_CMP_P averages
+ * out of LOWER_CMP_N averages are lower than L_CI_SDCCH_XX_P */
+ .lower_cmp_p = 5, /* P3 as in 3GPP TS 45.008, A.3.2.1 (case c) */
+ .lower_cmp_n = 7, /* N3 as in 3GPP TS 45.008, A.3.2.1 (case c) */
+ /* Decrease {UL,DL}_TXPWR if at least UPPER_CMP_P averages
+ * out of UPPER_CMP_N averages are greater than L_CI_SDCCH_XX_P */
+ .upper_cmp_p = 15, /* P4 as in 3GPP TS 45.008, A.3.2.1 (case d) */
+ .upper_cmp_n = 18, /* N4 as in 3GPP TS 45.008, A.3.2.1 (case d) */
+
+ /* No averaging (filtering) by default */
+ .algo = GSM_PWR_CTRL_MEAS_AVG_ALGO_NONE,
+
+ /* Hreqave: the period over which an average is produced */
+ .h_reqave = 4, /* TODO: investigate a reasonable default value */
+ /* Hreqt: the number of averaged results maintained */
+ .h_reqt = 6, /* TODO: investigate a reasonable default value */
+ },
+ .ci_gprs_meas = { /* GPRS: Target C/I = 20 dB, Soft blocking threshold = 15 dB */
+ .lower_thresh = 18,
+ .upper_thresh = 24,
+
+ /* Increase {UL,DL}_TXPWR if at least LOWER_CMP_P averages
+ * out of LOWER_CMP_N averages are lower than L_CI_GPRS_XX_P */
+ .lower_cmp_p = 5, /* P3 as in 3GPP TS 45.008, A.3.2.1 (case c) */
+ .lower_cmp_n = 7, /* N3 as in 3GPP TS 45.008, A.3.2.1 (case c) */
+ /* Decrease {UL,DL}_TXPWR if at least UPPER_CMP_P averages
+ * out of UPPER_CMP_N averages are greater than L_CI_GPRS_XX_P */
+ .upper_cmp_p = 15, /* P4 as in 3GPP TS 45.008, A.3.2.1 (case d) */
+ .upper_cmp_n = 18, /* N4 as in 3GPP TS 45.008, A.3.2.1 (case d) */
+
+ /* No averaging (filtering) by default */
+ .algo = GSM_PWR_CTRL_MEAS_AVG_ALGO_NONE,
+
+ /* Hreqave: the period over which an average is produced */
+ .h_reqave = 4, /* TODO: investigate a reasonable default value */
+ /* Hreqt: the number of averaged results maintained */
+ .h_reqt = 6, /* TODO: investigate a reasonable default value */
+ },
+};
+
+void power_ctrl_params_def_reset(struct gsm_power_ctrl_params *params, bool is_bs_pwr)
+{
+ *params = power_ctrl_params_def;
+ if (!is_bs_pwr)
+ /* Trigger loop every fourth SACCH block (1.92s). TS 45.008 sec 4.7.1: */
+ params->ctrl_interval = 2;
+}