lists.osmocom.org
Sign In Sign Up
Manage this list Sign In Sign Up

Keyboard Shortcuts

Thread View

  • j: Next unread message
  • k: Previous unread message
  • j a: Jump to all threads
  • j l: Jump to MailingList overview

gerrit-log

Thread Start a new thread
Download
Threads by month
  • ----- 2026 -----
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2025 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2024 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2023 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2022 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
gerrit-log@lists.osmocom.org

October 2024

  • 1 participants
  • 1631 discussions
[S] Change in osmo-bts[master]: csd_v110: set E2 bit correctly for TCH/[FH]4.8 NT
by falconia 27 Oct '24

27 Oct '24
falconia has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-bts/+/38554?usp=email ) Change subject: csd_v110: set E2 bit correctly for TCH/[FH]4.8 NT ...................................................................... csd_v110: set E2 bit correctly for TCH/[FH]4.8 NT In all classic NT modes below 14.5 kbit/s, V.110 frame bits E2 and E3 are repurposed to indicate the alignment whereby a single 240-bit RLP frame is composed of 4 pseudo-V.110 frames in switching transport. (TS 48.020 section 15.1.) In the case of TCH/F9.6, setting both E2 and E3 is easy because all 4 pseudo-V.110 frames go out in the same clearmode RTP packet as a result of a single channel decoding operation. However, in the case of TCH/F4.8 there are two separate channel decoding operations producing two separate RTP packets 20 ms apart. Furthermore, GSM 05.03 section 3.4.1 specifies which TDMA frame positions hold which half of the RLP frame - therefore, the correct emission of bit E2 needs to be based on the TDMA frame number at which the block was received. A similar situation occurs with TCH/H4.8 NT: we receive a single block from the 05.03 decoder every 40 ms, containing a full RLP frame, but we emit it as two separate RTP packets, each carrying 20 ms worth of bits. These RTP packets also require correct setting of E2 bit. Related: OS#6579 Change-Id: I485af5e01ea87c1721a298a486cd344a17884200 --- M include/osmo-bts/csd_v110.h M src/common/csd_v110.c M src/common/l1sap.c M tests/csd/csd_test.c 4 files changed, 30 insertions(+), 10 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-bts refs/changes/54/38554/1 diff --git a/include/osmo-bts/csd_v110.h b/include/osmo-bts/csd_v110.h index d589551..0fcb852 100644 --- a/include/osmo-bts/csd_v110.h +++ b/include/osmo-bts/csd_v110.h @@ -14,6 +14,7 @@ extern const struct csd_v110_lchan_desc csd_v110_lchan_desc[256]; int csd_v110_rtp_encode(const struct gsm_lchan *lchan, uint8_t *rtp, - const uint8_t *data, size_t data_len); + const uint8_t *data, size_t data_len, + uint8_t nt48_half_num); int csd_v110_rtp_decode(const struct gsm_lchan *lchan, uint8_t *data, const uint8_t *rtp, size_t rtp_len); diff --git a/src/common/csd_v110.c b/src/common/csd_v110.c index 7254d2d..cbbb83b 100644 --- a/src/common/csd_v110.c +++ b/src/common/csd_v110.c @@ -78,7 +78,8 @@ }; int csd_v110_rtp_encode(const struct gsm_lchan *lchan, uint8_t *rtp, - const uint8_t *data, size_t data_len) + const uint8_t *data, size_t data_len, + uint8_t nt48_half_num) { const struct csd_v110_lchan_desc *desc; ubit_t ra_bits[80 * 4]; @@ -110,9 +111,15 @@ /* E1 .. E3 must set by out-of-band knowledge */ if (lchan->csd_mode == LCHAN_CSD_M_NT) { /* non-transparent: as per 3GPP TS 48.020, Table 7 */ - df.e_bits[0] = 0; /* E1: as per 15.1.2, shall be set to 0 (for BSS-MSC) */ - df.e_bits[1] = (i >> 1) & 0x01; /* E2: 0 for Q1/Q2, 1 for Q3/Q4 */ - df.e_bits[2] = (i >> 0) & 0x01; /* E3: 0 for Q1/Q3, 1 for Q2/Q4 */ + /* E1: as per 15.1.2, shall be set to 0 (for BSS-MSC) */ + df.e_bits[0] = 0; + /* E2: 0 for Q1/Q2, 1 for Q3/Q4 */ + if (desc->num_blocks == 4) + df.e_bits[1] = (i >> 1) & 0x01; + else + df.e_bits[1] = nt48_half_num; + /* E3: 0 for Q1/Q3, 1 for Q2/Q4 */ + df.e_bits[2] = (i >> 0) & 0x01; } else { /* transparent: as per 3GPP TS 44.021, Figure 4 */ df.e_bits[0] = e1e2e3_map[lchan->csd_mode][0]; /* E1 */ diff --git a/src/common/l1sap.c b/src/common/l1sap.c index e579356..8bcb241 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -2060,15 +2060,27 @@ lchan->rtp_tx_marker = false; } +/* In the case of TCH/F4.8 NT, we have to set bit E2 based on the TDMA + * frame number at which we received the block in question. See + * GSM 05.03 section 3.4.1 and the mapping tables of GSM 05.02. */ +static const uint8_t tchf48_nt_e2_map[26] = { + [4] = 1, /* B1 position */ + [13] = 1, /* B3 position */ + [21] = 1, /* B5 position */ +}; + static void handle_tch_ind_csd_fr(struct gsm_lchan *lchan, const struct ph_tch_param *tch_ind, const uint8_t *data, uint16_t data_len) { uint8_t rtp_pl[RFC4040_RTP_PLEN]; + uint8_t tchf48_half = tchf48_nt_e2_map[tch_ind->fn % 26]; int rc; gsmtap_csd_rlp_process(lchan, true, tch_ind, data, data_len); - rc = csd_v110_rtp_encode(lchan, rtp_pl, data, data_len); + /* the last argument matters only for TCH/F4.8 NT mode, + * ignored in all other cases. */ + rc = csd_v110_rtp_encode(lchan, rtp_pl, data, data_len, tchf48_half); if (rc < 0) return; @@ -2080,7 +2092,7 @@ uint8_t rtp_pl[RFC4040_RTP_PLEN]; int rc, i; - rc = csd_v110_rtp_encode(lchan, rtp_pl, NULL, 0); + rc = csd_v110_rtp_encode(lchan, rtp_pl, NULL, 0, 0); if (rc < 0) return; @@ -2115,7 +2127,7 @@ for (i = 0; i < 2; i++) { rc = csd_v110_rtp_encode(lchan, rtp_pl, data + i * bits_per_20ms, - bits_per_20ms); + bits_per_20ms, i); if (rc < 0) return; send_ul_rtp_packet_hrdata(lchan, rtp_pl, sizeof(rtp_pl)); diff --git a/tests/csd/csd_test.c b/tests/csd/csd_test.c index b6edec9..15ee84f 100644 --- a/tests/csd/csd_test.c +++ b/tests/csd/csd_test.c @@ -124,7 +124,7 @@ data_enc[i] = i & 0x01; /* encode an RTP frame and print it */ - rc = csd_v110_rtp_encode(&lchan, &rtp[0], &data_enc[0], bit_num); + rc = csd_v110_rtp_encode(&lchan, &rtp[0], &data_enc[0], bit_num, 0); fprintf(stderr, "[i] csd_v110_rtp_encode() returns %d\n", rc); if (rc != RFC4040_RTP_PLEN) return; @@ -148,7 +148,7 @@ fprintf(stderr, "[i] Testing '%s' (IDLE)\n", tc->name); /* encode an idle RTP frame and print it */ - rc = csd_v110_rtp_encode(&lchan, &rtp[0], &data_enc[0], 0); + rc = csd_v110_rtp_encode(&lchan, &rtp[0], &data_enc[0], 0, 0); fprintf(stderr, "[i] csd_v110_rtp_encode() returns %d\n", rc); if (rc != RFC4040_RTP_PLEN) return; -- To view, visit https://gerrit.osmocom.org/c/osmo-bts/+/38554?usp=email To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email Gerrit-MessageType: newchange Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Change-Id: I485af5e01ea87c1721a298a486cd344a17884200 Gerrit-Change-Number: 38554 Gerrit-PatchSet: 1 Gerrit-Owner: falconia <falcon(a)freecalypso.org>
1 0
0 0
[L] Change in osmo-bts[master]: CSD: implement half-rate modes correctly
by falconia 27 Oct '24

27 Oct '24
falconia has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-bts/+/38553?usp=email ) Change subject: CSD: implement half-rate modes correctly ...................................................................... CSD: implement half-rate modes correctly TCH/H4.8 and TCH/H2.4 modes are different from all other TCH in that the channel coder runs (statistically) every 40 ms instead of the usual 20 ms. However, the standard RTP interface of TS 48.103 still requires 20 ms packets for all CSD modes; furtherfore, this requirement is not just a matter of 3GPP spec being obstinent, but is highly useful for interoperability, both between FR and HR and between OsmoBTS and E1 BTS. The handling of CSD HR was totally broken in this regard: wrong RA2 packing mode, RTP clock model was violated, and even an internal mismatch with l1sap sending TCH.req prims at twice the rate at which the PHY expects them. With this patch CSD HR handling becomes correct for TCH/H2.4 and for TCH/H4.8 transparent; fully correct handling for TCH/H4.8 NT will appear in a follow-up patch. The packet/frame rate mismatch (40 ms Rx/Tx times while each RTP packet carries 20 ms worth of data) is reconciled by emitting two RTP packets directly back-to-back for UL, and pulling two RTP packets at a time from the Rx jitter buffer at the needed times for DL. Note: due to bug OS#6604, TTCN3 tests for CSD half-rate transparent modes will start failing once this patch is merged; to make them pass again, TTCN3 test code will need to be reworked to fix that bug. Related: OS#6577 Change-Id: Ib35e910df263743cd243f51fb0bd6551ddfcf4c5 --- M include/osmo-bts/csd_v110.h M src/common/csd_v110.c M src/common/l1sap.c M src/osmo-bts-trx/sched_lchan_tchh.c M tests/csd/csd_test.c M tests/csd/csd_test.err 6 files changed, 258 insertions(+), 112 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-bts refs/changes/53/38553/1 diff --git a/include/osmo-bts/csd_v110.h b/include/osmo-bts/csd_v110.h index f6be0ae..d589551 100644 --- a/include/osmo-bts/csd_v110.h +++ b/include/osmo-bts/csd_v110.h @@ -5,14 +5,10 @@ struct gsm_lchan; -struct csd_v110_frame_desc { +struct csd_v110_lchan_desc { uint16_t num_blocks; uint16_t num_bits; -}; - -struct csd_v110_lchan_desc { - struct csd_v110_frame_desc fr; - struct csd_v110_frame_desc hr; + uint8_t ra2_ir; }; extern const struct csd_v110_lchan_desc csd_v110_lchan_desc[256]; diff --git a/src/common/csd_v110.c b/src/common/csd_v110.c index d6c00b0..7254d2d 100644 --- a/src/common/csd_v110.c +++ b/src/common/csd_v110.c @@ -37,24 +37,28 @@ #if 0 [GSM48_CMODE_DATA_14k5] = { /* TCH/F14.4: 290 bits every 20 ms (14.5 kbit/s) */ - .fr = { .num_blocks = 1, .num_bits = 290 }, + .num_blocks = 1, + .num_bits = 290, + .ra2_ir = 16, }, #endif [GSM48_CMODE_DATA_12k0] = { /* TCH/F9.6: 4 * 60 bits every 20 ms (12.0 kbit/s) */ - .fr = { .num_blocks = 4, .num_bits = 60 }, + .num_blocks = 4, + .num_bits = 60, + .ra2_ir = 16, }, [GSM48_CMODE_DATA_6k0] = { - /* TCH/F4.8: 2 * 60 bits every 20 ms (6.0 kbit/s) */ - .fr = { .num_blocks = 2, .num_bits = 60 }, - /* TCH/H4.8: 4 * 60 bits every 40 ms (6.0 kbit/s) */ - .hr = { .num_blocks = 4, .num_bits = 60 }, + /* TCH/[FH]4.8: 2 * 60 bits every 20 ms (6.0 kbit/s) */ + .num_blocks = 2, + .num_bits = 60, + .ra2_ir = 8, }, [GSM48_CMODE_DATA_3k6] = { - /* TCH/F2.4: 2 * 36 bits every 20 ms (3.6 kbit/s) */ - .fr = { .num_blocks = 2, .num_bits = 36 }, - /* TCH/H2.4: 4 * 36 bits every 40 ms (3.6 kbit/s) */ - .hr = { .num_blocks = 4, .num_bits = 36 }, + /* TCH/[FH]2.4: 2 * 36 bits every 20 ms (3.6 kbit/s) */ + .num_blocks = 2, + .num_bits = 36, + .ra2_ir = 8, }, }; @@ -76,14 +80,11 @@ int csd_v110_rtp_encode(const struct gsm_lchan *lchan, uint8_t *rtp, const uint8_t *data, size_t data_len) { - const struct csd_v110_frame_desc *desc; + const struct csd_v110_lchan_desc *desc; ubit_t ra_bits[80 * 4]; OSMO_ASSERT(lchan->tch_mode < ARRAY_SIZE(csd_v110_lchan_desc)); - if (lchan->type == GSM_LCHAN_TCH_F) - desc = &csd_v110_lchan_desc[lchan->tch_mode].fr; - else - desc = &csd_v110_lchan_desc[lchan->tch_mode].hr; + desc = &csd_v110_lchan_desc[lchan->tch_mode]; if (OSMO_UNLIKELY(desc->num_blocks == 0)) return -ENOTSUP; @@ -124,7 +125,7 @@ ra1_ra2: /* RA1/RA2: convert from an intermediate rate to 64 kbit/s */ - if (desc->num_blocks == 4) { + if (desc->ra2_ir == 16) { /* 4 * 80 bits (16 kbit/s) => 2 bits per octet */ for (unsigned int i = 0, j = 0; i < RFC4040_RTP_PLEN; i++) { rtp[i] = (0xff >> 2); @@ -145,14 +146,11 @@ int csd_v110_rtp_decode(const struct gsm_lchan *lchan, uint8_t *data, const uint8_t *rtp, size_t rtp_len) { - const struct csd_v110_frame_desc *desc; + const struct csd_v110_lchan_desc *desc; ubit_t ra_bits[80 * 4]; OSMO_ASSERT(lchan->tch_mode < ARRAY_SIZE(csd_v110_lchan_desc)); - if (lchan->type == GSM_LCHAN_TCH_F) - desc = &csd_v110_lchan_desc[lchan->tch_mode].fr; - else - desc = &csd_v110_lchan_desc[lchan->tch_mode].hr; + desc = &csd_v110_lchan_desc[lchan->tch_mode]; if (OSMO_UNLIKELY(desc->num_blocks == 0)) return -ENOTSUP; @@ -160,7 +158,7 @@ return -EINVAL; /* RA1/RA2: convert from 64 kbit/s to an intermediate rate */ - if (desc->num_blocks == 4) { + if (desc->ra2_ir == 16) { /* 4 * 80 bits (16 kbit/s) => 2 bits per octet */ for (unsigned int i = 0, j = 0; i < RFC4040_RTP_PLEN; i++) { ra_bits[j++] = (rtp[i] >> 7); diff --git a/src/common/l1sap.c b/src/common/l1sap.c index 3157807..e579356 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -1490,6 +1490,95 @@ lchan->tch.dtx_fr_hr_efr.dl_sid_transmitted = true; } +/* TDMA frame number of burst 'a' % 26 is the table index. + * This mapping is valid for both TCH/H(0) and TCH/H(1). */ +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) */ +}; + +/* In the case of half-rate CSD, we need to send TCH.req every 40 ms instead of + * every 20 ms. However, both TS 48.103 and common sense desire for + * interoperability (between FR and HR, between OsmoBTS and E1 BTS) + * require 20 ms RTP packetization interval. Hence a special adapter + * function is needed. */ +static int tch_rts_ind_csd_hr(struct gsm_bts_trx *trx, struct gsm_lchan *lchan, + struct ph_tch_param *rts_ind) +{ + uint8_t chan_nr = rts_ind->chan_nr; + uint32_t fn = rts_ind->fn; + unsigned bits_per_20ms; + struct msgb *input_msg[2], *phy_msg; + struct osmo_phsap_prim *resp_l1sap, empty_l1sap; + uint8_t *phy_data; + struct gsm_time g_time; + int i; + + /* The generic scheduler still sends us TCH-RTS.ind every 20 ms, + * hence we have to filter out half of them here. */ + if (!sched_tchh_dl_csd_map[fn % 26]) + return 0; + + gsm_fn2gsmtime(&g_time, fn); + + switch (lchan->tch_mode) { + case GSM48_CMODE_DATA_6k0: + bits_per_20ms = 60 * 2; + break; + case GSM48_CMODE_DATA_3k6: + bits_per_20ms = 36 * 2; + break; + default: + OSMO_ASSERT(0); + } + + for (i = 0; i < 2; i++) { + if (!lchan->loopback && lchan->abis_ip.rtp_socket) { + osmo_rtp_socket_poll(lchan->abis_ip.rtp_socket); + lchan->abis_ip.rtp_socket->rx_user_ts += GSM_RTP_DURATION; + } + input_msg[i] = msgb_dequeue_count(&lchan->dl_tch_queue, + &lchan->dl_tch_queue_len); + } + + phy_msg = l1sap_msgb_alloc(bits_per_20ms * 2); + if (phy_msg) { + resp_l1sap = msgb_l1sap_prim(phy_msg); + phy_msg->l2h = phy_msg->tail; + for (i = 0; i < 2; i++) { + phy_data = msgb_put(phy_msg, bits_per_20ms); + if (input_msg[i]) + memcpy(phy_data, input_msg[i]->data, bits_per_20ms); + else + memset(phy_data, 0x01, bits_per_20ms); + } + } else { + resp_l1sap = &empty_l1sap; + } + + for (i = 0; i < 2; i++) { + if (input_msg[i]) + msgb_free(input_msg[i]); + } + + memset(resp_l1sap, 0, sizeof(*resp_l1sap)); + osmo_prim_init(&resp_l1sap->oph, SAP_GSM_PH, PRIM_TCH, PRIM_OP_REQUEST, + phy_msg); + resp_l1sap->u.tch.chan_nr = chan_nr; + resp_l1sap->u.tch.fn = fn; + resp_l1sap->u.tch.marker = 0; /* M bit is undefined for clearmode */ + + LOGPLCGT(lchan, &g_time, DL1P, LOGL_DEBUG, "Tx TCH.req\n"); + + l1sap_down(trx, resp_l1sap); + + return 0; +} + /* TCH-RTS-IND prim received from bts model */ static int l1sap_tch_rts_ind(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap, struct ph_tch_param *rts_ind) @@ -1515,6 +1604,9 @@ LOGPLCGT(lchan, &g_time, DL1P, LOGL_DEBUG, "Rx TCH-RTS.ind\n"); } + if (lchan->rsl_cmode == RSL_CMOD_SPD_DATA && lchan->type == GSM_LCHAN_TCH_H) + return tch_rts_ind_csd_hr(trx, lchan, rts_ind); + if (!lchan->loopback && lchan->abis_ip.rtp_socket) { osmo_rtp_socket_poll(lchan->abis_ip.rtp_socket); /* FIXME: we _assume_ that we never miss TDMA @@ -1928,34 +2020,9 @@ } -static void send_ul_rtp_packet_data(struct gsm_lchan *lchan, const struct ph_tch_param *tch_ind, - const uint8_t *data, uint16_t data_len) -{ - struct gsm_bts *bts = lchan->ts->trx->bts; - uint8_t rtp_pl[RFC4040_RTP_PLEN]; - int rc; - - gsmtap_csd_rlp_process(lchan, true, tch_ind, data, data_len); - - rc = csd_v110_rtp_encode(lchan, &rtp_pl[0], data, data_len); - if (rc < 0) - return; - - rate_ctr_inc2(bts->ctrs, BTS_CTR_RTP_TX_TOTAL); - if (lchan->rtp_tx_marker) - rate_ctr_inc2(bts->ctrs, BTS_CTR_RTP_TX_MARKER); - - osmo_rtp_send_frame_ext(lchan->abis_ip.rtp_socket, - &rtp_pl[0], sizeof(rtp_pl), - fn_ms_adj(tch_ind->fn, lchan), - lchan->rtp_tx_marker); - /* Only clear the marker bit once we have sent a RTP packet with it */ - lchan->rtp_tx_marker = false; -} - /* a helper function for the logic in l1sap_tch_ind() */ -static void send_ul_rtp_packet_speech(struct gsm_lchan *lchan, uint32_t fn, - const uint8_t *rtp_pl, uint16_t rtp_pl_len) +static void send_ul_rtp_packet(struct gsm_lchan *lchan, uint32_t fn, + const uint8_t *rtp_pl, uint16_t rtp_pl_len) { struct gsm_bts *bts = lchan->ts->trx->bts; @@ -1973,6 +2040,97 @@ lchan->rtp_tx_marker = false; } +/* A modified version of send_ul_rtp_packet() that skips fn_ms_adj() check: + * this check will produce a lot of noise when we send two RTP packets + * back-to-back every 40 ms on the same frame number, */ +static void send_ul_rtp_packet_hrdata(struct gsm_lchan *lchan, + const uint8_t *rtp_pl, uint16_t rtp_pl_len) +{ + struct gsm_bts *bts = lchan->ts->trx->bts; + + rate_ctr_inc2(bts->ctrs, BTS_CTR_RTP_TX_TOTAL); + if (lchan->rtp_tx_marker) + rate_ctr_inc2(bts->ctrs, BTS_CTR_RTP_TX_MARKER); + + osmo_rtp_send_frame_ext(lchan->abis_ip.rtp_socket, + rtp_pl, rtp_pl_len, + GSM_RTP_DURATION, + lchan->rtp_tx_marker); + /* Only clear the marker bit once we have sent a RTP packet with it */ + lchan->rtp_tx_marker = false; +} + +static void handle_tch_ind_csd_fr(struct gsm_lchan *lchan, const struct ph_tch_param *tch_ind, + const uint8_t *data, uint16_t data_len) +{ + uint8_t rtp_pl[RFC4040_RTP_PLEN]; + int rc; + + gsmtap_csd_rlp_process(lchan, true, tch_ind, data, data_len); + + rc = csd_v110_rtp_encode(lchan, rtp_pl, data, data_len); + if (rc < 0) + return; + + send_ul_rtp_packet(lchan, tch_ind->fn, rtp_pl, sizeof(rtp_pl)); +} + +static void handle_csd_hr_bfi(struct gsm_lchan *lchan) +{ + uint8_t rtp_pl[RFC4040_RTP_PLEN]; + int rc, i; + + rc = csd_v110_rtp_encode(lchan, rtp_pl, NULL, 0); + if (rc < 0) + return; + + for (i = 0; i < 2; i++) + send_ul_rtp_packet_hrdata(lchan, rtp_pl, sizeof(rtp_pl)); +} + +static void handle_tch_ind_csd_hr(struct gsm_lchan *lchan, const struct ph_tch_param *tch_ind, + const uint8_t *data, uint16_t data_len) +{ + unsigned bits_per_20ms; + uint8_t rtp_pl[RFC4040_RTP_PLEN]; + int rc, i; + + switch (lchan->tch_mode) { + case GSM48_CMODE_DATA_6k0: + bits_per_20ms = 60 * 2; + break; + case GSM48_CMODE_DATA_3k6: + bits_per_20ms = 36 * 2; + break; + default: + OSMO_ASSERT(0); + } + + if (data_len != bits_per_20ms * 2) { + handle_csd_hr_bfi(lchan); + return; + } + gsmtap_csd_rlp_process(lchan, true, tch_ind, data, data_len); + + for (i = 0; i < 2; i++) { + rc = csd_v110_rtp_encode(lchan, rtp_pl, + data + i * bits_per_20ms, + bits_per_20ms); + if (rc < 0) + return; + send_ul_rtp_packet_hrdata(lchan, rtp_pl, sizeof(rtp_pl)); + } +} + +static void handle_tch_ind_csd(struct gsm_lchan *lchan, const struct ph_tch_param *tch_ind, + const uint8_t *data, uint16_t data_len) +{ + if (lchan->type == GSM_LCHAN_TCH_F) + handle_tch_ind_csd_fr(lchan, tch_ind, data, data_len); + else + handle_tch_ind_csd_hr(lchan, tch_ind, data, data_len); +} + /* a helper function for emitting HR1 UL in RFC 5993 format */ static void send_rtp_rfc5993(struct gsm_lchan *lchan, uint32_t fn, struct msgb *msg) @@ -1988,7 +2146,7 @@ else toc = 0x00; msgb_push_u8(msg, toc); - send_ul_rtp_packet_speech(lchan, fn, msg->data, msg->len); + send_ul_rtp_packet(lchan, fn, msg->data, msg->len); } /* a helper function for emitting FR/EFR UL in TW-TS-001 format */ @@ -2015,9 +2173,9 @@ teh |= 0x01; if (send_frame) { msgb_push_u8(msg, teh); - send_ul_rtp_packet_speech(lchan, fn, msg->data, msg->len); + send_ul_rtp_packet(lchan, fn, msg->data, msg->len); } else { - send_ul_rtp_packet_speech(lchan, fn, &teh, 1); + send_ul_rtp_packet(lchan, fn, &teh, 1); } } @@ -2056,7 +2214,7 @@ /* did it actually give us some output? */ if (rc > 0) { /* yes, send it out in RTP */ - send_ul_rtp_packet_speech(lchan, fn, ecu_out, rc); + send_ul_rtp_packet(lchan, fn, ecu_out, rc); return; } } @@ -2064,7 +2222,7 @@ /* Are we in rtp continuous-streaming special mode? If so, send out * a BFI packet as zero-length RTP payload. */ if (lchan->ts->trx->bts->rtp_nogaps_mode) { - send_ul_rtp_packet_speech(lchan, fn, NULL, 0); + send_ul_rtp_packet(lchan, fn, NULL, 0); return; } @@ -2136,7 +2294,7 @@ if (lchan->abis_ip.rtp_extensions & OSMO_RTP_EXT_TWTS001) send_rtp_twts001(lchan, fn, msg, true); else - send_ul_rtp_packet_speech(lchan, fn, msg->data, msg->len); + send_ul_rtp_packet(lchan, fn, msg->data, msg->len); } else if (lchan->type == GSM_LCHAN_TCH_H && lchan->tch_mode == GSM48_CMODE_SPEECH_V1) { /* HR codec: TS 101 318 or RFC 5993, @@ -2144,14 +2302,14 @@ if (bts->emit_hr_rfc5993) send_rtp_rfc5993(lchan, fn, msg); else - send_ul_rtp_packet_speech(lchan, fn, msg->data, msg->len); + send_ul_rtp_packet(lchan, fn, msg->data, msg->len); } else { /* generic case, no RTP alterations */ - send_ul_rtp_packet_speech(lchan, fn, msg->data, msg->len); + send_ul_rtp_packet(lchan, fn, msg->data, msg->len); } break; case RSL_CMOD_SPD_DATA: - send_ul_rtp_packet_data(lchan, tch_ind, msg->data, msg->len); + handle_tch_ind_csd(lchan, tch_ind, msg->data, msg->len); break; case RSL_CMOD_SPD_SIGN: return 0; /* drop stale TCH.ind */ @@ -2166,7 +2324,11 @@ return 1; } } else { - tch_ul_bfi_handler(lchan, &g_time, msg); + if (lchan->rsl_cmode == RSL_CMOD_SPD_DATA && + lchan->type == GSM_LCHAN_TCH_H) + handle_csd_hr_bfi(lchan); + else + tch_ul_bfi_handler(lchan, &g_time, msg); } lchan->tch.last_fn = fn; diff --git a/src/osmo-bts-trx/sched_lchan_tchh.c b/src/osmo-bts-trx/sched_lchan_tchh.c index 66244cb..6027072 100644 --- a/src/osmo-bts-trx/sched_lchan_tchh.c +++ b/src/osmo-bts-trx/sched_lchan_tchh.c @@ -117,14 +117,7 @@ /* 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) */ -}; +extern const uint8_t sched_tchh_dl_csd_map[26]; static int decode_hr_facch(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi) diff --git a/tests/csd/csd_test.c b/tests/csd/csd_test.c index 0ad611f..b6edec9 100644 --- a/tests/csd/csd_test.c +++ b/tests/csd/csd_test.c @@ -93,7 +93,7 @@ static void exec_test_case(const struct test_case *tc) { - const struct csd_v110_frame_desc *desc; + const struct csd_v110_lchan_desc *desc; uint8_t rtp[RFC4040_RTP_PLEN] = { 0 }; ubit_t data_enc[BBUF_MAX]; ubit_t data_dec[BBUF_MAX]; @@ -101,10 +101,7 @@ /* obtain a V.110 frame description for the given channel type/rate */ OSMO_ASSERT(tc->tch_mode < ARRAY_SIZE(csd_v110_lchan_desc)); - if (tc->lchan_type == GSM_LCHAN_TCH_F) - desc = &csd_v110_lchan_desc[tc->tch_mode].fr; - else - desc = &csd_v110_lchan_desc[tc->tch_mode].hr; + desc = &csd_v110_lchan_desc[tc->tch_mode]; /* total number of bits carried by a radio interface block */ const unsigned int bit_num = desc->num_bits * desc->num_blocks; diff --git a/tests/csd/csd_test.err b/tests/csd/csd_test.err index cf19aff..1d7a9cf 100644 --- a/tests/csd/csd_test.err +++ b/tests/csd/csd_test.err @@ -99,29 +99,29 @@ ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff -[i] Testing 'TCH/H4.8' (bitnum=240) +[i] Testing 'TCH/H4.8' (bitnum=120) [i] csd_v110_rtp_encode() returns 160 - 3f 3f 3f 3f bf bf bf bf ff 7f 7f 7f bf bf bf bf - ff 7f 7f 7f bf ff 7f 7f bf bf bf bf ff 7f 7f 7f - bf bf bf bf ff 7f 7f 7f 3f 3f 3f 3f bf bf bf bf - ff 7f 7f 7f bf bf bf bf ff 7f 7f 7f bf ff 7f 7f - bf bf bf bf ff 7f 7f 7f bf bf bf bf ff 7f 7f 7f - 3f 3f 3f 3f bf bf bf bf ff 7f 7f 7f bf bf bf bf - ff 7f 7f 7f bf ff 7f 7f bf bf bf bf ff 7f 7f 7f - bf bf bf bf ff 7f 7f 7f 3f 3f 3f 3f bf bf bf bf - ff 7f 7f 7f bf bf bf bf ff 7f 7f 7f bf ff 7f 7f - bf bf bf bf ff 7f 7f 7f bf bf bf bf ff 7f 7f 7f -[i] csd_v110_rtp_decode() returns 240 + 7f 7f 7f 7f 7f 7f 7f 7f ff 7f ff 7f ff 7f ff 7f + ff ff 7f ff 7f ff 7f ff ff 7f ff 7f ff 7f ff 7f + ff ff 7f ff 7f ff 7f ff ff 7f ff ff 7f ff 7f ff + ff 7f ff 7f ff 7f ff 7f ff ff 7f ff 7f ff 7f ff + ff 7f ff 7f ff 7f ff 7f ff ff 7f ff 7f ff 7f ff + 7f 7f 7f 7f 7f 7f 7f 7f ff 7f ff 7f ff 7f ff 7f + ff ff 7f ff 7f ff 7f ff ff 7f ff 7f ff 7f ff 7f + ff ff 7f ff 7f ff 7f ff ff 7f ff ff 7f ff 7f ff + ff 7f ff 7f ff 7f ff 7f ff ff 7f ff 7f ff 7f ff + ff 7f ff 7f ff 7f ff 7f ff ff 7f ff 7f ff 7f ff +[i] csd_v110_rtp_decode() returns 120 [i] Testing 'TCH/H4.8' (IDLE) [i] csd_v110_rtp_encode() returns 160 - 3f 3f 3f 3f ff ff ff ff ff ff ff ff ff ff ff ff - ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff - ff ff ff ff ff ff ff ff 3f 3f 3f 3f ff ff ff ff + 7f 7f 7f 7f 7f 7f 7f 7f ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff - 3f 3f 3f 3f ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff - ff ff ff ff ff ff ff ff 3f 3f 3f 3f ff ff ff ff + ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff + 7f 7f 7f 7f 7f 7f 7f 7f ff ff ff ff ff ff ff ff + ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff + ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff [i] Testing 'TCH/F2.4' (bitnum=72) @@ -149,28 +149,28 @@ ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff -[i] Testing 'TCH/H2.4' (bitnum=144) +[i] Testing 'TCH/H2.4' (bitnum=72) [i] csd_v110_rtp_encode() returns 160 - 3f 3f 3f 3f bf 7f bf 7f bf 7f bf 7f bf 7f bf 7f - bf 7f bf 7f ff 3f 7f 7f bf 7f bf 7f bf 7f bf 7f - bf 7f bf 7f bf 7f bf 7f 3f 3f 3f 3f bf 7f bf 7f - bf 7f bf 7f bf 7f bf 7f bf 7f bf 7f ff 3f 7f 7f - bf 7f bf 7f bf 7f bf 7f bf 7f bf 7f bf 7f bf 7f - 3f 3f 3f 3f bf 7f bf 7f bf 7f bf 7f bf 7f bf 7f - bf 7f bf 7f ff 3f 7f 7f bf 7f bf 7f bf 7f bf 7f - bf 7f bf 7f bf 7f bf 7f 3f 3f 3f 3f bf 7f bf 7f - bf 7f bf 7f bf 7f bf 7f bf 7f bf 7f ff 3f 7f 7f - bf 7f bf 7f bf 7f bf 7f bf 7f bf 7f bf 7f bf 7f -[i] csd_v110_rtp_decode() returns 144 + 7f 7f 7f 7f 7f 7f 7f 7f ff 7f 7f ff ff 7f 7f ff + ff 7f 7f ff ff 7f 7f ff ff 7f 7f ff ff 7f 7f ff + ff 7f 7f ff ff 7f 7f ff ff ff 7f 7f 7f ff 7f ff + ff 7f 7f ff ff 7f 7f ff ff 7f 7f ff ff 7f 7f ff + ff 7f 7f ff ff 7f 7f ff ff 7f 7f ff ff 7f 7f ff + 7f 7f 7f 7f 7f 7f 7f 7f ff 7f 7f ff ff 7f 7f ff + ff 7f 7f ff ff 7f 7f ff ff 7f 7f ff ff 7f 7f ff + ff 7f 7f ff ff 7f 7f ff ff ff 7f 7f 7f ff 7f ff + ff 7f 7f ff ff 7f 7f ff ff 7f 7f ff ff 7f 7f ff + ff 7f 7f ff ff 7f 7f ff ff 7f 7f ff ff 7f 7f ff +[i] csd_v110_rtp_decode() returns 72 [i] Testing 'TCH/H2.4' (IDLE) [i] csd_v110_rtp_encode() returns 160 - 3f 3f 3f 3f ff ff ff ff ff ff ff ff ff ff ff ff - ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff - ff ff ff ff ff ff ff ff 3f 3f 3f 3f ff ff ff ff + 7f 7f 7f 7f 7f 7f 7f 7f ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff - 3f 3f 3f 3f ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff - ff ff ff ff ff ff ff ff 3f 3f 3f 3f ff ff ff ff + ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff + 7f 7f 7f 7f 7f 7f 7f 7f ff ff ff ff ff ff ff ff + ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff + ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff -- To view, visit https://gerrit.osmocom.org/c/osmo-bts/+/38553?usp=email To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email Gerrit-MessageType: newchange Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Change-Id: Ib35e910df263743cd243f51fb0bd6551ddfcf4c5 Gerrit-Change-Number: 38553 Gerrit-PatchSet: 1 Gerrit-Owner: falconia <falcon(a)freecalypso.org>
1 0
0 0
[S] Change in osmo-bts[master]: csd_v110_rtp_decode: preserve E2 & E3 bits for RLP alignment
by falconia 27 Oct '24

27 Oct '24
falconia has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-bts/+/38556?usp=email ) Change subject: csd_v110_rtp_decode: preserve E2 & E3 bits for RLP alignment ...................................................................... csd_v110_rtp_decode: preserve E2 & E3 bits for RLP alignment Modify CSD RTP input path code so incoming bits E2 & E3 from V.110 frames reach the TCH-RTS.ind handler in l1sap. These bits will be used in the next patch to ensure proper alignment of DL RLP frames in non-transparent CSD modes. Related: OS#6579 Change-Id: I43b97caa6030b9401779998ca5dddc4cfe636e2f --- M include/osmo-bts/csd_v110.h M include/osmo-bts/msg_utils.h M src/common/csd_v110.c M src/common/l1sap.c M tests/csd/csd_test.c 5 files changed, 17 insertions(+), 4 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-bts refs/changes/56/38556/1 diff --git a/include/osmo-bts/csd_v110.h b/include/osmo-bts/csd_v110.h index 0fcb852..f5c2658 100644 --- a/include/osmo-bts/csd_v110.h +++ b/include/osmo-bts/csd_v110.h @@ -17,4 +17,4 @@ const uint8_t *data, size_t data_len, uint8_t nt48_half_num); int csd_v110_rtp_decode(const struct gsm_lchan *lchan, uint8_t *data, - const uint8_t *rtp, size_t rtp_len); + uint8_t *align_bits, const uint8_t *rtp, size_t rtp_len); diff --git a/include/osmo-bts/msg_utils.h b/include/osmo-bts/msg_utils.h index fb8e11a..db7142d 100644 --- a/include/osmo-bts/msg_utils.h +++ b/include/osmo-bts/msg_utils.h @@ -25,6 +25,9 @@ /* Access 4th part of msgb control buffer */ #define rtpmsg_is_rfc5993_sid(x) ((x)->cb[3]) +/* Access 5th part of msgb control buffer */ +#define rtpmsg_csd_align_bits(x) ((x)->cb[4]) + /** * Classification of OML message. ETSI for plain GSM 12.21 * messages and IPA/Osmo for manufacturer messages. diff --git a/src/common/csd_v110.c b/src/common/csd_v110.c index edd051e..80cc345 100644 --- a/src/common/csd_v110.c +++ b/src/common/csd_v110.c @@ -167,10 +167,11 @@ } int csd_v110_rtp_decode(const struct gsm_lchan *lchan, uint8_t *data, - const uint8_t *rtp, size_t rtp_len) + uint8_t *align_bits, const uint8_t *rtp, size_t rtp_len) { const struct csd_v110_lchan_desc *desc; ubit_t ra_bits[80 * 4]; + uint8_t align_accum = 0; OSMO_ASSERT(lchan->tch_mode < ARRAY_SIZE(csd_v110_lchan_desc)); desc = &csd_v110_lchan_desc[lchan->tch_mode]; @@ -208,7 +209,13 @@ osmo_csd_12k_6k_encode_frame(&data[i * 60], 60, &df); else /* desc->num_bits == 36 */ osmo_csd_3k6_encode_frame(&data[i * 36], 36, &df); + /* save bits E2 & E3 that may be needed for RLP alignment */ + align_accum <<= 2; + align_accum |= df.e_bits[1] << 1; + align_accum |= df.e_bits[2] << 0; } + if (align_bits) + *align_bits = align_accum; return desc->num_blocks * desc->num_bits; } diff --git a/src/common/l1sap.c b/src/common/l1sap.c index 8bcb241..793b7a8 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -2607,6 +2607,7 @@ struct gsm_bts *bts = lchan->ts->trx->bts; struct msgb *msg; bool rfc5993_sid = false; + uint8_t csd_align_bits = 0; rate_ctr_inc2(bts->ctrs, BTS_CTR_RTP_RX_TOTAL); if (marker) @@ -2641,7 +2642,7 @@ return; if (lchan->rsl_cmode == RSL_CMOD_SPD_DATA) { - int rc = csd_v110_rtp_decode(lchan, msg->tail, + int rc = csd_v110_rtp_decode(lchan, msg->tail, &csd_align_bits, rtp_pl, rtp_pl_len); if (rc > 0) { /* 'fake' tch_ind containing all-zero so gsmtap code can be shared @@ -2674,6 +2675,8 @@ rtpmsg_ts(msg) = timestamp; /* Store RFC 5993 SID flag likewise */ rtpmsg_is_rfc5993_sid(msg) = rfc5993_sid; + /* ditto with CSD alignment bits */ + rtpmsg_csd_align_bits(msg) = csd_align_bits; /* make sure the queue doesn't get too long */ lchan_dl_tch_queue_enqueue(lchan, msg, 1); diff --git a/tests/csd/csd_test.c b/tests/csd/csd_test.c index 15ee84f..e52bde2 100644 --- a/tests/csd/csd_test.c +++ b/tests/csd/csd_test.c @@ -133,7 +133,7 @@ fprintf(stderr, " %s\n", osmo_hexdump(&rtp[i * 16], 16)); /* decode the encoded RTP frame */ - rc = csd_v110_rtp_decode(&lchan, &data_dec[0], &rtp[0], sizeof(rtp)); + rc = csd_v110_rtp_decode(&lchan, &data_dec[0], NULL, &rtp[0], sizeof(rtp)); fprintf(stderr, "[i] csd_v110_rtp_decode() returns %d\n", rc); if (rc != bit_num) return; -- To view, visit https://gerrit.osmocom.org/c/osmo-bts/+/38556?usp=email To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email Gerrit-MessageType: newchange Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Change-Id: I43b97caa6030b9401779998ca5dddc4cfe636e2f Gerrit-Change-Number: 38556 Gerrit-PatchSet: 1 Gerrit-Owner: falconia <falcon(a)freecalypso.org>
1 0
0 0
[L] Change in osmo-bts[master]: CSD NT modes: transmit properly aligned RLP frames on DL
by falconia 27 Oct '24

27 Oct '24
falconia has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-bts/+/38557?usp=email ) Change subject: CSD NT modes: transmit properly aligned RLP frames on DL ...................................................................... CSD NT modes: transmit properly aligned RLP frames on DL There are two levels of alignment inside clearmode RTP packets carrying CSData per TS 48.103 section 5.6: 1) Alignment of 2 or 4 V.110 (T) or pseudo-V.110 (NT) frames within one RTP packet of 160 octets of an imaginary ISDN B channel; 2) For NT modes only, alignment of 4 pseudo-V.110 frames to form a single 240-bit RLP frame. Per previous patch, alignment 1 is to be treated as mandatory for RTP transport inside an Osmocom network. Alignment 2 _could_ be made mandatory for TCH/F9.6 NT, but the same is not possible for TCH/[FH]4.8 NT: in the best case of half-alignment, alternating RTP packets will carry alternating halves of RLP frames. Implemented solution: allow arbitrary state of alignment 2 (aligned or misaligned) in the incoming RTP stream for all CSD NT modes, and perform the necessary alignment internally. This approach is consistent with the world of E1 BTS: a TRAU in data mode is responsible for alignment 1 (with 20 ms TRAU frames taking the place of our clearmode RTP packets), but only the BTS can perform alignment 2, as the TRAU is agnostic to T vs NT distinction. Related: OS#6579 Change-Id: Idaebfce6da13b23ba265a197502712d83991873e --- M include/osmo-bts/Makefile.am A include/osmo-bts/csd_rlp.h M include/osmo-bts/lchan.h M src/common/Makefile.am A src/common/csd_rlp.c M src/common/l1sap.c 6 files changed, 432 insertions(+), 100 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-bts refs/changes/57/38557/1 diff --git a/include/osmo-bts/Makefile.am b/include/osmo-bts/Makefile.am index cbd0fc3..1922f0d 100644 --- a/include/osmo-bts/Makefile.am +++ b/include/osmo-bts/Makefile.am @@ -24,6 +24,7 @@ tx_power.h \ control_if.h \ cbch.h \ + csd_rlp.h \ csd_v110.h \ l1sap.h \ lchan.h \ diff --git a/include/osmo-bts/csd_rlp.h b/include/osmo-bts/csd_rlp.h new file mode 100644 index 0000000..94fa3d2 --- /dev/null +++ b/include/osmo-bts/csd_rlp.h @@ -0,0 +1,36 @@ +/* + * Declarations for functions in csd_rlp.c: alignment of downlink RLP frames + * and RLP GSMTAP mechanism for CSD NT modes. + */ + +#pragma once + +#include <stdint.h> +#include <stdbool.h> +#include <osmocom/core/bits.h> +#include <osmocom/gsm/l1sap.h> +#include <osmo-bts/lchan.h> + +extern const uint8_t csd_tchf48_nt_e2_map[26]; + +/* Per TS 48.020 section 15.1, the cadence of E2+E3 bits in a properly + * aligned sequence of pseudo-V.110 frames forming a single RLP frame + * is 00-01-10-11. The following constant captures this bit sequence + * in hex, for comparison against align_bits output from + * csd_v110_rtp_decode() or against rlpdl_align_bits accumulator + * in CSD NT lchan state. + */ +#define NTCSD_ALIGNED_EBITS 0x1B + +void ntcsd_dl_reset(struct gsm_lchan *lchan); +void ntcsd_dl_input_48(struct gsm_lchan *lchan, const ubit_t *data_bits, + uint8_t align_bits); +void ntcsd_dl_input_96(struct gsm_lchan *lchan, const ubit_t *data_bits, + uint8_t align_bits); +bool ntcsd_dl_output(struct gsm_lchan *lchan, ubit_t *rlp_frame_out); + +void gsmtap_csd_rlp_process(struct gsm_lchan *lchan, bool is_uplink, + const struct ph_tch_param *tch_ind, + const ubit_t *data, unsigned int data_len); +void gsmtap_csd_rlp_dl(struct gsm_lchan *lchan, uint32_t fn, + const ubit_t *data, unsigned int data_len); diff --git a/include/osmo-bts/lchan.h b/include/osmo-bts/lchan.h index df2f4fa..5c34015 100644 --- a/include/osmo-bts/lchan.h +++ b/include/osmo-bts/lchan.h @@ -4,6 +4,7 @@ #include <stdint.h> #include <netinet/in.h> +#include <osmocom/core/bits.h> #include <osmocom/core/timer.h> #include <osmocom/core/linuxlist.h> #include <osmocom/core/logging.h> @@ -295,9 +296,14 @@ uint8_t last_cmr; uint32_t last_fn; struct { - /* buffers to re-combine RLP frame from multiple Um blocks */ + /* RLP GSMTAP mechanism */ uint8_t rlp_buf_ul[576/8]; /* maximum size of RLP frame */ uint8_t rlp_buf_dl[576/8]; /* maximum size of RLP frame */ + /* alignment of RLP frames in DL for NT modes */ + ubit_t rlpdl_data_bits[60 * 7]; + uint16_t rlpdl_align_bits; + uint8_t rlpdl_fill_level; + ubit_t tchf48_nt_2ndhalf[120]; } csd; } tch; diff --git a/src/common/Makefile.am b/src/common/Makefile.am index d13415d..1a62e8e 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -51,6 +51,7 @@ bts_ctrl_commands.c \ bts_ctrl_lookup.c \ bts_shutdown_fsm.c \ + csd_rlp.c \ csd_v110.c \ l1sap.c \ cbch.c \ diff --git a/src/common/csd_rlp.c b/src/common/csd_rlp.c new file mode 100644 index 0000000..349094c --- /dev/null +++ b/src/common/csd_rlp.c @@ -0,0 +1,228 @@ +/* This module has been split from l1sap.c; original header comments preserved: + * + * (C) 2011 by Harald Welte <laforge(a)gnumonks.org> + * (C) 2013 by Andreas Eversberg <jolly(a)eversberg.eu> + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdint.h> +#include <stdbool.h> +#include <string.h> +#include <errno.h> + +#include <osmocom/core/bits.h> +#include <osmocom/core/msgb.h> +#include <osmocom/gsm/l1sap.h> +#include <osmocom/gsm/gsm_utils.h> +#include <osmocom/gsm/rsl.h> +#include <osmocom/gsm/rlp.h> +#include <osmocom/gsm/rtp_extensions.h> +#include <osmocom/core/gsmtap.h> +#include <osmocom/core/gsmtap_util.h> +#include <osmocom/core/utils.h> + +#include <osmo-bts/logging.h> +#include <osmo-bts/gsm_data.h> +#include <osmo-bts/lchan.h> +#include <osmo-bts/bts.h> +#include <osmo-bts/csd_rlp.h> + +/* In the case of TCH/F4.8 NT, each 240-bit RLP frame is split between + * two channel-coding blocks of 120 bits each. We need to know which + * frame numbers correspond to which half: in the UL-to-RTP path we have + * to set bit E2 based on the TDMA frame number at which we received the + * block in question, and in the DL direction we have to transmit the + * right half at the right time. + * + * See GSM 05.03 section 3.4.1 and the mapping tables of GSM 05.02; + * having "e2_map" in the array name shall serve as a mnemonic as to + * the sense of this array: 0 means 1st half and 1 means 2nd half, + * exactly as the value of bit E2 per TS 48.020 section 15.1. + */ +const uint8_t csd_tchf48_nt_e2_map[26] = { + [4] = 1, /* B1 position */ + [13] = 1, /* B3 position */ + [21] = 1, /* B5 position */ +}; + +/* This function resets (clears) the state of the DL alignment buffer. + * It needs to be called when we encounter a gap (packet loss, invalid + * packets, etc) in our RTP input stream. */ +void ntcsd_dl_reset(struct gsm_lchan *lchan) +{ + lchan->tch.csd.rlpdl_fill_level = 0; +} + +/* This function is to be called with the decoded content of a single + * incoming RTP packet (data and alignment bits) for TCH/[FH]4.8 NT. */ +void ntcsd_dl_input_48(struct gsm_lchan *lchan, const ubit_t *data_bits, + uint8_t align_bits) +{ + memmove(lchan->tch.csd.rlpdl_data_bits, + lchan->tch.csd.rlpdl_data_bits + 60 * 2, 60 * 5); + memcpy(lchan->tch.csd.rlpdl_data_bits + 60 * 5, data_bits, 60 * 2); + lchan->tch.csd.rlpdl_align_bits <<= 4; + lchan->tch.csd.rlpdl_align_bits |= (align_bits & 0xF); + lchan->tch.csd.rlpdl_fill_level += 2; + if (lchan->tch.csd.rlpdl_fill_level > 7) + lchan->tch.csd.rlpdl_fill_level = 7; +} + +/* This function is to be called with the decoded content of a single + * incoming RTP packet (data and alignment bits) for TCH/F9.6 NT. */ +void ntcsd_dl_input_96(struct gsm_lchan *lchan, const ubit_t *data_bits, + uint8_t align_bits) +{ + memmove(lchan->tch.csd.rlpdl_data_bits, + lchan->tch.csd.rlpdl_data_bits + 60 * 4, 60 * 3); + memcpy(lchan->tch.csd.rlpdl_data_bits + 60 * 3, data_bits, 60 * 4); + lchan->tch.csd.rlpdl_align_bits <<= 8; + lchan->tch.csd.rlpdl_align_bits |= (align_bits & 0xFF); + lchan->tch.csd.rlpdl_fill_level += 4; + if (lchan->tch.csd.rlpdl_fill_level > 7) + lchan->tch.csd.rlpdl_fill_level = 7; +} + +/* This function is to be called to obtain a complete RLP frame for + * downlink transmission. It will provide either a properly aligned + * frame (return value true) or a filler (return value false). */ +bool ntcsd_dl_output(struct gsm_lchan *lchan, ubit_t *rlp_frame_out) +{ + if (lchan->tch.csd.rlpdl_fill_level < 4) + goto no_frame_out; + if (((lchan->tch.csd.rlpdl_align_bits >> 0) & 0xFF) == NTCSD_ALIGNED_EBITS) { + memcpy(rlp_frame_out, lchan->tch.csd.rlpdl_data_bits + 60 * 3, + 60 * 4); + return true; + } + if (lchan->tch.csd.rlpdl_fill_level < 5) + goto no_frame_out; + if (((lchan->tch.csd.rlpdl_align_bits >> 2) & 0xFF) == NTCSD_ALIGNED_EBITS) { + memcpy(rlp_frame_out, lchan->tch.csd.rlpdl_data_bits + 60 * 2, + 60 * 4); + return true; + } + if (lchan->tch.csd.rlpdl_fill_level < 6) + goto no_frame_out; + if (((lchan->tch.csd.rlpdl_align_bits >> 4) & 0xFF) == NTCSD_ALIGNED_EBITS) { + memcpy(rlp_frame_out, lchan->tch.csd.rlpdl_data_bits + 60 * 1, + 60 * 4); + return true; + } + if (lchan->tch.csd.rlpdl_fill_level < 7) + goto no_frame_out; + if (((lchan->tch.csd.rlpdl_align_bits >> 6) & 0xFF) == NTCSD_ALIGNED_EBITS) { + memcpy(rlp_frame_out, lchan->tch.csd.rlpdl_data_bits, 60 * 4); + return true; + } +no_frame_out: + /* TS 44.021 section 12.1 says that a missing/unavailable 240-bit + * RLP frame is to be filled with 0 bits, unlike ones-fill + * used everywhere else in the world of V.110 and CSD. */ + memset(rlp_frame_out, 0, 60 * 4); + return false; +} + +/* process one MAC block of unpacked bits of a non-transparent CSD channel */ +void gsmtap_csd_rlp_process(struct gsm_lchan *lchan, bool is_uplink, + const struct ph_tch_param *tch_ind, + const ubit_t *data, unsigned int data_len) +{ + struct gsm_bts_trx *trx = lchan->ts->trx; + struct gsmtap_inst *inst = trx->bts->gsmtap.inst; + pbit_t *rlp_buf; + uint16_t arfcn; + int byte_len; + + if (!inst || !trx->bts->gsmtap.rlp) + return; + + if (lchan->csd_mode != LCHAN_CSD_M_NT) + return; + + if (is_uplink) + rlp_buf = lchan->tch.csd.rlp_buf_ul; + else + rlp_buf = lchan->tch.csd.rlp_buf_dl; + + /* TCH/F 9.6: 4x60bit block => 240bit RLP frame + * TCH/F 4.8: 2x 2x60bit blocks starting at B0/B2/B4 => 240bit RLP frame + * TCH/H 4.8: 4x60bit block => 240bit RLP frame + * TCH/F 2.4: 2x36bit blocks => transparent only + * TCH/H 2.4: 4x36bit blocks => transparent only + * TCH/F 14.4: 2x 290 bit block (starting with M1=0) => 576-bit RLP frame + */ + + if (lchan->type == GSM_LCHAN_TCH_F && + lchan->tch_mode == GSM48_CMODE_DATA_6k0 && is_uplink) { + /* In this mode we have 120-bit MAC blocks; two of them need + * to be concatenated to render a 240-bit RLP frame. The first + * block is present in B0/B2/B4, and we have to use FN to + * detect this position. + * This code path is only for UL: in the case of DL, + * alignment logic elsewhere in the code will present us + * with a fully assembled RLP frame. */ + OSMO_ASSERT(data_len == 120); + if (csd_tchf48_nt_e2_map[tch_ind->fn % 26] == 0) { + osmo_ubit2pbit_ext(rlp_buf, 0, data, 0, data_len, 1); + return; + } + osmo_ubit2pbit_ext(rlp_buf, 120, data, 0, data_len, 1); + byte_len = 240/8; + } else if (lchan->type == GSM_LCHAN_TCH_F && lchan->tch_mode == GSM48_CMODE_DATA_14k5) { + /* in this mode we have 290bit MAC blocks containing M1, M2 and 288 data bits; + * two of them need to be concatenated to render a + * 576-bit RLP frame. The start of a RLP frame is + * denoted by a block with M1-bit set to 0. */ + OSMO_ASSERT(data_len == 290); + ubit_t m1 = data[0]; + if (m1 == 0) { + osmo_ubit2pbit_ext(rlp_buf, 0, data, 2, data_len, 1); + return; + } + osmo_ubit2pbit_ext(rlp_buf, 288, data, 2, data_len, 1); + byte_len = 576/8; + } else { + byte_len = osmo_ubit2pbit_ext(rlp_buf, 0, data, 0, data_len, 1); + } + + if (trx->bts->gsmtap.rlp_skip_null) { + struct osmo_rlp_frame_decoded rlpf; + int rc = osmo_rlp_decode(&rlpf, 0, rlp_buf, byte_len); + if (rc == 0 && rlpf.ftype == OSMO_RLP_FT_U && rlpf.u_ftype == OSMO_RLP_U_FT_NULL) + return; + } + + arfcn = trx->arfcn; + if (is_uplink) + arfcn |= GSMTAP_ARFCN_F_UPLINK; + + gsmtap_send_ex(inst, GSMTAP_TYPE_GSM_RLP, arfcn, lchan->ts->nr, + lchan->type == GSM_LCHAN_TCH_H ? GSMTAP_CHANNEL_VOICE_H : GSMTAP_CHANNEL_VOICE_F, + lchan->nr, tch_ind->fn, tch_ind->rssi, 0, rlp_buf, byte_len); + +} + +/* wrapper for downlink path */ +void gsmtap_csd_rlp_dl(struct gsm_lchan *lchan, uint32_t fn, + const ubit_t *data, unsigned int data_len) +{ + /* 'fake' tch_ind containing all-zero so gsmtap code can be shared + * between UL and DL */ + const struct ph_tch_param fake_tch_ind = { .fn = fn }; + gsmtap_csd_rlp_process(lchan, false, &fake_tch_ind, data, data_len); +} diff --git a/src/common/l1sap.c b/src/common/l1sap.c index 793b7a8..6c4eefe 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -60,6 +60,7 @@ #include <osmo-bts/pcuif_proto.h> #include <osmo-bts/cbch.h> #include <osmo-bts/asci.h> +#include <osmo-bts/csd_rlp.h> #include <osmo-bts/csd_v110.h> /* determine the CCCH block number based on the frame number */ @@ -1516,6 +1517,7 @@ struct osmo_phsap_prim *resp_l1sap, empty_l1sap; uint8_t *phy_data; struct gsm_time g_time; + bool good_rlp; int i; /* The generic scheduler still sends us TCH-RTS.ind every 20 ms, @@ -1545,16 +1547,36 @@ &lchan->dl_tch_queue_len); } + if (lchan->csd_mode == LCHAN_CSD_M_NT) { + for (i = 0; i < 2; i++) { + if (input_msg[i]) { + ntcsd_dl_input_48(lchan, input_msg[i]->data, + rtpmsg_csd_align_bits(input_msg[i])); + } else { + ntcsd_dl_reset(lchan); + } + } + } + phy_msg = l1sap_msgb_alloc(bits_per_20ms * 2); if (phy_msg) { resp_l1sap = msgb_l1sap_prim(phy_msg); phy_msg->l2h = phy_msg->tail; - for (i = 0; i < 2; i++) { - phy_data = msgb_put(phy_msg, bits_per_20ms); - if (input_msg[i]) - memcpy(phy_data, input_msg[i]->data, bits_per_20ms); - else - memset(phy_data, 0x01, bits_per_20ms); + if (lchan->csd_mode == LCHAN_CSD_M_NT) { + phy_data = msgb_put(phy_msg, 240); /* RLP frame */ + good_rlp = ntcsd_dl_output(lchan, phy_data); + if (good_rlp) + gsmtap_csd_rlp_dl(lchan, fn, phy_data, 240); + } else { + for (i = 0; i < 2; i++) { + phy_data = msgb_put(phy_msg, bits_per_20ms); + if (input_msg[i]) { + memcpy(phy_data, input_msg[i]->data, + bits_per_20ms); + } else { + memset(phy_data, 0x01, bits_per_20ms); + } + } } } else { resp_l1sap = &empty_l1sap; @@ -1579,6 +1601,111 @@ return 0; } +/* The case of TCH/F4.8 NT also requires special processing that is + * somewhat similar to half-rate CSD. We have to produce an RLP frame + * for DL every 40 ms, thus it makes the most sense for us to poll + * the Rx jitter buffer every 40 ms just like with CSD-HR. However, + * we need to send TCH.req to the PHY every 20 ms, sending either + * the first half or the second half of the RLP frame we put together + * every 40 ms. */ +static int tch_rts_ind_tchf48_nt(struct gsm_bts_trx *trx, + struct gsm_lchan *lchan, + struct ph_tch_param *rts_ind) +{ + uint8_t chan_nr = rts_ind->chan_nr; + uint32_t fn = rts_ind->fn; + struct msgb *input_msg, *phy_msg; + struct osmo_phsap_prim *resp_l1sap, empty_l1sap; + ubit_t rlp_frame[240]; + bool good_rlp; + struct gsm_time g_time; + int i; + + gsm_fn2gsmtime(&g_time, fn); + + /* Input processing happens every 40 ms */ + if (csd_tchf48_nt_e2_map[fn % 26] == 0) { + for (i = 0; i < 2; i++) { + if (!lchan->loopback && lchan->abis_ip.rtp_socket) { + osmo_rtp_socket_poll(lchan->abis_ip.rtp_socket); + lchan->abis_ip.rtp_socket->rx_user_ts += GSM_RTP_DURATION; + } + input_msg = msgb_dequeue_count(&lchan->dl_tch_queue, + &lchan->dl_tch_queue_len); + if (input_msg) { + ntcsd_dl_input_48(lchan, input_msg->data, + rtpmsg_csd_align_bits(input_msg)); + msgb_free(input_msg); + } else { + ntcsd_dl_reset(lchan); + } + } + good_rlp = ntcsd_dl_output(lchan, rlp_frame); + if (good_rlp) + gsmtap_csd_rlp_dl(lchan, fn, rlp_frame, 240); + memcpy(lchan->tch.csd.tchf48_nt_2ndhalf, rlp_frame+120, 120); + } + + /* back to every 20 ms code path */ + phy_msg = l1sap_msgb_alloc(120); /* half of RLP frame */ + if (phy_msg) { + resp_l1sap = msgb_l1sap_prim(phy_msg); + phy_msg->l2h = msgb_put(phy_msg, 120); + if (csd_tchf48_nt_e2_map[fn % 26] == 0) + memcpy(phy_msg->l2h, rlp_frame, 120); + else + memcpy(phy_msg->l2h, lchan->tch.csd.tchf48_nt_2ndhalf, 120); + } else { + resp_l1sap = &empty_l1sap; + } + + memset(resp_l1sap, 0, sizeof(*resp_l1sap)); + osmo_prim_init(&resp_l1sap->oph, SAP_GSM_PH, PRIM_TCH, PRIM_OP_REQUEST, + phy_msg); + resp_l1sap->u.tch.chan_nr = chan_nr; + resp_l1sap->u.tch.fn = fn; + resp_l1sap->u.tch.marker = 0; /* M bit is undefined for clearmode */ + + LOGPLCGT(lchan, &g_time, DL1P, LOGL_DEBUG, "Tx TCH.req\n"); + + l1sap_down(trx, resp_l1sap); + + return 0; +} + +/* For TCH/F9.6 NT we need much less special processing than for TCH/F4.8 NT + * or for CSD-HR, but we still need to handle the possibility of misaligned + * RTP input, i.e., pseudo-V.110 frames aligned in the packet, but not + * forming proper RLP frame alignment via E2 & E3 bits. */ +static void tchf96_nt_dl_alignment(struct gsm_lchan *lchan, struct msgb *msg, + uint32_t fn) +{ + bool good_rlp; + + if (!msg) { + ntcsd_dl_reset(lchan); + /* FIXME: do we really need to generate a PHY packet filled + * with 0 bits to satisfy TS 44.021 section 12.1, or can we + * get by with letting the PHY fill in ones like it does + * for all other CSD modes? */ + return; + } + /* Fast path: handle the good case of already proper alignment */ + if ((rtpmsg_csd_align_bits(msg) & 0xFF) == NTCSD_ALIGNED_EBITS) { + /* clear the buffer in case we have to do misaligned packets + * later, but otherwise let it go! */ + ntcsd_dl_reset(lchan); + gsmtap_csd_rlp_dl(lchan, fn, msgb_l2(msg), msgb_l2len(msg)); + return; + } + /* Slow path: realign like in other NT modes */ + OSMO_ASSERT(msgb_l2len(msg) == 240); + ntcsd_dl_input_96(lchan, msgb_l2(msg), rtpmsg_csd_align_bits(msg)); + good_rlp = ntcsd_dl_output(lchan, msgb_l2(msg)); + if (good_rlp) + gsmtap_csd_rlp_dl(lchan, fn, msgb_l2(msg), msgb_l2len(msg)); +} + /* TCH-RTS-IND prim received from bts model */ static int l1sap_tch_rts_ind(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap, struct ph_tch_param *rts_ind) @@ -1604,8 +1731,14 @@ LOGPLCGT(lchan, &g_time, DL1P, LOGL_DEBUG, "Rx TCH-RTS.ind\n"); } - if (lchan->rsl_cmode == RSL_CMOD_SPD_DATA && lchan->type == GSM_LCHAN_TCH_H) + /* CSD-HR requires special processing */ + if (lchan->rsl_cmode == RSL_CMOD_SPD_DATA && + lchan->type == GSM_LCHAN_TCH_H) return tch_rts_ind_csd_hr(trx, lchan, rts_ind); + /* so does TCH/F4.8 NT mode */ + if (lchan->tch_mode == GSM48_CMODE_DATA_6k0 && + lchan->csd_mode == LCHAN_CSD_M_NT) + return tch_rts_ind_tchf48_nt(trx, lchan, rts_ind); if (!lchan->loopback && lchan->abis_ip.rtp_socket) { osmo_rtp_socket_poll(lchan->abis_ip.rtp_socket); @@ -1653,6 +1786,24 @@ &resp_l1sap, &empty_l1sap); } + /* minimal extra handling for the remaining CSD NT modes */ + if (lchan->rsl_cmode == RSL_CMOD_SPD_DATA && + lchan->csd_mode == LCHAN_CSD_M_NT) { + switch (lchan->tch_mode) { + case GSM48_CMODE_DATA_12k0: + tchf96_nt_dl_alignment(lchan, resp_msg, fn); + break; + case GSM48_CMODE_DATA_14k5: + gsmtap_csd_rlp_dl(lchan, fn, msgb_l2(resp_msg), + msgb_l2len(resp_msg)); + break; + default: + LOGPLCGT(lchan, &g_time, DL1P, LOGL_ERROR, + "Invalid TCH mode in TCH-RTS.ind under CSD NT\n"); + break; + } + } + memset(resp_l1sap, 0, sizeof(*resp_l1sap)); osmo_prim_init(&resp_l1sap->oph, SAP_GSM_PH, PRIM_TCH, PRIM_OP_REQUEST, resp_msg); @@ -1942,84 +2093,6 @@ return 1; } -/* process one MAC block of unpacked bits of a non-transparent CSD channel */ -static void gsmtap_csd_rlp_process(struct gsm_lchan *lchan, bool is_uplink, - const struct ph_tch_param *tch_ind, - const uint8_t *data, unsigned int data_len) -{ - struct gsm_bts_trx *trx = lchan->ts->trx; - struct gsmtap_inst *inst = trx->bts->gsmtap.inst; - pbit_t *rlp_buf; - uint16_t arfcn; - int byte_len; - - if (!inst || !trx->bts->gsmtap.rlp) - return; - - if (lchan->csd_mode != LCHAN_CSD_M_NT) - return; - - if (is_uplink) - rlp_buf = lchan->tch.csd.rlp_buf_ul; - else - rlp_buf = lchan->tch.csd.rlp_buf_dl; - - /* TCH/F 9.6: 4x60bit block => 240bit RLP frame - * TCH/F 4.8: 2x 2x60bit blocks starting at B0/B2/B4 => 240bit RLP frame - * TCH/H 4.8: 4x60bit block => 240bit RLP frame - * TCH/F 2.4: 2x36bit blocks => transparent only - * TCH/H 2.4: 4x36bit blocks => transparent only - * TCH/F 14.4: 2x 290 bit block (starting with M1=0) => 576-bit RLP frame - */ - - if (lchan->type == GSM_LCHAN_TCH_F && lchan->tch_mode == GSM48_CMODE_DATA_6k0) { - /* in this mode we have 120bit MAC blocks; two of them need to be concatenated - * to render a 240-bit RLP frame. The fist block is present in B0/B2/B4. - * The E7 bit is used to indicate the Frame MF0a */ - OSMO_ASSERT(data_len == 120); - ubit_t e7 = data[4*7+3]; - if (e7 == 0) { - osmo_ubit2pbit_ext(rlp_buf, 0, data, 0, data_len, 1); - return; - } else { - osmo_ubit2pbit_ext(rlp_buf, 120, data, 0, data_len, 1); - byte_len = 240/8; - } - } else if (lchan->type == GSM_LCHAN_TCH_F && lchan->tch_mode == GSM48_CMODE_DATA_14k5) { - /* in this mode we have 290bit MAC blocks containing M1, M2 and 288 data bits; - * two of them need to be concatenated to render a - * 576-bit RLP frame. The start of a RLP frame is - * denoted by a block with M1-bit set to 0. */ - OSMO_ASSERT(data_len == 290); - ubit_t m1 = data[0]; - if (m1 == 0) { - osmo_ubit2pbit_ext(rlp_buf, 0, data, 2, data_len, 1); - return; - } else { - osmo_ubit2pbit_ext(rlp_buf, 288, data, 2, data_len, 1); - byte_len = 576/8; - } - } else { - byte_len = osmo_ubit2pbit_ext(rlp_buf, 0, data, 0, data_len, 1); - } - - if (trx->bts->gsmtap.rlp_skip_null) { - struct osmo_rlp_frame_decoded rlpf; - int rc = osmo_rlp_decode(&rlpf, 0, rlp_buf, byte_len); - if (rc == 0 && rlpf.ftype == OSMO_RLP_FT_U && rlpf.u_ftype == OSMO_RLP_U_FT_NULL) - return; - } - - arfcn = trx->arfcn; - if (is_uplink) - arfcn |= GSMTAP_ARFCN_F_UPLINK; - - gsmtap_send_ex(inst, GSMTAP_TYPE_GSM_RLP, arfcn, lchan->ts->nr, - lchan->type == GSM_LCHAN_TCH_H ? GSMTAP_CHANNEL_VOICE_H : GSMTAP_CHANNEL_VOICE_F, - lchan->nr, tch_ind->fn, tch_ind->rssi, 0, rlp_buf, byte_len); - -} - /* a helper function for the logic in l1sap_tch_ind() */ static void send_ul_rtp_packet(struct gsm_lchan *lchan, uint32_t fn, const uint8_t *rtp_pl, uint16_t rtp_pl_len) @@ -2060,20 +2133,11 @@ lchan->rtp_tx_marker = false; } -/* In the case of TCH/F4.8 NT, we have to set bit E2 based on the TDMA - * frame number at which we received the block in question. See - * GSM 05.03 section 3.4.1 and the mapping tables of GSM 05.02. */ -static const uint8_t tchf48_nt_e2_map[26] = { - [4] = 1, /* B1 position */ - [13] = 1, /* B3 position */ - [21] = 1, /* B5 position */ -}; - static void handle_tch_ind_csd_fr(struct gsm_lchan *lchan, const struct ph_tch_param *tch_ind, const uint8_t *data, uint16_t data_len) { uint8_t rtp_pl[RFC4040_RTP_PLEN]; - uint8_t tchf48_half = tchf48_nt_e2_map[tch_ind->fn % 26]; + uint8_t tchf48_half = csd_tchf48_nt_e2_map[tch_ind->fn % 26]; int rc; gsmtap_csd_rlp_process(lchan, true, tch_ind, data, data_len); @@ -2645,10 +2709,6 @@ int rc = csd_v110_rtp_decode(lchan, msg->tail, &csd_align_bits, rtp_pl, rtp_pl_len); if (rc > 0) { - /* 'fake' tch_ind containing all-zero so gsmtap code can be shared - * between UL and DL */ - static const struct ph_tch_param fake_tch_ind = {}; - gsmtap_csd_rlp_process(lchan, false, &fake_tch_ind, msg->tail, rc); msgb_put(msg, rc); } else { rate_ctr_inc2(bts->ctrs, BTS_CTR_RTP_RX_DROP_V110_DEC); -- To view, visit https://gerrit.osmocom.org/c/osmo-bts/+/38557?usp=email To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email Gerrit-MessageType: newchange Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Change-Id: Idaebfce6da13b23ba265a197502712d83991873e Gerrit-Change-Number: 38557 Gerrit-PatchSet: 1 Gerrit-Owner: falconia <falcon(a)freecalypso.org>
1 0
0 0
[L] Change in osmo-hlr[master]: gsupclient: Introduce gsup_client_mux
by lynxis lazus 27 Oct '24

27 Oct '24
lynxis lazus has posted comments on this change by lynxis lazus. ( https://gerrit.osmocom.org/c/osmo-hlr/+/38112?usp=email ) Change subject: gsupclient: Introduce gsup_client_mux ...................................................................... Patch Set 5: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/c/osmo-hlr/+/38112?usp=email To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email Gerrit-MessageType: comment Gerrit-Project: osmo-hlr Gerrit-Branch: master Gerrit-Change-Id: I916c1bb6cfc48f92fc5db2b5c914eb1b4e25fa7f Gerrit-Change-Number: 38112 Gerrit-PatchSet: 5 Gerrit-Owner: lynxis lazus <lynxis(a)fe80.eu> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-Reviewer: lynxis lazus <lynxis(a)fe80.eu> Gerrit-Reviewer: pespin <pespin(a)sysmocom.de> Gerrit-Comment-Date: Sun, 27 Oct 2024 14:41:05 +0000 Gerrit-HasComments: No Gerrit-Has-Labels: Yes
1 0
0 0
[XS] Change in pysim[master]: pySim-shell_test/utils: delete log files in general
by laforge 26 Oct '24

26 Oct '24
laforge has submitted this change. ( https://gerrit.osmocom.org/c/pysim/+/38543?usp=email ) Change subject: pySim-shell_test/utils: delete log files in general ...................................................................... pySim-shell_test/utils: delete log files in general When we get rid of temporary files, we delete those using a wildcard, but for the logs from pySim-shell we explicitly memorize the name of the pySim-shell logfile and delete it later by this explicit name. This is not necessary, let's just delete all log files present using a wildcard. Related: OS#6601 Change-Id: I09dc7e59d1a3dcb68f54e3a8dccb86a1bc6c9ee6 --- M tests/pySim-shell_test/utils.py 1 file changed, 1 insertion(+), 2 deletions(-) Approvals: laforge: Looks good to me, approved Jenkins Builder: Verified osmith: Looks good to me, but someone else must approve diff --git a/tests/pySim-shell_test/utils.py b/tests/pySim-shell_test/utils.py index fe8386a..943eb48 100644 --- a/tests/pySim-shell_test/utils.py +++ b/tests/pySim-shell_test/utils.py @@ -220,7 +220,7 @@ print("testcase execution done -- cleaning up ...") if not self.keepfiles: os.system("rm -f ./*.tmp") - os.system("rm -f ./" + self.__pySim_shell_logfile_name) + os.system("rm -f ./*.log") for template in self.__templates_generated: os.system("rm -f ./" + template) @@ -241,7 +241,6 @@ """ logfile_name = "pySim-shell_" + self._testMethodName + ".log" - self.__pySim_shell_logfile_name = logfile_name # Make sure the script file is available if not os.access(script, os.R_OK): -- To view, visit https://gerrit.osmocom.org/c/pysim/+/38543?usp=email To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email Gerrit-MessageType: merged Gerrit-Project: pysim Gerrit-Branch: master Gerrit-Change-Id: I09dc7e59d1a3dcb68f54e3a8dccb86a1bc6c9ee6 Gerrit-Change-Number: 38543 Gerrit-PatchSet: 2 Gerrit-Owner: dexter <pmaier(a)sysmocom.de> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-Reviewer: osmith <osmith(a)sysmocom.de>
1 0
0 0
[XS] Change in pysim[master]: pySim-shell_test/utils: display pySim-shell logfile content
by laforge 26 Oct '24

26 Oct '24
laforge has submitted this change. ( https://gerrit.osmocom.org/c/pysim/+/38545?usp=email ) Change subject: pySim-shell_test/utils: display pySim-shell logfile content ...................................................................... pySim-shell_test/utils: display pySim-shell logfile content When we configure the tests to display file content, we only display files that we compare, let's also display log file contents from pySim-shell. This will be useful in situations where we only have log output from the tests, but no access to the file system of the test host. Related: OS#6601 Change-Id: Ibf6f78d7e71c213c7ca1caaf21c4c890e892261e --- M tests/pySim-shell_test/utils.py 1 file changed, 5 insertions(+), 0 deletions(-) Approvals: laforge: Looks good to me, approved osmith: Looks good to me, but someone else must approve Jenkins Builder: Verified diff --git a/tests/pySim-shell_test/utils.py b/tests/pySim-shell_test/utils.py index 6acbd70..348c9b1 100644 --- a/tests/pySim-shell_test/utils.py +++ b/tests/pySim-shell_test/utils.py @@ -272,6 +272,11 @@ # Check for exceptions logfile = open(logfile_name) logfile_content = logfile.read() + if self.print_content: + print("pySim-shell logfile content: (%s)" % os.path.basename(logfile_name)) + print("-----------------------8<-----------------------") + print(logfile_content) + print("-----------------------8<-----------------------") logfile.close() exception_regex_compiled = re.compile('.*EXCEPTION.*') exceptions_strings = re.findall(exception_regex_compiled, logfile_content) -- To view, visit https://gerrit.osmocom.org/c/pysim/+/38545?usp=email To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email Gerrit-MessageType: merged Gerrit-Project: pysim Gerrit-Branch: master Gerrit-Change-Id: Ibf6f78d7e71c213c7ca1caaf21c4c890e892261e Gerrit-Change-Number: 38545 Gerrit-PatchSet: 2 Gerrit-Owner: dexter <pmaier(a)sysmocom.de> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-Reviewer: osmith <osmith(a)sysmocom.de>
1 0
0 0
[XS] Change in pysim[master]: pySim-shell_test/utils: enumerate pySim-shell logs
by laforge 26 Oct '24

26 Oct '24
laforge has submitted this change. ( https://gerrit.osmocom.org/c/pysim/+/38544?usp=email ) Change subject: pySim-shell_test/utils: enumerate pySim-shell logs ...................................................................... pySim-shell_test/utils: enumerate pySim-shell logs When pySim-shell is called by a testcase, a logfile is createted. The logfile filename contains the testcase name. However, a testcase may run pySim-shell multiple times. In this case we overwrite the log from previous run. Let's use a counter to generate unique file names for each run, so that we won't lose logs from previous runs. Related: OS#6601 Change-Id: Ib2195d9b2231f74d0a6c4fb28f4889b6c45efb1e --- M tests/pySim-shell_test/utils.py 1 file changed, 3 insertions(+), 1 deletion(-) Approvals: Jenkins Builder: Verified osmith: Looks good to me, but someone else must approve laforge: Looks good to me, approved diff --git a/tests/pySim-shell_test/utils.py b/tests/pySim-shell_test/utils.py index 943eb48..6acbd70 100644 --- a/tests/pySim-shell_test/utils.py +++ b/tests/pySim-shell_test/utils.py @@ -170,6 +170,7 @@ testcasepath = inspect.getfile(self.__class__) testcasename = testcasepath.split("/")[-2] + "." + self._testMethodName print(boxed_heading_str("testcase: " + testcasename)) + self.pysim_shell_log_counter = 0 # Find directories self.test_dir = os.path.dirname(testcasepath) @@ -240,7 +241,8 @@ no_exceptions : fail the testcase in case any exceptions occurred while running pySim_shell """ - logfile_name = "pySim-shell_" + self._testMethodName + ".log" + logfile_name = "pySim-shell_" + self._testMethodName + "_" + str(self.pysim_shell_log_counter) + ".log" + self.pysim_shell_log_counter+=1 # Make sure the script file is available if not os.access(script, os.R_OK): -- To view, visit https://gerrit.osmocom.org/c/pysim/+/38544?usp=email To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email Gerrit-MessageType: merged Gerrit-Project: pysim Gerrit-Branch: master Gerrit-Change-Id: Ib2195d9b2231f74d0a6c4fb28f4889b6c45efb1e Gerrit-Change-Number: 38544 Gerrit-PatchSet: 2 Gerrit-Owner: dexter <pmaier(a)sysmocom.de> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-Reviewer: osmith <osmith(a)sysmocom.de>
1 0
0 0
[XS] Change in pysim[master]: pySim-shell_test/utils: display pySim-shell logfile content
by laforge 26 Oct '24

26 Oct '24
Attention is currently required from: dexter. laforge has posted comments on this change by dexter. ( https://gerrit.osmocom.org/c/pysim/+/38545?usp=email ) Change subject: pySim-shell_test/utils: display pySim-shell logfile content ...................................................................... Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/c/pysim/+/38545?usp=email To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email Gerrit-MessageType: comment Gerrit-Project: pysim Gerrit-Branch: master Gerrit-Change-Id: Ibf6f78d7e71c213c7ca1caaf21c4c890e892261e Gerrit-Change-Number: 38545 Gerrit-PatchSet: 1 Gerrit-Owner: dexter <pmaier(a)sysmocom.de> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-Reviewer: osmith <osmith(a)sysmocom.de> Gerrit-Attention: dexter <pmaier(a)sysmocom.de> Gerrit-Comment-Date: Fri, 25 Oct 2024 23:41:25 +0000 Gerrit-HasComments: No Gerrit-Has-Labels: Yes
1 0
0 0
[XS] Change in pysim[master]: pySim-shell_test/utils: enumerate pySim-shell logs
by laforge 26 Oct '24

26 Oct '24
Attention is currently required from: dexter. laforge has posted comments on this change by dexter. ( https://gerrit.osmocom.org/c/pysim/+/38544?usp=email ) Change subject: pySim-shell_test/utils: enumerate pySim-shell logs ...................................................................... Patch Set 1: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/c/pysim/+/38544?usp=email To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email Gerrit-MessageType: comment Gerrit-Project: pysim Gerrit-Branch: master Gerrit-Change-Id: Ib2195d9b2231f74d0a6c4fb28f4889b6c45efb1e Gerrit-Change-Number: 38544 Gerrit-PatchSet: 1 Gerrit-Owner: dexter <pmaier(a)sysmocom.de> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-Reviewer: osmith <osmith(a)sysmocom.de> Gerrit-Attention: dexter <pmaier(a)sysmocom.de> Gerrit-Comment-Date: Fri, 25 Oct 2024 23:41:18 +0000 Gerrit-HasComments: No Gerrit-Has-Labels: Yes
1 0
0 0
  • ← Newer
  • 1
  • ...
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • ...
  • 164
  • Older →

HyperKitty Powered by HyperKitty version 1.3.12.