fixeria has uploaded this change for review.
trxcon/l1sched: implement CSD scheduling support
Change-Id: I0d7389a9a5f7019b9316ab1c0115797ff54a0e41
Related: OS#4396, OS#1572
---
M src/host/trxcon/include/osmocom/bb/l1sched/l1sched.h
M src/host/trxcon/src/sched_lchan_common.c
M src/host/trxcon/src/sched_lchan_desc.c
M src/host/trxcon/src/sched_lchan_pdtch.c
M src/host/trxcon/src/sched_lchan_tchf.c
M src/host/trxcon/src/sched_lchan_tchh.c
M src/host/trxcon/src/sched_lchan_xcch.c
7 files changed, 162 insertions(+), 36 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmocom-bb refs/changes/22/32922/1
diff --git a/src/host/trxcon/include/osmocom/bb/l1sched/l1sched.h b/src/host/trxcon/include/osmocom/bb/l1sched/l1sched.h
index 39aeeb9..f72ee71 100644
--- a/src/host/trxcon/include/osmocom/bb/l1sched/l1sched.h
+++ b/src/host/trxcon/include/osmocom/bb/l1sched/l1sched.h
@@ -220,9 +220,9 @@
/*! Burst type: GMSK or 8PSK */
enum l1sched_burst_type burst_type;
/*! Mask of received bursts */
- uint8_t rx_burst_mask;
+ uint32_t rx_burst_mask;
/*! Mask of transmitted bursts */
- uint8_t tx_burst_mask;
+ uint32_t tx_burst_mask;
/*! Burst buffer for RX */
sbit_t *rx_bursts;
/*! Burst buffer for TX */
@@ -409,7 +409,7 @@
/* Shared declarations for lchan handlers */
extern const uint8_t l1sched_nb_training_bits[8][26];
-const char *l1sched_burst_mask2str(const uint8_t *mask, int bits);
+const char *l1sched_burst_mask2str(const uint32_t *mask, int bits);
size_t l1sched_bad_frame_ind(uint8_t *l2, struct l1sched_lchan_state *lchan);
/* Interleaved TCH/H block TDMA frame mapping */
diff --git a/src/host/trxcon/src/sched_lchan_common.c b/src/host/trxcon/src/sched_lchan_common.c
index cddc9e5..84763f7 100644
--- a/src/host/trxcon/src/sched_lchan_common.c
+++ b/src/host/trxcon/src/sched_lchan_common.c
@@ -78,13 +78,12 @@
* Examples: " ****.." (incomplete, 4/6 bursts)
* " ****" (complete, all 4 bursts)
* "**.***.." (incomplete, 5/8 bursts) */
-const char *l1sched_burst_mask2str(const uint8_t *mask, int bits)
+const char *l1sched_burst_mask2str(const uint32_t *mask, int bits)
{
- /* TODO: CSD is interleaved over 22 bursts, so the mask needs to be extended */
- static char buf[8 + 1];
+ static char buf[32 + 1];
char *ptr = buf;
- OSMO_ASSERT(bits <= 8 && bits > 0);
+ OSMO_ASSERT(bits <= 32 && bits > 0);
while (--bits >= 0)
*(ptr++) = (*mask & (1 << bits)) ? '*' : '.';
diff --git a/src/host/trxcon/src/sched_lchan_desc.c b/src/host/trxcon/src/sched_lchan_desc.c
index 3b37c57..5163269 100644
--- a/src/host/trxcon/src/sched_lchan_desc.c
+++ b/src/host/trxcon/src/sched_lchan_desc.c
@@ -130,7 +130,7 @@
*
* The MS shall continuously transmit bursts, even if there is nothing
* to send, unless DTX (Discontinuous Transmission) is used. */
- .burst_buf_size = 8 * GSM_NBITS_NB_GMSK_PAYLOAD,
+ .burst_buf_size = 22 * GSM_NBITS_NB_GMSK_PAYLOAD,
.flags = L1SCHED_CH_FLAG_CBTX,
.rx_fn = rx_tchf_fn,
.tx_fn = tx_tchf_fn,
@@ -157,7 +157,7 @@
*
* The MS shall continuously transmit bursts, even if there is nothing
* to send, unless DTX (Discontinuous Transmission) is used. */
- .burst_buf_size = 6 * GSM_NBITS_NB_GMSK_PAYLOAD,
+ .burst_buf_size = 22 * GSM_NBITS_NB_GMSK_PAYLOAD,
.flags = L1SCHED_CH_FLAG_CBTX,
.rx_fn = rx_tchh_fn,
.tx_fn = tx_tchh_fn,
@@ -169,7 +169,7 @@
.link_id = L1SCHED_CH_LID_DEDIC,
/* Same as for L1SCHED_TCHH_0, see above. */
- .burst_buf_size = 6 * GSM_NBITS_NB_GMSK_PAYLOAD,
+ .burst_buf_size = 22 * GSM_NBITS_NB_GMSK_PAYLOAD,
.flags = L1SCHED_CH_FLAG_CBTX,
.rx_fn = rx_tchh_fn,
.tx_fn = tx_tchh_fn,
diff --git a/src/host/trxcon/src/sched_lchan_pdtch.c b/src/host/trxcon/src/sched_lchan_pdtch.c
index b6c3b4c..90021e3 100644
--- a/src/host/trxcon/src/sched_lchan_pdtch.c
+++ b/src/host/trxcon/src/sched_lchan_pdtch.c
@@ -36,10 +36,11 @@
int rx_pdtch_fn(struct l1sched_lchan_state *lchan,
const struct l1sched_burst_ind *bi)
{
- uint8_t l2[GPRS_L2_MAX_LEN], *mask;
+ uint8_t l2[GPRS_L2_MAX_LEN];
int n_errors, n_bits_total, rc;
sbit_t *bursts_p, *burst;
size_t l2_len;
+ uint32_t *mask;
/* Set up pointers */
mask = &lchan->rx_burst_mask;
@@ -107,7 +108,7 @@
{
ubit_t *bursts_p, *burst;
const uint8_t *tsc;
- uint8_t *mask;
+ uint32_t *mask;
int rc;
/* Set up pointers */
diff --git a/src/host/trxcon/src/sched_lchan_tchf.c b/src/host/trxcon/src/sched_lchan_tchf.c
index f749ff4..f64ecb7 100644
--- a/src/host/trxcon/src/sched_lchan_tchf.c
+++ b/src/host/trxcon/src/sched_lchan_tchf.c
@@ -3,7 +3,7 @@
* TDMA scheduler: handlers for DL / UL bursts on logical channels
*
* (C) 2017-2022 by Vadim Yanitskiy <axilirator@gmail.com>
- * Contributions by sysmocom - s.f.m.c. GmbH
+ * (C) 2021-2023 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
*
* All Rights Reserved
*
@@ -28,6 +28,7 @@
#include <osmocom/gsm/protocol/gsm_04_08.h>
#include <osmocom/gsm/gsm_utils.h>
+#include <osmocom/gsm/gsm0502.h>
#include <osmocom/coding/gsm0503_coding.h>
#include <osmocom/coding/gsm0503_amr_dtx.h>
@@ -36,6 +37,9 @@
#include <osmocom/bb/l1sched/l1sched.h>
#include <osmocom/bb/l1sched/logging.h>
+/* Burst Payload LENgth (short alias) */
+#define BPLEN GSM_NBITS_NB_GMSK_PAYLOAD
+
/* 3GPP TS 45.009, table 3.2.1.3-{1,3}: AMR on Downlink TCH/F.
*
* +---+---+---+---+---+---+---+---+
@@ -64,7 +68,7 @@
sbit_t *bursts_p, *burst;
uint8_t tch_data[128];
size_t tch_data_len;
- uint8_t *mask;
+ uint32_t *mask;
int amr = 0;
uint8_t ft;
@@ -77,8 +81,8 @@
if (bi->bid == 0) {
/* Shift the burst buffer by 4 bursts leftwards */
- memcpy(&bursts_p[0], &bursts_p[464], 464);
- memset(&bursts_p[464], 0, 464);
+ memmove(&bursts_p[0], &bursts_p[4 * BPLEN], 18 * BPLEN);
+ memset(&bursts_p[18 * BPLEN], 0, 4 * BPLEN);
*mask = *mask << 4;
} else {
/* Align to the first burst of a block */
@@ -92,8 +96,8 @@
/* Store the measurements */
l1sched_lchan_meas_push(lchan, 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) * BPLEN;
memcpy(burst, bi->burst + 3, 58);
memcpy(burst + 58, bi->burst + 87, 58);
@@ -115,6 +119,11 @@
}
+ /* 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. */
+ bursts_p += (22 - 8) * BPLEN;
+
switch (lchan->tch_mode) {
case GSM48_CMODE_SIGN:
case GSM48_CMODE_SPEECH_V1: /* FR */
@@ -156,6 +165,24 @@
"osmo_amr_rtp_enc() returned rc=%d\n", rc);
}
break;
+ /* CSD (TCH/F9.6): 12.0 kbit/s radio interface rate */
+ case GSM48_CMODE_DATA_12k0:
+ rc = gsm0503_tch_fr96_decode(&tch_data[0], bursts_p, &n_errors, &n_bits_total);
+ break;
+ /* CSD (TCH/F4.8): 6.0 kbit/s radio interface rate */
+ case GSM48_CMODE_DATA_6k0:
+ rc = gsm0503_tch_fr48_decode(&tch_data[0], bursts_p, &n_errors, &n_bits_total);
+ break;
+#if 0
+ /* TODO: CSD (TCH/F2.4): 3.6 kbit/s radio interface rate */
+ case GSM48_CMODE_DATA_3k6:
+ rc = gsm0503_tch_fr24_decode(&tch_data[0], bursts_p, &n_errors, &n_bits_total);
+ break;
+#endif
+ /* CSD (TCH/F14.4): 14.5 kbit/s radio interface rate */
+ case GSM48_CMODE_DATA_14k5:
+ rc = gsm0503_tch_fr144_decode(&tch_data[0], bursts_p, &n_errors, &n_bits_total);
+ break;
default:
LOGP_LCHAND(lchan, LOGL_ERROR, "Invalid TCH mode: %u\n", lchan->tch_mode);
return -EINVAL;
@@ -218,7 +245,7 @@
{
ubit_t *bursts_p, *burst;
const uint8_t *tsc;
- uint8_t *mask;
+ uint32_t *mask;
int rc;
/* Set up pointers */
@@ -230,8 +257,8 @@
goto send_burst;
/* Shift the burst buffer by 4 bursts leftwards for interleaving */
- memcpy(&bursts_p[0], &bursts_p[464], 464);
- memset(&bursts_p[464], 0, 464);
+ memmove(&bursts_p[0], &bursts_p[4 * BPLEN], 18 * BPLEN);
+ memset(&bursts_p[18 * BPLEN], 0, 4 * BPLEN);
/* populate the buffer with bursts */
switch (lchan->tch_mode) {
@@ -299,6 +326,28 @@
lchan->amr.ul_cmr);
break;
}
+ /* CSD (TCH/F9.6): 12.0 kbit/s radio interface rate */
+ case GSM48_CMODE_DATA_12k0:
+ OSMO_ASSERT(msgb_l2len(lchan->prim) == OSMO_BYTES_FOR_BITS(4 * 60));
+ rc = gsm0503_tch_fr96_encode(bursts_p, msgb_l2(lchan->prim));
+ break;
+ /* CSD (TCH/F4.8): 6.0 kbit/s radio interface rate */
+ case GSM48_CMODE_DATA_6k0:
+ OSMO_ASSERT(msgb_l2len(lchan->prim) == OSMO_BYTES_FOR_BITS(2 * 60));
+ rc = gsm0503_tch_fr48_encode(bursts_p, msgb_l2(lchan->prim));
+ break;
+#if 0
+ /* TODO: CSD (TCH/F2.4): 3.6 kbit/s radio interface rate */
+ case GSM48_CMODE_DATA_3k6:
+ OSMO_ASSERT(msgb_l2len(lchan->prim) == OSMO_BYTES_FOR_BITS(2 * 36));
+ rc = gsm0503_tch_fr24_encode(bursts_p, msgb_l2(lchan->prim));
+ break;
+#endif
+ /* CSD (TCH/F14.4): 14.5 kbit/s radio interface rate */
+ case GSM48_CMODE_DATA_14k5:
+ OSMO_ASSERT(msgb_l2len(lchan->prim) == OSMO_BYTES_FOR_BITS(290));
+ rc = gsm0503_tch_fr144_encode(bursts_p, msgb_l2(lchan->prim));
+ break;
default:
LOGP_LCHAND(lchan, LOGL_ERROR,
"TCH mode %s is unknown or not supported\n",
@@ -316,7 +365,7 @@
send_burst:
/* Determine which burst should be sent */
- burst = bursts_p + br->bid * 116;
+ burst = bursts_p + br->bid * BPLEN;
/* Update mask */
*mask |= (1 << br->bid);
diff --git a/src/host/trxcon/src/sched_lchan_tchh.c b/src/host/trxcon/src/sched_lchan_tchh.c
index 9e53e50..1c4dae4 100644
--- a/src/host/trxcon/src/sched_lchan_tchh.c
+++ b/src/host/trxcon/src/sched_lchan_tchh.c
@@ -4,7 +4,7 @@
*
* (C) 2018-2022 by Vadim Yanitskiy <axilirator@gmail.com>
* (C) 2018 by Harald Welte <laforge@gnumonks.org>
- * Contributions by sysmocom - s.f.m.c. GmbH
+ * (C) 2020-2023 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
*
* All Rights Reserved
*
@@ -31,6 +31,7 @@
#include <osmocom/gsm/protocol/gsm_04_08.h>
#include <osmocom/gsm/gsm_utils.h>
+#include <osmocom/gsm/gsm0502.h>
#include <osmocom/coding/gsm0503_coding.h>
#include <osmocom/coding/gsm0503_amr_dtx.h>
@@ -39,6 +40,9 @@
#include <osmocom/bb/l1sched/l1sched.h>
#include <osmocom/bb/l1sched/logging.h>
+/* Burst Payload LENgth (short alias) */
+#define BPLEN GSM_NBITS_NB_GMSK_PAYLOAD
+
/* 3GPP TS 45.009, table 3.2.1.3-{2,4}: AMR on Downlink TCH/H.
*
* +---+---+---+---+---+---+
@@ -123,6 +127,41 @@
[7] = 1, /* FACCH/H(1): B2(22,24,1,3,5,7) */
};
+/* 3GPP TS 45.002, table 2 in clause 7: Mapping tables for TCH/H2.4 and TCH/H4.8.
+ *
+ * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ * | a | b | c | d | e | f | g | h | i | j | k | l | m | n | o | p | q | r | s | t | u | v |
+ * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ *
+ * TCH/H(0): B0(0,2,4,6,8,10,13,15,17,19,21,23,0,2,4,6,8,10,13,15,17,19)
+ * TCH/H(1): B0(1,3,5,7,9,11,14,16,18,20,22,24,1,3,5,7,9,11,14,16,18,20)
+ * TCH/H(0): B1(8,10,13,15,17,19,21,23,0,2,4,6,8,10,13,15,17,19,21,23,0,2)
+ * TCH/H(1): B1(9,11,14,16,18,20,22,24,1,3,5,7,9,11,14,16,18,20,22,24,1,3)
+ * TCH/H(0): B2(17,19,21,23,0,2,4,6,8,10,13,15,17,19,21,23,0,2,4,6,8,10)
+ * TCH/H(1): B2(18,20,22,24,1,3,5,7,9,11,14,16,18,20,22,24,1,3,5,7,9,11)
+ *
+ * TDMA frame number of burst 'a' % 26 is the table index.
+ * This mapping is valid for both TCH/H(0) and TCH/H(1). */
+static const uint8_t sched_tchh_ul_csd_map[26] = {
+ [0] = 1, /* TCH/H(0): B0(0 ... 19) */
+ [1] = 1, /* TCH/H(1): B0(1 ... 20) */
+ [8] = 1, /* TCH/H(0): B1(8 ... 2) */
+ [9] = 1, /* TCH/H(1): B1(9 ... 3) */
+ [17] = 1, /* TCH/H(0): B2(17 ... 10) */
+ [18] = 1, /* TCH/H(1): B2(18 ... 11) */
+};
+
+/* TDMA frame number of burst 'v' % 26 is the table index.
+ * This mapping is valid for both TCH/H(0) and TCH/H(1). */
+static const uint8_t sched_tchh_dl_csd_map[26] = {
+ [19] = 1, /* TCH/H(0): B0(0 ... 19) */
+ [20] = 1, /* TCH/H(1): B0(1 ... 20) */
+ [2] = 1, /* TCH/H(0): B1(8 ... 2) */
+ [3] = 1, /* TCH/H(1): B1(9 ... 3) */
+ [10] = 1, /* TCH/H(0): B2(17 ... 10) */
+ [11] = 1, /* TCH/H(1): B2(18 ... 11) */
+};
+
/**
* Can a TCH/H block transmission be initiated / finished
* on a given frame number and a given channel type?
@@ -241,7 +280,7 @@
sbit_t *bursts_p, *burst;
uint8_t tch_data[128];
size_t tch_data_len;
- uint8_t *mask;
+ uint32_t *mask;
int amr = 0;
uint8_t ft;
@@ -254,9 +293,8 @@
if (bi->bid == 0) {
/* Shift the burst buffer by 2 bursts leftwards */
- memcpy(&bursts_p[0], &bursts_p[232], 232);
- memcpy(&bursts_p[232], &bursts_p[464], 232);
- memset(&bursts_p[464], 0, 232);
+ memmove(&bursts_p[0], &bursts_p[2 * BPLEN], 20 * BPLEN);
+ memset(&bursts_p[20 * BPLEN], 0, 2 * BPLEN);
*mask = *mask << 2;
}
@@ -281,8 +319,8 @@
/* Store the measurements */
l1sched_lchan_meas_push(lchan, bi);
- /* Copy burst to the end of buffer of 6 bursts */
- burst = bursts_p + bi->bid * 116 + 464;
+ /* Copy burst to the end of buffer of 22 bursts */
+ burst = bursts_p + (bi->bid + 20) * BPLEN;
memcpy(burst, bi->burst + 3, 58);
memcpy(burst + 58, bi->burst + 87, 58);
@@ -307,6 +345,17 @@
goto bfi; /* 2/2 BFI */
}
+ /* TCH/H: speech and signalling frames are interleaved over 4 and 6 bursts,
+ * respectively, while CSD frames are interleaved over 22 bursts. Unless
+ * we're in CSD mode, decode only the last 6 bursts to avoid introducing
+ * additional delays. */
+ bursts_p += (22 - 6) * BPLEN;
+
+#if 0
+ else if (!sched_tchh_ul_csd_map[bi->fn % 26])
+ return 0; /* CSD: skip decoding attempt, need 2 more bursts */
+#endif
+
switch (lchan->tch_mode) {
case GSM48_CMODE_SIGN:
case GSM48_CMODE_SPEECH_V1: /* HR */
@@ -343,6 +392,14 @@
"osmo_amr_rtp_enc() returned rc=%d\n", rc);
}
break;
+ /* CSD (TCH/H4.8): 6.0 kbit/s radio interface rate */
+ case GSM48_CMODE_DATA_6k0:
+ rc = gsm0503_tch_hr48_decode(&tch_data[0], bursts_p, &n_errors, &n_bits_total);
+ break;
+ /* CSD (TCH/H2.4): 3.6 kbit/s radio interface rate */
+ case GSM48_CMODE_DATA_3k6:
+ rc = gsm0503_tch_hr24_decode(&tch_data[0], bursts_p, &n_errors, &n_bits_total);
+ break;
default:
LOGP_LCHAND(lchan, LOGL_ERROR, "Invalid TCH mode: %u\n", lchan->tch_mode);
return -EINVAL;
@@ -417,7 +474,7 @@
{
ubit_t *bursts_p, *burst;
const uint8_t *tsc;
- uint8_t *mask;
+ uint32_t *mask;
int rc;
/* Set up pointers */
@@ -439,9 +496,8 @@
}
/* Shift the burst buffer by 2 bursts leftwards for interleaving */
- memcpy(&bursts_p[0], &bursts_p[232], 232);
- memcpy(&bursts_p[232], &bursts_p[464], 232);
- memset(&bursts_p[464], 0, 232);
+ memmove(&bursts_p[0], &bursts_p[2 * BPLEN], 20 * BPLEN);
+ memset(&bursts_p[20 * BPLEN], 0, 2 * BPLEN);
*mask = *mask << 2;
/* If FACCH/H blocks are still pending */
@@ -513,6 +569,16 @@
lchan->amr.ul_cmr);
break;
}
+ /* CSD (TCH/H4.8): 6.0 kbit/s radio interface rate */
+ case GSM48_CMODE_DATA_6k0:
+ OSMO_ASSERT(msgb_l2len(lchan->prim) == OSMO_BYTES_FOR_BITS(4 * 60));
+ rc = gsm0503_tch_hr48_encode(bursts_p, msgb_l2(lchan->prim));
+ break;
+ /* CSD (TCH/H2.4): 3.6 kbit/s radio interface rate */
+ case GSM48_CMODE_DATA_3k6:
+ OSMO_ASSERT(msgb_l2len(lchan->prim) == OSMO_BYTES_FOR_BITS(2 * 36));
+ rc = gsm0503_tch_hr24_encode(bursts_p, msgb_l2(lchan->prim));
+ break;
default:
LOGP_LCHAND(lchan, LOGL_ERROR,
"TCH mode %s is unknown or not supported\n",
@@ -530,7 +596,7 @@
send_burst:
/* Determine which burst should be sent */
- burst = bursts_p + br->bid * 116;
+ burst = bursts_p + br->bid * BPLEN;
/* Update mask */
*mask |= (1 << br->bid);
diff --git a/src/host/trxcon/src/sched_lchan_xcch.c b/src/host/trxcon/src/sched_lchan_xcch.c
index b246a17..09eac8a 100644
--- a/src/host/trxcon/src/sched_lchan_xcch.c
+++ b/src/host/trxcon/src/sched_lchan_xcch.c
@@ -36,9 +36,10 @@
int rx_data_fn(struct l1sched_lchan_state *lchan,
const struct l1sched_burst_ind *bi)
{
- uint8_t l2[GSM_MACBLOCK_LEN], *mask;
+ uint8_t l2[GSM_MACBLOCK_LEN];
int n_errors, n_bits_total, rc;
sbit_t *bursts_p, *burst;
+ uint32_t *mask;
/* Set up pointers */
mask = &lchan->rx_burst_mask;
@@ -103,7 +104,7 @@
{
ubit_t *bursts_p, *burst;
const uint8_t *tsc;
- uint8_t *mask;
+ uint32_t *mask;
int rc;
/* Set up pointers */
To view, visit change 32922. To unsubscribe, or for help writing mail filters, visit settings.