From 6fd4f77243b40156b7929ab6b2ee865bc040d8db Mon Sep 17 00:00:00 2001 From: Vadim Yanitskiy Date: Tue, 8 Jun 2021 17:54:24 +0200 Subject: osmo-bts-trx: report interference levels to the upper layers In trx_sched_ul_burst(), treat all BURST.ind and NOPE.ind mapped to inactive logical channels as interference. Average the RSSI values on the fly using a sliding average with constant a=0.5. Report averaged values for each logical channel every 104 TDMA frames (SACCH period) by calling gsm_lchan_interf_meas_push(). Change-Id: I4686448e42a40df56c1d27a14fd0a4d43fd144a5 Related: I78b6d8beffa5228a28231b75728e7aebdd3cb23c Related: SYS#5313, OS#1569 --- include/osmo-bts/scheduler.h | 8 +++-- src/common/scheduler.c | 39 ++++++++++++++++++++----- src/osmo-bts-trx/scheduler_trx.c | 63 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 100 insertions(+), 10 deletions(-) diff --git a/include/osmo-bts/scheduler.h b/include/osmo-bts/scheduler.h index 40b73301..80a260fe 100644 --- a/include/osmo-bts/scheduler.h +++ b/include/osmo-bts/scheduler.h @@ -136,10 +136,14 @@ struct l1sched_chan_state { uint8_t ul_encr_key[MAX_A5_KEY_LEN]; uint8_t dl_encr_key[MAX_A5_KEY_LEN]; - /* Simple ring buffer (up to 8 unique measurements) */ + /* Uplink measurements */ struct { - struct l1sched_meas_set buf[8]; + /* Active channel measurements (simple ring buffer) */ + struct l1sched_meas_set buf[8]; /* up to 8 entries */ unsigned int current; /* current position */ + + /* Interference measurements */ + int interf_avg; /* sliding average */ } meas; /* handover */ diff --git a/src/common/scheduler.c b/src/common/scheduler.c index 0e1f4957..a010b396 100644 --- a/src/common/scheduler.c +++ b/src/common/scheduler.c @@ -1444,6 +1444,31 @@ static int trx_sched_calc_frame_loss(struct l1sched_ts *l1ts, return 0; } +/* Process a single noise measurement for an inactive timeslot. */ +static void trx_sched_noise_meas(struct l1sched_chan_state *l1cs, + const struct trx_ul_burst_ind *bi) +{ + int *Avg = &l1cs->meas.interf_avg; + + /* EWMA (Exponentially Weighted Moving Average): + * + * Avg[n] = a * Val[n] + (1 - a) * Avg[n - 1] + * + * Implemented using the '+=' operator: + * + * Avg += a * Val - a * Avg + * Avg += a * (Val - Avg) + * + * We use constant 'a' = 0.5, what is equal to: + * + * Avg += (Val - Avg) / 2 + * + * We don't really need precisity here, so no scaling. + */ + + *Avg += (bi->rssi - *Avg) / 2; +} + /* Process an Uplink burst indication */ int trx_sched_ul_burst(struct l1sched_ts *l1ts, struct trx_ul_burst_ind *bi) { @@ -1469,15 +1494,13 @@ int trx_sched_ul_burst(struct l1sched_ts *l1ts, struct trx_ul_burst_ind *bi) l1cs = &l1ts->chan_state[bi->chan]; func = trx_chan_desc[bi->chan].ul_fn; - /* TODO: handle noise measurements */ - if (bi->chan == TRXC_IDLE && bi->flags & TRX_BI_F_NOPE_IND) { - LOGL1SB(DL1P, LOGL_DEBUG, l1ts, bi, "Rx noise measurement (%d)\n", bi->rssi); - return -ENOTSUP; - } - /* check if channel is active */ - if (!TRX_CHAN_IS_ACTIVE(l1cs, bi->chan)) - return -EINVAL; + if (!TRX_CHAN_IS_ACTIVE(l1cs, bi->chan)) { + /* handle noise measurements */ + if (TRX_CHAN_IS_DEDIC(bi->chan)) + trx_sched_noise_meas(l1cs, bi); + return 0; + } /* omit bursts which have no handler, like IDLE bursts */ if (!func) diff --git a/src/osmo-bts-trx/scheduler_trx.c b/src/osmo-bts-trx/scheduler_trx.c index 1a4f03fa..0a2052c1 100644 --- a/src/osmo-bts-trx/scheduler_trx.c +++ b/src/osmo-bts-trx/scheduler_trx.c @@ -60,6 +60,65 @@ int tx_idle_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br) return 0; } +static void ts_report_interf_meas(const struct gsm_bts_trx_ts *ts) +{ + const struct l1sched_ts *l1ts = ts->priv; + unsigned int ln; + + for (ln = 0; ln < ARRAY_SIZE(ts->lchan); ln++) { + const struct gsm_lchan *lchan = &ts->lchan[ln]; + enum trx_chan_type dcch, acch; + int interf_avg; + + /* We're not interested in active channels */ + if (lchan->state == LCHAN_S_ACTIVE) + continue; + + switch (lchan->type) { + case GSM_LCHAN_SDCCH: + if (ts->pchan == GSM_PCHAN_CCCH_SDCCH4 || + ts->pchan == GSM_PCHAN_CCCH_SDCCH4_CBCH) { + dcch = TRXC_SDCCH4_0 + ln; + acch = TRXC_SACCH4_0 + ln; + } else { /* SDCCH/8 otherwise */ + dcch = TRXC_SDCCH8_0 + ln; + acch = TRXC_SACCH8_0 + ln; + } + break; + case GSM_LCHAN_TCH_F: + dcch = TRXC_TCHF; + acch = TRXC_SACCHTF; + break; + case GSM_LCHAN_TCH_H: + dcch = TRXC_TCHH_0 + ln; + acch = TRXC_SACCHTH_0 + ln; + break; + default: + /* Skip other lchan types */ + continue; + } + + OSMO_ASSERT(dcch < ARRAY_SIZE(l1ts->chan_state)); + OSMO_ASSERT(acch < ARRAY_SIZE(l1ts->chan_state)); + + interf_avg = (l1ts->chan_state[dcch].meas.interf_avg + + l1ts->chan_state[acch].meas.interf_avg) / 2; + + gsm_lchan_interf_meas_push((struct gsm_lchan *) lchan, interf_avg); + } +} + +static void bts_report_interf_meas(const struct gsm_bts *bts) +{ + const struct gsm_bts_trx *trx; + unsigned int tn; + + llist_for_each_entry(trx, &bts->trx_list, list) { + for (tn = 0; tn < ARRAY_SIZE(trx->ts); tn++) + ts_report_interf_meas(&trx->ts[tn]); + } +} + /* Find a route (PHY instance) for a given Downlink burst request */ static struct phy_instance *dlfh_route_br(const struct trx_dl_burst_req *br, struct gsm_bts_trx_ts *ts) @@ -189,6 +248,10 @@ static void bts_sched_fn(struct gsm_bts *bts, const uint32_t fn) struct gsm_bts_trx *trx; unsigned int tn; + /* Report interference measurements */ + if (fn % 104 == 0) /* SACCH period */ + bts_report_interf_meas(bts); + /* send time indication */ l1if_mph_time_ind(bts, fn); -- cgit v1.2.3