mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-bts.git
synced 2025-11-03 05:33:26 +00:00
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
This commit is contained in:
@@ -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; /* intermediate rate (8 or 16 kbit/s) for RA2 step */
|
||||
};
|
||||
|
||||
extern const struct csd_v110_lchan_desc csd_v110_lchan_desc[256];
|
||||
|
||||
@@ -37,24 +37,28 @@ const struct csd_v110_lchan_desc csd_v110_lchan_desc[256] = {
|
||||
#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 @@ static const uint8_t e1e2e3_map[_LCHAN_CSD_M_NUM][3] = {
|
||||
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 @@ int csd_v110_rtp_encode(const struct gsm_lchan *lchan, uint8_t *rtp,
|
||||
|
||||
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 @@ ra1_ra2:
|
||||
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 @@ int csd_v110_rtp_decode(const struct gsm_lchan *lchan, uint8_t *data,
|
||||
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);
|
||||
|
||||
@@ -1490,6 +1490,91 @@ static void fr_hr_efr_dtxd_output(struct gsm_lchan *lchan, uint32_t fn,
|
||||
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;
|
||||
const struct csd_v110_lchan_desc *desc;
|
||||
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);
|
||||
|
||||
desc = &csd_v110_lchan_desc[lchan->tch_mode];
|
||||
bits_per_20ms = desc->num_blocks * desc->num_bits;
|
||||
OSMO_ASSERT(bits_per_20ms != 0);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(input_msg); 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 < ARRAY_SIZE(input_msg); 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 {
|
||||
/* IDLE frame, filled with 1 bits */
|
||||
memset(phy_data, 0x01, bits_per_20ms);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
resp_l1sap = &empty_l1sap;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(input_msg); 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 +1600,9 @@ static int l1sap_tch_rts_ind(struct gsm_bts_trx *trx,
|
||||
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 +2016,9 @@ static void gsmtap_csd_rlp_process(struct gsm_lchan *lchan, bool is_uplink,
|
||||
|
||||
}
|
||||
|
||||
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 +2036,91 @@ static void send_ul_rtp_packet_speech(struct gsm_lchan *lchan, uint32_t fn,
|
||||
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)
|
||||
{
|
||||
const struct csd_v110_lchan_desc *desc;
|
||||
unsigned bits_per_20ms;
|
||||
uint8_t rtp_pl[RFC4040_RTP_PLEN];
|
||||
int rc, i;
|
||||
|
||||
desc = &csd_v110_lchan_desc[lchan->tch_mode];
|
||||
bits_per_20ms = desc->num_blocks * desc->num_bits;
|
||||
OSMO_ASSERT(bits_per_20ms != 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 +2136,7 @@ static void send_rtp_rfc5993(struct gsm_lchan *lchan, uint32_t fn,
|
||||
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 +2163,9 @@ static void send_rtp_twts001(struct gsm_lchan *lchan, uint32_t fn,
|
||||
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 +2204,7 @@ static void tch_ul_bfi_handler(struct gsm_lchan *lchan,
|
||||
/* 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 +2212,7 @@ static void tch_ul_bfi_handler(struct gsm_lchan *lchan,
|
||||
/* 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 +2284,7 @@ static int l1sap_tch_ind(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap,
|
||||
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 +2292,14 @@ static int l1sap_tch_ind(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap,
|
||||
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 +2314,11 @@ static int l1sap_tch_ind(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap,
|
||||
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;
|
||||
|
||||
@@ -117,14 +117,7 @@ static const uint8_t sched_tchh_ul_csd_map[26] = {
|
||||
|
||||
/* 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)
|
||||
|
||||
@@ -93,7 +93,7 @@ static const struct test_case tests[] = {
|
||||
|
||||
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 @@ static void exec_test_case(const struct test_case *tc)
|
||||
|
||||
/* 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;
|
||||
|
||||
@@ -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
|
||||
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
|
||||
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
|
||||
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
|
||||
|
||||
Reference in New Issue
Block a user