mirror of https://gerrit.osmocom.org/libosmocore
coding: implement dedicated codec API for FACCH/[FH]
Currently FACCH/[FH] encoding and decoding is implemented as part of the gsm0503_tch_[fh]r_{en,de}code and gsm0503_tch_a[fh]s_{en,de}code API. This works fine for speech because one FACCH frame completely replaces one or two speech frames, but this is not the case for CSD. According to 3GPP TS 45.002, sections 4.2.5 and 4.3.5, for TCH data channels FACCH does not replace data frames but disturbs some amount of bits from them. Therefore we need to be able to perform FACCH encoding and decoding independently from CSD specific coding API. Change-Id: I0c7a9c180dcafe64e6aebe53518d3d11e1f29886 Related: OS#1572
This commit is contained in:
parent
9a22827cf6
commit
b334022aba
|
@ -109,4 +109,12 @@ int gsm0503_tch_fr144_encode(ubit_t *bursts, const ubit_t *data);
|
|||
int gsm0503_tch_fr144_decode(ubit_t *data, const sbit_t *bursts,
|
||||
int *n_errors, int *n_bits_total);
|
||||
|
||||
int gsm0503_tch_fr_facch_encode(ubit_t *bursts, const uint8_t *data);
|
||||
int gsm0503_tch_fr_facch_decode(uint8_t *data, const sbit_t *bursts,
|
||||
int *n_errors, int *n_bits_total);
|
||||
|
||||
int gsm0503_tch_hr_facch_encode(ubit_t *bursts, const uint8_t *data);
|
||||
int gsm0503_tch_hr_facch_decode(uint8_t *data, const sbit_t *bursts,
|
||||
int *n_errors, int *n_bits_total);
|
||||
|
||||
/*! @} */
|
||||
|
|
|
@ -3589,4 +3589,138 @@ int gsm0503_tch_fr144_decode(ubit_t *data, const sbit_t *bursts,
|
|||
return 290;
|
||||
}
|
||||
|
||||
/*
|
||||
* FACCH/[FH] transcoding
|
||||
*/
|
||||
|
||||
/*! Perform channel encoding of a FACCH/F data as per section 4.2.
|
||||
* \param[out] bursts Caller-allocated buffer for symbols of 8 bursts,
|
||||
* 8 * 2 * 58 == 928 bits total.
|
||||
* \param[in] data FACCH MAC block to be encoded (GSM_MACBLOCK_LEN).
|
||||
* \returns 0 in case of success; negative on error */
|
||||
int gsm0503_tch_fr_facch_encode(ubit_t *bursts, const uint8_t *data)
|
||||
{
|
||||
ubit_t iB[8 * 114], cB[4 * 114];
|
||||
const ubit_t h = 1;
|
||||
|
||||
/* 4.2.1-3 as specified for the SACCH in 4.1.1-3 */
|
||||
_xcch_encode_cB(&cB[0], &data[0]);
|
||||
|
||||
/* 4.2.4 Interleaving: as specified for the TCH/FS in subclause 3.1.3 */
|
||||
gsm0503_tch_fr_interleave(&cB[0], &iB[0]);
|
||||
|
||||
/* 4.2.5 Mapping on a Burst:
|
||||
* - hu(B)=1 the even numbered bits in the first 4 bursts and
|
||||
* - hl(B)=1 the odd numbered bits of the last 4 bursts are stolen. */
|
||||
for (unsigned int i = 0; i < 8; i++)
|
||||
gsm0503_tch_burst_map(&iB[i * 114], &bursts[i * 116], &h, i >> 2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Perform channel decoding of a FACCH/F data as per section 4.2.
|
||||
* \param[out] data Caller-allocated buffer for decoded FACCH (GSM_MACBLOCK_LEN).
|
||||
* \param[in] bursts Buffer containing the symbols of 8 bursts,
|
||||
* 8 * 2 * 58 == 928 bits total.
|
||||
* \param[out] n_errors Number of detected bit errors.
|
||||
* \param[out] n_bits_total Total number of bits.
|
||||
* \returns Number of bytes used in the output buffer; negative on error. */
|
||||
int gsm0503_tch_fr_facch_decode(uint8_t *data, const sbit_t *bursts,
|
||||
int *n_errors, int *n_bits_total)
|
||||
{
|
||||
sbit_t iB[8 * 114], cB[4 * 114];
|
||||
int steal = 0;
|
||||
|
||||
/* FACCH decision: sum of 4 first hu(B) and 4 last hl(B) soft-bits */
|
||||
for (unsigned int i = 0; i < 4; i++)
|
||||
steal -= bursts[i * 116 + 58]; /* hu(B) */
|
||||
for (unsigned int i = 4; i < 8; i++)
|
||||
steal -= bursts[i * 116 + 57]; /* hl(B) */
|
||||
if (steal <= 0)
|
||||
return -1;
|
||||
|
||||
/* 4.2.5 Mapping on a Burst:
|
||||
* - hu(B)=1 the even numbered bits in the first 4 bursts and
|
||||
* - hl(B)=1 the odd numbered bits of the last 4 bursts are stolen. */
|
||||
for (unsigned int i = 0; i < 8; i++)
|
||||
gsm0503_tch_burst_unmap(&iB[i * 114], &bursts[i * 116], NULL, i >> 2);
|
||||
|
||||
/* 4.2.4 Interleaving: as specified for the TCH/FS in subclause 3.1.3 */
|
||||
gsm0503_tch_fr_deinterleave(&cB[0], &iB[0]);
|
||||
|
||||
/* 4.2.1-3 as specified for the SACCH in 4.1.1-3 */
|
||||
if (_xcch_decode_cB(&data[0], &cB[0], n_errors, n_bits_total) != 0)
|
||||
return -1;
|
||||
|
||||
return GSM_MACBLOCK_LEN;
|
||||
}
|
||||
|
||||
/*! Perform channel encoding of a FACCH/H data as per section 4.3.
|
||||
* \param[out] bursts Caller-allocated buffer for symbols of 6 bursts,
|
||||
* 6 * 2 * 58 == 696 bits total.
|
||||
* \param[in] data FACCH MAC block to be encoded (GSM_MACBLOCK_LEN).
|
||||
* \returns 0 in case of success; negative on error */
|
||||
int gsm0503_tch_hr_facch_encode(ubit_t *bursts, const uint8_t *data)
|
||||
{
|
||||
ubit_t iB[8 * 114], cB[4 * 114];
|
||||
const ubit_t h = 1;
|
||||
|
||||
/* 4.3.1-3 as specified for the SACCH in 4.1.1-3 */
|
||||
_xcch_encode_cB(&cB[0], &data[0]);
|
||||
|
||||
/* 4.3.4 Interleaving */
|
||||
gsm0503_tch_fr_interleave(&cB[0], &iB[0]);
|
||||
|
||||
/* 4.3.5 Mapping on a Burst:
|
||||
* - hu(B)=1 the even numbered bits of the first 2 bursts,
|
||||
* - hu(B)=1 & hl(B)=1 all bits of the middle 2 bursts and
|
||||
* - hl(B)=1 the odd numbered bits of the last 2 bursts are stolen. */
|
||||
for (unsigned int i = 0; i < 6; i++)
|
||||
gsm0503_tch_burst_map(&iB[i * 114], &bursts[i * 116], &h, i >> 2);
|
||||
for (unsigned int i = 2; i < 4; i++)
|
||||
gsm0503_tch_burst_map(&iB[i * 114 + 456], &bursts[i * 116], &h, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Perform channel decoding of a FACCH/H data as per section 4.3.
|
||||
* \param[out] data Caller-allocated buffer for decoded FACCH (GSM_MACBLOCK_LEN).
|
||||
* \param[in] bursts Buffer containing the symbols of 6 bursts,
|
||||
* 6 * 2 * 58 == 696 bits total.
|
||||
* \param[out] n_errors Number of detected bit errors.
|
||||
* \param[out] n_bits_total Total number of bits.
|
||||
* \returns Number of bytes used in the output buffer; negative on error. */
|
||||
int gsm0503_tch_hr_facch_decode(uint8_t *data, const sbit_t *bursts,
|
||||
int *n_errors, int *n_bits_total)
|
||||
{
|
||||
sbit_t iB[8 * 114], cB[4 * 114];
|
||||
int steal = 0;
|
||||
|
||||
/* FACCH decision: sum of 4 first hu(B) and 4 last hl(B) soft-bits */
|
||||
for (unsigned int i = 0; i < 4; i++)
|
||||
steal -= bursts[i * 116 + 58]; /* hu(B) */
|
||||
for (unsigned int i = 2; i < 6; i++)
|
||||
steal -= bursts[i * 116 + 57]; /* hl(B) */
|
||||
if (steal <= 0)
|
||||
return -1;
|
||||
|
||||
/* 4.3.5 Mapping on a Burst:
|
||||
* - hu(B)=1 the even numbered bits of the first 2 bursts,
|
||||
* - hu(B)=1 & hl(B)=1 all bits of the middle 2 bursts and
|
||||
* - hl(B)=1 the odd numbered bits of the last 2 bursts are stolen. */
|
||||
for (unsigned int i = 0; i < 6; i++)
|
||||
gsm0503_tch_burst_unmap(&iB[i * 114], &bursts[i * 116], NULL, i >> 2);
|
||||
for (unsigned int i = 2; i < 4; i++)
|
||||
gsm0503_tch_burst_unmap(&iB[i * 114 + 456], &bursts[i * 116], NULL, 1);
|
||||
|
||||
/* 4.3.4 Interleaving */
|
||||
gsm0503_tch_fr_deinterleave(&cB[0], &iB[0]);
|
||||
|
||||
/* 4.3.1-3 as specified for the SACCH in 4.1.1-3 */
|
||||
if (_xcch_decode_cB(&data[0], &cB[0], n_errors, n_bits_total) != 0)
|
||||
return -1;
|
||||
|
||||
return GSM_MACBLOCK_LEN;
|
||||
}
|
||||
|
||||
/*! @} */
|
||||
|
|
|
@ -140,5 +140,10 @@ gsm0503_tch_hr24_decode;
|
|||
gsm0503_tch_fr144_encode;
|
||||
gsm0503_tch_fr144_decode;
|
||||
|
||||
gsm0503_tch_fr_facch_encode;
|
||||
gsm0503_tch_fr_facch_decode;
|
||||
gsm0503_tch_hr_facch_encode;
|
||||
gsm0503_tch_hr_facch_decode;
|
||||
|
||||
local: *;
|
||||
};
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <osmocom/core/bits.h>
|
||||
#include <osmocom/core/utils.h>
|
||||
|
||||
#include <osmocom/gsm/protocol/gsm_04_08.h>
|
||||
#include <osmocom/coding/gsm0503_coding.h>
|
||||
|
||||
#define DUMP_U_AT(b, x, u) do { \
|
||||
|
@ -312,6 +313,51 @@ static void test_hr(uint8_t *speech, int len)
|
|||
printf("\n");
|
||||
}
|
||||
|
||||
static void test_facch(const uint8_t *data, bool half_rate)
|
||||
{
|
||||
ubit_t bursts_u[116 * 8 * 2] = { 0 };
|
||||
sbit_t bursts_s[116 * 8 * 2] = { 0 };
|
||||
int rc;
|
||||
|
||||
/* Encode the given FACCH message three times (at different offsets) */
|
||||
printf("%s(FACCH/%c): encoding: %s\n",
|
||||
__func__, half_rate ? 'H' : 'F',
|
||||
osmo_hexdump(&data[0], GSM_MACBLOCK_LEN));
|
||||
for (unsigned int i = 0; i < 3; i++) {
|
||||
ubit_t *pos = &bursts_u[116 * 4 * i];
|
||||
|
||||
if (half_rate)
|
||||
rc = gsm0503_tch_hr_facch_encode(pos, &data[0]);
|
||||
else
|
||||
rc = gsm0503_tch_fr_facch_encode(pos, &data[0]);
|
||||
CHECK_RC_OR_RET(rc == 0, "encoding");
|
||||
}
|
||||
|
||||
/* Prepare soft-bits */
|
||||
osmo_ubit2sbit(bursts_s, bursts_u, sizeof(bursts_s));
|
||||
|
||||
/* Decode three FACCH messages (at different offsets) */
|
||||
for (unsigned int i = 0; i < 3; i++) {
|
||||
const sbit_t *pos = &bursts_s[116 * 4 * i];
|
||||
uint8_t result[GSM_MACBLOCK_LEN];
|
||||
int n_errors, n_bits_total;
|
||||
|
||||
if (half_rate)
|
||||
rc = gsm0503_tch_hr_facch_decode(&result[0], pos,
|
||||
&n_errors, &n_bits_total);
|
||||
else
|
||||
rc = gsm0503_tch_fr_facch_decode(&result[0], pos,
|
||||
&n_errors, &n_bits_total);
|
||||
CHECK_RC_OR_RET(rc == GSM_MACBLOCK_LEN, "decoding");
|
||||
|
||||
printf("%s(FACCH/%c): decoded (BER=%d/%d): %s\n",
|
||||
__func__, half_rate ? 'H' : 'F', n_errors, n_bits_total,
|
||||
osmo_hexdump(result, GSM_MACBLOCK_LEN));
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
struct test_macblock {
|
||||
bool is_egprs;
|
||||
uint16_t exp_burst_bits;
|
||||
|
@ -635,6 +681,13 @@ int main(int argc, char **argv)
|
|||
}
|
||||
}
|
||||
|
||||
printf("\nTesting FACCH/F codec:\n");
|
||||
for (i = 0; i < ARRAY_SIZE(test_l2); i++)
|
||||
test_facch(test_l2[i], false);
|
||||
printf("\nTesting FACCH/H codec:\n");
|
||||
for (i = 0; i < ARRAY_SIZE(test_l2); i++)
|
||||
test_facch(test_l2[i], true);
|
||||
|
||||
printf("\nTesting CSD functions:\n");
|
||||
for (i = 0; i < ARRAY_SIZE(csd_tests); i++)
|
||||
test_csd(&csd_tests[i]);
|
||||
|
|
|
@ -368,6 +368,40 @@ S-Bits:
|
|||
81 81 81 81 7f 7f 7f 7f 81 81 7f 81 7f 7f 81 7f 81 81 7f 81 7f 7f 7f 7f 81 81 7f 81 81 81 81 7f 7f 7f 7f 81 7f 7f 81 7f 7f 81 7f 7f 7f 7f 7f 81 7f 7f 7f 81 7f 7f 81 81 7f 7f 81 7f 7f 7f 7f 7f 7f 81 81 7f 81 81 7f 81 81 7f 81 7f 7f 7f 81 81 81 81 81 7f 81 81 81 81 7f 7f 81 81 7f 7f 81 81 7f 81 81 7f 7f 7f 7f 7f 81 81 81 81 7f 7f 7f 81 7f 7f 7f 81
|
||||
7f 7f 81 7f 7f 7f 81 81 7f 7f 81 81 7f 81 7f 81 81 7f 7f 81 81 7f 81 81 7f 7f 81 7f 81 81 81 7f 7f 81 7f 7f 7f 81 7f 7f 7f 81 81 7f 81 81 7f 81 7f 81 81 81 7f 7f 7f 7f 7f 81 7f 7f 7f 7f 7f 81 7f 7f 7f 7f 7f 81 7f 7f 81 7f 81 81 7f 7f 7f 81 81 81 81 81 81 81 7f 7f 81 7f 81 81 81 7f 81 7f 81 81 7f 7f 7f 7f 7f 7f 7f 81 81 81 7f 81 81 7f 7f 7f 81 7f
|
||||
|
||||
Testing FACCH/F codec:
|
||||
test_facch(FACCH/F): encoding: 03 03 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
test_facch(FACCH/F): decoded (BER=0/456): 03 03 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
test_facch(FACCH/F): decoded (BER=0/456): 03 03 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
test_facch(FACCH/F): decoded (BER=0/456): 03 03 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
|
||||
test_facch(FACCH/F): encoding: a3 af 5f 00 36 43 44 ab d9 6d 7d 62 24 c9 d2 92 fa 27 5d 71 7a 59 a8
|
||||
test_facch(FACCH/F): decoded (BER=0/456): a3 af 5f 00 36 43 44 ab d9 6d 7d 62 24 c9 d2 92 fa 27 5d 71 7a 59 a8
|
||||
test_facch(FACCH/F): decoded (BER=0/456): a3 af 5f 00 36 43 44 ab d9 6d 7d 62 24 c9 d2 92 fa 27 5d 71 7a 59 a8
|
||||
test_facch(FACCH/F): decoded (BER=0/456): a3 af 5f 00 36 43 44 ab d9 6d 7d 62 24 c9 d2 92 fa 27 5d 71 7a 59 a8
|
||||
|
||||
test_facch(FACCH/F): encoding: 01 02 03 00 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17
|
||||
test_facch(FACCH/F): decoded (BER=0/456): 01 02 03 00 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17
|
||||
test_facch(FACCH/F): decoded (BER=0/456): 01 02 03 00 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17
|
||||
test_facch(FACCH/F): decoded (BER=0/456): 01 02 03 00 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17
|
||||
|
||||
|
||||
Testing FACCH/H codec:
|
||||
test_facch(FACCH/H): encoding: 03 03 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
test_facch(FACCH/H): decoded (BER=0/456): 03 03 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
test_facch(FACCH/H): decoded (BER=0/456): 03 03 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
test_facch(FACCH/H): decoded (BER=0/456): 03 03 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
|
||||
test_facch(FACCH/H): encoding: a3 af 5f 00 36 43 44 ab d9 6d 7d 62 24 c9 d2 92 fa 27 5d 71 7a 59 a8
|
||||
test_facch(FACCH/H): decoded (BER=0/456): a3 af 5f 00 36 43 44 ab d9 6d 7d 62 24 c9 d2 92 fa 27 5d 71 7a 59 a8
|
||||
test_facch(FACCH/H): decoded (BER=0/456): a3 af 5f 00 36 43 44 ab d9 6d 7d 62 24 c9 d2 92 fa 27 5d 71 7a 59 a8
|
||||
test_facch(FACCH/H): decoded (BER=0/456): a3 af 5f 00 36 43 44 ab d9 6d 7d 62 24 c9 d2 92 fa 27 5d 71 7a 59 a8
|
||||
|
||||
test_facch(FACCH/H): encoding: 01 02 03 00 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17
|
||||
test_facch(FACCH/H): decoded (BER=0/456): 01 02 03 00 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17
|
||||
test_facch(FACCH/H): decoded (BER=0/456): 01 02 03 00 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17
|
||||
test_facch(FACCH/H): decoded (BER=0/456): 01 02 03 00 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17
|
||||
|
||||
|
||||
Testing CSD functions:
|
||||
test_csd(TCH/F9.6): block #0 (pattern 0x00): n_errors=0 / n_bits_total=456
|
||||
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||
|
|
Loading…
Reference in New Issue