fixeria has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-bts/+/32727 )
Change subject: [WIP] osmo-bts-trx: implement TCH/F9.6 support for CSD ......................................................................
[WIP] osmo-bts-trx: implement TCH/F9.6 support for CSD
According to 3GPP TS 45.003, Figure 1a and section 3.3.4, for CSD a new block of coded data starts with every fourth burst and is distributed over 22 bursts. This requires us to:
* enlarge the maximum burst buffer size to 22 * (2 * 58) bytes; * enlarge per-l1cs Uplink burst mask to hold up to 32 bits; * enlarge per-l1cs Uplink meas ring buffer to 22 entries; * add SCHED_MEAS_AVG_M_S22N22 - new Uplink meas AVG mode.
Change-Id: I08ffbf8e79ce76a586d61f5463890c6e72a6d9b9 Related: OS#1572 --- M include/osmo-bts/scheduler.h M src/common/bts.c M src/common/scheduler.c M src/osmo-bts-trx/sched_lchan_pdtch.c M src/osmo-bts-trx/sched_lchan_tchf.c M src/osmo-bts-trx/sched_lchan_tchh.c M src/osmo-bts-trx/sched_lchan_xcch.c M src/osmo-bts-trx/scheduler_trx.c 8 files changed, 126 insertions(+), 38 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-bts refs/changes/27/32727/1
diff --git a/include/osmo-bts/scheduler.h b/include/osmo-bts/scheduler.h index 01e8e2b..b0c4b2f 100644 --- a/include/osmo-bts/scheduler.h +++ b/include/osmo-bts/scheduler.h @@ -93,7 +93,7 @@ sbit_t *ul_bursts; /* burst buffer for RX */ sbit_t *ul_bursts_prev;/* previous burst buffer for RX (repeated SACCH) */ uint32_t ul_first_fn; /* fn of first burst */ - uint8_t ul_mask; /* mask of received bursts */ + uint32_t ul_mask; /* mask of received bursts */
/* loss detection */ uint32_t last_tdma_fn; /* last processed TDMA frame number */ @@ -131,7 +131,7 @@ /* Uplink measurements */ struct { /* Active channel measurements (simple ring buffer) */ - struct l1sched_meas_set buf[8]; /* up to 8 entries */ + struct l1sched_meas_set buf[22]; /* up to 22 entries */ unsigned int current; /* current position */
/* Interference measurements */ @@ -300,6 +300,8 @@
/* Averaging mode for trx_sched_meas_avg() */ enum sched_meas_avg_mode { + /* last 22 bursts (for CSD on TCH/F and TCH/H) */ + SCHED_MEAS_AVG_M_S22N22, /* last 4 bursts (default for xCCH, PTCCH and PDTCH) */ SCHED_MEAS_AVG_M_S4N4, /* last 8 bursts (default for TCH/F and FACCH/F) */ diff --git a/src/common/bts.c b/src/common/bts.c index 242c5dd..0f8dcc7 100644 --- a/src/common/bts.c +++ b/src/common/bts.c @@ -776,23 +776,11 @@ return &bts->gsm_time; }
-int bts_supports_cm(const struct gsm_bts *bts, - const struct rsl_ie_chan_mode *cm) +static int bts_supports_cm_speech(const struct gsm_bts *bts, + const struct rsl_ie_chan_mode *cm) { enum osmo_bts_features feature = _NUM_BTS_FEAT;
- switch (cm->spd_ind) { - case RSL_CMOD_SPD_SIGN: - /* We assume that signalling support is mandatory, - * there is no BTS_FEAT_* definition to check that. */ - return 1; - case RSL_CMOD_SPD_SPEECH: - break; - case RSL_CMOD_SPD_DATA: - default: - return 0; - } - /* Before the requested pchan/cm combination can be checked, we need to * convert it to a feature identifier we can check */ switch (cm->chan_rt) { @@ -849,6 +837,44 @@ return 0; }
+static int bts_supports_cm_data(const struct gsm_bts *bts, + const struct rsl_ie_chan_mode *cm) +{ + /* XXX: only osmo-bts-trx has limited support of CSD */ + switch (bts->variant) { + case BTS_OSMO_TRX: + /* XXX: only TCH/F9.6 (Um rate 12.0 kbit/s) is supported */ + if (cm->chan_rt != RSL_CMOD_CRT_TCH_Bm) + return 0; + switch (cm->chan_rate) { + case RSL_CMOD_CSD_NT_12k0: + case RSL_CMOD_CSD_T_9k6: + return 1; + } + return 0; + default: + return 0; + } +} + +int bts_supports_cm(const struct gsm_bts *bts, + const struct rsl_ie_chan_mode *cm) +{ + switch (cm->spd_ind) { + case RSL_CMOD_SPD_SIGN: + /* We assume that signalling support is mandatory, + * there is no BTS_FEAT_* definition to check that. */ + return 1; + case RSL_CMOD_SPD_SPEECH: + return bts_supports_cm_speech(bts, cm); + case RSL_CMOD_SPD_DATA: + return bts_supports_cm_data(bts, cm); + default: + return 0; + } + +} + /* return the gsm_lchan for the CBCH (if it exists at all) */ struct gsm_lchan *gsm_bts_get_cbch(struct gsm_bts *bts) { diff --git a/src/common/scheduler.c b/src/common/scheduler.c index cacae6c..62fe758 100644 --- a/src/common/scheduler.c +++ b/src/common/scheduler.c @@ -1077,9 +1077,9 @@ chan_state->lchan = lchan;
/* Allocate memory for Rx/Tx burst buffers. Use the maximim size - * of 4 * (3 * 2 * 58) bytes, which is sufficient to store 4 8PSK - * modulated bursts. */ - const size_t buf_size = 4 * GSM_NBITS_NB_8PSK_PAYLOAD; + * of 22 * (2 * 58) bytes, which is sufficient to store 22 GMSK + * modulated bursts for CSD or 4 8PSK modulated bursts for EGPRS. */ + const size_t buf_size = 22 * GSM_NBITS_NB_GMSK_PAYLOAD; if (trx_chan_desc[chan].dl_fn != NULL) chan_state->dl_bursts = talloc_zero_size(l1ts, buf_size); if (trx_chan_desc[chan].ul_fn != NULL) { diff --git a/src/osmo-bts-trx/sched_lchan_pdtch.c b/src/osmo-bts-trx/sched_lchan_pdtch.c index 5ff7229..9ae68d0 100644 --- a/src/osmo-bts-trx/sched_lchan_pdtch.c +++ b/src/osmo-bts-trx/sched_lchan_pdtch.c @@ -44,7 +44,7 @@ struct l1sched_chan_state *chan_state = &l1ts->chan_state[bi->chan]; sbit_t *burst, *bursts_p = chan_state->ul_bursts; uint32_t first_fn; - uint8_t *mask = &chan_state->ul_mask; + uint32_t *mask = &chan_state->ul_mask; struct l1sched_meas_set meas_avg; uint8_t l2[EGPRS_0503_MAX_BYTES]; int n_errors = 0; diff --git a/src/osmo-bts-trx/sched_lchan_tchf.c b/src/osmo-bts-trx/sched_lchan_tchf.c index 6dfdff8..400252d 100644 --- a/src/osmo-bts-trx/sched_lchan_tchf.c +++ b/src/osmo-bts-trx/sched_lchan_tchf.c @@ -76,7 +76,7 @@ struct l1sched_chan_state *chan_state = &l1ts->chan_state[bi->chan]; struct gsm_lchan *lchan = chan_state->lchan; sbit_t *burst, *bursts_p = chan_state->ul_bursts; - uint8_t *mask = &chan_state->ul_mask; + uint32_t *mask = &chan_state->ul_mask; 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 */ @@ -101,8 +101,9 @@
/* shift the buffer by 4 bursts leftwards */ if (bi->bid == 0) { - memcpy(bursts_p, bursts_p + 464, 464); - memset(bursts_p + 464, 0, 464); + const size_t bl = GSM_NBITS_NB_GMSK_PAYLOAD; + memmove(&bursts_p[0], &bursts_p[4 * bl], 18 * bl); + memset(&bursts_p[18 * bl], 0, 4 * bl); *mask = *mask << 4; }
@@ -112,13 +113,13 @@ /* store measurements */ trx_sched_meas_push(chan_state, bi);
- /* copy burst to end of buffer of 8 bursts */ - burst = bursts_p + bi->bid * 116 + 464; + /* copy burst to end of buffer of 22 bursts */ + burst = bursts_p + (bi->bid + 18) * GSM_NBITS_NB_GMSK_PAYLOAD; if (bi->burst_len > 0) { memcpy(burst, bi->burst + 3, 58); memcpy(burst + 58, bi->burst + 87, 58); } else - memset(burst, 0, 116); + memset(burst, 0, GSM_NBITS_NB_GMSK_PAYLOAD);
/* wait until complete set of bursts */ if (bi->bid != 3) @@ -132,8 +133,13 @@ return 0; /* TODO: send BFI */ }
- /* decode - * also shift buffer by 4 bursts for interleaving */ + /* TCH/F: speech and signalling frames are interleaved over 8 bursts, while + * CSD frames are interleaved over 22 bursts. Unless we're in CSD mode, + * decode only the last 8 bursts to avoid introducing additional delays. */ + if (rsl_cmode != RSL_CMOD_SPD_DATA) + bursts_p += (22 - 8) * GSM_NBITS_NB_GMSK_PAYLOAD; + + /* decode the payload */ switch (tch_mode) { case GSM48_CMODE_SIGN: case GSM48_CMODE_SPEECH_V1: /* FR */ @@ -221,6 +227,21 @@ }
break; +#if 0 + /* CSD (TCH/F9.6): 12.0 kbit/s radio interface rate */ + case GSM48_CMODE_DATA_12k0: + { + ubit_t decoded[244]; + sbit_t cB[456]; + + /* TODO: unmap, handle FACCH */ + gsm0503_tch_f96_deinterleave(&cB[0], bursts_p); + osmo_conv_decode(&gsm0503_tch_f96, &cB[0], &decoded[0]); + osmo_ubit2pbit_ext(&tch_data[0], 0, decoded, 0, 240, 1); + meas_avg_mode = SCHED_MEAS_AVG_M_S22N22; + break; + } +#endif default: LOGL1SB(DL1P, LOGL_ERROR, l1ts, bi, "TCH mode %u invalid, please fix!\n", @@ -474,6 +495,7 @@ struct l1sched_chan_state *chan_state = &l1ts->chan_state[br->chan]; uint8_t tch_mode = chan_state->tch_mode; ubit_t *burst, *bursts_p = chan_state->dl_bursts; + const size_t bl = GSM_NBITS_NB_GMSK_PAYLOAD; struct msgb *msg;
/* send burst, if we already got a frame */ @@ -483,8 +505,8 @@ /* BURST BYPASS */
/* shift buffer by 4 bursts for interleaving */ - memcpy(bursts_p, bursts_p + 464, 464); - memset(bursts_p + 464, 0, 464); + memmove(&bursts_p[0], &bursts_p[4 * bl], 18 * bl); + memset(&bursts_p[18 * bl], 0, 4 * bl);
/* dequeue a message to be transmitted */ msg = tch_dl_dequeue(l1ts, br); @@ -503,11 +525,17 @@ goto send_burst; }
- /* populate the buffer with bursts */ - if (msgb_l2len(msg) == GSM_MACBLOCK_LEN) { - gsm0503_tch_fr_encode(bursts_p, msg->l2h, msgb_l2len(msg), 1); + if (msgb_l2len(msg) == GSM_MACBLOCK_LEN) chan_state->dl_facch_bursts = 8; - } else if (tch_mode == GSM48_CMODE_SPEECH_AMR) { + + /* populate the buffer with bursts */ + switch (tch_mode) { + case GSM48_CMODE_SIGN: + case GSM48_CMODE_SPEECH_V1: + case GSM48_CMODE_SPEECH_EFR: + gsm0503_tch_fr_encode(bursts_p, msg->l2h, msgb_l2len(msg), 1); + break; + case GSM48_CMODE_SPEECH_AMR: /* the first FN 4,13,21 defines that CMI is included in frame, * the first FN 0,8,17 defines that CMR is included in frame. */ @@ -517,8 +545,20 @@ chan_state->codec, chan_state->codecs, chan_state->dl_ft, chan_state->dl_cmr); - } else { - gsm0503_tch_fr_encode(bursts_p, msg->l2h, msgb_l2len(msg), 1); + break; +#if 0 + case GSM48_CMODE_DATA_12k0: + { + ubit_t encoded[244]; + sbit_t cB[456]; + + // osmo_conv_encode(&gsm0503_tch_f96, &cB[0], &decoded[0]); + // gsm0503_tch_f96_interleave(&cB[0], bursts_p); + break; + } +#endif + default: + OSMO_ASSERT(0); }
/* free message */ diff --git a/src/osmo-bts-trx/sched_lchan_tchh.c b/src/osmo-bts-trx/sched_lchan_tchh.c index 94e2a9c..e9f0b6f 100644 --- a/src/osmo-bts-trx/sched_lchan_tchh.c +++ b/src/osmo-bts-trx/sched_lchan_tchh.c @@ -98,7 +98,7 @@ struct l1sched_chan_state *chan_state = &l1ts->chan_state[bi->chan]; struct gsm_lchan *lchan = chan_state->lchan; sbit_t *burst, *bursts_p = chan_state->ul_bursts; - uint8_t *mask = &chan_state->ul_mask; + uint32_t *mask = &chan_state->ul_mask; 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 */ diff --git a/src/osmo-bts-trx/sched_lchan_xcch.c b/src/osmo-bts-trx/sched_lchan_xcch.c index 1945d32..34b37c1 100644 --- a/src/osmo-bts-trx/sched_lchan_xcch.c +++ b/src/osmo-bts-trx/sched_lchan_xcch.c @@ -52,7 +52,7 @@ struct l1sched_chan_state *chan_state = &l1ts->chan_state[bi->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; + uint32_t *mask = &chan_state->ul_mask; uint8_t l2[GSM_MACBLOCK_LEN], l2_len; struct l1sched_meas_set meas_avg; int n_errors = 0; diff --git a/src/osmo-bts-trx/scheduler_trx.c b/src/osmo-bts-trx/scheduler_trx.c index e7ed5ea..08f3fda 100644 --- a/src/osmo-bts-trx/scheduler_trx.c +++ b/src/osmo-bts-trx/scheduler_trx.c @@ -638,6 +638,7 @@
/* Measurement averaging mode sets: [MODE] = { SHIFT, NUM } */ static const uint8_t trx_sched_meas_modeset[][2] = { + [SCHED_MEAS_AVG_M_S22N22] = { 22, 22 }, [SCHED_MEAS_AVG_M_S4N4] = { 4, 4 }, [SCHED_MEAS_AVG_M_S8N8] = { 8, 8 }, [SCHED_MEAS_AVG_M_S6N4] = { 6, 4 },