TRX: Support for AMR half speech

This commit is contained in:
Andreas Eversberg 2013-03-31 12:19:26 +02:00
parent 9eaf31e5be
commit b0d65315ab
7 changed files with 748 additions and 0 deletions

View File

@ -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
*/

View File

@ -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);

View File

@ -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,
};

View File

@ -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 */

View File

@ -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 },

View File

@ -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 */

View File

@ -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");