osmo-bts-trx/scheduler: refactor UL burst measurement processing

Currently the UL measurements (RSSI, ToA256, C/I) of the burst that
concludes a block are passed up to the higher layers. This means
that the measurement values of the other bursts are skipped.

Let's keep record of all UL measurements and average the values
before we pass them up to the higher layers. Use a simple ring
buffer to store the measurement history (up to 8 unique entries
for now). Remove *_num/*_sum variables from l1sched_chan_state.

Change-Id: I2b02b51fea5664f161382a4ddc63dbf14ffc9ac5
Related: OS#3032, OS#2978
This commit is contained in:
Vadim Yanitskiy 2020-06-23 05:44:48 +07:00 committed by laforge
parent 27c5fd9369
commit 4ded469b0f
6 changed files with 149 additions and 86 deletions

View File

@ -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 */

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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).

View File

@ -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);
}

View File

@ -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);
}