fixeria has submitted this change. ( 
https://gerrit.osmocom.org/c/osmo-bts/+/32727 )

Change subject: osmo-bts-trx: implement CSD scheduling support
......................................................................

osmo-bts-trx: implement CSD scheduling support

* enlarge the maximum burst buffer size to 24 * (2 * 58) bytes;
* enlarge per-l1cs Uplink burst mask to hold up to 32 bits;
* enlarge per-l1cs Uplink meas ring buffer to 24 entries;
* add new meas modes: SCHED_MEAS_AVG_M_{S22N22,S24N22};

Change-Id: I08ffbf8e79ce76a586d61f5463890c6e72a6d9b9
Depends: libosmocore.git Ib482817b5f6a4e3c7299f6e0b3841143b60fc93d
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/sched_utils.h
M src/osmo-bts-trx/scheduler_trx.c
9 files changed, 284 insertions(+), 72 deletions(-)

Approvals:
  laforge: Looks good to me, but someone else must approve
  Jenkins Builder: Verified
  pespin: Looks good to me, approved




diff --git a/include/osmo-bts/scheduler.h b/include/osmo-bts/scheduler.h
index 4d76b9b..23d01fb 100644
--- a/include/osmo-bts/scheduler.h
+++ b/include/osmo-bts/scheduler.h
@@ -94,7 +94,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 */
@@ -132,7 +132,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[24]; /* up to 24 entries */
                unsigned int current; /* current position */

                /* Interference measurements */
@@ -301,6 +301,10 @@

 /* Averaging mode for trx_sched_meas_avg() */
 enum sched_meas_avg_mode {
+       /* first 22 of last 24 bursts (for TCH/F14.4, TCH/F9.6, TCH/F4.8) */
+       SCHED_MEAS_AVG_M_S24N22,
+       /* last 22 bursts (for TCH/H4.8, TCH/H2.4) */
+       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 2e73ad4..6a07ea5 100644
--- a/src/common/bts.c
+++ b/src/common/bts.c
@@ -780,23 +780,11 @@
        return &bts->gsm_time;
 }

-bool bts_supports_cm(const struct gsm_bts *bts,
-                    const struct rsl_ie_chan_mode *cm)
+bool 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 true;
-       case RSL_CMOD_SPD_SPEECH:
-               break;
-       case RSL_CMOD_SPD_DATA:
-       default:
-               return false;
-       }
-
        /* Stage 1: check support for the requested channel type */
        switch (cm->chan_rt) {
        case RSL_CMOD_CRT_TCH_GROUP_Bm:
@@ -869,6 +857,52 @@
        return false;
 }

+static bool bts_supports_cm_data(const struct gsm_bts *bts,
+                                const struct rsl_ie_chan_mode *cm)
+{
+       switch (bts->variant) {
+       case BTS_OSMO_TRX:
+               switch (cm->chan_rate) {
+               case RSL_CMOD_CSD_T_14k4:
+               case RSL_CMOD_CSD_T_9k6:
+                       if (cm->chan_rt != RSL_CMOD_CRT_TCH_Bm)
+                               return false; /* invalid */
+                       /* fall-through */
+               case RSL_CMOD_CSD_T_4k8:
+                       return true;
+               case RSL_CMOD_CSD_T_2k4:
+               case RSL_CMOD_CSD_T_1k2:
+               case RSL_CMOD_CSD_T_600:
+               case RSL_CMOD_CSD_T_1200_75:
+                       /* TODO: osmo-bts-trx does not support TCH/F2.4 */
+                       if (cm->chan_rt == RSL_CMOD_CRT_TCH_Bm)
+                               return false;
+                       return true;
+               default:
+                       return false;
+               }
+       default:
+               return 0;
+       }
+}
+
+bool 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 true;
+       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 false;
+       }
+}
+
 /* 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 007dd7c..e68d01f 100644
--- a/src/common/scheduler.c
+++ b/src/common/scheduler.c
@@ -1079,9 +1079,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 24 * (2 * 58) bytes, which is sufficient to store up to 
24 GMSK
+                * modulated bursts for CSD or up to 8 8PSK modulated bursts 
for EGPRS. */
+               const size_t buf_size = 24 * 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 2aa43f9..fd813b9 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 444cda2..ac9a15c 100644
--- a/src/osmo-bts-trx/sched_lchan_tchf.c
+++ b/src/osmo-bts-trx/sched_lchan_tchf.c
@@ -1,7 +1,7 @@
 /*
  * (C) 2013 by Andreas Eversberg <[email protected]>
  * (C) 2015-2017 by Harald Welte <[email protected]>
- * Contributions by sysmocom - s.f.m.c. GmbH
+ * (C) 2020-2023 by sysmocom - s.f.m.c. GmbH <[email protected]>
  *
  * All Rights Reserved
  *
@@ -75,10 +75,10 @@
        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 */
+       uint8_t tch_data[290]; /* large enough to hold 290 unpacked bits for 
CSD */
        enum sched_meas_avg_mode meas_avg_mode = SCHED_MEAS_AVG_M_S8N8;
        struct l1sched_meas_set meas_avg;
        int rc, amr = 0;
@@ -100,8 +100,8 @@

        /* shift the buffer by 4 bursts leftwards */
        if (bi->bid == 0) {
-               memcpy(bursts_p, bursts_p + 464, 464);
-               memset(bursts_p + 464, 0, 464);
+               memmove(BUFPOS(bursts_p, 0), BUFPOS(bursts_p, 4), 20 * BPLEN);
+               memset(BUFPOS(bursts_p, 20), 0, 4 * BPLEN);
                *mask = *mask << 4;
        }

@@ -111,8 +111,8 @@
        /* 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 24 bursts */
+       burst = BUFPOS(bursts_p, 20 + bi->bid);
        if (bi->burst_len > 0) {
                memcpy(burst, bi->burst + 3, 58);
                memcpy(burst + 58, bi->burst + 87, 58);
@@ -130,17 +130,20 @@
                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. */
        switch (tch_mode) {
        case GSM48_CMODE_SIGN:
        case GSM48_CMODE_SPEECH_V1: /* FR */
-               rc = gsm0503_tch_fr_decode(tch_data, bursts_p, 1, 0, &n_errors, 
&n_bits_total);
+               rc = gsm0503_tch_fr_decode(tch_data, BUFTAIL8(bursts_p),
+                                          1, 0, &n_errors, &n_bits_total);
                if (rc == GSM_FR_BYTES) /* only for valid *speech* frames */
                        lchan_set_marker(osmo_fr_is_any_sid(tch_data), lchan); 
/* DTXu */
                break;
        case GSM48_CMODE_SPEECH_EFR: /* EFR */
-               rc = gsm0503_tch_fr_decode(tch_data, bursts_p, 1, 1, &n_errors, 
&n_bits_total);
+               rc = gsm0503_tch_fr_decode(tch_data, BUFTAIL8(bursts_p),
+                                          1, 1, &n_errors, &n_bits_total);
                if (rc == GSM_EFR_BYTES) /* only for valid *speech* frames */
                        lchan_set_marker(osmo_efr_is_any_sid(tch_data), lchan); 
/* DTXu */
                break;
@@ -166,7 +169,7 @@
                 * we receive an FACCH frame instead of a voice frame (we
                 * do not know this before we actually decode the frame) */
                amr = sizeof(struct amr_hdr);
-               rc = gsm0503_tch_afs_decode_dtx(tch_data + amr, bursts_p,
+               rc = gsm0503_tch_afs_decode_dtx(tch_data + amr, 
BUFTAIL8(bursts_p),
                        amr_is_cmr, chan_state->codec, chan_state->codecs, 
&chan_state->ul_ft,
                        &chan_state->ul_cmr, &n_errors, &n_bits_total, 
&chan_state->amr_last_dtx);

@@ -219,6 +222,33 @@
                }

                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], BUFPOS(bursts_p, 0),
+                                            &n_errors, &n_bits_total);
+               meas_avg_mode = SCHED_MEAS_AVG_M_S24N22;
+               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], BUFPOS(bursts_p, 0),
+                                            &n_errors, &n_bits_total);
+               meas_avg_mode = SCHED_MEAS_AVG_M_S24N22;
+               break;
+#if 0
+       /* TODO: CSD (TCH/F2.4): 3.6 kbit/s radio interface rate */
+       case GSM48_CMODE_DATA_3k6:
+               /* TCH/F2.4 employs the same interleaving as TCH/FS (8 bursts) 
*/
+               rc = gsm0503_tch_fr24_decode(&tch_data[0], BUFTAIL8(bursts_p),
+                                            &n_errors, &n_bits_total);
+               meas_avg_mode = SCHED_MEAS_AVG_M_S8N8;
+               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], BUFPOS(bursts_p, 0),
+                                             &n_errors, &n_bits_total);
+               meas_avg_mode = SCHED_MEAS_AVG_M_S24N22;
+               break;
        default:
                LOGL1SB(DL1P, LOGL_ERROR, l1ts, bi,
                        "TCH mode %u invalid, please fix!\n",
@@ -271,7 +301,7 @@
                rc = 0;
        }

-       if (rsl_cmode != RSL_CMOD_SPD_SPEECH)
+       if (rsl_cmode == RSL_CMOD_SPD_SIGN)
                return 0;

        /* TCH or BFI */
@@ -406,6 +436,29 @@
                        msg_tch->l2h += sizeof(struct amr_hdr);
                        len -= sizeof(struct amr_hdr);
                        break;
+               case GSM48_CMODE_DATA_14k5: /* TCH/F14.4 */
+                       if (OSMO_UNLIKELY(br->chan != TRXC_TCHF))
+                               goto inval_mode2;
+                       len = 290;
+                       break;
+               case GSM48_CMODE_DATA_12k0: /* TCH/F9.6 */
+                       if (OSMO_UNLIKELY(br->chan != TRXC_TCHF))
+                               goto inval_mode2;
+                       len = 4 * 60;
+                       break;
+               case GSM48_CMODE_DATA_6k0: /* TCH/[FH]4.8 */
+                       if (br->chan == TRXC_TCHF)
+                               len = 2 * 60;
+                       else
+                               len = 4 * 60;
+                       break;
+               case GSM48_CMODE_DATA_3k6: /* TCH/[FH]2.4 */
+                       /* FIXME: TCH/F2.4 is not supported */
+                       if (br->chan == TRXC_TCHF)
+                               goto inval_mode2; /* 2 * 36 */
+                       else
+                               len = 4 * 36;
+                       break;
                default:
 inval_mode2:
                        LOGL1SB(DL1P, LOGL_ERROR, l1ts, br, "TCH mode invalid, 
please fix!\n");
@@ -446,8 +499,8 @@
        /* BURST BYPASS */

         /* shift buffer by 4 bursts for interleaving */
-       memcpy(bursts_p, bursts_p + 464, 464);
-       memset(bursts_p + 464, 0, 464);
+       memmove(BUFPOS(bursts_p, 0), BUFPOS(bursts_p, 4), 20 * BPLEN);
+       memset(BUFPOS(bursts_p, 20), 0, 4 * BPLEN);

        /* dequeue a message to be transmitted */
        msg = tch_dl_dequeue(l1ts, br);
@@ -485,23 +538,48 @@
                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(BUFPOS(bursts_p, 0), 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.
                 */
-               gsm0503_tch_afs_encode(bursts_p,
+               gsm0503_tch_afs_encode(BUFPOS(bursts_p, 0),
                                       msgb_l2(msg), msgb_l2len(msg),
                                       !sched_tchf_dl_amr_cmi_map[br->fn % 26],
                                       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;
+       /* CSD (TCH/F9.6): 12.0 kbit/s radio interface rate */
+       case GSM48_CMODE_DATA_12k0:
+               gsm0503_tch_fr96_encode(BUFPOS(bursts_p, 0), msgb_l2(msg));
+               break;
+       /* CSD (TCH/F4.8): 6.0 kbit/s radio interface rate */
+       case GSM48_CMODE_DATA_6k0:
+               gsm0503_tch_fr48_encode(BUFPOS(bursts_p, 0), msgb_l2(msg));
+               break;
+#if 0
+       /* TODO: CSD (TCH/F2.4): 3.6 kbit/s radio interface rate */
+       case GSM48_CMODE_DATA_3k6:
+               gsm0503_tch_fr24_encode(BUFPOS(bursts_p, 0), msgb_l2(msg));
+               break;
+#endif
+       /* CSD (TCH/F14.4): 14.5 kbit/s radio interface rate */
+       case GSM48_CMODE_DATA_14k5:
+               gsm0503_tch_fr144_encode(BUFPOS(bursts_p, 0), msgb_l2(msg));
+               break;
+       default:
+               OSMO_ASSERT(0);
        }
 
        /* free message */
@@ -509,7 +587,7 @@

 send_burst:
        /* compose burst */
-       burst = bursts_p + br->bid * 116;
+       burst = BUFPOS(bursts_p, br->bid);
        memcpy(br->burst + 3, burst, 58);
        memcpy(br->burst + 61, TRX_GMSK_NB_TSC(br), 26);
        memcpy(br->burst + 87, burst + 58, 58);
diff --git a/src/osmo-bts-trx/sched_lchan_tchh.c 
b/src/osmo-bts-trx/sched_lchan_tchh.c
index 541feab..6ab4c31 100644
--- a/src/osmo-bts-trx/sched_lchan_tchh.c
+++ b/src/osmo-bts-trx/sched_lchan_tchh.c
@@ -1,7 +1,7 @@
 /*
  * (C) 2013 by Andreas Eversberg <[email protected]>
  * (C) 2015-2017 by Harald Welte <[email protected]>
- * Contributions by sysmocom - s.f.m.c. GmbH
+ * (C) 2020-2023 by sysmocom - s.f.m.c. GmbH <[email protected]>
  *
  * All Rights Reserved
  *
@@ -91,16 +91,51 @@
 /* TDMA frame number of burst 'a' is used as the table index. */
 extern const uint8_t sched_tchh_dl_facch_map[26];

+/* 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 '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_ul_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) */
+};
+
+/* 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_dl_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) */
+};
+
 /*! \brief a single TCH/H burst was received by the PHY, process it */
 int rx_tchh_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi)
 {
        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 */
+       uint8_t tch_data[240]; /* large enough to hold 240 unpacked bits for 
CSD */
        int rc = 0; /* initialize to make gcc happy */
        int amr = 0;
        int n_errors = 0;
@@ -123,9 +158,8 @@

        /* shift the buffer by 2 bursts leftwards */
        if (bi->bid == 0) {
-               memcpy(bursts_p, bursts_p + 232, 232);
-               memcpy(bursts_p + 232, bursts_p + 464, 232);
-               memset(bursts_p + 464, 0, 232);
+               memmove(BUFPOS(bursts_p, 0), BUFPOS(bursts_p, 2), 20 * BPLEN);
+               memset(BUFPOS(bursts_p, 20), 0, 2 * BPLEN);
                *mask = *mask << 2;
        }

@@ -135,8 +169,8 @@
        /* store measurements */
        trx_sched_meas_push(chan_state, bi);

-       /* copy burst to end of buffer of 6 bursts */
-       burst = bursts_p + bi->bid * 116 + 464;
+       /* copy burst to end of buffer of 24 bursts */
+       burst = BUFPOS(bursts_p, 20 + bi->bid);
        if (bi->burst_len > 0) {
                memcpy(burst, bi->burst + 3, 58);
                memcpy(burst + 58, bi->burst + 87, 58);
@@ -165,14 +199,16 @@
                goto bfi;
        }

-       /* decode
-        * also shift buffer by 4 bursts for interleaving */
+       /* 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. */
        switch (tch_mode) {
        case GSM48_CMODE_SIGN:
                meas_avg_mode = SCHED_MEAS_AVG_M_S6N6;
                /* fall-through */
        case GSM48_CMODE_SPEECH_V1: /* HR or signalling */
-               rc = gsm0503_tch_hr_decode2(tch_data, bursts_p,
+               rc = gsm0503_tch_hr_decode2(tch_data, BUFTAIL8(bursts_p),
                                            !sched_tchh_ul_facch_map[bi->fn % 
26],
                                            &n_errors, &n_bits_total);
                if (rc == GSM_HR_BYTES) { /* only for valid *speech* frames */
@@ -199,7 +235,7 @@

                /* See comment in function rx_tchf_fn() */
                amr = sizeof(struct amr_hdr);
-               rc = gsm0503_tch_ahs_decode_dtx(tch_data + amr, bursts_p,
+               rc = gsm0503_tch_ahs_decode_dtx(tch_data + amr, 
BUFTAIL8(bursts_p),
                                                !sched_tchh_ul_facch_map[bi->fn 
% 26],
                                                !fn_is_cmi, chan_state->codec,
                                                chan_state->codecs, 
&chan_state->ul_ft,
@@ -255,6 +291,22 @@
                }

                break;
+       /* CSD (TCH/H4.8): 6.0 kbit/s radio interface rate */
+       case GSM48_CMODE_DATA_6k0:
+               if (!sched_tchh_ul_csd_map[bi->fn % 26])
+                       return 0; /* CSD: skip decoding attempt, need 2 more 
bursts */
+               rc = gsm0503_tch_hr48_decode(&tch_data[0], BUFPOS(bursts_p, 0),
+                                            &n_errors, &n_bits_total);
+               meas_avg_mode = SCHED_MEAS_AVG_M_S22N22;
+               break;
+       /* CSD (TCH/H2.4): 3.6 kbit/s radio interface rate */
+       case GSM48_CMODE_DATA_3k6:
+               if (!sched_tchh_ul_csd_map[bi->fn % 26])
+                       return 0; /* CSD: skip decoding attempt, need 2 more 
bursts */
+               rc = gsm0503_tch_hr24_decode(&tch_data[0], BUFPOS(bursts_p, 0),
+                                            &n_errors, &n_bits_total);
+               meas_avg_mode = SCHED_MEAS_AVG_M_S22N22;
+               break;
        default:
                LOGL1SB(DL1P, LOGL_ERROR, l1ts, bi,
                        "TCH mode %u invalid, please fix!\n",
@@ -308,7 +360,7 @@
                rc = 0;
        }

-       if (rsl_cmode != RSL_CMOD_SPD_SPEECH)
+       if (rsl_cmode == RSL_CMOD_SPD_SIGN)
                return 0;

        /* TCH or BFI */
@@ -345,13 +397,14 @@

        /* BURST BYPASS */

-        /* shift buffer by 2 bursts for interleaving */
-       memcpy(bursts_p, bursts_p + 232, 232);
-       if (chan_state->dl_ongoing_facch) {
-               memcpy(bursts_p + 232, bursts_p + 464, 232);
-               memset(bursts_p + 464, 0, 232);
-       } else {
-               memset(bursts_p + 232, 0, 232);
+       /* shift buffer by 2 bursts for interleaving */
+       memmove(BUFPOS(bursts_p, 0), BUFPOS(bursts_p, 2), 20 * BPLEN);
+       memset(BUFPOS(bursts_p, 20), 0, 2 * BPLEN);
+
+       /* for half-rate CSD we dequeue every 4th burst */
+       if (chan_state->rsl_cmode == RSL_CMOD_SPD_DATA) {
+               if (!sched_tchh_dl_csd_map[br->fn % 26])
+                       goto send_burst;
        }

        /* dequeue a message to be transmitted */
@@ -397,30 +450,45 @@
                        goto send_burst;
                }

-               gsm0503_tch_hr_encode(bursts_p, dummy, sizeof(dummy));
+               gsm0503_tch_hr_encode(BUFPOS(bursts_p, 0), dummy, 
sizeof(dummy));
                chan_state->dl_ongoing_facch = 1;
                chan_state->dl_facch_bursts = 6;
                goto send_burst;
        }

-       /* populate the buffer with bursts */
        if (msgb_l2len(msg) == GSM_MACBLOCK_LEN) {
-               gsm0503_tch_hr_encode(bursts_p, msg->l2h, msgb_l2len(msg));
                chan_state->dl_ongoing_facch = 1; /* first of two TCH frames */
                chan_state->dl_facch_bursts = 6;
-       } 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:
+               gsm0503_tch_hr_encode(BUFPOS(bursts_p, 0), msg->l2h, 
msgb_l2len(msg));
+               break;
+       case GSM48_CMODE_SPEECH_AMR:
                /* the first FN 4,13,21 or 5,14,22 defines that CMI is included
                 * in frame, the first FN 0,8,17 or 1,9,18 defines that CMR is
                 * included in frame. */
-               gsm0503_tch_ahs_encode(bursts_p,
+               gsm0503_tch_ahs_encode(BUFPOS(bursts_p, 0),
                                       msgb_l2(msg), msgb_l2len(msg),
                                       !sched_tchh_dl_amr_cmi_map[br->fn % 26],
                                       chan_state->codec,
                                       chan_state->codecs,
                                       chan_state->dl_ft,
                                       chan_state->dl_cmr);
-       } else {
-               gsm0503_tch_hr_encode(bursts_p, msg->l2h, msgb_l2len(msg));
+               break;
+       /* CSD (TCH/H4.8): 6.0 kbit/s radio interface rate */
+       case GSM48_CMODE_DATA_6k0:
+               gsm0503_tch_hr48_encode(BUFPOS(bursts_p, 0), msgb_l2(msg));
+               break;
+       /* CSD (TCH/H2.4): 3.6 kbit/s radio interface rate */
+       case GSM48_CMODE_DATA_3k6:
+               gsm0503_tch_hr24_encode(BUFPOS(bursts_p, 0), msgb_l2(msg));
+               break;
+       default:
+               OSMO_ASSERT(0);
        }

        /* free message */
@@ -428,7 +496,7 @@

 send_burst:
        /* compose burst */
-       burst = bursts_p + br->bid * 116;
+       burst = BUFPOS(bursts_p, br->bid);
        memcpy(br->burst + 3, burst, 58);
        memcpy(br->burst + 61, TRX_GMSK_NB_TSC(br), 26);
        memcpy(br->burst + 87, burst + 58, 58);
diff --git a/src/osmo-bts-trx/sched_lchan_xcch.c 
b/src/osmo-bts-trx/sched_lchan_xcch.c
index 87561ea..3c67b23 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/sched_utils.h b/src/osmo-bts-trx/sched_utils.h
index 95f4a77..4521a2e 100644
--- a/src/osmo-bts-trx/sched_utils.h
+++ b/src/osmo-bts-trx/sched_utils.h
@@ -23,6 +23,16 @@

 #include <stdint.h>

+/* Burst Payload LENgth (short alias) */
+#define BPLEN GSM_NBITS_NB_GMSK_PAYLOAD
+
+/* Burst BUFfer capacity (in BPLEN units) */
+#define BUFMAX 24
+
+/* Burst BUFfer position macros */
+#define BUFPOS(buf, n) &buf[(n) * BPLEN]
+#define BUFTAIL8(buf) BUFPOS(buf, (BUFMAX - 8))
+
 extern void *tall_bts_ctx;

 /* Compute the bit error rate in 1/10000 units */
diff --git a/src/osmo-bts-trx/scheduler_trx.c b/src/osmo-bts-trx/scheduler_trx.c
index 7203944..fc44f41 100644
--- a/src/osmo-bts-trx/scheduler_trx.c
+++ b/src/osmo-bts-trx/scheduler_trx.c
@@ -638,6 +638,8 @@

 /* Measurement averaging mode sets: [MODE] = { SHIFT, NUM } */
 static const uint8_t trx_sched_meas_modeset[][2] = {
+       [SCHED_MEAS_AVG_M_S24N22] = { 24, 22 },
+       [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: 17
Gerrit-Owner: fixeria <[email protected]>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: fixeria <[email protected]>
Gerrit-Reviewer: laforge <[email protected]>
Gerrit-Reviewer: pespin <[email protected]>
Gerrit-MessageType: merged

Reply via email to