diff --git a/TODO-RELEASE b/TODO-RELEASE index 81aa83401..ac45e9ff2 100644 --- a/TODO-RELEASE +++ b/TODO-RELEASE @@ -8,3 +8,4 @@ # If any interfaces have been removed or changed since the last public release: c:r:0. #library what description / commit summary line libosmotrau >1.6.0 osmo_csd_ra2_{16k,8k}_{pack,unpack}() API +libosmotrau >1.6.0 osmo_csd144_{to,from}_atrau_bits() API diff --git a/src/common/bts.c b/src/common/bts.c index 633e0d13f..282d7302d 100644 --- a/src/common/bts.c +++ b/src/common/bts.c @@ -896,8 +896,8 @@ static bool bts_supports_cm_data(const struct gsm_bts *bts, switch (bts->variant) { case BTS_OSMO_TRX: switch (cm->chan_rate) { - /* TODO: RSL_CMOD_CSD_NT_14k5 */ - /* TODO: RSL_CMOD_CSD_T_14k4 */ + case RSL_CMOD_CSD_NT_14k5: + case RSL_CMOD_CSD_T_14k4: case RSL_CMOD_CSD_NT_12k0: case RSL_CMOD_CSD_T_9k6: if (cm->chan_rt != RSL_CMOD_CRT_TCH_Bm) diff --git a/src/common/csd_v110.c b/src/common/csd_v110.c index 9bbc5fe70..9ba3df312 100644 --- a/src/common/csd_v110.c +++ b/src/common/csd_v110.c @@ -30,13 +30,13 @@ #include #include #include +#include #include #include /* key is enum gsm48_chan_mode, so assuming a value in range 0..255 */ const struct csd_v110_lchan_desc csd_v110_lchan_desc[256] = { -#if 0 [GSM48_CMODE_DATA_14k5] = { /* TCH/F14.4: 8 * 36 + 2 bits every 20 ms (14.5 kbit/s) */ .num_frames = 8, @@ -44,7 +44,6 @@ const struct csd_v110_lchan_desc csd_v110_lchan_desc[256] = { .num_other_bits = 2, /* M-bits */ .ra2_ir = 16, }, -#endif [GSM48_CMODE_DATA_12k0] = { /* TCH/F9.6: 4 * 60 bits every 20 ms (12.0 kbit/s) */ .num_frames = 4, @@ -92,6 +91,32 @@ int csd_v110_rtp_encode(const struct gsm_lchan *lchan, uint8_t *rtp, if (OSMO_UNLIKELY(desc->num_frames == 0)) return -ENOTSUP; + /* TCH/F14.4 is special: RAA' function is employed */ + if (lchan->tch_mode == GSM48_CMODE_DATA_14k5) { + /* 3GPP TS 44.021, section 10.3 "TCH/F14.4 channel coding" + * 3GPP TS 48.020, chapter 11 "THE RAA' FUNCTION" */ + const ubit_t *m_bits = &data[0]; /* M-bits */ + const ubit_t *d_bits = &data[2]; /* D-bits */ + ubit_t c4, c5; + + /* 3GPP TS 48.020, Table 3 + * | C4 | Date Rate | + * | =1 | 14,4 kbit/s | + * | =0 | 14.4 kbit/s idle (IWF to BSS only) | */ + c4 = 1; + /* 3GPP TS 48.020, Table 4 + * | C5 | BSS to IWF FT | IWF to BSS UFE | + * | =1 | idle | framing error | + * | =0 | data | no framing error | */ + c5 = 0; + + /* Unless there is a bug, it's highly unlikely */ + OSMO_ASSERT(data_len == CSD_V110_NUM_BITS(desc)); + + osmo_csd144_to_atrau_bits(&ra_bits[0], m_bits, d_bits, c4, c5); + goto ra1_ra2; + } + /* handle empty/incomplete Uplink frames gracefully */ if (OSMO_UNLIKELY(data_len < CSD_V110_NUM_BITS(desc))) { /* encode N idle frames as per 3GPP TS 44.021, section 8.1.6 */ @@ -178,6 +203,18 @@ int csd_v110_rtp_decode(const struct gsm_lchan *lchan, uint8_t *data, else /* desc->ra2_ir == 8 */ osmo_csd_ra2_8k_unpack(&ra_bits[0], &rtp[0], RFC4040_RTP_PLEN); + /* TCH/F14.4 is special: RAA' function is employed */ + if (lchan->tch_mode == GSM48_CMODE_DATA_14k5) { + /* 3GPP TS 44.021, section 10.3 "TCH/F14.4 channel coding" + * 3GPP TS 48.020, chapter 11 "THE RAA' FUNCTION" */ + ubit_t *m_bits = &data[0]; /* M-bits */ + ubit_t *d_bits = &data[2]; /* D-bits */ + int rc; + + rc = osmo_csd144_from_atrau_bits(m_bits, d_bits, NULL, NULL, &ra_bits[0]); + return rc == 0 ? CSD_V110_NUM_BITS(desc) : rc; + } + /* RA1'/RA1: convert from an intermediate rate to radio rate */ for (unsigned int i = 0; i < desc->num_frames; i++) { struct osmo_v110_decoded_frame df; diff --git a/src/osmo-bts-trx/main.c b/src/osmo-bts-trx/main.c index ddc44285b..c870dfbb8 100644 --- a/src/osmo-bts-trx/main.c +++ b/src/osmo-bts-trx/main.c @@ -196,9 +196,6 @@ int bts_model_trx_init(struct gsm_bts_trx *trx) trx->support.chan_modes = NM_IPAC_MASK_CHANM_SPEECH | NM_IPAC_MASK_CHANM_CSD_NT | NM_IPAC_MASK_CHANM_CSD_T; - /* TODO: missing rate adaptation for TCH/F14.4 (see OS#6167) */ - trx->support.chan_modes &= ~NM_IPAC_F_CHANM_CSD_T_14k4; - trx->support.chan_modes &= ~NM_IPAC_F_CHANM_CSD_NT_14k4; /* The nominal value for each TRX is later overwritten through VTY cmd * 'nominal-tx-power' if present, otherwise through TRXC cmd NOMTXPOWER. diff --git a/src/osmo-bts-virtual/main.c b/src/osmo-bts-virtual/main.c index 82becc37f..932005cec 100644 --- a/src/osmo-bts-virtual/main.c +++ b/src/osmo-bts-virtual/main.c @@ -99,9 +99,6 @@ int bts_model_trx_init(struct gsm_bts_trx *trx) trx->support.chan_modes = NM_IPAC_MASK_CHANM_SPEECH | NM_IPAC_MASK_CHANM_CSD_NT | NM_IPAC_MASK_CHANM_CSD_T; - /* TODO: missing rate adaptation for TCH/F14.4 (see OS#6167) */ - trx->support.chan_modes &= ~NM_IPAC_F_CHANM_CSD_T_14k4; - trx->support.chan_modes &= ~NM_IPAC_F_CHANM_CSD_NT_14k4; return 0; } diff --git a/tests/csd/csd_test.c b/tests/csd/csd_test.c index c46bbd97b..ad78162b1 100644 --- a/tests/csd/csd_test.c +++ b/tests/csd/csd_test.c @@ -145,6 +145,10 @@ static void exec_test_case(const struct test_case *tc) i, data_dec[i], data_enc[i]); } + /* for TCH/F14.4, we always expect a valid block */ + if (tc->tch_mode == GSM48_CMODE_DATA_14k5) + return; + fprintf(stderr, "[i] Testing '%s' (IDLE)\n", tc->name); /* encode an idle RTP frame and print it */ diff --git a/tests/csd/csd_test.err b/tests/csd/csd_test.err index 1d7a9cfda..cb1eac21a 100644 --- a/tests/csd/csd_test.err +++ b/tests/csd/csd_test.err @@ -1,4 +1,16 @@ -[i] Skipping 'TCH/F14.4' (not implemented) +[i] Testing 'TCH/F14.4' (bitnum=290) +[i] csd_v110_rtp_encode() returns 160 + 3f 3f 3f 3f 3f 3f 3f 3f bf ff bf 7f bf bf bf bf + bf bf bf bf bf bf bf bf bf bf bf bf bf bf ff 7f + 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f + 7f bf bf bf bf bf bf bf bf bf bf bf bf bf bf bf + bf bf bf ff 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f + 7f 7f 7f 7f 7f 7f bf bf bf bf bf bf bf bf bf bf + bf bf bf bf bf bf bf bf ff 7f 7f 7f 7f 7f 7f 7f + 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f bf bf bf bf bf + bf bf bf bf bf bf bf bf bf bf bf bf bf ff 7f 7f + 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f +[i] csd_v110_rtp_decode() returns 290 [i] Testing 'TCH/F9.6' (bitnum=240) [i] csd_v110_rtp_encode() returns 160 3f 3f 3f 3f bf bf bf bf ff 7f 7f 7f bf bf bf bf