TRX: Support for AMR half speech
This commit is contained in:
parent
9eaf31e5be
commit
b0d65315ab
|
@ -1227,6 +1227,375 @@ facch:
|
|||
return 0;
|
||||
}
|
||||
|
||||
int tch_ahs_decode(uint8_t *tch_data, sbit_t *bursts, int odd,
|
||||
int codec_mode_req, uint8_t *codec, int codecs, uint8_t *ft,
|
||||
uint8_t *cmr, float *ber)
|
||||
{
|
||||
sbit_t iB[912], cB[456], h;
|
||||
ubit_t test[456], d[244], p[6], conv[135];
|
||||
int i, j, k, best = 0, rv, len, steal = 0, id = 0;
|
||||
|
||||
/* only unmap the stealing bits */
|
||||
if (!odd) {
|
||||
for (i=0; i<4; i++) {
|
||||
gsm0503_tch_burst_unmap(NULL, &bursts[i * 116], &h, 0);
|
||||
steal -= h;
|
||||
}
|
||||
for (i=2; i<5; i++) {
|
||||
gsm0503_tch_burst_unmap(NULL, &bursts[i * 116], &h, 1);
|
||||
steal -= h;
|
||||
}
|
||||
}
|
||||
|
||||
/* if we found a stole FACCH, but only at correct alignment */
|
||||
if (steal > 0) {
|
||||
for (i=0; i<6; i++)
|
||||
gsm0503_tch_burst_unmap(&iB[i * 114], &bursts[i * 116],
|
||||
NULL, i>>2);
|
||||
for (i=2; i<4; i++)
|
||||
gsm0503_tch_burst_unmap(&iB[i * 114 + 456],
|
||||
&bursts[i * 116], NULL, 1);
|
||||
|
||||
gsm0503_tch_fr_deinterleave(cB, iB);
|
||||
|
||||
rv = _xcch_decode_cB(tch_data, cB);
|
||||
if (rv)
|
||||
return -1;
|
||||
|
||||
return 23;
|
||||
}
|
||||
|
||||
for (i=0; i<4; i++)
|
||||
gsm0503_tch_burst_unmap(&iB[i * 114], &bursts[i * 116], NULL,
|
||||
i>>1);
|
||||
|
||||
gsm0503_tch_hr_deinterleave(cB, iB);
|
||||
|
||||
for (i=0; i<4; i++) {
|
||||
for (j=0, k=0; j<4; j++)
|
||||
k += abs(((int)gsm0503_ahs_ic_sbit[i][j]) -
|
||||
((int)cB[j]));
|
||||
if (i == 0 || k < best) {
|
||||
best = k;
|
||||
id = i;
|
||||
}
|
||||
}
|
||||
|
||||
/* check if indicated codec fits into range of codecs */
|
||||
if (id >= codecs) {
|
||||
/* codec mode out of range, return id */
|
||||
return id;
|
||||
}
|
||||
|
||||
switch ((codec_mode_req) ? codec[*ft] : codec[id]) {
|
||||
case 5: /* TCH/AHS7.95 */
|
||||
osmo_conv_decode(&gsm0503_conv_tch_ahs_7_95, cB+4, conv);
|
||||
|
||||
tch_amr_unmerge(d, p, conv, 123, 67);
|
||||
|
||||
rv = osmo_crc8gen_check_bits(&gsm0503_amr_crc6, d, 67, p);
|
||||
if (rv)
|
||||
return -1;
|
||||
|
||||
for (i=0; i<36;i++)
|
||||
d[i+123] = (cB[i+192] < 0) ? 1:0;
|
||||
|
||||
tch_amr_reassemble(tch_data, d, 159);
|
||||
|
||||
len = 20;
|
||||
|
||||
if (ber) {
|
||||
osmo_conv_encode(&gsm0503_conv_tch_ahs_7_95, conv,
|
||||
test+4);
|
||||
*ber = amr_calc_ber(cB+4, test+4, 188);
|
||||
}
|
||||
|
||||
break;
|
||||
case 4: /* TCH/AHS7.4 */
|
||||
osmo_conv_decode(&gsm0503_conv_tch_ahs_7_4, cB+4, conv);
|
||||
|
||||
tch_amr_unmerge(d, p, conv, 120, 61);
|
||||
|
||||
rv = osmo_crc8gen_check_bits(&gsm0503_amr_crc6, d, 61, p);
|
||||
if (rv)
|
||||
return -1;
|
||||
|
||||
for (i=0; i<28;i++)
|
||||
d[i+120] = (cB[i+200] < 0) ? 1:0;
|
||||
|
||||
tch_amr_reassemble(tch_data, d, 148);
|
||||
|
||||
len = 19;
|
||||
|
||||
if (ber) {
|
||||
osmo_conv_encode(&gsm0503_conv_tch_ahs_7_4, conv,
|
||||
test+4);
|
||||
*ber = amr_calc_ber(cB+4, test+4, 196);
|
||||
}
|
||||
|
||||
break;
|
||||
case 3: /* TCH/AHS6.7 */
|
||||
osmo_conv_decode(&gsm0503_conv_tch_ahs_6_7, cB+4, conv);
|
||||
|
||||
tch_amr_unmerge(d, p, conv, 110, 55);
|
||||
|
||||
rv = osmo_crc8gen_check_bits(&gsm0503_amr_crc6, d, 55, p);
|
||||
if (rv)
|
||||
return -1;
|
||||
|
||||
for (i=0; i<24;i++)
|
||||
d[i+110] = (cB[i+204] < 0) ? 1:0;
|
||||
|
||||
tch_amr_reassemble(tch_data, d, 134);
|
||||
|
||||
len = 17;
|
||||
|
||||
if (ber) {
|
||||
osmo_conv_encode(&gsm0503_conv_tch_ahs_6_7, conv,
|
||||
test+4);
|
||||
*ber = amr_calc_ber(cB+4, test+4, 200);
|
||||
}
|
||||
|
||||
break;
|
||||
case 2: /* TCH/AHS5.9 */
|
||||
osmo_conv_decode(&gsm0503_conv_tch_ahs_5_9, cB+4, conv);
|
||||
|
||||
tch_amr_unmerge(d, p, conv, 102, 55);
|
||||
|
||||
rv = osmo_crc8gen_check_bits(&gsm0503_amr_crc6, d, 55, p);
|
||||
if (rv)
|
||||
return -1;
|
||||
|
||||
for (i=0; i<16;i++)
|
||||
d[i+102] = (cB[i+212] < 0) ? 1:0;
|
||||
|
||||
tch_amr_reassemble(tch_data, d, 118);
|
||||
|
||||
len = 15;
|
||||
|
||||
if (ber) {
|
||||
osmo_conv_encode(&gsm0503_conv_tch_ahs_5_9, conv,
|
||||
test+4);
|
||||
*ber = amr_calc_ber(cB+4, test+4, 208);
|
||||
}
|
||||
|
||||
break;
|
||||
case 1: /* TCH/AHS5.15 */
|
||||
osmo_conv_decode(&gsm0503_conv_tch_ahs_5_15, cB+4, conv);
|
||||
|
||||
tch_amr_unmerge(d, p, conv, 91, 49);
|
||||
|
||||
rv = osmo_crc8gen_check_bits(&gsm0503_amr_crc6, d, 49, p);
|
||||
if (rv)
|
||||
return -1;
|
||||
|
||||
for (i=0; i<12;i++)
|
||||
d[i+91] = (cB[i+216] < 0) ? 1:0;
|
||||
|
||||
tch_amr_reassemble(tch_data, d, 103);
|
||||
|
||||
len = 13;
|
||||
|
||||
if (ber) {
|
||||
osmo_conv_encode(&gsm0503_conv_tch_ahs_5_15, conv,
|
||||
test+4);
|
||||
*ber = amr_calc_ber(cB+4, test+4, 212);
|
||||
}
|
||||
|
||||
break;
|
||||
case 0: /* TCH/AHS4.75 */
|
||||
osmo_conv_decode(&gsm0503_conv_tch_ahs_4_75, cB+4, conv);
|
||||
|
||||
tch_amr_unmerge(d, p, conv, 83, 39);
|
||||
|
||||
rv = osmo_crc8gen_check_bits(&gsm0503_amr_crc6, d, 39, p);
|
||||
if (rv)
|
||||
return -1;
|
||||
|
||||
for (i=0; i<12;i++)
|
||||
d[i+83] = (cB[i+216] < 0) ? 1:0;
|
||||
|
||||
tch_amr_reassemble(tch_data, d, 95);
|
||||
|
||||
len = 12;
|
||||
|
||||
if (ber) {
|
||||
osmo_conv_encode(&gsm0503_conv_tch_ahs_4_75, conv,
|
||||
test+4);
|
||||
*ber = amr_calc_ber(cB+4, test+4, 212);
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "FIXME: FT %d not supported!\n", *ft);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* change codec request / indication, if frame is valid */
|
||||
if (codec_mode_req)
|
||||
*cmr = id;
|
||||
else
|
||||
*ft = id;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int tch_ahs_encode(ubit_t *bursts, uint8_t *tch_data, int len,
|
||||
int codec_mode_req, uint8_t *codec, int codecs, uint8_t ft,
|
||||
uint8_t cmr)
|
||||
{
|
||||
ubit_t iB[912], cB[456], h;
|
||||
ubit_t d[244], p[6], conv[135];
|
||||
int i;
|
||||
uint8_t id;
|
||||
|
||||
if (len == 23) { /* FACCH */
|
||||
_xcch_encode_cB(cB, tch_data);
|
||||
|
||||
h = 1;
|
||||
|
||||
gsm0503_tch_fr_interleave(cB, iB);
|
||||
|
||||
for (i=0; i<6; i++)
|
||||
gsm0503_tch_burst_map(&iB[i * 114], &bursts[i * 116],
|
||||
&h, i>>2);
|
||||
for (i=2; i<4; i++)
|
||||
gsm0503_tch_burst_map(&iB[i * 114 + 456],
|
||||
&bursts[i * 116], &h, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
h = 0;
|
||||
|
||||
if (codec_mode_req) {
|
||||
if (cmr >= codecs) {
|
||||
fprintf(stderr, "FIXME: CMR ID %d not in codec list!\n",
|
||||
cmr);
|
||||
return -1;
|
||||
}
|
||||
id = cmr;
|
||||
} else {
|
||||
if (ft >= codecs) {
|
||||
fprintf(stderr, "FIXME: FT ID %d not in codec list!\n",
|
||||
ft);
|
||||
return -1;
|
||||
}
|
||||
id = ft;
|
||||
}
|
||||
|
||||
switch (codec[ft]) {
|
||||
case 5: /* TCH/AHS7.95 */
|
||||
if (len != 20) {
|
||||
invalid_length:
|
||||
fprintf(stderr, "FIXME: payload length %d does not "
|
||||
"comply with codec type %d!\n", len, ft);
|
||||
return -1;
|
||||
}
|
||||
|
||||
tch_amr_disassemble(d, tch_data, 159);
|
||||
|
||||
osmo_crc8gen_set_bits(&gsm0503_amr_crc6, d, 67, p);
|
||||
|
||||
tch_amr_merge(conv, d, p, 123, 67);
|
||||
|
||||
osmo_conv_encode(&gsm0503_conv_tch_ahs_7_95, conv, cB+4);
|
||||
|
||||
memcpy(cB+192, d+123, 36);
|
||||
|
||||
break;
|
||||
case 4: /* TCH/AHS7.4 */
|
||||
if (len != 19)
|
||||
goto invalid_length;
|
||||
|
||||
tch_amr_disassemble(d, tch_data, 148);
|
||||
|
||||
osmo_crc8gen_set_bits(&gsm0503_amr_crc6, d, 61, p);
|
||||
|
||||
tch_amr_merge(conv, d, p, 120, 61);
|
||||
|
||||
osmo_conv_encode(&gsm0503_conv_tch_ahs_7_4, conv, cB+4);
|
||||
|
||||
memcpy(cB+200, d+120, 28);
|
||||
|
||||
break;
|
||||
case 3: /* TCH/AHS6.7 */
|
||||
if (len != 17)
|
||||
goto invalid_length;
|
||||
|
||||
tch_amr_disassemble(d, tch_data, 134);
|
||||
|
||||
osmo_crc8gen_set_bits(&gsm0503_amr_crc6, d, 55, p);
|
||||
|
||||
tch_amr_merge(conv, d, p, 110, 55);
|
||||
|
||||
osmo_conv_encode(&gsm0503_conv_tch_ahs_6_7, conv, cB+4);
|
||||
|
||||
memcpy(cB+204, d+110, 24);
|
||||
|
||||
break;
|
||||
case 2: /* TCH/AHS5.9 */
|
||||
if (len != 15)
|
||||
goto invalid_length;
|
||||
|
||||
tch_amr_disassemble(d, tch_data, 118);
|
||||
|
||||
osmo_crc8gen_set_bits(&gsm0503_amr_crc6, d, 55, p);
|
||||
|
||||
tch_amr_merge(conv, d, p, 102, 55);
|
||||
|
||||
osmo_conv_encode(&gsm0503_conv_tch_ahs_5_9, conv, cB+4);
|
||||
|
||||
memcpy(cB+212, d+102, 16);
|
||||
|
||||
break;
|
||||
case 1: /* TCH/AHS5.15 */
|
||||
if (len != 13)
|
||||
goto invalid_length;
|
||||
|
||||
tch_amr_disassemble(d, tch_data, 103);
|
||||
|
||||
osmo_crc8gen_set_bits(&gsm0503_amr_crc6, d, 49, p);
|
||||
|
||||
tch_amr_merge(conv, d, p, 91, 49);
|
||||
|
||||
osmo_conv_encode(&gsm0503_conv_tch_ahs_5_15, conv, cB+4);
|
||||
|
||||
memcpy(cB+216, d+91, 12);
|
||||
|
||||
break;
|
||||
case 0: /* TCH/AHS4.75 */
|
||||
if (len != 12)
|
||||
goto invalid_length;
|
||||
|
||||
tch_amr_disassemble(d, tch_data, 95);
|
||||
|
||||
osmo_crc8gen_set_bits(&gsm0503_amr_crc6, d, 39, p);
|
||||
|
||||
tch_amr_merge(conv, d, p, 83, 39);
|
||||
|
||||
osmo_conv_encode(&gsm0503_conv_tch_ahs_4_75, conv, cB+4);
|
||||
|
||||
memcpy(cB+216, d+83, 12);
|
||||
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "FIXME: FT %d not supported!\n", ft);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(cB, gsm0503_afs_ic_ubit[id], 4);
|
||||
|
||||
gsm0503_tch_hr_interleave(cB, iB);
|
||||
|
||||
for (i=0; i<4; i++)
|
||||
gsm0503_tch_burst_map(&iB[i * 114], &bursts[i * 116], &h, i>>1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* GSM RACH transcoding
|
||||
*/
|
||||
|
|
|
@ -14,6 +14,12 @@ int tch_afs_decode(uint8_t *tch_data, sbit_t *bursts, int codec_mode_req,
|
|||
int tch_afs_encode(ubit_t *bursts, uint8_t *tch_data, int len,
|
||||
int codec_mode_req, uint8_t *codec, int codecs, uint8_t ft,
|
||||
uint8_t cmr);
|
||||
int tch_ahs_decode(uint8_t *tch_data, sbit_t *bursts, int odd,
|
||||
int codec_mode_req, uint8_t *codec, int codecs, uint8_t *ft,
|
||||
uint8_t *cmr, float *ber);
|
||||
int tch_ahs_encode(ubit_t *bursts, uint8_t *tch_data, int len,
|
||||
int codec_mode_req, uint8_t *codec, int codecs, uint8_t ft,
|
||||
uint8_t cmr);
|
||||
int rach_decode(uint8_t *ra, sbit_t *burst, uint8_t bsic);
|
||||
int rach_encode(ubit_t *burst, uint8_t *ra, uint8_t bsic);
|
||||
int sch_decode(uint8_t *sb_info, sbit_t *burst);
|
||||
|
|
|
@ -639,3 +639,312 @@ const struct osmo_conv_code gsm0503_conv_tch_afs_4_75 = {
|
|||
};
|
||||
|
||||
|
||||
/* TCH/AHS7.95 */
|
||||
/* ----------- */
|
||||
|
||||
static const uint8_t conv_tch_ahs_7_95_next_output[][2] = {
|
||||
{ 0, 3 }, { 1, 2 }, { 0, 3 }, { 1, 2 },
|
||||
{ 0, 3 }, { 1, 2 }, { 0, 3 }, { 1, 2 },
|
||||
{ 0, 3 }, { 1, 2 }, { 0, 3 }, { 1, 2 },
|
||||
{ 0, 3 }, { 1, 2 }, { 0, 3 }, { 1, 2 },
|
||||
};
|
||||
|
||||
static const uint8_t conv_tch_ahs_7_95_next_state[][2] = {
|
||||
{ 0, 1 }, { 2, 3 }, { 4, 5 }, { 6, 7 },
|
||||
{ 9, 8 }, { 11, 10 }, { 13, 12 }, { 15, 14 },
|
||||
{ 1, 0 }, { 3, 2 }, { 5, 4 }, { 7, 6 },
|
||||
{ 8, 9 }, { 10, 11 }, { 12, 13 }, { 14, 15 },
|
||||
};
|
||||
|
||||
static const uint8_t conv_tch_ahs_7_95_next_term_output[] = {
|
||||
0, 1, 0, 1, 3, 2, 3, 2, 3, 2, 3, 2, 0, 1, 0, 1,
|
||||
};
|
||||
|
||||
static const uint8_t conv_tch_ahs_7_95_next_term_state[] = {
|
||||
0, 2, 4, 6, 8, 10, 12, 14, 0, 2, 4, 6, 8, 10, 12, 14,
|
||||
};
|
||||
|
||||
static int conv_tch_ahs_7_95_puncture[] = {
|
||||
1, 3, 5, 7, 11, 15, 19, 23, 27, 31, 35, 43,
|
||||
47, 51, 55, 59, 63, 67, 71, 79, 83, 87, 91, 95,
|
||||
99, 103, 107, 115, 119, 123, 127, 131, 135, 139, 143, 151,
|
||||
155, 159, 163, 167, 171, 175, 177, 179, 183, 185, 187, 191,
|
||||
193, 195, 197, 199, 203, 205, 207, 211, 213, 215, 219, 221,
|
||||
223, 227, 229, 231, 233, 235, 239, 241, 243, 247, 249, 251,
|
||||
255, 257, 259, 261, 263, 265,
|
||||
-1, /* end */
|
||||
};
|
||||
|
||||
const struct osmo_conv_code gsm0503_conv_tch_ahs_7_95 = {
|
||||
.N = 2,
|
||||
.K = 5,
|
||||
.len = 129,
|
||||
.next_output = conv_tch_ahs_7_95_next_output,
|
||||
.next_state = conv_tch_ahs_7_95_next_state,
|
||||
.next_term_output = conv_tch_ahs_7_95_next_term_output,
|
||||
.next_term_state = conv_tch_ahs_7_95_next_term_state,
|
||||
.puncture = conv_tch_ahs_7_95_puncture,
|
||||
};
|
||||
|
||||
|
||||
/* TCH/AHS7.4 */
|
||||
/* ---------- */
|
||||
|
||||
static const uint8_t conv_tch_ahs_7_4_next_output[][2] = {
|
||||
{ 0, 3 }, { 1, 2 }, { 0, 3 }, { 1, 2 },
|
||||
{ 0, 3 }, { 1, 2 }, { 0, 3 }, { 1, 2 },
|
||||
{ 0, 3 }, { 1, 2 }, { 0, 3 }, { 1, 2 },
|
||||
{ 0, 3 }, { 1, 2 }, { 0, 3 }, { 1, 2 },
|
||||
};
|
||||
|
||||
static const uint8_t conv_tch_ahs_7_4_next_state[][2] = {
|
||||
{ 0, 1 }, { 2, 3 }, { 4, 5 }, { 6, 7 },
|
||||
{ 9, 8 }, { 11, 10 }, { 13, 12 }, { 15, 14 },
|
||||
{ 1, 0 }, { 3, 2 }, { 5, 4 }, { 7, 6 },
|
||||
{ 8, 9 }, { 10, 11 }, { 12, 13 }, { 14, 15 },
|
||||
};
|
||||
|
||||
static const uint8_t conv_tch_ahs_7_4_next_term_output[] = {
|
||||
0, 1, 0, 1, 3, 2, 3, 2, 3, 2, 3, 2, 0, 1, 0, 1,
|
||||
};
|
||||
|
||||
static const uint8_t conv_tch_ahs_7_4_next_term_state[] = {
|
||||
0, 2, 4, 6, 8, 10, 12, 14, 0, 2, 4, 6, 8, 10, 12, 14,
|
||||
};
|
||||
|
||||
static int conv_tch_ahs_7_4_puncture[] = {
|
||||
1, 3, 7, 11, 19, 23, 27, 35, 39, 43, 51, 55,
|
||||
59, 67, 71, 75, 83, 87, 91, 99, 103, 107, 115, 119,
|
||||
123, 131, 135, 139, 143, 147, 151, 155, 159, 163, 167, 171,
|
||||
175, 179, 183, 187, 191, 195, 199, 203, 207, 211, 215, 219,
|
||||
221, 223, 227, 229, 231, 235, 237, 239, 243, 245, 247, 251,
|
||||
253, 255, 257, 259,
|
||||
-1, /* end */
|
||||
};
|
||||
|
||||
const struct osmo_conv_code gsm0503_conv_tch_ahs_7_4 = {
|
||||
.N = 2,
|
||||
.K = 5,
|
||||
.len = 126,
|
||||
.next_output = conv_tch_ahs_7_4_next_output,
|
||||
.next_state = conv_tch_ahs_7_4_next_state,
|
||||
.next_term_output = conv_tch_ahs_7_4_next_term_output,
|
||||
.next_term_state = conv_tch_ahs_7_4_next_term_state,
|
||||
.puncture = conv_tch_ahs_7_4_puncture,
|
||||
};
|
||||
|
||||
|
||||
/* TCH/AHS6.7 */
|
||||
/* ---------- */
|
||||
|
||||
static const uint8_t conv_tch_ahs_6_7_next_output[][2] = {
|
||||
{ 0, 3 }, { 1, 2 }, { 0, 3 }, { 1, 2 },
|
||||
{ 0, 3 }, { 1, 2 }, { 0, 3 }, { 1, 2 },
|
||||
{ 0, 3 }, { 1, 2 }, { 0, 3 }, { 1, 2 },
|
||||
{ 0, 3 }, { 1, 2 }, { 0, 3 }, { 1, 2 },
|
||||
};
|
||||
|
||||
static const uint8_t conv_tch_ahs_6_7_next_state[][2] = {
|
||||
{ 0, 1 }, { 2, 3 }, { 4, 5 }, { 6, 7 },
|
||||
{ 9, 8 }, { 11, 10 }, { 13, 12 }, { 15, 14 },
|
||||
{ 1, 0 }, { 3, 2 }, { 5, 4 }, { 7, 6 },
|
||||
{ 8, 9 }, { 10, 11 }, { 12, 13 }, { 14, 15 },
|
||||
};
|
||||
|
||||
static const uint8_t conv_tch_ahs_6_7_next_term_output[] = {
|
||||
0, 1, 0, 1, 3, 2, 3, 2, 3, 2, 3, 2, 0, 1, 0, 1,
|
||||
};
|
||||
|
||||
static const uint8_t conv_tch_ahs_6_7_next_term_state[] = {
|
||||
0, 2, 4, 6, 8, 10, 12, 14, 0, 2, 4, 6, 8, 10, 12, 14,
|
||||
};
|
||||
|
||||
static int conv_tch_ahs_6_7_puncture[] = {
|
||||
1, 3, 9, 19, 29, 39, 49, 59, 69, 79, 89, 99,
|
||||
109, 119, 129, 139, 149, 159, 167, 169, 177, 179, 187, 189,
|
||||
197, 199, 203, 207, 209, 213, 217, 219, 223, 227, 229, 231,
|
||||
233, 235, 237, 239,
|
||||
-1, /* end */
|
||||
};
|
||||
|
||||
const struct osmo_conv_code gsm0503_conv_tch_ahs_6_7 = {
|
||||
.N = 2,
|
||||
.K = 5,
|
||||
.len = 116,
|
||||
.next_output = conv_tch_ahs_6_7_next_output,
|
||||
.next_state = conv_tch_ahs_6_7_next_state,
|
||||
.next_term_output = conv_tch_ahs_6_7_next_term_output,
|
||||
.next_term_state = conv_tch_ahs_6_7_next_term_state,
|
||||
.puncture = conv_tch_ahs_6_7_puncture,
|
||||
};
|
||||
|
||||
|
||||
/* TCH/AHS5.9 */
|
||||
/* ---------- */
|
||||
|
||||
static const uint8_t conv_tch_ahs_5_9_next_output[][2] = {
|
||||
{ 0, 3 }, { 1, 2 }, { 0, 3 }, { 1, 2 },
|
||||
{ 0, 3 }, { 1, 2 }, { 0, 3 }, { 1, 2 },
|
||||
{ 0, 3 }, { 1, 2 }, { 0, 3 }, { 1, 2 },
|
||||
{ 0, 3 }, { 1, 2 }, { 0, 3 }, { 1, 2 },
|
||||
};
|
||||
|
||||
static const uint8_t conv_tch_ahs_5_9_next_state[][2] = {
|
||||
{ 0, 1 }, { 2, 3 }, { 4, 5 }, { 6, 7 },
|
||||
{ 9, 8 }, { 11, 10 }, { 13, 12 }, { 15, 14 },
|
||||
{ 1, 0 }, { 3, 2 }, { 5, 4 }, { 7, 6 },
|
||||
{ 8, 9 }, { 10, 11 }, { 12, 13 }, { 14, 15 },
|
||||
};
|
||||
|
||||
static const uint8_t conv_tch_ahs_5_9_next_term_output[] = {
|
||||
0, 1, 0, 1, 3, 2, 3, 2, 3, 2, 3, 2, 0, 1, 0, 1,
|
||||
};
|
||||
|
||||
static const uint8_t conv_tch_ahs_5_9_next_term_state[] = {
|
||||
0, 2, 4, 6, 8, 10, 12, 14, 0, 2, 4, 6, 8, 10, 12, 14,
|
||||
};
|
||||
|
||||
static int conv_tch_ahs_5_9_puncture[] = {
|
||||
1, 15, 71, 127, 139, 151, 163, 175, 187, 195, 203, 211,
|
||||
215, 219, 221, 223,
|
||||
-1, /* end */
|
||||
};
|
||||
|
||||
const struct osmo_conv_code gsm0503_conv_tch_ahs_5_9 = {
|
||||
.N = 2,
|
||||
.K = 5,
|
||||
.len = 108,
|
||||
.next_output = conv_tch_ahs_5_9_next_output,
|
||||
.next_state = conv_tch_ahs_5_9_next_state,
|
||||
.next_term_output = conv_tch_ahs_5_9_next_term_output,
|
||||
.next_term_state = conv_tch_ahs_5_9_next_term_state,
|
||||
.puncture = conv_tch_ahs_5_9_puncture,
|
||||
};
|
||||
|
||||
|
||||
/* TCH/AHS5.15 */
|
||||
/* ----------- */
|
||||
|
||||
static const uint8_t conv_tch_ahs_5_15_next_output[][2] = {
|
||||
{ 0, 7 }, { 2, 5 }, { 4, 3 }, { 6, 1 },
|
||||
{ 2, 5 }, { 0, 7 }, { 6, 1 }, { 4, 3 },
|
||||
{ 0, 7 }, { 2, 5 }, { 4, 3 }, { 6, 1 },
|
||||
{ 2, 5 }, { 0, 7 }, { 6, 1 }, { 4, 3 },
|
||||
};
|
||||
|
||||
static const uint8_t conv_tch_ahs_5_15_next_state[][2] = {
|
||||
{ 0, 1 }, { 3, 2 }, { 5, 4 }, { 6, 7 },
|
||||
{ 9, 8 }, { 10, 11 }, { 12, 13 }, { 15, 14 },
|
||||
{ 1, 0 }, { 2, 3 }, { 4, 5 }, { 7, 6 },
|
||||
{ 8, 9 }, { 11, 10 }, { 13, 12 }, { 14, 15 },
|
||||
};
|
||||
|
||||
static const uint8_t conv_tch_ahs_5_15_next_term_output[] = {
|
||||
0, 5, 3, 6, 5, 0, 6, 3, 7, 2, 4, 1, 2, 7, 1, 4,
|
||||
};
|
||||
|
||||
static const uint8_t conv_tch_ahs_5_15_next_term_state[] = {
|
||||
0, 2, 4, 6, 8, 10, 12, 14, 0, 2, 4, 6, 8, 10, 12, 14,
|
||||
};
|
||||
|
||||
static int conv_tch_ahs_5_15_puncture[] = {
|
||||
0, 1, 3, 4, 6, 9, 12, 15, 18, 21, 27, 33,
|
||||
39, 45, 51, 54, 57, 63, 69, 75, 81, 87, 90, 93,
|
||||
99, 105, 111, 117, 123, 126, 129, 135, 141, 147, 153, 159,
|
||||
162, 165, 168, 171, 174, 177, 180, 183, 186, 189, 192, 195,
|
||||
198, 201, 204, 207, 210, 213, 216, 219, 222, 225, 228, 231,
|
||||
234, 237, 240, 243, 244, 246, 249, 252, 255, 256, 258, 261,
|
||||
264, 267, 268, 270, 273, 276, 279, 280, 282, 285, 288, 289,
|
||||
291, 294, 295, 297, 298, 300, 301,
|
||||
-1, /* end */
|
||||
};
|
||||
|
||||
const struct osmo_conv_code gsm0503_conv_tch_ahs_5_15 = {
|
||||
.N = 3,
|
||||
.K = 5,
|
||||
.len = 97,
|
||||
.next_output = conv_tch_ahs_5_15_next_output,
|
||||
.next_state = conv_tch_ahs_5_15_next_state,
|
||||
.next_term_output = conv_tch_ahs_5_15_next_term_output,
|
||||
.next_term_state = conv_tch_ahs_5_15_next_term_state,
|
||||
.puncture = conv_tch_ahs_5_15_puncture,
|
||||
};
|
||||
|
||||
|
||||
/* TCH/AHS4.75 */
|
||||
/* ----------- */
|
||||
|
||||
static const uint8_t conv_tch_ahs_4_75_next_output[][2] = {
|
||||
{ 0, 7 }, { 3, 4 }, { 2, 5 }, { 1, 6 },
|
||||
{ 2, 5 }, { 1, 6 }, { 0, 7 }, { 3, 4 },
|
||||
{ 3, 4 }, { 0, 7 }, { 1, 6 }, { 2, 5 },
|
||||
{ 1, 6 }, { 2, 5 }, { 3, 4 }, { 0, 7 },
|
||||
{ 3, 4 }, { 0, 7 }, { 1, 6 }, { 2, 5 },
|
||||
{ 1, 6 }, { 2, 5 }, { 3, 4 }, { 0, 7 },
|
||||
{ 0, 7 }, { 3, 4 }, { 2, 5 }, { 1, 6 },
|
||||
{ 2, 5 }, { 1, 6 }, { 0, 7 }, { 3, 4 },
|
||||
{ 0, 7 }, { 3, 4 }, { 2, 5 }, { 1, 6 },
|
||||
{ 2, 5 }, { 1, 6 }, { 0, 7 }, { 3, 4 },
|
||||
{ 3, 4 }, { 0, 7 }, { 1, 6 }, { 2, 5 },
|
||||
{ 1, 6 }, { 2, 5 }, { 3, 4 }, { 0, 7 },
|
||||
{ 3, 4 }, { 0, 7 }, { 1, 6 }, { 2, 5 },
|
||||
{ 1, 6 }, { 2, 5 }, { 3, 4 }, { 0, 7 },
|
||||
{ 0, 7 }, { 3, 4 }, { 2, 5 }, { 1, 6 },
|
||||
{ 2, 5 }, { 1, 6 }, { 0, 7 }, { 3, 4 },
|
||||
};
|
||||
|
||||
static const uint8_t conv_tch_ahs_4_75_next_state[][2] = {
|
||||
{ 0, 1 }, { 2, 3 }, { 5, 4 }, { 7, 6 },
|
||||
{ 9, 8 }, { 11, 10 }, { 12, 13 }, { 14, 15 },
|
||||
{ 16, 17 }, { 18, 19 }, { 21, 20 }, { 23, 22 },
|
||||
{ 25, 24 }, { 27, 26 }, { 28, 29 }, { 30, 31 },
|
||||
{ 33, 32 }, { 35, 34 }, { 36, 37 }, { 38, 39 },
|
||||
{ 40, 41 }, { 42, 43 }, { 45, 44 }, { 47, 46 },
|
||||
{ 49, 48 }, { 51, 50 }, { 52, 53 }, { 54, 55 },
|
||||
{ 56, 57 }, { 58, 59 }, { 61, 60 }, { 63, 62 },
|
||||
{ 1, 0 }, { 3, 2 }, { 4, 5 }, { 6, 7 },
|
||||
{ 8, 9 }, { 10, 11 }, { 13, 12 }, { 15, 14 },
|
||||
{ 17, 16 }, { 19, 18 }, { 20, 21 }, { 22, 23 },
|
||||
{ 24, 25 }, { 26, 27 }, { 29, 28 }, { 31, 30 },
|
||||
{ 32, 33 }, { 34, 35 }, { 37, 36 }, { 39, 38 },
|
||||
{ 41, 40 }, { 43, 42 }, { 44, 45 }, { 46, 47 },
|
||||
{ 48, 49 }, { 50, 51 }, { 53, 52 }, { 55, 54 },
|
||||
{ 57, 56 }, { 59, 58 }, { 60, 61 }, { 62, 63 },
|
||||
};
|
||||
|
||||
static const uint8_t conv_tch_ahs_4_75_next_term_output[] = {
|
||||
0, 3, 5, 6, 5, 6, 0, 3, 3, 0, 6, 5, 6, 5, 3, 0,
|
||||
4, 7, 1, 2, 1, 2, 4, 7, 7, 4, 2, 1, 2, 1, 7, 4,
|
||||
7, 4, 2, 1, 2, 1, 7, 4, 4, 7, 1, 2, 1, 2, 4, 7,
|
||||
3, 0, 6, 5, 6, 5, 3, 0, 0, 3, 5, 6, 5, 6, 0, 3,
|
||||
};
|
||||
|
||||
static const uint8_t conv_tch_ahs_4_75_next_term_state[] = {
|
||||
0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30,
|
||||
32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62,
|
||||
0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30,
|
||||
32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62,
|
||||
};
|
||||
|
||||
static int conv_tch_ahs_4_75_puncture[] = {
|
||||
1, 2, 4, 5, 7, 8, 10, 13, 16, 22, 28, 34,
|
||||
40, 46, 52, 58, 64, 70, 76, 82, 88, 94, 100, 106,
|
||||
112, 118, 124, 130, 136, 142, 148, 151, 154, 160, 163, 166,
|
||||
172, 175, 178, 184, 187, 190, 196, 199, 202, 208, 211, 214,
|
||||
220, 223, 226, 232, 235, 238, 241, 244, 247, 250, 253, 256,
|
||||
259, 262, 265, 268, 271, 274, 275, 277, 278, 280, 281, 283,
|
||||
284,
|
||||
-1, /* end */
|
||||
};
|
||||
|
||||
const struct osmo_conv_code gsm0503_conv_tch_ahs_4_75 = {
|
||||
.N = 3,
|
||||
.K = 7,
|
||||
.len = 89,
|
||||
.next_output = conv_tch_ahs_4_75_next_output,
|
||||
.next_state = conv_tch_ahs_4_75_next_state,
|
||||
.next_term_output = conv_tch_ahs_4_75_next_term_output,
|
||||
.next_term_state = conv_tch_ahs_4_75_next_term_state,
|
||||
.puncture = conv_tch_ahs_4_75_puncture,
|
||||
};
|
||||
|
||||
|
|
|
@ -16,5 +16,11 @@ extern const struct osmo_conv_code gsm0503_conv_tch_afs_6_7;
|
|||
extern const struct osmo_conv_code gsm0503_conv_tch_afs_5_9;
|
||||
extern const struct osmo_conv_code gsm0503_conv_tch_afs_5_15;
|
||||
extern const struct osmo_conv_code gsm0503_conv_tch_afs_4_75;
|
||||
extern const struct osmo_conv_code gsm0503_conv_tch_ahs_7_95;
|
||||
extern const struct osmo_conv_code gsm0503_conv_tch_ahs_7_4;
|
||||
extern const struct osmo_conv_code gsm0503_conv_tch_ahs_6_7;
|
||||
extern const struct osmo_conv_code gsm0503_conv_tch_ahs_5_9;
|
||||
extern const struct osmo_conv_code gsm0503_conv_tch_ahs_5_15;
|
||||
extern const struct osmo_conv_code gsm0503_conv_tch_ahs_4_75;
|
||||
|
||||
#endif /* _0503_CONV_H */
|
||||
|
|
|
@ -136,6 +136,20 @@ const sbit_t gsm0503_afs_ic_sbit[4][8] = {
|
|||
{ -127,-127,-127, 127, 127,-127,-127,-127 },
|
||||
};
|
||||
|
||||
const ubit_t gsm0503_ahs_ic_ubit[4][4] = {
|
||||
{ 0,0,0,0 },
|
||||
{ 1,0,0,1 },
|
||||
{ 1,1,1,0 },
|
||||
{ 0,1,1,1 },
|
||||
};
|
||||
|
||||
const sbit_t gsm0503_ahs_ic_sbit[4][4] = {
|
||||
{ 127, 127, 127, 127 },
|
||||
{ -127, 127, 127,-127 },
|
||||
{ -127,-127,-127, 127 },
|
||||
{ 127,-127,-127,-127 },
|
||||
};
|
||||
|
||||
const uint8_t gsm0503_tch_hr_interleaving[228][2] = {
|
||||
{ 0 ,0 }, { 1 ,2 }, { 78 ,1 }, { 79 ,3 }, { 48 ,0 }, { 49 ,2 },
|
||||
{ 54 ,1 }, { 55 ,3 }, { 24 ,0 }, { 25 ,2 }, { 30 ,1 }, { 31 ,3 },
|
||||
|
|
|
@ -12,6 +12,8 @@ extern const uint8_t gsm0503_gsm_fr_map[76];
|
|||
extern const uint8_t gsm0503_gsm_efr_protected_bits[65];
|
||||
extern const ubit_t gsm0503_afs_ic_ubit[4][8];
|
||||
extern const sbit_t gsm0503_afs_ic_sbit[4][8];
|
||||
extern const ubit_t gsm0503_ahs_ic_ubit[4][4];
|
||||
extern const sbit_t gsm0503_ahs_ic_sbit[4][4];
|
||||
extern const uint8_t gsm0503_tch_hr_interleaving[228][2];
|
||||
|
||||
#endif /* _0503_TABLES_H */
|
||||
|
|
|
@ -1065,6 +1065,7 @@ static ubit_t *tx_tchh_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
|
|||
{
|
||||
struct msgb *msg_tch = NULL, *msg_facch = NULL;
|
||||
struct trx_chan_state *chan_state = &l1h->chan_states[tn][chan];
|
||||
uint8_t tch_mode = chan_state->tch_mode;
|
||||
ubit_t *burst, **bursts_p = &chan_state->dl_bursts;
|
||||
static ubit_t bits[148];
|
||||
|
||||
|
@ -1118,6 +1119,15 @@ static ubit_t *tx_tchh_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
|
|||
chan_state->dl_ongoing_facch = 1; /* first of two tch frames */
|
||||
} else if (chan_state->dl_ongoing_facch) /* second of two tch frames */
|
||||
chan_state->dl_ongoing_facch = 0; /* we are done with FACCH */
|
||||
else if (tch_mode == GSM48_CMODE_SPEECH_AMR)
|
||||
/* the first FN 4,13,21 or 5,14,22 defines that CMI is included
|
||||
* in frame, the first FN 0,8,17 or 1,9,18 defines that CMR is
|
||||
* included in frame. */
|
||||
tch_ahs_encode(*bursts_p, msg_tch->l2h + 2,
|
||||
msgb_l2len(msg_tch) - 2, (((fn + 4) % 26) >> 2) & 1,
|
||||
chan_state->codec, chan_state->codecs,
|
||||
chan_state->dl_ft,
|
||||
chan_state->dl_cmr);
|
||||
else
|
||||
tch_hr_encode(*bursts_p, msg_tch->l2h, msgb_l2len(msg_tch));
|
||||
|
||||
|
@ -1486,6 +1496,7 @@ static int rx_tchh_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
|
|||
uint8_t tch_mode = chan_state->tch_mode;
|
||||
uint8_t tch_data[128]; /* just to be safe */
|
||||
int rc, amr = 0;
|
||||
float ber;
|
||||
|
||||
LOGP(DL1C, LOGL_DEBUG, "TCH/H received %s fn=%u ts=%u trx=%u bid=%u\n",
|
||||
trx_chan_desc[chan].name, fn, tn, l1h->trx->nr, bid);
|
||||
|
@ -1544,6 +1555,28 @@ static int rx_tchh_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
|
|||
rc = tch_hr_decode(tch_data, *bursts_p,
|
||||
(((fn + 26 - 10) % 26) >> 2) & 1);
|
||||
break;
|
||||
case GSM48_CMODE_SPEECH_AMR: /* AMR */
|
||||
/* the first FN 0,8,17 or 1,9,18 defines that CMI is included
|
||||
* in frame, the first FN 4,13,21 or 5,14,22 defines that CMR
|
||||
* is included in frame.
|
||||
*/
|
||||
rc = tch_ahs_decode(tch_data + 2, *bursts_p,
|
||||
(((fn + 26 - 10) % 26) >> 2) & 1,
|
||||
(((fn + 26 - 10) % 26) >> 2) & 1, chan_state->codec,
|
||||
chan_state->codecs, &chan_state->ul_ft,
|
||||
&chan_state->ul_cmr, &ber);
|
||||
if (rc)
|
||||
trx_loop_amr_input(l1h,
|
||||
trx_chan_desc[chan].chan_nr | tn, chan_state,
|
||||
ber);
|
||||
amr = 2; /* we store tch_data + 2 two */
|
||||
/* only good speech frames get rtp header */
|
||||
if (rc != 23 && rc >= 4) {
|
||||
rc = amr_compose_payload(tch_data,
|
||||
chan_state->codec[chan_state->ul_cmr],
|
||||
chan_state->codec[chan_state->ul_ft], 0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOGP(DL1C, LOGL_ERROR, "TCH mode %u invalid, please fix!\n",
|
||||
tch_mode);
|
||||
|
@ -1578,6 +1611,15 @@ bfi:
|
|||
memset(tch_data + 1, 0, 14);
|
||||
rc = 15;
|
||||
break;
|
||||
case GSM48_CMODE_SPEECH_AMR: /* AMR */
|
||||
rc = amr_compose_payload(tch_data,
|
||||
chan_state->codec[chan_state->dl_cmr],
|
||||
chan_state->codec[chan_state->dl_ft],
|
||||
1);
|
||||
if (rc < 2)
|
||||
break;
|
||||
memset(tch_data + 2, 0, rc - 2);
|
||||
break;
|
||||
default:
|
||||
LOGP(DL1C, LOGL_ERROR, "TCH mode invalid, "
|
||||
"please fix!\n");
|
||||
|
|
Loading…
Reference in New Issue