diff --git a/include/osmo-bts/scheduler.h b/include/osmo-bts/scheduler.h index 4d76b9bf4..23d01fb8a 100644 --- a/include/osmo-bts/scheduler.h +++ b/include/osmo-bts/scheduler.h @@ -94,7 +94,7 @@ struct l1sched_chan_state { 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 @@ struct l1sched_chan_state { /* 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 @@ int trx_sched_ul_burst(struct l1sched_ts *l1ts, struct trx_ul_burst_ind *bi); /* 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 2e73ad4ff..6a07ea5db 100644 --- a/src/common/bts.c +++ b/src/common/bts.c @@ -780,23 +780,11 @@ struct gsm_time *get_time(struct gsm_bts *bts) 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 @@ bool bts_supports_cm(const struct gsm_bts *bts, 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 007dd7c92..e68d01f0f 100644 --- a/src/common/scheduler.c +++ b/src/common/scheduler.c @@ -1079,9 +1079,9 @@ static void _trx_sched_set_lchan(struct gsm_lchan *lchan, 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 2aa43f975..fd813b9b4 100644 --- a/src/osmo-bts-trx/sched_lchan_pdtch.c +++ b/src/osmo-bts-trx/sched_lchan_pdtch.c @@ -44,7 +44,7 @@ int rx_pdtch_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi) 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 444cda2a8..ac9a15c6f 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 * (C) 2015-2017 by Harald Welte - * Contributions by sysmocom - s.f.m.c. GmbH + * (C) 2020-2023 by sysmocom - s.f.m.c. GmbH * * All Rights Reserved * @@ -75,10 +75,10 @@ int rx_tchf_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[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 @@ int rx_tchf_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi) /* 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 @@ int rx_tchf_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi) /* 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 @@ int rx_tchf_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi) 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 @@ int rx_tchf_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi) * 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); @@ -218,6 +221,33 @@ int rx_tchf_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi) ft, AMR_GOOD); } + 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, @@ -271,7 +301,7 @@ int rx_tchf_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi) 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 @@ struct msgb *tch_dl_dequeue(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br 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 @@ int tx_tchf_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br) /* 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 @@ int tx_tchf_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br) 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 @@ int tx_tchf_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br) 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 541feab82..6ab4c319e 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 * (C) 2015-2017 by Harald Welte - * Contributions by sysmocom - s.f.m.c. GmbH + * (C) 2020-2023 by sysmocom - s.f.m.c. GmbH * * All Rights Reserved * @@ -91,16 +91,51 @@ static const uint8_t sched_tchh_ul_facch_map[26] = { /* 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 @@ int rx_tchh_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi) /* 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 @@ int rx_tchh_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi) /* 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 @@ int rx_tchh_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi) 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 @@ int rx_tchh_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi) /* 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, @@ -254,6 +290,22 @@ int rx_tchh_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi) ft, AMR_GOOD); } + 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, @@ -308,7 +360,7 @@ bfi: 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 @@ int tx_tchh_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br) /* 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 @@ int tx_tchh_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br) 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 @@ int tx_tchh_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br) 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 87561ea60..3c67b2339 100644 --- a/src/osmo-bts-trx/sched_lchan_xcch.c +++ b/src/osmo-bts-trx/sched_lchan_xcch.c @@ -52,7 +52,7 @@ int rx_data_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi) 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 95f4a77f2..4521a2eb3 100644 --- a/src/osmo-bts-trx/sched_utils.h +++ b/src/osmo-bts-trx/sched_utils.h @@ -23,6 +23,16 @@ #include +/* 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 720394478..fc44f412c 100644 --- a/src/osmo-bts-trx/scheduler_trx.c +++ b/src/osmo-bts-trx/scheduler_trx.c @@ -638,6 +638,8 @@ void trx_sched_meas_push(struct l1sched_chan_state *chan_state, /* 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 },