fixeria has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmocom-bb/+/32922 )
Change subject: trxcon/l1sched: implement CSD scheduling support ......................................................................
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 */