trxcon/scheduler: refactor TDMA frame number calculation
Using TDMA frame number of a burst with bid=0 is fine for xCCH, but not for TCH and FACCH, because they use the block-diagonel interleaving. A single block on TCH may be interleaved over 8, 4 or even 6 consecutive bursts depending on its type. Since we now have the measurement history, we can attach TDMA frame number to each measurement set, and then look up N-th one when averaging the measurements in sched_trx_meas_avg(). Change-Id: I9221957297a6154edc1767a0e3753f5ee383173f
This commit is contained in:
parent
b9ab7150bf
commit
8c760f8f05
|
@ -137,9 +137,11 @@ int sched_send_dt_ind(struct trx_instance *trx, struct trx_ts *ts,
|
||||||
dl_hdr.chan_nr = lchan_desc->chan_nr | ts->index;
|
dl_hdr.chan_nr = lchan_desc->chan_nr | ts->index;
|
||||||
dl_hdr.link_id = lchan_desc->link_id;
|
dl_hdr.link_id = lchan_desc->link_id;
|
||||||
dl_hdr.band_arfcn = htons(trx->band_arfcn);
|
dl_hdr.band_arfcn = htons(trx->band_arfcn);
|
||||||
dl_hdr.frame_nr = htonl(lchan->rx_first_fn);
|
|
||||||
dl_hdr.num_biterr = bit_error_count;
|
dl_hdr.num_biterr = bit_error_count;
|
||||||
|
|
||||||
|
/* sched_trx_meas_avg() gives us TDMA frame number of the first burst */
|
||||||
|
dl_hdr.frame_nr = htonl(meas->fn);
|
||||||
|
|
||||||
/* RX level: 0 .. 63 in typical GSM notation (dBm + 110) */
|
/* RX level: 0 .. 63 in typical GSM notation (dBm + 110) */
|
||||||
dl_hdr.rx_level = dbm2rxlev(meas->rssi);
|
dl_hdr.rx_level = dbm2rxlev(meas->rssi);
|
||||||
|
|
||||||
|
@ -154,7 +156,7 @@ int sched_send_dt_ind(struct trx_instance *trx, struct trx_ts *ts,
|
||||||
|
|
||||||
/* Optional GSMTAP logging */
|
/* Optional GSMTAP logging */
|
||||||
if (l2_len > 0 && (!traffic || lchan_desc->chan_nr == RSL_CHAN_OSMO_PDCH)) {
|
if (l2_len > 0 && (!traffic || lchan_desc->chan_nr == RSL_CHAN_OSMO_PDCH)) {
|
||||||
sched_gsmtap_send(lchan->type, lchan->rx_first_fn, ts->index,
|
sched_gsmtap_send(lchan->type, meas->fn, ts->index,
|
||||||
trx->band_arfcn, meas->rssi, 0, l2, l2_len);
|
trx->band_arfcn, meas->rssi, 0, l2, l2_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,12 +48,10 @@ int rx_pdtch_fn(struct trx_instance *trx, struct trx_ts *ts,
|
||||||
uint8_t l2[GPRS_L2_MAX_LEN], *mask;
|
uint8_t l2[GPRS_L2_MAX_LEN], *mask;
|
||||||
int n_errors, n_bits_total, rc;
|
int n_errors, n_bits_total, rc;
|
||||||
sbit_t *buffer, *offset;
|
sbit_t *buffer, *offset;
|
||||||
uint32_t *first_fn;
|
|
||||||
size_t l2_len;
|
size_t l2_len;
|
||||||
|
|
||||||
/* Set up pointers */
|
/* Set up pointers */
|
||||||
lchan_desc = &trx_lchan_desc[lchan->type];
|
lchan_desc = &trx_lchan_desc[lchan->type];
|
||||||
first_fn = &lchan->rx_first_fn;
|
|
||||||
mask = &lchan->rx_burst_mask;
|
mask = &lchan->rx_burst_mask;
|
||||||
buffer = lchan->rx_bursts;
|
buffer = lchan->rx_bursts;
|
||||||
|
|
||||||
|
@ -61,10 +59,8 @@ int rx_pdtch_fn(struct trx_instance *trx, struct trx_ts *ts,
|
||||||
"fn=%u ts=%u bid=%u\n", lchan_desc->name, fn, ts->index, bid);
|
"fn=%u ts=%u bid=%u\n", lchan_desc->name, fn, ts->index, bid);
|
||||||
|
|
||||||
/* Reset internal state */
|
/* Reset internal state */
|
||||||
if (bid == 0) {
|
if (bid == 0)
|
||||||
*first_fn = fn;
|
|
||||||
*mask = 0x0;
|
*mask = 0x0;
|
||||||
}
|
|
||||||
|
|
||||||
/* Update mask */
|
/* Update mask */
|
||||||
*mask |= (1 << bid);
|
*mask |= (1 << bid);
|
||||||
|
@ -88,8 +84,8 @@ int rx_pdtch_fn(struct trx_instance *trx, struct trx_ts *ts,
|
||||||
if ((*mask & 0xf) != 0xf) {
|
if ((*mask & 0xf) != 0xf) {
|
||||||
LOGP(DSCHD, LOGL_ERROR, "Received incomplete (%s) data frame at "
|
LOGP(DSCHD, LOGL_ERROR, "Received incomplete (%s) data frame at "
|
||||||
"fn=%u (%u/%u) for %s\n",
|
"fn=%u (%u/%u) for %s\n",
|
||||||
burst_mask2str(mask, 4), *first_fn,
|
burst_mask2str(mask, 4), lchan->meas_avg.fn,
|
||||||
(*first_fn) % ts->mf_layout->period,
|
lchan->meas_avg.fn % ts->mf_layout->period,
|
||||||
ts->mf_layout->period,
|
ts->mf_layout->period,
|
||||||
lchan_desc->name);
|
lchan_desc->name);
|
||||||
|
|
||||||
|
@ -101,8 +97,8 @@ int rx_pdtch_fn(struct trx_instance *trx, struct trx_ts *ts,
|
||||||
NULL, &n_errors, &n_bits_total);
|
NULL, &n_errors, &n_bits_total);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
LOGP(DSCHD, LOGL_ERROR, "Received bad packet data frame "
|
LOGP(DSCHD, LOGL_ERROR, "Received bad packet data frame "
|
||||||
"at fn=%u (%u/%u) for %s\n", *first_fn,
|
"at fn=%u (%u/%u) for %s\n", lchan->meas_avg.fn,
|
||||||
(*first_fn) % ts->mf_layout->period,
|
lchan->meas_avg.fn % ts->mf_layout->period,
|
||||||
ts->mf_layout->period,
|
ts->mf_layout->period,
|
||||||
lchan_desc->name);
|
lchan_desc->name);
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,12 +50,10 @@ int rx_tchf_fn(struct trx_instance *trx, struct trx_ts *ts,
|
||||||
int n_errors = -1, n_bits_total, rc;
|
int n_errors = -1, n_bits_total, rc;
|
||||||
sbit_t *buffer, *offset;
|
sbit_t *buffer, *offset;
|
||||||
uint8_t l2[128], *mask;
|
uint8_t l2[128], *mask;
|
||||||
uint32_t *first_fn;
|
|
||||||
size_t l2_len;
|
size_t l2_len;
|
||||||
|
|
||||||
/* Set up pointers */
|
/* Set up pointers */
|
||||||
lchan_desc = &trx_lchan_desc[lchan->type];
|
lchan_desc = &trx_lchan_desc[lchan->type];
|
||||||
first_fn = &lchan->rx_first_fn;
|
|
||||||
mask = &lchan->rx_burst_mask;
|
mask = &lchan->rx_burst_mask;
|
||||||
buffer = lchan->rx_bursts;
|
buffer = lchan->rx_bursts;
|
||||||
|
|
||||||
|
@ -63,10 +61,8 @@ int rx_tchf_fn(struct trx_instance *trx, struct trx_ts *ts,
|
||||||
lchan_desc->name, fn, ts->index, bid);
|
lchan_desc->name, fn, ts->index, bid);
|
||||||
|
|
||||||
/* Reset internal state */
|
/* Reset internal state */
|
||||||
if (bid == 0) {
|
if (bid == 0)
|
||||||
*first_fn = fn;
|
|
||||||
*mask = 0x00;
|
*mask = 0x00;
|
||||||
}
|
|
||||||
|
|
||||||
/* Update mask */
|
/* Update mask */
|
||||||
*mask |= (1 << bid);
|
*mask |= (1 << bid);
|
||||||
|
@ -90,8 +86,8 @@ int rx_tchf_fn(struct trx_instance *trx, struct trx_ts *ts,
|
||||||
if ((*mask & 0xf) != 0xf) {
|
if ((*mask & 0xf) != 0xf) {
|
||||||
LOGP(DSCHD, LOGL_ERROR, "Received incomplete (%s) traffic frame at "
|
LOGP(DSCHD, LOGL_ERROR, "Received incomplete (%s) traffic frame at "
|
||||||
"fn=%u (%u/%u) for %s\n",
|
"fn=%u (%u/%u) for %s\n",
|
||||||
burst_mask2str(mask, 8), *first_fn,
|
burst_mask2str(mask, 8), lchan->meas_avg.fn,
|
||||||
(*first_fn) % ts->mf_layout->period,
|
lchan->meas_avg.fn % ts->mf_layout->period,
|
||||||
ts->mf_layout->period,
|
ts->mf_layout->period,
|
||||||
lchan_desc->name);
|
lchan_desc->name);
|
||||||
|
|
||||||
|
@ -152,6 +148,7 @@ bfi:
|
||||||
/* Didn't try to decode, fake measurements */
|
/* Didn't try to decode, fake measurements */
|
||||||
if (n_errors < 0) {
|
if (n_errors < 0) {
|
||||||
lchan->meas_avg = (struct trx_meas_set) {
|
lchan->meas_avg = (struct trx_meas_set) {
|
||||||
|
.fn = lchan->meas_avg.fn,
|
||||||
.toa256 = 0,
|
.toa256 = 0,
|
||||||
.rssi = -110,
|
.rssi = -110,
|
||||||
};
|
};
|
||||||
|
|
|
@ -291,23 +291,19 @@ int rx_tchh_fn(struct trx_instance *trx, struct trx_ts *ts,
|
||||||
|
|
||||||
/* Check decoding result */
|
/* Check decoding result */
|
||||||
if (rc < 4) {
|
if (rc < 4) {
|
||||||
LOGP(DSCHD, LOGL_ERROR, "Received bad TCH frame (%s) ending at "
|
|
||||||
"fn=%u on %s (rc=%d)\n", burst_mask2str(mask, 6),
|
|
||||||
fn, lchan_desc->name, rc);
|
|
||||||
|
|
||||||
/* Calculate AVG of the measurements (assuming 4 bursts) */
|
/* Calculate AVG of the measurements (assuming 4 bursts) */
|
||||||
sched_trx_meas_avg(lchan, 4);
|
sched_trx_meas_avg(lchan, 4);
|
||||||
|
|
||||||
|
LOGP(DSCHD, LOGL_ERROR, "Received bad TCH frame (%s) "
|
||||||
|
"at fn=%u on %s (rc=%d)\n", burst_mask2str(mask, 6),
|
||||||
|
lchan->meas_avg.fn, lchan_desc->name, rc);
|
||||||
|
|
||||||
/* Send BFI */
|
/* Send BFI */
|
||||||
goto bfi;
|
goto bfi;
|
||||||
} else if (rc == GSM_MACBLOCK_LEN) {
|
} else if (rc == GSM_MACBLOCK_LEN) {
|
||||||
/* Skip decoding of the next 2 stolen bursts */
|
/* Skip decoding of the next 2 stolen bursts */
|
||||||
lchan->dl_ongoing_facch = true;
|
lchan->dl_ongoing_facch = true;
|
||||||
|
|
||||||
/* Calculate TDMA frame number of the first burst */
|
|
||||||
lchan->rx_first_fn = sched_tchh_block_dl_first_fn(lchan->type,
|
|
||||||
fn, true); /* FACCH/H */
|
|
||||||
|
|
||||||
/* Calculate AVG of the measurements (FACCH/H takes 6 bursts) */
|
/* Calculate AVG of the measurements (FACCH/H takes 6 bursts) */
|
||||||
sched_trx_meas_avg(lchan, 6);
|
sched_trx_meas_avg(lchan, 6);
|
||||||
|
|
||||||
|
@ -326,10 +322,6 @@ int rx_tchh_fn(struct trx_instance *trx, struct trx_ts *ts,
|
||||||
sched_trx_meas_avg(lchan, 4);
|
sched_trx_meas_avg(lchan, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Calculate TDMA frame number of the first burst */
|
|
||||||
lchan->rx_first_fn = sched_tchh_block_dl_first_fn(lchan->type,
|
|
||||||
fn, false); /* TCH/H */
|
|
||||||
|
|
||||||
/* Send a traffic frame to the higher layers */
|
/* Send a traffic frame to the higher layers */
|
||||||
return sched_send_dt_ind(trx, ts, lchan, l2, l2_len,
|
return sched_send_dt_ind(trx, ts, lchan, l2, l2_len,
|
||||||
n_errors, false, true);
|
n_errors, false, true);
|
||||||
|
@ -346,6 +338,7 @@ bfi:
|
||||||
/* Didn't try to decode, fake measurements */
|
/* Didn't try to decode, fake measurements */
|
||||||
if (n_errors < 0) {
|
if (n_errors < 0) {
|
||||||
lchan->meas_avg = (struct trx_meas_set) {
|
lchan->meas_avg = (struct trx_meas_set) {
|
||||||
|
.fn = sched_tchh_block_dl_first_fn(lchan->type, fn, false),
|
||||||
.toa256 = 0,
|
.toa256 = 0,
|
||||||
.rssi = -110,
|
.rssi = -110,
|
||||||
};
|
};
|
||||||
|
@ -354,10 +347,6 @@ bfi:
|
||||||
n_errors = 0;
|
n_errors = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Calculate TDMA frame number of the first burst */
|
|
||||||
lchan->rx_first_fn = sched_tchh_block_dl_first_fn(lchan->type,
|
|
||||||
fn, false); /* TCH/H */
|
|
||||||
|
|
||||||
/* BFI is not applicable in signalling mode */
|
/* BFI is not applicable in signalling mode */
|
||||||
if (lchan->tch_mode == GSM48_CMODE_SIGN)
|
if (lchan->tch_mode == GSM48_CMODE_SIGN)
|
||||||
return sched_send_dt_ind(trx, ts, lchan, NULL, 0,
|
return sched_send_dt_ind(trx, ts, lchan, NULL, 0,
|
||||||
|
|
|
@ -48,11 +48,9 @@ int rx_data_fn(struct trx_instance *trx, struct trx_ts *ts,
|
||||||
uint8_t l2[GSM_MACBLOCK_LEN], *mask;
|
uint8_t l2[GSM_MACBLOCK_LEN], *mask;
|
||||||
int n_errors, n_bits_total, rc;
|
int n_errors, n_bits_total, rc;
|
||||||
sbit_t *buffer, *offset;
|
sbit_t *buffer, *offset;
|
||||||
uint32_t *first_fn;
|
|
||||||
|
|
||||||
/* Set up pointers */
|
/* Set up pointers */
|
||||||
lchan_desc = &trx_lchan_desc[lchan->type];
|
lchan_desc = &trx_lchan_desc[lchan->type];
|
||||||
first_fn = &lchan->rx_first_fn;
|
|
||||||
mask = &lchan->rx_burst_mask;
|
mask = &lchan->rx_burst_mask;
|
||||||
buffer = lchan->rx_bursts;
|
buffer = lchan->rx_bursts;
|
||||||
|
|
||||||
|
@ -60,10 +58,8 @@ int rx_data_fn(struct trx_instance *trx, struct trx_ts *ts,
|
||||||
lchan_desc->name, fn, ts->index, bid);
|
lchan_desc->name, fn, ts->index, bid);
|
||||||
|
|
||||||
/* Reset internal state */
|
/* Reset internal state */
|
||||||
if (bid == 0) {
|
if (bid == 0)
|
||||||
*first_fn = fn;
|
|
||||||
*mask = 0x0;
|
*mask = 0x0;
|
||||||
}
|
|
||||||
|
|
||||||
/* Update mask */
|
/* Update mask */
|
||||||
*mask |= (1 << bid);
|
*mask |= (1 << bid);
|
||||||
|
@ -87,8 +83,8 @@ int rx_data_fn(struct trx_instance *trx, struct trx_ts *ts,
|
||||||
if ((*mask & 0xf) != 0xf) {
|
if ((*mask & 0xf) != 0xf) {
|
||||||
LOGP(DSCHD, LOGL_ERROR, "Received incomplete (%s) data frame at "
|
LOGP(DSCHD, LOGL_ERROR, "Received incomplete (%s) data frame at "
|
||||||
"fn=%u (%u/%u) for %s\n",
|
"fn=%u (%u/%u) for %s\n",
|
||||||
burst_mask2str(mask, 4), *first_fn,
|
burst_mask2str(mask, 4), lchan->meas_avg.fn,
|
||||||
(*first_fn) % ts->mf_layout->period,
|
lchan->meas_avg.fn % ts->mf_layout->period,
|
||||||
ts->mf_layout->period,
|
ts->mf_layout->period,
|
||||||
lchan_desc->name);
|
lchan_desc->name);
|
||||||
/* NOTE: xCCH has an insane amount of redundancy for error
|
/* NOTE: xCCH has an insane amount of redundancy for error
|
||||||
|
@ -101,8 +97,8 @@ int rx_data_fn(struct trx_instance *trx, struct trx_ts *ts,
|
||||||
rc = gsm0503_xcch_decode(l2, buffer, &n_errors, &n_bits_total);
|
rc = gsm0503_xcch_decode(l2, buffer, &n_errors, &n_bits_total);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
LOGP(DSCHD, LOGL_ERROR, "Received bad data frame at fn=%u "
|
LOGP(DSCHD, LOGL_ERROR, "Received bad data frame at fn=%u "
|
||||||
"(%u/%u) for %s\n", *first_fn,
|
"(%u/%u) for %s\n", lchan->meas_avg.fn,
|
||||||
(*first_fn) % ts->mf_layout->period,
|
lchan->meas_avg.fn % ts->mf_layout->period,
|
||||||
ts->mf_layout->period,
|
ts->mf_layout->period,
|
||||||
lchan_desc->name);
|
lchan_desc->name);
|
||||||
|
|
||||||
|
|
|
@ -464,7 +464,6 @@ static void sched_trx_reset_lchan(struct trx_lchan_state *lchan)
|
||||||
/* Reset internal state variables */
|
/* Reset internal state variables */
|
||||||
lchan->rx_burst_mask = 0x00;
|
lchan->rx_burst_mask = 0x00;
|
||||||
lchan->tx_burst_mask = 0x00;
|
lchan->tx_burst_mask = 0x00;
|
||||||
lchan->rx_first_fn = 0;
|
|
||||||
|
|
||||||
/* Free burst memory */
|
/* Free burst memory */
|
||||||
talloc_free(lchan->rx_bursts);
|
talloc_free(lchan->rx_bursts);
|
||||||
|
@ -747,6 +746,10 @@ void sched_trx_meas_avg(struct trx_lchan_state *lchan, unsigned int n)
|
||||||
toa256_sum += meas->toa256;
|
toa256_sum += meas->toa256;
|
||||||
rssi_sum += meas->rssi;
|
rssi_sum += meas->rssi;
|
||||||
|
|
||||||
|
/* Do not go below the first burst */
|
||||||
|
if (i + 1 == n)
|
||||||
|
break;
|
||||||
|
|
||||||
if (meas == MEAS_HIST_FIRST(hist))
|
if (meas == MEAS_HIST_FIRST(hist))
|
||||||
meas = MEAS_HIST_LAST(hist);
|
meas = MEAS_HIST_LAST(hist);
|
||||||
else
|
else
|
||||||
|
@ -756,4 +759,7 @@ void sched_trx_meas_avg(struct trx_lchan_state *lchan, unsigned int n)
|
||||||
/* Calculate the AVG */
|
/* Calculate the AVG */
|
||||||
lchan->meas_avg.toa256 = toa256_sum / n;
|
lchan->meas_avg.toa256 = toa256_sum / n;
|
||||||
lchan->meas_avg.rssi = rssi_sum / n;
|
lchan->meas_avg.rssi = rssi_sum / n;
|
||||||
|
|
||||||
|
/* As a bonus, store TDMA frame number of the first burst */
|
||||||
|
lchan->meas_avg.fn = meas->fn;
|
||||||
}
|
}
|
||||||
|
|
|
@ -159,6 +159,8 @@ struct trx_multiframe {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct trx_meas_set {
|
struct trx_meas_set {
|
||||||
|
/*! \brief TDMA frame number of the first burst this set belongs to */
|
||||||
|
uint32_t fn;
|
||||||
/*! \brief ToA256 (Timing of Arrival, 1/256 of a symbol) */
|
/*! \brief ToA256 (Timing of Arrival, 1/256 of a symbol) */
|
||||||
int16_t toa256;
|
int16_t toa256;
|
||||||
/*! \brief RSSI (Received Signal Strength Indication) */
|
/*! \brief RSSI (Received Signal Strength Indication) */
|
||||||
|
@ -182,8 +184,6 @@ struct trx_lchan_state {
|
||||||
|
|
||||||
/*! \brief Burst type: GMSK or 8PSK */
|
/*! \brief Burst type: GMSK or 8PSK */
|
||||||
enum trx_burst_type burst_type;
|
enum trx_burst_type burst_type;
|
||||||
/*! \brief Frame number of first burst */
|
|
||||||
uint32_t rx_first_fn;
|
|
||||||
/*! \brief Mask of received bursts */
|
/*! \brief Mask of received bursts */
|
||||||
uint8_t rx_burst_mask;
|
uint8_t rx_burst_mask;
|
||||||
/*! \brief Mask of transmitted bursts */
|
/*! \brief Mask of transmitted bursts */
|
||||||
|
|
|
@ -600,6 +600,7 @@ static int trx_data_rx_cb(struct osmo_fd *ofd, unsigned int what)
|
||||||
meas = (struct trx_meas_set) {
|
meas = (struct trx_meas_set) {
|
||||||
.toa256 = toa256,
|
.toa256 = toa256,
|
||||||
.rssi = rssi,
|
.rssi = rssi,
|
||||||
|
.fn = fn,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Poke scheduler */
|
/* Poke scheduler */
|
||||||
|
|
Loading…
Reference in New Issue