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 },
--
To view, visit
https://gerrit.osmocom.org/c/osmo-bts/+/32727
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-bts
Gerrit-Branch: master
Gerrit-Change-Id: I08ffbf8e79ce76a586d61f5463890c6e72a6d9b9
Gerrit-Change-Number: 32727
Gerrit-PatchSet: 1
Gerrit-Owner: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-MessageType: newchange