TRX: Add support for EFR transcoding
This commit is contained in:
parent
84b9a44535
commit
917cf7018b
|
@ -300,7 +300,7 @@ int pdtch_encode(ubit_t *bursts, uint8_t *l2_data, uint8_t l2_len)
|
|||
|
||||
|
||||
/*
|
||||
* GSM TCH/F FR transcoding
|
||||
* GSM TCH/F FR/EFR transcoding
|
||||
*/
|
||||
|
||||
static void tch_fr_reassemble(uint8_t *tch_data, ubit_t *b_bits, int net_order)
|
||||
|
@ -338,6 +338,35 @@ static void tch_fr_reassemble(uint8_t *tch_data, ubit_t *b_bits, int net_order)
|
|||
}
|
||||
}
|
||||
|
||||
static void tch_efr_reassemble(uint8_t *tch_data, ubit_t *b_bits)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
tch_data[0] = 0xc << 4;
|
||||
memset(tch_data + 1, 0, 30);
|
||||
|
||||
i = 0; /* counts bits */
|
||||
j = 4; /* counts output bits */
|
||||
while (i < 244) {
|
||||
tch_data[j>>3] |= (b_bits[i] << (7-(j&7)));
|
||||
i++;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
static void tch_efr_disassemble(ubit_t *b_bits, uint8_t *tch_data)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
i = 0; /* counts bits */
|
||||
j = 4; /* counts output bits */
|
||||
while (i < 244) {
|
||||
b_bits[i] = (tch_data[j>>3] >> (7-(j&7))) & 1;
|
||||
i++;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
static void tch_fr_disassemble(ubit_t *b_bits, uint8_t *tch_data, int net_order)
|
||||
{
|
||||
int i, j, k, l, o;
|
||||
|
@ -386,6 +415,30 @@ static void tch_fr_b_to_d(ubit_t *d_bits, ubit_t *b_bits)
|
|||
d_bits[i] = b_bits[gsm610_bitorder[i]];
|
||||
}
|
||||
|
||||
static void tch_efr_d_to_w(ubit_t *b_bits, ubit_t *d_bits)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 260; i++)
|
||||
b_bits[gsm660_bitorder[i]] = d_bits[i];
|
||||
}
|
||||
|
||||
static void tch_efr_w_to_d(ubit_t *d_bits, ubit_t *b_bits)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 260; i++)
|
||||
d_bits[i] = b_bits[gsm660_bitorder[i]];
|
||||
}
|
||||
|
||||
static void tch_efr_protected(ubit_t *s_bits, ubit_t *b_bits)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 65; i++)
|
||||
b_bits[i] = s_bits[gsm0503_gsm_efr_protected_bits[i]-1];
|
||||
}
|
||||
|
||||
static void tch_fr_unreorder(ubit_t *d, ubit_t *p, ubit_t *u)
|
||||
{
|
||||
int i;
|
||||
|
@ -410,10 +463,43 @@ static void tch_fr_reorder(ubit_t *u, ubit_t *d, ubit_t *p)
|
|||
u[91+i] = p[i];
|
||||
}
|
||||
|
||||
int tch_fr_decode(uint8_t *tch_data, sbit_t *bursts, int net_order)
|
||||
static void tch_efr_reorder(ubit_t *w, ubit_t *s, ubit_t *p)
|
||||
{
|
||||
memcpy(w, s, 71);
|
||||
w[71] = w[72] = s[69];
|
||||
memcpy(w+73, s+71, 50);
|
||||
w[123] = w[124] = s[119];
|
||||
memcpy(w+125, s+121, 53);
|
||||
w[178] = w[179] = s[172];
|
||||
memcpy(w+180, s+174, 50);
|
||||
w[230] = w[231] = s[222];
|
||||
memcpy(w+232, s+224, 20);
|
||||
memcpy(w+252, p, 8);
|
||||
}
|
||||
|
||||
static void tch_efr_unreorder(ubit_t *s, ubit_t *p, ubit_t *w)
|
||||
{
|
||||
int sum;
|
||||
|
||||
memcpy(s, w, 71);
|
||||
sum = s[69] + w[71] + w[72];
|
||||
s[69] = (sum > 2);
|
||||
memcpy(s+71, w+73, 50);
|
||||
sum = s[119] + w[123] + w[124];
|
||||
s[119] = (sum > 2);
|
||||
memcpy(s+121, w+125, 53);
|
||||
sum = s[172] + w[178] + w[179];
|
||||
s[172] = (sum > 2);
|
||||
memcpy(s+174, w+180, 50);
|
||||
sum = s[220] + w[230] + w[231];
|
||||
s[222] = (sum > 2);
|
||||
memcpy(s+224, w+232, 20);
|
||||
memcpy(p, w+252, 8);
|
||||
}
|
||||
int tch_fr_decode(uint8_t *tch_data, sbit_t *bursts, int net_order, int efr)
|
||||
{
|
||||
sbit_t iB[912], cB[456], h;
|
||||
ubit_t conv[185], b[260], d[260], p[3];
|
||||
ubit_t conv[185], s[244], w[260], b[65], d[260], p[8];
|
||||
int i, rv, len, steal = 0;
|
||||
|
||||
for (i=0; i<8; i++) {
|
||||
|
@ -444,11 +530,28 @@ int tch_fr_decode(uint8_t *tch_data, sbit_t *bursts, int net_order)
|
|||
return -1;
|
||||
|
||||
|
||||
tch_fr_d_to_b(b, d);
|
||||
if (efr) {
|
||||
tch_efr_d_to_w(w, d);
|
||||
|
||||
tch_fr_reassemble(tch_data, b, net_order);
|
||||
tch_efr_unreorder(s, p, w);
|
||||
|
||||
len = 33;
|
||||
tch_efr_protected(s, b);
|
||||
|
||||
rv = osmo_crc8gen_check_bits(&gsm0503_tch_efr_crc8, b,
|
||||
65, p);
|
||||
if (rv)
|
||||
return -1;
|
||||
|
||||
tch_efr_reassemble(tch_data, s);
|
||||
|
||||
len = 31;
|
||||
} else {
|
||||
tch_fr_d_to_b(w, d);
|
||||
|
||||
tch_fr_reassemble(tch_data, w, net_order);
|
||||
|
||||
len = 33;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
@ -456,15 +559,29 @@ int tch_fr_decode(uint8_t *tch_data, sbit_t *bursts, int net_order)
|
|||
int tch_fr_encode(ubit_t *bursts, uint8_t *tch_data, int len, int net_order)
|
||||
{
|
||||
ubit_t iB[912], cB[456], h;
|
||||
ubit_t conv[185], w[260], d[260], p[8];
|
||||
ubit_t conv[185], w[260], b[65], s[244], d[260], p[8];
|
||||
int i;
|
||||
|
||||
switch (len) {
|
||||
case 31: /* TCH EFR */
|
||||
|
||||
tch_efr_disassemble(s, tch_data);
|
||||
|
||||
tch_efr_protected(s, b);
|
||||
|
||||
osmo_crc8gen_set_bits(&gsm0503_tch_efr_crc8, b, 65, p);
|
||||
|
||||
tch_efr_reorder(w, s, p);
|
||||
|
||||
tch_efr_w_to_d(d, w);
|
||||
|
||||
goto coding_efr_fr;
|
||||
case 33: /* TCH FR */
|
||||
tch_fr_disassemble(w, tch_data, net_order);
|
||||
|
||||
tch_fr_b_to_d(d, w);
|
||||
|
||||
coding_efr_fr:
|
||||
osmo_crc8gen_set_bits(&gsm0503_tch_fr_crc3, d, 50, p);
|
||||
|
||||
tch_fr_reorder(conv, d, p);
|
||||
|
|
|
@ -5,7 +5,7 @@ int xcch_decode(uint8_t *l2_data, sbit_t *bursts);
|
|||
int xcch_encode(ubit_t *bursts, uint8_t *l2_data);
|
||||
int pdtch_decode(uint8_t *l2_data, sbit_t *bursts, uint8_t *usf_p);
|
||||
int pdtch_encode(ubit_t *bursts, uint8_t *l2_data, uint8_t l2_len);
|
||||
int tch_fr_decode(uint8_t *tch_data, sbit_t *bursts, int net_order);
|
||||
int tch_fr_decode(uint8_t *tch_data, sbit_t *bursts, int net_order, int efr);
|
||||
int tch_fr_encode(ubit_t *bursts, uint8_t *tch_data, int len, int net_order);
|
||||
int rach_decode(uint8_t *ra, sbit_t *burst, uint8_t bsic);
|
||||
int rach_encode(ubit_t *burst, uint8_t *ra, uint8_t bsic);
|
||||
|
|
|
@ -75,3 +75,16 @@ const struct osmo_crc8gen_code gsm0503_tch_fr_crc3 = {
|
|||
.remainder = 0x7,
|
||||
};
|
||||
|
||||
/*
|
||||
* GSM TCH EFR parity
|
||||
*
|
||||
* g(x) = x^8 + x^4 + x^3 + x^2 + 1
|
||||
*/
|
||||
|
||||
const struct osmo_crc8gen_code gsm0503_tch_efr_crc8 = {
|
||||
.bits = 8,
|
||||
.poly = 0x1d,
|
||||
.init = 0x00,
|
||||
.remainder = 0x00,
|
||||
};
|
||||
|
||||
|
|
|
@ -6,5 +6,6 @@ const struct osmo_crc16gen_code gsm0503_cs234_crc16;
|
|||
const struct osmo_crc8gen_code gsm0503_rach_crc6;
|
||||
const struct osmo_crc16gen_code gsm0503_sch_crc10;
|
||||
const struct osmo_crc8gen_code gsm0503_tch_fr_crc3;
|
||||
const struct osmo_crc8gen_code gsm0503_tch_efr_crc8;
|
||||
|
||||
#endif /* _0503_PARITY_H */
|
||||
|
|
|
@ -109,3 +109,15 @@ const uint8_t gsm0503_gsm_fr_map[76] = {
|
|||
3, 3, 3, 3
|
||||
};
|
||||
|
||||
/* this table describes the 65 most importaint bits from EFR coded
|
||||
* bits as indicated in TS 05.03 (3.1.1.1) */
|
||||
const uint8_t gsm0503_gsm_efr_protected_bits[65] = {
|
||||
39, 40, 41, 42, 43, 44, 48, 87, 45, 2,
|
||||
3, 8, 10, 18, 19, 24, 46, 47,142,143,
|
||||
144,145,146,147, 92, 93,195,196, 98,137,
|
||||
148, 94,197,149,150, 95,198, 4, 5, 11,
|
||||
12, 16, 9, 6, 7, 13, 17, 20, 96,199,
|
||||
1, 14, 15, 21, 25, 26, 28,151,201,190,
|
||||
240, 88,138,191,241
|
||||
};
|
||||
|
||||
|
|
|
@ -9,5 +9,6 @@ extern const sbit_t gsm0503_usf2twelve_sbit[8][12];
|
|||
extern const uint8_t gsm0503_puncture_cs2[588];
|
||||
extern const uint8_t gsm0503_puncture_cs3[676];
|
||||
extern const uint8_t gsm0503_gsm_fr_map[76];
|
||||
extern const uint8_t gsm0503_gsm_efr_protected_bits[65];
|
||||
|
||||
#endif /* _0503_TABLES_H */
|
||||
|
|
|
@ -779,7 +779,14 @@ static void tx_tch_common(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
|
|||
memset(tch_data, 0, 33);
|
||||
len = 33;
|
||||
break;
|
||||
case GSM48_CMODE_SPEECH_EFR: /* EFR */
|
||||
if (chan != TRXC_TCHF)
|
||||
goto inval_mode1;
|
||||
memset(tch_data, 0, 31);
|
||||
len = 31;
|
||||
break;
|
||||
default:
|
||||
inval_mode1:
|
||||
LOGP(DL1C, LOGL_ERROR, "TCH mode invalid, please "
|
||||
"fix!\n");
|
||||
len = 0;
|
||||
|
@ -857,7 +864,21 @@ static void tx_tch_common(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
|
|||
goto free_bad_msg;
|
||||
}
|
||||
break;
|
||||
case GSM48_CMODE_SPEECH_EFR: /* EFR */
|
||||
if (chan != TRXC_TCHF)
|
||||
goto inval_mode2;
|
||||
len = 31;
|
||||
if (msgb_l2len(msg_tch) >= 1
|
||||
&& (msg_tch->l2h[0] >> 4) != 0xc) {
|
||||
LOGP(DL1C, LOGL_NOTICE, "%s Transmitting 'bad "
|
||||
"EFR frame' trx=%u ts=%u at fn=%u.\n",
|
||||
trx_chan_desc[chan].name,
|
||||
l1h->trx->nr, tn, fn);
|
||||
goto free_bad_msg;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
inval_mode2:
|
||||
LOGP(DL1C, LOGL_ERROR, "TCH mode invalid, please "
|
||||
"fix!\n");
|
||||
goto free_bad_msg;
|
||||
|
@ -1185,7 +1206,10 @@ static int rx_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
|
|||
switch ((rsl_cmode != RSL_CMOD_SPD_SPEECH) ? GSM48_CMODE_SPEECH_V1
|
||||
: tch_mode) {
|
||||
case GSM48_CMODE_SPEECH_V1: /* FR */
|
||||
rc = tch_fr_decode(tch_data, *bursts_p, 1);
|
||||
rc = tch_fr_decode(tch_data, *bursts_p, 1, 0);
|
||||
break;
|
||||
case GSM48_CMODE_SPEECH_EFR: /* EFR */
|
||||
rc = tch_fr_decode(tch_data, *bursts_p, 1, 1);
|
||||
break;
|
||||
default:
|
||||
LOGP(DL1C, LOGL_ERROR, "TCH mode %u invalid, please fix!\n",
|
||||
|
@ -1217,6 +1241,10 @@ bfi:
|
|||
memset(tch_data, 0, 33);
|
||||
rc = 33;
|
||||
break;
|
||||
case GSM48_CMODE_SPEECH_EFR: /* EFR */
|
||||
memset(tch_data, 0, 31);
|
||||
rc = 31;
|
||||
break;
|
||||
default:
|
||||
LOGP(DL1C, LOGL_ERROR, "TCH mode invalid, "
|
||||
"please fix!\n");
|
||||
|
|
|
@ -243,7 +243,7 @@ static void test_fr(uint8_t *speech, int len)
|
|||
printd("%s\n", osmo_hexdump((uint8_t *)bursts_s + 59 + 812, 57));
|
||||
|
||||
/* decode */
|
||||
rc = tch_fr_decode(result, bursts_s, 1);
|
||||
rc = tch_fr_decode(result, bursts_s, 1, len == 31);
|
||||
|
||||
ASSERT_TRUE(rc == len);
|
||||
|
||||
|
@ -349,7 +349,8 @@ uint8_t test_macblock[][54] = {
|
|||
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 },
|
||||
};
|
||||
|
||||
uint8_t test_speech[33];
|
||||
uint8_t test_speech_fr[33];
|
||||
uint8_t test_speech_efr[31];
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
|
@ -367,10 +368,16 @@ int main(int argc, char **argv)
|
|||
for (i = 0; i < sizeof(test_l2) / sizeof(test_l2[0]); i++)
|
||||
test_sch(test_l2[i]);
|
||||
|
||||
for (i = 0; i < sizeof(test_speech); i++)
|
||||
test_speech[i] = i;
|
||||
test_speech[0] = 0xd0;
|
||||
test_fr(test_speech, sizeof(test_speech));
|
||||
for (i = 0; i < sizeof(test_speech_fr); i++)
|
||||
test_speech_fr[i] = i;
|
||||
test_speech_fr[0] = 0xd0;
|
||||
test_fr(test_speech_fr, sizeof(test_speech_fr));
|
||||
|
||||
for (i = 0; i < sizeof(test_speech_efr); i++)
|
||||
test_speech_efr[i] = i;
|
||||
test_speech_efr[0] = 0xc0;
|
||||
test_fr(test_speech_efr, sizeof(test_speech_efr));
|
||||
|
||||
for (i = 0; i < sizeof(test_l2) / sizeof(test_l2[0]); i++)
|
||||
test_fr(test_l2[i], sizeof(test_l2[0]));
|
||||
|
||||
|
|
Loading…
Reference in New Issue