diff --git a/include/osmo-bts/scheduler.h b/include/osmo-bts/scheduler.h index 0d863474c..b488b6c44 100644 --- a/include/osmo-bts/scheduler.h +++ b/include/osmo-bts/scheduler.h @@ -70,6 +70,13 @@ enum trx_burst_type { TRX_BURST_8PSK, }; +/* A set of measurements belonging to one Uplink burst */ +struct l1sched_meas_set { + int16_t toa256; /* Timing of Arrival (1/256 of a symbol) */ + int16_t ci_cb; /* Carrier-to-Interference (cB) */ + float rssi; /* RSSI (dBm) */ +}; + /* States each channel on a multiframe */ struct l1sched_chan_state { /* Pointer to the associated logical channel state from gsm_data_shared. @@ -85,14 +92,6 @@ struct l1sched_chan_state { uint32_t ul_first_fn; /* fn of first burst */ uint8_t ul_mask; /* mask of received bursts */ - /* measurements */ - uint8_t rssi_num; /* number of RSSI values */ - float rssi_sum; /* sum of RSSI values */ - uint8_t toa_num; /* number of TOA values */ - int32_t toa256_sum; /* sum of TOA values (1/256 symbol) */ - uint8_t ci_cb_num; /* number of C/I values */ - int32_t ci_cb_sum; /* sum of C/I values (in centiBels) */ - /* loss detection */ uint8_t lost_frames; /* how many L2 frames were lost */ uint32_t last_tdma_fn; /* last processed TDMA frame number */ @@ -126,8 +125,11 @@ struct l1sched_chan_state { uint8_t ul_encr_key[MAX_A5_KEY_LEN]; uint8_t dl_encr_key[MAX_A5_KEY_LEN]; - /* measurements */ - /* TODO: measurement history (ring buffer) will be added here */ + /* Simple ring buffer (up to 8 unique measurements) */ + struct { + struct l1sched_meas_set buf[8]; + unsigned int current; /* current position */ + } meas; /* handover */ bool ho_rach_detect; /* if rach detection is on */ @@ -266,4 +268,20 @@ struct trx_dl_burst_req { int trx_sched_route_burst_ind(struct trx_ul_burst_ind *bi, struct l1sched_trx *l1t); int trx_sched_ul_burst(struct l1sched_trx *l1t, struct trx_ul_burst_ind *bi); +/* Averaging mode for trx_sched_meas_avg() */ +enum sched_meas_avg_mode { + /* last 4 bursts (default for xCCH, TCH/H, PTCCH and PDTCH) */ + SCHED_MEAS_AVG_M_QUAD, + /* last 8 bursts (default for TCH/F and FACCH/F) */ + SCHED_MEAS_AVG_M_OCTO, + /* last 6 bursts (default for FACCH/H) */ + SCHED_MEAS_AVG_M_SIX, +}; + +void trx_sched_meas_push(struct l1sched_chan_state *chan_state, + const struct trx_ul_burst_ind *bi); +void trx_sched_meas_avg(const struct l1sched_chan_state *chan_state, + struct l1sched_meas_set *avg, + enum sched_meas_avg_mode mode); + #endif /* TRX_SCHEDULER_H */ diff --git a/src/osmo-bts-trx/sched_lchan_pdtch.c b/src/osmo-bts-trx/sched_lchan_pdtch.c index 259d33643..28a45f58a 100644 --- a/src/osmo-bts-trx/sched_lchan_pdtch.c +++ b/src/osmo-bts-trx/sched_lchan_pdtch.c @@ -46,17 +46,11 @@ int rx_pdtch_fn(struct l1sched_trx *l1t, enum trx_chan_type chan, sbit_t *burst, **bursts_p = &chan_state->ul_bursts; uint32_t *first_fn = &chan_state->ul_first_fn; uint8_t *mask = &chan_state->ul_mask; - float *rssi_sum = &chan_state->rssi_sum; - uint8_t *rssi_num = &chan_state->rssi_num; - int32_t *toa256_sum = &chan_state->toa256_sum; - uint8_t *toa_num = &chan_state->toa_num; - int32_t *ci_cb_sum = &chan_state->ci_cb_sum; - uint8_t *ci_cb_num = &chan_state->ci_cb_num; + struct l1sched_meas_set meas_avg; uint8_t l2[EGPRS_0503_MAX_BYTES]; int n_errors = 0; int n_bursts_bits = 0; int n_bits_total = 0; - int16_t lqual_cb; uint16_t ber10k; int rc; @@ -76,26 +70,13 @@ int rx_pdtch_fn(struct l1sched_trx *l1t, enum trx_chan_type chan, memset(*bursts_p, 0, GSM0503_EGPRS_BURSTS_NBITS); *mask = 0x0; *first_fn = bi->fn; - *rssi_sum = 0; - *rssi_num = 0; - *toa256_sum = 0; - *toa_num = 0; - *ci_cb_sum = 0; - *ci_cb_num = 0; } - /* update mask + rssi */ + /* update mask */ *mask |= (1 << bid); - *rssi_sum += bi->rssi; - (*rssi_num)++; - *toa256_sum += bi->toa256; - (*toa_num)++; - /* C/I: Carrier-to-Interference ratio (in centiBels) */ - if (bi->flags & TRX_BI_F_CI_CB) { - *ci_cb_sum += bi->ci_cb; - (*ci_cb_num)++; - } + /* store measurements */ + trx_sched_meas_push(chan_state, bi); /* copy burst to buffer of 4 bursts */ if (bi->burst_len == EGPRS_BURST_LEN) { @@ -114,6 +95,9 @@ int rx_pdtch_fn(struct l1sched_trx *l1t, enum trx_chan_type chan, if (bid != 3) return 0; + /* average measurements of the last 4 bursts */ + trx_sched_meas_avg(chan_state, &meas_avg, SCHED_MEAS_AVG_M_QUAD); + /* check for complete set of bursts */ if ((*mask & 0xf) != 0xf) { LOGL1S(DL1P, LOGL_DEBUG, l1t, bi->tn, chan, bi->fn, @@ -143,13 +127,11 @@ int rx_pdtch_fn(struct l1sched_trx *l1t, enum trx_chan_type chan, return 0; } - lqual_cb = *ci_cb_num ? (*ci_cb_sum / *ci_cb_num) : 0; ber10k = compute_ber10k(n_bits_total, n_errors); return _sched_compose_ph_data_ind(l1t, bi->tn, *first_fn, chan, l2, rc, - *rssi_sum / *rssi_num, - *toa256_sum / *toa_num, - lqual_cb, ber10k, + meas_avg.rssi, meas_avg.toa256, + meas_avg.ci_cb, ber10k, PRES_INFO_BOTH); } diff --git a/src/osmo-bts-trx/sched_lchan_tchf.c b/src/osmo-bts-trx/sched_lchan_tchf.c index d28962034..e29a47e23 100644 --- a/src/osmo-bts-trx/sched_lchan_tchf.c +++ b/src/osmo-bts-trx/sched_lchan_tchf.c @@ -56,6 +56,8 @@ int rx_tchf_fn(struct l1sched_trx *l1t, enum trx_chan_type chan, uint8_t rsl_cmode = chan_state->rsl_cmode; uint8_t tch_mode = chan_state->tch_mode; uint8_t tch_data[128]; /* just to be safe */ + enum sched_meas_avg_mode meas_avg_mode = SCHED_MEAS_AVG_M_OCTO; + struct l1sched_meas_set meas_avg; int rc, amr = 0; int n_errors = 0; int n_bits_total = 0; @@ -89,6 +91,9 @@ int rx_tchf_fn(struct l1sched_trx *l1t, enum trx_chan_type chan, /* update mask */ *mask |= (1 << bid); + /* store measurements */ + trx_sched_meas_push(chan_state, bi); + /* copy burst to end of buffer of 8 bursts */ burst = *bursts_p + bid * 116 + 464; if (bi->burst_len > 0) { @@ -194,6 +199,9 @@ int rx_tchf_fn(struct l1sched_trx *l1t, enum trx_chan_type chan, } memcpy(*bursts_p, *bursts_p + 464, 464); + /* average measurements of the last N (depends on mode) bursts */ + trx_sched_meas_avg(chan_state, &meas_avg, meas_avg_mode); + /* Check if the frame is bad */ if (rc < 0) { LOGL1S(DL1P, LOGL_NOTICE, l1t, bi->tn, chan, bi->fn, @@ -219,10 +227,9 @@ int rx_tchf_fn(struct l1sched_trx *l1t, enum trx_chan_type chan, fn_begin = gsm0502_fn_remap(bi->fn, FN_REMAP_FACCH_F); _sched_compose_ph_data_ind(l1t, bi->tn, fn_begin, chan, tch_data + amr, GSM_MACBLOCK_LEN, - /* FIXME: AVG RSSI and ToA256 */ - bi->rssi, bi->toa256, - 0 /* FIXME: AVG C/I */, - ber10k, PRES_INFO_UNKNOWN); + meas_avg.rssi, meas_avg.toa256, + meas_avg.ci_cb, ber10k, + PRES_INFO_UNKNOWN); bfi: if (rsl_cmode == RSL_CMOD_SPD_SPEECH) { /* indicate bad frame */ @@ -277,8 +284,10 @@ bfi: /* TCH or BFI */ compose_l1sap: fn_begin = gsm0502_fn_remap(bi->fn, FN_REMAP_TCH_F); - return _sched_compose_tch_ind(l1t, bi->tn, fn_begin, chan, - tch_data, rc, bi->toa256, ber10k, bi->rssi, is_sub); + return _sched_compose_tch_ind(l1t, bi->tn, fn_begin, chan, tch_data, rc, + /* FIXME: what should we use for BFI here? */ + bfi_flag ? bi->toa256 : meas_avg.toa256, ber10k, + bfi_flag ? bi->rssi : meas_avg.rssi, is_sub); } /* common section for generation of TCH bursts (TCH/H and TCH/F). @@ -293,9 +302,6 @@ void tx_tch_common(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, uint8_t rsl_cmode = chan_state->rsl_cmode; uint8_t tch_mode = chan_state->tch_mode; struct osmo_phsap_prim *l1sap; - int32_t *toa256_sum = &chan_state->toa256_sum; - uint8_t *toa_num = &chan_state->toa_num; - int16_t toa256; /* handle loss detection of received TCH frames */ if (rsl_cmode == RSL_CMOD_SPD_SPEECH @@ -343,14 +349,9 @@ inval_mode1: } if (len) { - if (*toa_num == 0) - toa256 = 0; - else - toa256 = *toa256_sum / *toa_num; - - /* Note: RSSI is set to 0 to indicate to the higher + /* Note: RSSI/ToA256 is set to 0 to indicate to the higher * layers that this is a faked tch_ind */ - _sched_compose_tch_ind(l1t, tn, fn, chan, tch_data, len, toa256, 10000, 0, 0); + _sched_compose_tch_ind(l1t, tn, fn, chan, tch_data, len, 0, 10000, 0, 0); } } diff --git a/src/osmo-bts-trx/sched_lchan_tchh.c b/src/osmo-bts-trx/sched_lchan_tchh.c index 0281342c3..2a561e1ed 100644 --- a/src/osmo-bts-trx/sched_lchan_tchh.c +++ b/src/osmo-bts-trx/sched_lchan_tchh.c @@ -65,6 +65,8 @@ int rx_tchh_fn(struct l1sched_trx *l1t, enum trx_chan_type chan, * Even FN ending at: 10,11,19,20,2,3 */ int fn_is_odd = (((bi->fn + 26 - 10) % 26) >> 2) & 1; + enum sched_meas_avg_mode meas_avg_mode = SCHED_MEAS_AVG_M_QUAD; + struct l1sched_meas_set meas_avg; unsigned int fn_begin; uint16_t ber10k; uint8_t is_sub = 0; @@ -94,6 +96,9 @@ int rx_tchh_fn(struct l1sched_trx *l1t, enum trx_chan_type chan, /* update mask */ *mask |= (1 << bid); + /* store measurements */ + trx_sched_meas_push(chan_state, bi); + /* copy burst to end of buffer of 6 bursts */ burst = *bursts_p + bid * 116 + 464; if (bi->burst_len > 0) { @@ -208,6 +213,10 @@ int rx_tchh_fn(struct l1sched_trx *l1t, enum trx_chan_type chan, memcpy(*bursts_p + 232, *bursts_p + 464, 232); ber10k = compute_ber10k(n_bits_total, n_errors); + /* average measurements of the last N (depends on mode) bursts */ + if (rc == GSM_MACBLOCK_LEN) + meas_avg_mode = SCHED_MEAS_AVG_M_SIX; + trx_sched_meas_avg(chan_state, &meas_avg, meas_avg_mode); /* Check if the frame is bad */ if (rc < 0) { @@ -238,10 +247,9 @@ int rx_tchh_fn(struct l1sched_trx *l1t, enum trx_chan_type chan, fn_begin = gsm0502_fn_remap(bi->fn, FN_REMAP_FACCH_H1); _sched_compose_ph_data_ind(l1t, bi->tn, fn_begin, chan, tch_data + amr, GSM_MACBLOCK_LEN, - /* FIXME: AVG both RSSI and ToA */ - bi->rssi, bi->toa256, - 0 /* FIXME: AVG C/I */, - ber10k, PRES_INFO_UNKNOWN); + meas_avg.rssi, meas_avg.toa256, + meas_avg.ci_cb, ber10k, + PRES_INFO_UNKNOWN); bfi: /* FIXME: a FACCH/H frame replaces two speech frames, * so we actually need to send two bad frame indications! */ @@ -301,8 +309,10 @@ compose_l1sap: fn_begin = gsm0502_fn_remap(bi->fn, FN_REMAP_TCH_H0); else fn_begin = gsm0502_fn_remap(bi->fn, FN_REMAP_TCH_H1); - return _sched_compose_tch_ind(l1t, bi->tn, fn_begin, chan, - tch_data, rc, bi->toa256, ber10k, bi->rssi, is_sub); + return _sched_compose_tch_ind(l1t, bi->tn, fn_begin, chan, tch_data, rc, + /* FIXME: what should we use for BFI here? */ + bfi_flag ? bi->toa256 : meas_avg.toa256, ber10k, + bfi_flag ? bi->rssi : meas_avg.rssi, is_sub); } /* common section for generation of TCH bursts (TCH/H and TCH/F). diff --git a/src/osmo-bts-trx/sched_lchan_xcch.c b/src/osmo-bts-trx/sched_lchan_xcch.c index e2670d808..b96bc0bd6 100644 --- a/src/osmo-bts-trx/sched_lchan_xcch.c +++ b/src/osmo-bts-trx/sched_lchan_xcch.c @@ -43,16 +43,10 @@ int rx_data_fn(struct l1sched_trx *l1t, enum trx_chan_type chan, sbit_t *burst, **bursts_p = &chan_state->ul_bursts; uint32_t *first_fn = &chan_state->ul_first_fn; uint8_t *mask = &chan_state->ul_mask; - float *rssi_sum = &chan_state->rssi_sum; - uint8_t *rssi_num = &chan_state->rssi_num; - int32_t *toa256_sum = &chan_state->toa256_sum; - uint8_t *toa_num = &chan_state->toa_num; - int32_t *ci_cb_sum = &chan_state->ci_cb_sum; - uint8_t *ci_cb_num = &chan_state->ci_cb_num; uint8_t l2[GSM_MACBLOCK_LEN], l2_len; + struct l1sched_meas_set meas_avg; int n_errors = 0; int n_bits_total = 0; - int16_t lqual_cb; uint16_t ber10k; int rc; @@ -76,26 +70,13 @@ int rx_data_fn(struct l1sched_trx *l1t, enum trx_chan_type chan, memset(*bursts_p, 0, 464); *mask = 0x0; *first_fn = bi->fn; - *rssi_sum = 0; - *rssi_num = 0; - *toa256_sum = 0; - *toa_num = 0; - *ci_cb_sum = 0; - *ci_cb_num = 0; } - /* update mask + RSSI */ + /* update mask */ *mask |= (1 << bid); - *rssi_sum += bi->rssi; - (*rssi_num)++; - *toa256_sum += bi->toa256; - (*toa_num)++; - /* C/I: Carrier-to-Interference ratio (in centiBels) */ - if (bi->flags & TRX_BI_F_CI_CB) { - *ci_cb_sum += bi->ci_cb; - (*ci_cb_num)++; - } + /* store measurements */ + trx_sched_meas_push(chan_state, bi); /* Copy burst to buffer of 4 bursts. If the burst indication contains * no data, ensure that the buffer does not stay uninitialized */ @@ -110,6 +91,9 @@ int rx_data_fn(struct l1sched_trx *l1t, enum trx_chan_type chan, if (bid != 3) return 0; + /* average measurements of the last 4 bursts */ + trx_sched_meas_avg(chan_state, &meas_avg, SCHED_MEAS_AVG_M_QUAD); + /* check for complete set of bursts */ if ((*mask & 0xf) != 0xf) { LOGL1S(DL1P, LOGL_NOTICE, l1t, bi->tn, chan, bi->fn, @@ -134,13 +118,11 @@ int rx_data_fn(struct l1sched_trx *l1t, enum trx_chan_type chan, } else l2_len = GSM_MACBLOCK_LEN; - lqual_cb = *ci_cb_num ? (*ci_cb_sum / *ci_cb_num) : 0; ber10k = compute_ber10k(n_bits_total, n_errors); return _sched_compose_ph_data_ind(l1t, bi->tn, *first_fn, chan, l2, l2_len, - *rssi_sum / *rssi_num, - *toa256_sum / *toa_num, - lqual_cb, ber10k, + meas_avg.rssi, meas_avg.toa256, + meas_avg.ci_cb, ber10k, PRES_INFO_UNKNOWN); } diff --git a/src/osmo-bts-trx/scheduler_trx.c b/src/osmo-bts-trx/scheduler_trx.c index e79e674cd..3921280b8 100644 --- a/src/osmo-bts-trx/scheduler_trx.c +++ b/src/osmo-bts-trx/scheduler_trx.c @@ -473,3 +473,73 @@ void _sched_act_rach_det(struct l1sched_trx *l1t, uint8_t tn, uint8_t ss, int ac else trx_if_cmd_nohandover(l1h, tn, ss); } + +/* Add a set of UL burst measurements to the history */ +void trx_sched_meas_push(struct l1sched_chan_state *chan_state, + const struct trx_ul_burst_ind *bi) +{ + unsigned int hist_size = ARRAY_SIZE(chan_state->meas.buf); + unsigned int current = chan_state->meas.current; + + chan_state->meas.buf[current] = (struct l1sched_meas_set) { + .ci_cb = (bi->flags & TRX_BI_F_CI_CB) ? bi->ci_cb : 0, + .toa256 = bi->toa256, + .rssi = bi->rssi, + }; + + chan_state->meas.current = (current + 1) % hist_size; +} + +/* Calculate the AVG of n measurements from the history */ +void trx_sched_meas_avg(const struct l1sched_chan_state *chan_state, + struct l1sched_meas_set *avg, + enum sched_meas_avg_mode mode) +{ + unsigned int hist_size = ARRAY_SIZE(chan_state->meas.buf); + unsigned int current = chan_state->meas.current; + const struct l1sched_meas_set *set; + unsigned int shift, pos, i, n; + + float rssi_sum = 0; + int toa256_sum = 0; + int ci_cb_sum = 0; + + switch (mode) { + /* last 4 bursts (default for xCCH, TCH/H, PTCCH and PDTCH) */ + case SCHED_MEAS_AVG_M_QUAD: + n = 4; shift = n; + break; + /* last 8 bursts (default for TCH/F and FACCH/F) */ + case SCHED_MEAS_AVG_M_OCTO: + n = 8; shift = n; + break; + /* last 6 bursts (default for FACCH/H) */ + case SCHED_MEAS_AVG_M_SIX: + n = 6; shift = n; + break; + default: + /* Shall not happen */ + OSMO_ASSERT(false); + } + + /* Calculate the sum of n entries starting from pos */ + for (i = 0; i < n; i++) { + pos = (current + hist_size - shift + i) % hist_size; + set = &chan_state->meas.buf[pos]; + + rssi_sum += set->rssi; + toa256_sum += set->toa256; + ci_cb_sum += set->ci_cb; + } + + /* Calculate the average for each value */ + *avg = (struct l1sched_meas_set) { + .rssi = (rssi_sum / n), + .toa256 = (toa256_sum / n), + .ci_cb = (ci_cb_sum / n), + }; + + LOGP(DL1C, LOGL_DEBUG, "Measurement AVG (num=%u, shift=%u): " + "RSSI %f, ToA256 %d, C/I %d cB\n", n, shift, + avg->rssi, avg->toa256, avg->ci_cb); +}