diff options
Diffstat (limited to 'src/coding')
-rw-r--r-- | src/coding/Makefile.am | 21 | ||||
-rw-r--r-- | src/coding/gsm0503_amr_dtx.c | 191 | ||||
-rw-r--r-- | src/coding/gsm0503_coding.c | 1125 | ||||
-rw-r--r-- | src/coding/gsm0503_interleaving.c | 56 | ||||
-rw-r--r-- | src/coding/gsm0503_mapping.c | 4 | ||||
-rw-r--r-- | src/coding/gsm0503_parity.c | 4 | ||||
-rw-r--r-- | src/coding/gsm0503_tables.c | 4 | ||||
-rw-r--r-- | src/coding/libosmocoding.map | 23 |
8 files changed, 1091 insertions, 337 deletions
diff --git a/src/coding/Makefile.am b/src/coding/Makefile.am index b023668e..c2a02d5b 100644 --- a/src/coding/Makefile.am +++ b/src/coding/Makefile.am @@ -1,13 +1,14 @@ # This is _NOT_ the library release version, it's an API version. # Please read Chapter 6 "Library interface versions" of the libtool # documentation before making any modification -LIBVERSION=1:1:1 +LIBVERSION=3:1:3 AM_CPPFLAGS = \ -I"$(top_srcdir)/include" \ -I"$(top_builddir)/include" \ - $(TALLOC_CFLAGS) -AM_CFLAGS = -Wall + -I"$(top_builddir)" \ + $(NULL) +AM_CFLAGS = -Wall $(TALLOC_CFLAGS) if ENABLE_PSEUDOTALLOC AM_CPPFLAGS += -I$(top_srcdir)/src/pseudotalloc @@ -24,13 +25,15 @@ libosmocoding_la_SOURCES = \ gsm0503_amr_dtx.c libosmocoding_la_LDFLAGS = \ $(LTLDFLAGS_OSMOCODING) \ - -version-info \ - $(LIBVERSION) \ + -version-info $(LIBVERSION) \ -no-undefined \ - $(TALLOC_LIBS) + $(NULL) + libosmocoding_la_LIBADD = \ - ../libosmocore.la \ - ../gsm/libosmogsm.la \ - ../codec/libosmocodec.la + $(top_builddir)/src/core/libosmocore.la \ + $(top_builddir)/src/gsm/libosmogsm.la \ + $(top_builddir)/src/codec/libosmocodec.la \ + $(NULL) EXTRA_DIST = libosmocoding.map +EXTRA_libosmocoding_la_DEPENDENCIES = libosmocoding.map diff --git a/src/coding/gsm0503_amr_dtx.c b/src/coding/gsm0503_amr_dtx.c index 7069b967..7de3b281 100644 --- a/src/coding/gsm0503_amr_dtx.c +++ b/src/coding/gsm0503_amr_dtx.c @@ -1,5 +1,5 @@ /* - * (C) 2020 by sysmocom - s.f.m.c. GmbH, Author: Philipp Maier + * (C) 2020-2022 by sysmocom - s.f.m.c. GmbH, Author: Philipp Maier * All Rights Reserved * * SPDX-License-Identifier: GPL-2.0+ @@ -32,6 +32,8 @@ #include <osmocom/coding/gsm0503_parity.h> #include <osmocom/gsm/gsm0503.h> +#define S2U(b) ((b) < 0) + /* See also: 3GPP TS 05.03, chapter 3.10.1.3, 3.10.5.2 Identification marker */ static const ubit_t id_marker_1[] = { 1, 0, 1, 1, 0, 0, 0, 0, 1 }; @@ -60,7 +62,7 @@ const struct value_string gsm0503_amr_dtx_frame_names[] = { { 0, NULL } }; -static bool detect_afs_id_marker(int *n_errors, int *n_bits_total, const ubit_t * ubits, uint8_t offset, uint8_t count, +static bool detect_afs_id_marker(int *n_errors, int *n_bits_total, const sbit_t *sbits, uint8_t offset, uint8_t count, const ubit_t * id_marker, uint8_t id_marker_len) { unsigned int i, k; @@ -69,20 +71,20 @@ static bool detect_afs_id_marker(int *n_errors, int *n_bits_total, const ubit_t int bits = 0; /* Override coded in-band data */ - ubits += offset; + sbits += offset; /* Check for identification marker bits */ for (i = 0; i < count; i++) { for (k = 0; k < 4; k++) { - if (id_marker[id_bit_nr % id_marker_len] != *ubits) + if (*sbits == 0 || id_marker[id_bit_nr % id_marker_len] != S2U(*sbits)) errors++; id_bit_nr++; - ubits++; + sbits++; bits++; } /* Jump to the next block of 4 bits */ - ubits += 4; + sbits += 4; } *n_errors = errors; @@ -92,30 +94,30 @@ static bool detect_afs_id_marker(int *n_errors, int *n_bits_total, const ubit_t return *n_errors < *n_bits_total / 8; } -static bool detect_ahs_id_marker(int *n_errors, int *n_bits_total, const ubit_t * ubits, const ubit_t * id_marker) +static bool detect_ahs_id_marker(int *n_errors, int *n_bits_total, const sbit_t *sbits, const ubit_t *id_marker) { unsigned int i, k; int errors = 0; int bits = 0; /* Override coded in-band data */ - ubits += 16; + sbits += 16; /* Check first identification marker bits (23*9 bits) */ for (i = 0; i < 23; i++) { for (k = 0; k < 9; k++) { - if (id_marker[k] != *ubits) + if (*sbits == 0 || id_marker[k] != S2U(*sbits)) errors++; - ubits++; + sbits++; bits++; } } /* Check remaining identification marker bits (5 bits) */ for (k = 0; k < 5; k++) { - if (id_marker[k] != *ubits) + if (*sbits == 0 || id_marker[k] != S2U(*sbits)) errors++; - ubits++; + sbits++; bits++; } @@ -126,7 +128,7 @@ static bool detect_ahs_id_marker(int *n_errors, int *n_bits_total, const ubit_t return *n_errors < *n_bits_total / 8; } -static bool detect_interleaved_ahs_id_marker(int *n_errors, int *n_bits_total, const ubit_t * ubits, uint8_t offset, +static bool detect_interleaved_ahs_id_marker(int *n_errors, int *n_bits_total, const sbit_t *sbits, uint8_t offset, uint8_t n_bits, const ubit_t * id_marker, uint8_t id_marker_len) { unsigned int i, k; @@ -136,23 +138,23 @@ static bool detect_interleaved_ahs_id_marker(int *n_errors, int *n_bits_total, c uint8_t remainder = n_bits % id_marker_len; /* Override coded in-band data */ - ubits += offset; + sbits += offset; /* Check first identification marker bits (23*9 bits) */ for (i = 0; i < full_rounds; i++) { for (k = 0; k < id_marker_len; k++) { - if (id_marker[k] != *ubits) + if (*sbits == 0 || id_marker[k] != S2U(*sbits)) errors++; - ubits += 2; + sbits += 2; bits++; } } /* Check remaining identification marker bits (5 bits) */ for (k = 0; k < remainder; k++) { - if (id_marker[k] != *ubits) + if (*sbits == 0 || id_marker[k] != S2U(*sbits)) errors++; - ubits += 2; + sbits += 2; bits++; } @@ -163,126 +165,128 @@ static bool detect_interleaved_ahs_id_marker(int *n_errors, int *n_bits_total, c return *n_errors < *n_bits_total / 8; } -/* Detect a an FR AMR SID_FIRST frame by its identifcation marker */ -static bool detect_afs_sid_first(int *n_errors, int *n_bits_total, const ubit_t * ubits) +/* Detect an FR AMR SID_FIRST frame by its identifcation marker */ +static bool detect_afs_sid_first(int *n_errors, int *n_bits_total, const sbit_t *sbits) { - return detect_afs_id_marker(n_errors, n_bits_total, ubits, 32, 53, id_marker_0, 9); + return detect_afs_id_marker(n_errors, n_bits_total, sbits, 32, 53, id_marker_0, 9); } -/* Detect an FR AMR SID_FIRST frame by its identification marker */ -static bool detect_afs_sid_update(int *n_errors, int *n_bits_total, const ubit_t * ubits) +/* Detect an FR AMR SID_UPDATE frame by its identification marker */ +static bool detect_afs_sid_update(int *n_errors, int *n_bits_total, const sbit_t *sbits) { - return detect_afs_id_marker(n_errors, n_bits_total, ubits, 36, 53, id_marker_0, 9); + return detect_afs_id_marker(n_errors, n_bits_total, sbits, 36, 53, id_marker_0, 9); } -/* Detect an FR AMR SID_FIRST frame by its repeating coded inband data */ -static bool detect_afs_onset(int *n_errors, int *n_bits_total, const ubit_t * ubits) +/* Detect an FR AMR ONSET frame by its repeating coded inband data */ +static int detect_afs_onset(int *n_errors, int *n_bits_total, const sbit_t *sbits) { bool rc; - rc = detect_afs_id_marker(n_errors, n_bits_total, ubits, 4, 57, codec_mode_1_sid, 16); + rc = detect_afs_id_marker(n_errors, n_bits_total, sbits, 4, 57, codec_mode_1_sid, 16); if (rc) - return true; + return 0; - rc = detect_afs_id_marker(n_errors, n_bits_total, ubits, 4, 57, codec_mode_2_sid, 16); + rc = detect_afs_id_marker(n_errors, n_bits_total, sbits, 4, 57, codec_mode_2_sid, 16); if (rc) - return true; + return 1; - rc = detect_afs_id_marker(n_errors, n_bits_total, ubits, 4, 57, codec_mode_3_sid, 16); + rc = detect_afs_id_marker(n_errors, n_bits_total, sbits, 4, 57, codec_mode_3_sid, 16); if (rc) - return true; + return 2; - rc = detect_afs_id_marker(n_errors, n_bits_total, ubits, 4, 57, codec_mode_4_sid, 16); + rc = detect_afs_id_marker(n_errors, n_bits_total, sbits, 4, 57, codec_mode_4_sid, 16); if (rc) - return true; + return 3; - return false; + return -1; } /* Detect an HR AMR SID UPDATE frame by its identification marker */ -static bool detect_ahs_sid_update(int *n_errors, int *n_bits_total, const ubit_t * ubits) +static bool detect_ahs_sid_update(int *n_errors, int *n_bits_total, const sbit_t *sbits) { - return detect_ahs_id_marker(n_errors, n_bits_total, ubits, id_marker_1); + return detect_ahs_id_marker(n_errors, n_bits_total, sbits, id_marker_1); } /* Detect an HR AMR SID FIRST (part 1) frame by its identification marker */ -static bool detect_ahs_sid_first_p1(int *n_errors, int *n_bits_total, const ubit_t * ubits) +static bool detect_ahs_sid_first_p1(int *n_errors, int *n_bits_total, const sbit_t *sbits) { - return detect_ahs_id_marker(n_errors, n_bits_total, ubits, id_marker_0); + return detect_ahs_id_marker(n_errors, n_bits_total, sbits, id_marker_0); } /* Detect an HR AMR SID FIRST (part 2) frame by its repeating coded inband data */ -static bool detect_ahs_sid_first_p2(int *n_errors, int *n_bits_total, const ubit_t * ubits) +static int detect_ahs_sid_first_p2(int *n_errors, int *n_bits_total, const sbit_t *sbits) { bool rc; - rc = detect_interleaved_ahs_id_marker(n_errors, n_bits_total, ubits, 0, 114, codec_mode_1_sid, 16); + rc = detect_interleaved_ahs_id_marker(n_errors, n_bits_total, sbits, 0, 114, codec_mode_1_sid, 16); if (rc) - return true; + return 0; - rc = detect_interleaved_ahs_id_marker(n_errors, n_bits_total, ubits, 0, 114, codec_mode_2_sid, 16); + rc = detect_interleaved_ahs_id_marker(n_errors, n_bits_total, sbits, 0, 114, codec_mode_2_sid, 16); if (rc) - return true; + return 1; - rc = detect_interleaved_ahs_id_marker(n_errors, n_bits_total, ubits, 0, 114, codec_mode_3_sid, 16); + rc = detect_interleaved_ahs_id_marker(n_errors, n_bits_total, sbits, 0, 114, codec_mode_3_sid, 16); if (rc) - return true; + return 2; - rc = detect_interleaved_ahs_id_marker(n_errors, n_bits_total, ubits, 0, 114, codec_mode_4_sid, 16); + rc = detect_interleaved_ahs_id_marker(n_errors, n_bits_total, sbits, 0, 114, codec_mode_4_sid, 16); if (rc) - return true; + return 3; - return false; + return -1; } /* Detect an HR AMR ONSET frame by its repeating coded inband data */ -static bool detect_ahs_onset(int *n_errors, int *n_bits_total, const ubit_t * ubits) +static int detect_ahs_onset(int *n_errors, int *n_bits_total, const sbit_t *sbits) { bool rc; - rc = detect_interleaved_ahs_id_marker(n_errors, n_bits_total, ubits, 1, 114, codec_mode_1_sid, 16); + rc = detect_interleaved_ahs_id_marker(n_errors, n_bits_total, sbits, 1, 114, codec_mode_1_sid, 16); if (rc) - return true; + return 0; - rc = detect_interleaved_ahs_id_marker(n_errors, n_bits_total, ubits, 1, 114, codec_mode_2_sid, 16); + rc = detect_interleaved_ahs_id_marker(n_errors, n_bits_total, sbits, 1, 114, codec_mode_2_sid, 16); if (rc) - return true; + return 1; - rc = detect_interleaved_ahs_id_marker(n_errors, n_bits_total, ubits, 1, 114, codec_mode_3_sid, 16); + rc = detect_interleaved_ahs_id_marker(n_errors, n_bits_total, sbits, 1, 114, codec_mode_3_sid, 16); if (rc) - return true; + return 2; - rc = detect_interleaved_ahs_id_marker(n_errors, n_bits_total, ubits, 1, 114, codec_mode_4_sid, 16); + rc = detect_interleaved_ahs_id_marker(n_errors, n_bits_total, sbits, 1, 114, codec_mode_4_sid, 16); if (rc) - return true; + return 3; - return false; + return -1; } /* Detect an HR AMR SID FIRST INHIBIT frame by its identification marker */ -static bool detect_ahs_sid_first_inh(int *n_errors, int *n_bits_total, const ubit_t * ubits) +static bool detect_ahs_sid_first_inh(int *n_errors, int *n_bits_total, const sbit_t *sbits) { - return detect_interleaved_ahs_id_marker(n_errors, n_bits_total, ubits, 33, 212, id_marker_1, 9); + return detect_interleaved_ahs_id_marker(n_errors, n_bits_total, sbits, 33, 212, id_marker_1, 9); } /* Detect an HR AMR SID UPDATE INHIBIT frame by its identification marker */ -static bool detect_ahs_sid_update_inh(int *n_errors, int *n_bits_total, const ubit_t * ubits) +static bool detect_ahs_sid_update_inh(int *n_errors, int *n_bits_total, const sbit_t *sbits) { - return detect_interleaved_ahs_id_marker(n_errors, n_bits_total, ubits, 33, 212, id_marker_0, 9); + return detect_interleaved_ahs_id_marker(n_errors, n_bits_total, sbits, 33, 212, id_marker_0, 9); } /*! Detect FR AMR DTX frame in unmapped, deinterleaved frame bits. - * \param[in] ubits input bits (456 bit). * \param[out] n_errors number of errornous bits. * \param[out] n_bits_total number of checked bits. + * \param[out] mode_id codec mode ID (0..3 or -1). + * \param[in] sbits input soft-bits (456 bit). * \returns dtx frame type. */ -enum gsm0503_amr_dtx_frames gsm0503_detect_afs_dtx_frame(int *n_errors, int *n_bits_total, const ubit_t * ubits) +enum gsm0503_amr_dtx_frames gsm0503_detect_afs_dtx_frame2(int *n_errors, int *n_bits_total, + int *mode_id, const sbit_t *sbits) { - if (detect_afs_sid_first(n_errors, n_bits_total, ubits)) + if (detect_afs_sid_first(n_errors, n_bits_total, sbits)) return AFS_SID_FIRST; - if (detect_afs_sid_update(n_errors, n_bits_total, ubits)) + if (detect_afs_sid_update(n_errors, n_bits_total, sbits)) return AFS_SID_UPDATE; - if (detect_afs_onset(n_errors, n_bits_total, ubits)) + if ((*mode_id = detect_afs_onset(n_errors, n_bits_total, sbits)) != -1) return AFS_ONSET; *n_errors = 0; @@ -290,27 +294,62 @@ enum gsm0503_amr_dtx_frames gsm0503_detect_afs_dtx_frame(int *n_errors, int *n_b return AMR_OTHER; } -/*! Detect HR AMR DTX frame in unmapped, deinterleaved frame bits. +/*! Detect FR AMR DTX frame in unmapped, deinterleaved frame bits. + * DEPRECATED: use gsm0503_detect_afs_dtx_frame2() instead. + * \param[out] n_errors number of errornous bits. + * \param[out] n_bits_total number of checked bits. * \param[in] ubits input bits (456 bit). + * \returns dtx frame type. */ +enum gsm0503_amr_dtx_frames gsm0503_detect_afs_dtx_frame(int *n_errors, int *n_bits_total, + const ubit_t *ubits) +{ + int mode_id; /* unused */ + sbit_t sbits[456]; + + osmo_ubit2sbit(&sbits[0], &ubits[0], sizeof(sbits)); + return gsm0503_detect_afs_dtx_frame2(n_errors, n_bits_total, &mode_id, &sbits[0]); +} + +/*! Detect HR AMR DTX frame in unmapped, deinterleaved frame bits. * \param[out] n_errors number of errornous bits. * \param[out] n_bits_total number of checked bits. + * \param[out] mode_id codec ID (CMI or CMC/CMR). + * \param[out] mode_id codec mode ID (0..3 or -1). + * \param[in] sbits input soft-bits (456 bit). * \returns dtx frame type, */ -enum gsm0503_amr_dtx_frames gsm0503_detect_ahs_dtx_frame(int *n_errors, int *n_bits_total, const ubit_t * ubits) +enum gsm0503_amr_dtx_frames gsm0503_detect_ahs_dtx_frame2(int *n_errors, int *n_bits_total, + int *mode_id, const sbit_t *sbits) { - if (detect_ahs_sid_update(n_errors, n_bits_total, ubits)) + if (detect_ahs_sid_update(n_errors, n_bits_total, sbits)) return AHS_SID_UPDATE; - if (detect_ahs_sid_first_inh(n_errors, n_bits_total, ubits)) + if (detect_ahs_sid_first_inh(n_errors, n_bits_total, sbits)) return AHS_SID_FIRST_INH; - if (detect_ahs_sid_update_inh(n_errors, n_bits_total, ubits)) + if (detect_ahs_sid_update_inh(n_errors, n_bits_total, sbits)) return AHS_SID_UPDATE_INH; - if (detect_ahs_sid_first_p1(n_errors, n_bits_total, ubits)) + if (detect_ahs_sid_first_p1(n_errors, n_bits_total, sbits)) return AHS_SID_FIRST_P1; - if (detect_ahs_sid_first_p2(n_errors, n_bits_total, ubits)) + if ((*mode_id = detect_ahs_sid_first_p2(n_errors, n_bits_total, sbits)) != -1) return AHS_SID_FIRST_P2; - if (detect_ahs_onset(n_errors, n_bits_total, ubits)) + if ((*mode_id = detect_ahs_onset(n_errors, n_bits_total, sbits)) != -1) return AHS_ONSET; *n_errors = 0; *n_bits_total = 0; return AMR_OTHER; } + +/*! Detect HR AMR DTX frame in unmapped, deinterleaved frame bits. + * DEPRECATED: use gsm0503_detect_ahs_dtx_frame2() instead. + * \param[out] n_errors number of errornous bits. + * \param[out] n_bits_total number of checked bits. + * \param[in] ubits input bits (456 bit). + * \returns dtx frame type, */ +enum gsm0503_amr_dtx_frames gsm0503_detect_ahs_dtx_frame(int *n_errors, int *n_bits_total, + const ubit_t *ubits) +{ + int mode_id; /* unused */ + sbit_t sbits[456]; + + osmo_ubit2sbit(&sbits[0], &ubits[0], sizeof(sbits)); + return gsm0503_detect_ahs_dtx_frame2(n_errors, n_bits_total, &mode_id, &sbits[0]); +} diff --git a/src/coding/gsm0503_coding.c b/src/coding/gsm0503_coding.c index 1bec56ea..022f4656 100644 --- a/src/coding/gsm0503_coding.c +++ b/src/coding/gsm0503_coding.c @@ -17,10 +17,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include <stdio.h> @@ -35,9 +31,7 @@ #include <osmocom/core/crcgen.h> #include <osmocom/core/endian.h> -#include <osmocom/gprs/protocol/gsm_04_60.h> -#include <osmocom/gprs/gprs_rlc.h> - +#include <osmocom/gsm/protocol/gsm_44_060.h> #include <osmocom/gsm/protocol/gsm_04_08.h> #include <osmocom/gsm/gsm0503.h> #include <osmocom/codec/codec.h> @@ -542,24 +536,29 @@ static int osmo_conv_decode_ber_punctured(const struct osmo_conv_code *code, int *n_errors, int *n_bits_total, const uint8_t *data_punc) { - int res, i, coded_len; + int res, coded_len; ubit_t recoded[EGPRS_DATA_C_MAX]; res = osmo_conv_decode(code, input, output); - if (n_bits_total || n_errors) { - coded_len = osmo_conv_encode(code, output, recoded); - OSMO_ASSERT(sizeof(recoded) / sizeof(recoded[0]) >= coded_len); - } + if (!n_bits_total && !n_errors) + return res; + + coded_len = osmo_conv_encode(code, output, recoded); + OSMO_ASSERT(ARRAY_SIZE(recoded) >= coded_len); /* Count bit errors */ if (n_errors) { *n_errors = 0; - for (i = 0; i < coded_len; i++) { - if (((!data_punc) || (data_punc && !data_punc[i])) && - !((recoded[i] && input[i] < 0) || - (!recoded[i] && input[i] > 0)) ) - *n_errors += 1; + for (unsigned int i = 0; i < coded_len; i++) { + /* punctured bits do not count as bit errors */ + if (data_punc != NULL && data_punc[i]) + continue; + if (recoded[i] == 1 && input[i] < 0) + continue; + if (recoded[i] == 0 && input[i] > 0) + continue; + *n_errors += 1; } } @@ -611,7 +610,7 @@ static int _xcch_decode_cB(uint8_t *l2_data, const sbit_t *cB, /*! convenience wrapper for encoding to coded bits * \param[out] cB caller-allocated buffer for 456 coded bits as per TS 05.03 4.1.3 - * \param[out] l2_data to-be-encoded L2 Frame + * \param[in] l2_data to-be-encoded L2 Frame * \returns 0 */ static int _xcch_encode_cB(ubit_t *cB, const uint8_t *l2_data) { @@ -926,10 +925,10 @@ static int egprs_decode_data(uint8_t *l2_data, const sbit_t *c, * \param[out] l2_data caller-allocated buffer for L2 Frame * \param[in] bursts burst input data as soft unpacked bits * \param[in] nbits number of bits in \a bursts - * \param usf_p unused argument ?!? + * \param usf_p Uplink State Flag, FIXME: not implemented * \param[out] n_errors number of detected bit-errors * \param[out] n_bits_total total number of decoded bits - * \returns 0 on success; negative on error */ + * \returns number of bytes decoded; negative on error */ int gsm0503_pdtch_egprs_decode(uint8_t *l2_data, const sbit_t *bursts, uint16_t nbits, uint8_t *usf_p, int *n_errors, int *n_bits_total) { @@ -1015,10 +1014,10 @@ int gsm0503_pdtch_egprs_decode(uint8_t *l2_data, const sbit_t *bursts, uint16_t /*! Decode GPRS PDTCH * \param[out] l2_data caller-allocated buffer for L2 Frame * \param[in] bursts burst input data as soft unpacked bits - * \param[out] usf_p uplink stealing flag + * \param[out] usf_p Uplink State Flag, only relevant for DL blocks * \param[out] n_errors number of detected bit-errors - * \param[out] n_bits_total total number of dcoded bits - * \returns 0 on success; negative on error */ + * \param[out] n_bits_total total number of decoded bits + * \returns number of bytes decoded; negative on error */ int gsm0503_pdtch_decode(uint8_t *l2_data, const sbit_t *bursts, uint8_t *usf_p, int *n_errors, int *n_bits_total) { @@ -1047,6 +1046,10 @@ int gsm0503_pdtch_decode(uint8_t *l2_data, const sbit_t *bursts, uint8_t *usf_p, osmo_conv_decode_ber(&gsm0503_xcch, cB, conv, n_errors, n_bits_total); + /* the three USF bits d(0),d(1),d(2) are *not* precoded */ + if (usf_p) + *usf_p = (conv[0] << 2) | (conv[1] << 1) | (conv[2] << 0); + rv = osmo_crc64gen_check_bits(&gsm0503_fire_crc40, conv, 184, conv + 184); if (rv) @@ -1056,6 +1059,7 @@ int gsm0503_pdtch_decode(uint8_t *l2_data, const sbit_t *bursts, uint8_t *usf_p, return 23; case 2: + /* reorder, set punctured bits to 0 (unknown state) */ for (i = 587, j = 455; i >= 0; i--) { if (!gsm0503_puncture_cs2[i]) cB[i] = cB[j--]; @@ -1063,9 +1067,15 @@ int gsm0503_pdtch_decode(uint8_t *l2_data, const sbit_t *bursts, uint8_t *usf_p, cB[i] = 0; } - osmo_conv_decode_ber(&gsm0503_cs2_np, cB, - conv, n_errors, n_bits_total); + /* decode as if puncturing was not employed (note '_np') */ + osmo_conv_decode_ber_punctured(&gsm0503_cs2_np, cB, conv, + n_errors, NULL, + gsm0503_puncture_cs2); + /* indicate the actual amount of coded bits (excluding punctured ones) */ + if (n_bits_total != NULL) + *n_bits_total = 456; + /* 5.1.2.2 a) the three USF bits d(0),d(1),d(2) are precoded into six bits */ for (i = 0; i < 8; i++) { for (j = 0, k = 0; j < 6; j++) k += abs(((int)gsm0503_usf2six[i][j]) - ((int)conv[j])); @@ -1091,6 +1101,7 @@ int gsm0503_pdtch_decode(uint8_t *l2_data, const sbit_t *bursts, uint8_t *usf_p, return 34; case 3: + /* reorder, set punctured bits to 0 (unknown state) */ for (i = 675, j = 455; i >= 0; i--) { if (!gsm0503_puncture_cs3[i]) cB[i] = cB[j--]; @@ -1098,9 +1109,15 @@ int gsm0503_pdtch_decode(uint8_t *l2_data, const sbit_t *bursts, uint8_t *usf_p, cB[i] = 0; } - osmo_conv_decode_ber(&gsm0503_cs3_np, cB, - conv, n_errors, n_bits_total); + /* decode as if puncturing was not employed (note '_np') */ + osmo_conv_decode_ber_punctured(&gsm0503_cs3_np, cB, conv, + n_errors, NULL, + gsm0503_puncture_cs3); + /* indicate the actual amount of coded bits (excluding punctured ones) */ + if (n_bits_total != NULL) + *n_bits_total = 456; + /* 5.1.3.2 a) the three USF bits d(0),d(1),d(2) are precoded into six bits */ for (i = 0; i < 8; i++) { for (j = 0, k = 0; j < 6; j++) k += abs(((int)gsm0503_usf2six[i][j]) - ((int)conv[j])); @@ -1129,6 +1146,7 @@ int gsm0503_pdtch_decode(uint8_t *l2_data, const sbit_t *bursts, uint8_t *usf_p, for (i = 12; i < 456; i++) conv[i] = (cB[i] < 0) ? 1 : 0; + /* 5.1.4.2 a) the three USF bits d(0),d(1),d(2) are precoded into twelve bits */ for (i = 0; i < 8; i++) { for (j = 0, k = 0; j < 12; j++) k += abs(((int)gsm0503_usf2twelve_sbit[i][j]) - ((int)cB[j])); @@ -1577,24 +1595,22 @@ static void tch_fr_disassemble(ubit_t *b_bits, } } -/* assemble a HR codec frame in format as used inside RTP */ +/* assemble a HR codec frame in the canonical format of ETSI TS 101 318 */ static void tch_hr_reassemble(uint8_t *tch_data, const ubit_t *b_bits) { - int i, j; - - tch_data[0] = 0x00; /* F = 0, FT = 000 */ - memset(tch_data + 1, 0, 14); + int i; - for (i = 0, j = 8; i < 112; i++, j++) - tch_data[j >> 3] |= (b_bits[i] << (7 - (j & 7))); + memset(tch_data, 0, GSM_HR_BYTES); + for (i = 0; i < 112; i++) + tch_data[i >> 3] |= (b_bits[i] << (7 - (i & 7))); } static void tch_hr_disassemble(ubit_t *b_bits, const uint8_t *tch_data) { - int i, j; + int i; - for (i = 0, j = 8; i < 112; i++, j++) - b_bits[i] = (tch_data[j >> 3] >> (7 - (j & 7))) & 1; + for (i = 0; i < 112; i++) + b_bits[i] = (tch_data[i >> 3] >> (7 - (i & 7))) & 1; } /* assemble a EFR codec frame in format as used inside RTP */ @@ -1809,7 +1825,7 @@ static void tch_efr_unreorder(ubit_t *s, ubit_t *p, const ubit_t *w) s[119] = (sum >= 2); memcpy(s + 121, w + 125, 53); sum = s[172] + w[178] + w[179]; - s[172] = (sum > 2); + s[172] = (sum >= 2); memcpy(s + 174, w + 180, 50); sum = s[222] + w[230] + w[231]; s[222] = (sum >= 2); @@ -1865,7 +1881,7 @@ int gsm0503_tch_fr_decode(uint8_t *tch_data, const sbit_t *bursts, return -1; } - return 23; + return GSM_MACBLOCK_LEN; } osmo_conv_decode_ber(&gsm0503_tch_fr, cB, conv, n_errors, n_bits_total); @@ -1932,40 +1948,39 @@ int gsm0503_tch_fr_encode(ubit_t *bursts, const uint8_t *tch_data, switch (len) { case GSM_EFR_BYTES: /* 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 GSM_FR_BYTES: /* 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); - memcpy(cB + 378, d + 182, 78); - osmo_conv_encode(&gsm0503_tch_fr, conv, cB); - h = 0; - + break; + case 0: /* no data, induce BFI in the receiver */ + /* Do the same thing that sysmoBTS PHY does when fed a 0-length + * payload for DL: set all u(k) bits to 0, and do the same + * with all class 2 bits. This operation is NOT the same as + * an FR codec frame of all zero bits: with all-zeros d(k) input + * the CRC3 function will produce 111 output, whereas we + * transmit 000 in those parity bits too. The result will be + * an induced BFI (bad frame indication) condition in the + * receiver, for both TCH/FS and TCH/EFS decoders. */ + memset(conv, 0, sizeof(conv)); + memset(cB + 378, 0, 78); + osmo_conv_encode(&gsm0503_tch_fr, conv, cB); + h = 0; break; case GSM_MACBLOCK_LEN: /* FACCH */ _xcch_encode_cB(cB, tch_data); - h = 1; - break; default: return -1; @@ -1982,13 +1997,13 @@ coding_efr_fr: } /*! Perform channel decoding of a HR(v1) channel according TS 05.03 - * \param[out] tch_data Codec frame in RTP payload format - * \param[in] bursts buffer containing the symbols of 8 bursts + * \param[out] tch_data Codec frame in TS 101 318 canonical format + * \param[in] bursts buffer containing the symbols of 6 bursts * \param[in] odd Odd (1) or even (0) frame number * \param[out] n_errors Number of detected bit errors * \param[out] n_bits_total Total number of bits * \returns length of bytes used in \a tch_data output buffer; negative on error */ -int gsm0503_tch_hr_decode(uint8_t *tch_data, const sbit_t *bursts, int odd, +int gsm0503_tch_hr_decode2(uint8_t *tch_data, const sbit_t *bursts, int odd, int *n_errors, int *n_bits_total) { sbit_t iB[912], cB[456], h; @@ -2002,7 +2017,7 @@ int gsm0503_tch_hr_decode(uint8_t *tch_data, const sbit_t *bursts, int odd, steal -= h; } - for (i = 2; i < 5; i++) { + for (i = 2; i < 6; i++) { gsm0503_tch_burst_unmap(NULL, &bursts[i * 116], &h, 1); steal -= h; } @@ -2055,7 +2070,35 @@ int gsm0503_tch_hr_decode(uint8_t *tch_data, const sbit_t *bursts, int odd, tch_hr_reassemble(tch_data, b); - return 15; + return GSM_HR_BYTES; +} + +/*! Perform channel decoding of a HR(v1) channel according TS 05.03, + * deprecated legacy API. + * \param[out] tch_data Codec frame in pseudo-RFC5993 format + * \param[in] bursts buffer containing the symbols of 6 bursts + * \param[in] odd Odd (1) or even (0) frame number + * \param[out] n_errors Number of detected bit errors + * \param[out] n_bits_total Total number of bits + * \returns length of bytes used in \a tch_data output buffer; negative on error + * + * The HR1 codec frame format returned by this function is pseudo-RFC5993, + * not true RFC 5993, as there is no SID classification being done + * and the FT bits in the ToC octet are always set to 0 - but this + * arguably-bogus format is the legacy public API. + */ +int gsm0503_tch_hr_decode(uint8_t *tch_data, const sbit_t *bursts, int odd, + int *n_errors, int *n_bits_total) +{ + int rc; + + rc = gsm0503_tch_hr_decode2(tch_data, bursts, odd, n_errors, + n_bits_total); + if (rc != GSM_HR_BYTES) + return rc; + memmove(tch_data + 1, tch_data, GSM_HR_BYTES); + tch_data[0] = 0x00; /* FT=0, note absence of SID classification */ + return GSM_HR_BYTES_RTP_RFC5993; } /*! Perform channel encoding on a TCH/HS channel according to TS 05.03 @@ -2070,46 +2113,41 @@ int gsm0503_tch_hr_encode(ubit_t *bursts, const uint8_t *tch_data, int len) int i; switch (len) { - case 15: /* TCH HR */ + case GSM_HR_BYTES_RTP_RFC5993: /* TCH HR with RFC 5993 prefix */ + tch_data++; + /* fall-through */ + case GSM_HR_BYTES: /* TCH HR in "pure" form */ tch_hr_disassemble(b, tch_data); - tch_hr_b_to_d(d, b); - osmo_crc8gen_set_bits(&gsm0503_tch_fr_crc3, d + 73, 22, p); - tch_hr_reorder(conv, d, p); - - osmo_conv_encode(&gsm0503_tch_hr, conv, cB); - memcpy(cB + 211, d + 95, 17); - +hr_conv_coding: + osmo_conv_encode(&gsm0503_tch_hr, conv, cB); h = 0; - 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); } - break; + case 0: /* no data, induce BFI in the receiver */ + /* see comments in gsm0503_tch_fr_encode() - same deal here */ + memset(conv, 0, sizeof(conv)); + memset(cB + 211, 0, 17); + goto hr_conv_coding; case GSM_MACBLOCK_LEN: /* 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); } - break; default: return -1; @@ -2118,6 +2156,26 @@ int gsm0503_tch_hr_encode(ubit_t *bursts, const uint8_t *tch_data, int len) return 0; } +/* TCH/AFS: parse codec ID (CMI or CMC/CMR) from coded in-band data (16 bit) */ +static uint8_t gsm0503_tch_afs_decode_inband(const sbit_t *cB) +{ + unsigned int id = 0, best = 0; + unsigned int i, j, k; + + for (i = 0; i < 4; i++) { + /* FIXME: why not using remaining (16 - 8) soft-bits here? */ + for (j = 0, k = 0; j < 8; j++) + k += abs(((int)gsm0503_afs_ic_sbit[i][j]) - ((int)cB[j])); + + if (i == 0 || k < best) { + best = k; + id = i; + } + } + + return id; +} + /*! Perform channel decoding of a TCH/AFS channel according TS 05.03 * \param[out] tch_data Codec frame in RTP payload format * \param[in] bursts buffer containing the symbols of 8 bursts @@ -2160,12 +2218,10 @@ int gsm0503_tch_afs_decode_dtx(uint8_t *tch_data, const sbit_t *bursts, { sbit_t iB[912], cB[456], h; ubit_t d[244], p[6], conv[250]; - int i, j, k, best = 0, rv, len, steal = 0, id = 0; - ubit_t cBd[456]; + int i, rv, len, steal = 0, id = -1; *n_errors = 0; *n_bits_total = 0; static ubit_t sid_first_dummy[64] = { 0 }; sbit_t sid_update_enc[256]; - uint8_t dtx_prev; for (i=0; i<8; i++) { gsm0503_tch_burst_unmap(&iB[i * 114], &bursts[i * 116], &h, i >> 2); @@ -2175,6 +2231,12 @@ int gsm0503_tch_afs_decode_dtx(uint8_t *tch_data, const sbit_t *bursts, gsm0503_tch_fr_deinterleave(cB, iB); if (steal > 0) { + /* If not NULL, dtx indicates type of previously decoded TCH/AFS frame. + * It's normally updated by gsm0503_detect_afs_dtx_frame2(), which is not + * reached in case of FACCH. Reset it here to avoid FACCH/F frames being + * misinterpreted as AMR's special DTX frames. */ + if (dtx != NULL) + *dtx = AMR_OTHER; rv = _xcch_decode_cB(tch_data, cB, n_errors, n_bits_total); if (rv) { /* Error decoding FACCH frame */ @@ -2186,16 +2248,20 @@ int gsm0503_tch_afs_decode_dtx(uint8_t *tch_data, const sbit_t *bursts, /* Determine the DTX frame type (SID_UPDATE, ONSET etc...) */ if (dtx) { - osmo_sbit2ubit(cBd, cB, 456); - dtx_prev = *dtx; - *dtx = gsm0503_detect_afs_dtx_frame(n_errors, n_bits_total, cBd); + const enum gsm0503_amr_dtx_frames dtx_prev = *dtx; + + *dtx = gsm0503_detect_afs_dtx_frame2(n_errors, n_bits_total, &id, cB); - if (dtx_prev == AFS_SID_UPDATE && *dtx == AMR_OTHER) { + switch (*dtx) { + case AMR_OTHER: /* NOTE: The AFS_SID_UPDATE frame is splitted into * two half rate frames. If the id marker frame * (AFS_SID_UPDATE) is detected the following frame * contains the actual comfort noised data part of * (AFS_SID_UPDATE_CN). */ + if (dtx_prev != AFS_SID_UPDATE) + break; + /* TODO: parse CMI _and_ CMC/CMR (16 + 16 bit) */ *dtx = AFS_SID_UPDATE_CN; extract_afs_sid_update(sid_update_enc, cB); @@ -2211,35 +2277,28 @@ int gsm0503_tch_afs_decode_dtx(uint8_t *tch_data, const sbit_t *bursts, tch_amr_sid_update_append(conv, 1, (codec_mode_req) ? codec[*ft] - : codec[id]); + : codec[id > 0 ? id : 0]); tch_amr_reassemble(tch_data, conv, 39); len = 5; goto out; - } else if (*dtx == AFS_SID_FIRST) { + case AFS_SID_FIRST: /* TODO: parse CMI or CMC/CMR (16 bit) */ tch_amr_sid_update_append(sid_first_dummy, 0, (codec_mode_req) ? codec[*ft] - : codec[id]); - tch_amr_reassemble(tch_data, conv, 39); + : codec[id > 0 ? id : 0]); + tch_amr_reassemble(tch_data, sid_first_dummy, 39); len = 5; goto out; - } else if (*dtx == AFS_ONSET) { + case AFS_SID_UPDATE: /* TODO: parse CMI _and_ CMC/CMR (16 + 16 bit) */ + case AFS_ONSET: len = 0; goto out; + default: + break; } } - for (i = 0; i < 4; i++) { - for (j = 0, k = 0; j < 8; j++) - k += abs(((int)gsm0503_afs_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) { + /* Parse codec ID (CMI or CMC/CMR) and check if it fits into range of codecs */ + if ((id = gsm0503_tch_afs_decode_inband(&cB[0])) >= codecs) { /* Codec mode out of range, return id */ return id; } @@ -2390,10 +2449,12 @@ int gsm0503_tch_afs_decode_dtx(uint8_t *tch_data, const sbit_t *bursts, out: /* Change codec request / indication, if frame is valid */ - if (codec_mode_req) - *cmr = id; - else - *ft = id; + if (id != -1) { + if (codec_mode_req) + *cmr = id; + else + *ft = id; + } return len; } @@ -2401,7 +2462,7 @@ out: /*! Perform channel encoding on a TCH/AFS channel according to TS 05.03 * \param[out] bursts caller-allocated output buffer for bursts bits * \param[in] tch_data Codec input data in RTP payload format - * \param[in] len Length of \a tch_data in bytes + * \param[in] len Length of \a tch_data in bytes or 0 to generate a bad frame * \param[in] codec_mode_req Use CMR (1) or FT (0) * \param[in] codec Array of codecs (active codec set) * \param[in] codecs Number of entries in \a codec @@ -2409,7 +2470,7 @@ out: * \param[in] cmr Codec Mode Request (used in codec_mode_req = 1 only) * \returns 0 in case of success; negative on error */ int gsm0503_tch_afs_encode(ubit_t *bursts, const uint8_t *tch_data, int len, - int codec_mode_req, uint8_t *codec, int codecs, uint8_t ft, + int codec_mode_req, const uint8_t *codec, int codecs, uint8_t ft, uint8_t cmr) { ubit_t iB[912], cB[456], h; @@ -2427,28 +2488,27 @@ int gsm0503_tch_afs_encode(ubit_t *bursts, const uint8_t *tch_data, int len, h = 0; - if (codec_mode_req) { - if (cmr >= codecs) { - /* FIXME: CMR ID is not in codec list! */ - return -1; - } - id = cmr; - } else { - if (ft >= codecs) { - /* FIXME: FT ID is not in codec list! */ - return -1; - } - id = ft; - } + id = codec_mode_req ? cmr : ft; + if (OSMO_UNLIKELY(id >= ARRAY_SIZE(gsm0503_afs_ic_ubit))) + return -1; + if (OSMO_UNLIKELY(ft >= codecs)) + return -1; switch (codec[ft]) { case 7: /* TCH/AFS12.2 */ - if (len != 31) - goto invalid_length; - - tch_amr_disassemble(d, tch_data, 244); - - osmo_crc8gen_set_bits(&gsm0503_amr_crc6, d, 81, p); + if (!len) { + /* No data, induce BFI in the receiver by inverted CRC bits. + * The data bit are all 0, so the correct parity bits would be 111111. */ + memset(d, 0, 244); + memset(p, 0, 6); + } else { + if (len != 31) + goto invalid_length; + + tch_amr_disassemble(d, tch_data, 244); + + osmo_crc8gen_set_bits(&gsm0503_amr_crc6, d, 81, p); + } tch_amr_merge(conv, d, p, 244, 81); @@ -2456,12 +2516,18 @@ int gsm0503_tch_afs_encode(ubit_t *bursts, const uint8_t *tch_data, int len, break; case 6: /* TCH/AFS10.2 */ - if (len != 26) - goto invalid_length; + if (!len) { + /* See comment above. */ + memset(d, 0, 204); + memset(p, 0, 6); + } else { + if (len != 26) + goto invalid_length; - tch_amr_disassemble(d, tch_data, 204); + tch_amr_disassemble(d, tch_data, 204); - osmo_crc8gen_set_bits(&gsm0503_amr_crc6, d, 65, p); + osmo_crc8gen_set_bits(&gsm0503_amr_crc6, d, 65, p); + } tch_amr_merge(conv, d, p, 204, 65); @@ -2469,12 +2535,18 @@ int gsm0503_tch_afs_encode(ubit_t *bursts, const uint8_t *tch_data, int len, break; case 5: /* TCH/AFS7.95 */ - if (len != 20) - goto invalid_length; + if (!len) { + /* See comment above. */ + memset(d, 0, 159); + memset(p, 0, 6); + } else { + if (len != 20) + goto invalid_length; - tch_amr_disassemble(d, tch_data, 159); + tch_amr_disassemble(d, tch_data, 159); - osmo_crc8gen_set_bits(&gsm0503_amr_crc6, d, 75, p); + osmo_crc8gen_set_bits(&gsm0503_amr_crc6, d, 75, p); + } tch_amr_merge(conv, d, p, 159, 75); @@ -2482,12 +2554,18 @@ int gsm0503_tch_afs_encode(ubit_t *bursts, const uint8_t *tch_data, int len, break; case 4: /* TCH/AFS7.4 */ - if (len != 19) - goto invalid_length; + if (!len) { + /* See comment above. */ + memset(d, 0, 148); + memset(p, 0, 6); + } else { + if (len != 19) + goto invalid_length; - tch_amr_disassemble(d, tch_data, 148); + tch_amr_disassemble(d, tch_data, 148); - osmo_crc8gen_set_bits(&gsm0503_amr_crc6, d, 61, p); + osmo_crc8gen_set_bits(&gsm0503_amr_crc6, d, 61, p); + } tch_amr_merge(conv, d, p, 148, 61); @@ -2495,12 +2573,18 @@ int gsm0503_tch_afs_encode(ubit_t *bursts, const uint8_t *tch_data, int len, break; case 3: /* TCH/AFS6.7 */ - if (len != 17) - goto invalid_length; + if (!len) { + /* See comment above. */ + memset(d, 0, 134); + memset(p, 0, 6); + } else { + if (len != 17) + goto invalid_length; - tch_amr_disassemble(d, tch_data, 134); + tch_amr_disassemble(d, tch_data, 134); - osmo_crc8gen_set_bits(&gsm0503_amr_crc6, d, 55, p); + osmo_crc8gen_set_bits(&gsm0503_amr_crc6, d, 55, p); + } tch_amr_merge(conv, d, p, 134, 55); @@ -2508,12 +2592,18 @@ int gsm0503_tch_afs_encode(ubit_t *bursts, const uint8_t *tch_data, int len, break; case 2: /* TCH/AFS5.9 */ - if (len != 15) - goto invalid_length; + if (!len) { + /* See comment above. */ + memset(d, 0, 118); + memset(p, 0, 6); + } else { + if (len != 15) + goto invalid_length; - tch_amr_disassemble(d, tch_data, 118); + tch_amr_disassemble(d, tch_data, 118); - osmo_crc8gen_set_bits(&gsm0503_amr_crc6, d, 55, p); + osmo_crc8gen_set_bits(&gsm0503_amr_crc6, d, 55, p); + } tch_amr_merge(conv, d, p, 118, 55); @@ -2521,12 +2611,18 @@ int gsm0503_tch_afs_encode(ubit_t *bursts, const uint8_t *tch_data, int len, break; case 1: /* TCH/AFS5.15 */ - if (len != 13) - goto invalid_length; + if (!len) { + /* See comment above. */ + memset(d, 0, 103); + memset(p, 0, 6); + } else { + if (len != 13) + goto invalid_length; - tch_amr_disassemble(d, tch_data, 103); + tch_amr_disassemble(d, tch_data, 103); - osmo_crc8gen_set_bits(&gsm0503_amr_crc6, d, 49, p); + osmo_crc8gen_set_bits(&gsm0503_amr_crc6, d, 49, p); + } tch_amr_merge(conv, d, p, 103, 49); @@ -2534,12 +2630,18 @@ int gsm0503_tch_afs_encode(ubit_t *bursts, const uint8_t *tch_data, int len, break; case 0: /* TCH/AFS4.75 */ - if (len != 12) - goto invalid_length; + if (!len) { + /* See comment above. */ + memset(d, 0, 95); + memset(p, 0, 6); + } else { + if (len != 12) + goto invalid_length; - tch_amr_disassemble(d, tch_data, 95); + tch_amr_disassemble(d, tch_data, 95); - osmo_crc8gen_set_bits(&gsm0503_amr_crc6, d, 39, p); + osmo_crc8gen_set_bits(&gsm0503_amr_crc6, d, 39, p); + } tch_amr_merge(conv, d, p, 95, 39); @@ -2568,9 +2670,29 @@ invalid_length: return -1; } -/*! Perform channel decoding of a TCH/AFS channel according TS 05.03 +/* TCH/AHS: parse codec ID (CMI or CMC/CMR) from coded in-band data (16 bit) */ +static uint8_t gsm0503_tch_ahs_decode_inband(const sbit_t *cB) +{ + unsigned int id = 0, best = 0; + unsigned int i, j, k; + + for (i = 0, k = 0; i < 4; i++) { + /* FIXME: why not using remaining (16 - 4) soft-bits here? */ + 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; + } + } + + return id; +} + +/*! Perform channel decoding of a TCH/AHS channel according TS 05.03 * \param[out] tch_data Codec frame in RTP payload format - * \param[in] bursts buffer containing the symbols of 8 bursts + * \param[in] bursts buffer containing the symbols of 6 bursts * \param[in] odd Is this an odd (1) or even (0) frame number? * \param[in] codec_mode_req is this CMR (1) or CMC (0) * \param[in] codec array of active codecs (active codec set) @@ -2591,9 +2713,9 @@ int gsm0503_tch_ahs_decode(uint8_t *tch_data, const sbit_t *bursts, int odd, n_bits_total, NULL); } -/*! Perform channel decoding of a TCH/AFS channel according TS 05.03 +/*! Perform channel decoding of a TCH/AHS channel according TS 05.03 * \param[out] tch_data Codec frame in RTP payload format - * \param[in] bursts buffer containing the symbols of 8 bursts + * \param[in] bursts buffer containing the symbols of 6 bursts * \param[in] odd Is this an odd (1) or even (0) frame number? * \param[in] codec_mode_req is this CMR (1) or CMC (0) * \param[in] codec array of active codecs (active codec set) @@ -2612,10 +2734,8 @@ int gsm0503_tch_ahs_decode_dtx(uint8_t *tch_data, const sbit_t *bursts, int odd, { sbit_t iB[912], cB[456], h; ubit_t d[244], p[6], conv[135]; - int i, j, k, best = 0, rv, len, steal = 0, id = 0; - ubit_t cBd[456]; + int i, rv, len, steal = 0, id = -1; static ubit_t sid_first_dummy[64] = { 0 }; - uint8_t dtx_prev; /* only unmap the stealing bits */ if (!odd) { @@ -2631,6 +2751,13 @@ int gsm0503_tch_ahs_decode_dtx(uint8_t *tch_data, const sbit_t *bursts, int odd, /* if we found a stole FACCH, but only at correct alignment */ if (steal > 0) { + /* If not NULL, dtx indicates type of previously decoded TCH/AHS frame. + * It's normally updated by gsm0503_detect_ahs_dtx_frame2(), which is not + * reached in case of FACCH. Reset it here to avoid FACCH/H frames being + * misinterpreted as AMR's special DTX frames. */ + if (dtx != NULL) + *dtx = AMR_OTHER; + for (i = 0; i < 6; i++) { gsm0503_tch_burst_unmap(&iB[i * 114], &bursts[i * 116], NULL, i >> 2); @@ -2661,21 +2788,37 @@ int gsm0503_tch_ahs_decode_dtx(uint8_t *tch_data, const sbit_t *bursts, int odd, /* Determine the DTX frame type (SID_UPDATE, ONSET etc...) */ if (dtx) { - osmo_sbit2ubit(cBd, cB, 456); - dtx_prev = *dtx; - *dtx = gsm0503_detect_ahs_dtx_frame(n_errors, n_bits_total, cBd); - - if (dtx_prev == AHS_SID_UPDATE && *dtx == AMR_OTHER) { - /* NOTE: The AHS_SID_UPDATE frame is splitted into - * two half rate frames. If the id marker frame - * (AHS_SID_UPDATE) is detected the following frame - * contains the actual comfort noised data part of - * (AHS_SID_UPDATE_CN). */ + int n_bits_total_sid; + int n_errors_sid; + + *dtx = gsm0503_detect_ahs_dtx_frame2(n_errors, n_bits_total, &id, cB); + /* TODO: detect and handle AHS_SID_UPDATE + AHS_SID_UPDATE_INH */ + + switch (*dtx) { + case AHS_SID_UPDATE: /* TODO: parse CMI _and_ CMC/CMR (16 + 16 bit) */ + /* cB[] contains 16 bits of coded in-band data and 212 bits containing + * the identification marker. We need to unmap/deinterleave 114 odd + * bits from the last two blocks, 114 even bits from the first two + * blocks and combine them together. */ + gsm0503_tch_burst_unmap(&iB[0 * 114], &bursts[2 * 116], NULL, 0); + gsm0503_tch_burst_unmap(&iB[1 * 114], &bursts[3 * 116], NULL, 0); + gsm0503_tch_burst_unmap(&iB[2 * 114], &bursts[0 * 116], NULL, 1); + gsm0503_tch_burst_unmap(&iB[3 * 114], &bursts[1 * 116], NULL, 1); + gsm0503_tch_hr_deinterleave(cB, iB); + + /* cB[] is expected to contain 16 bits of coded in-band data and + * 212 bits containing the coded data (53 bits coded at 1/4 rate). */ *dtx = AHS_SID_UPDATE_CN; osmo_conv_decode_ber(&gsm0503_tch_axs_sid_update, - cB + 16, conv, n_errors, - n_bits_total); + cB + 16, conv, &n_errors_sid, + &n_bits_total_sid); + /* gsm0503_detect_ahs_dtx_frame2() calculates BER for the marker, + * osmo_conv_decode_ber() calculates BER for the coded data. */ + if (n_errors != NULL) + *n_errors += n_errors_sid; + if (n_bits_total != NULL) + *n_bits_total += n_bits_total_sid; rv = osmo_crc16gen_check_bits(&gsm0503_amr_crc14, conv, 35, conv + 35); if (rv != 0) { @@ -2685,38 +2828,30 @@ int gsm0503_tch_ahs_decode_dtx(uint8_t *tch_data, const sbit_t *bursts, int odd, tch_amr_sid_update_append(conv, 1, (codec_mode_req) ? codec[*ft] - : codec[id]); + : codec[id > 0 ? id : 0]); tch_amr_reassemble(tch_data, conv, 39); len = 5; goto out; - } else if (*dtx == AHS_SID_FIRST_P2) { + case AHS_SID_FIRST_P2: tch_amr_sid_update_append(sid_first_dummy, 0, (codec_mode_req) ? codec[*ft] - : codec[id]); + : codec[id > 0 ? id : 0]); tch_amr_reassemble(tch_data, sid_first_dummy, 39); len = 5; goto out; - } else if (*dtx == AHS_SID_UPDATE || *dtx == AHS_ONSET - || *dtx == AHS_SID_FIRST_INH - || *dtx == AHS_SID_UPDATE_INH - || *dtx == AHS_SID_FIRST_P1) { + case AHS_ONSET: + case AHS_SID_FIRST_INH: /* TODO: parse CMI or CMC/CMR (16 bit) */ + case AHS_SID_UPDATE_INH: /* TODO: parse CMI or CMC/CMR (16 bit) */ + case AHS_SID_FIRST_P1: /* TODO: parse CMI or CMC/CMR (16 bit) */ len = 0; goto out; + default: + break; } } - 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) { + /* Parse codec ID (CMI or CMC/CMR) and check if it fits into range of codecs */ + if ((id = gsm0503_tch_ahs_decode_inband(&cB[0])) >= codecs) { /* Codec mode out of range, return id */ return id; } @@ -2851,10 +2986,12 @@ int gsm0503_tch_ahs_decode_dtx(uint8_t *tch_data, const sbit_t *bursts, int odd, out: /* Change codec request / indication, if frame is valid */ - if (codec_mode_req) - *cmr = id; - else - *ft = id; + if (id != -1) { + if (codec_mode_req) + *cmr = id; + else + *ft = id; + } return len; } @@ -2862,7 +2999,7 @@ out: /*! Perform channel encoding on a TCH/AHS channel according to TS 05.03 * \param[out] bursts caller-allocated output buffer for bursts bits * \param[in] tch_data Codec input data in RTP payload format - * \param[in] len Length of \a tch_data in bytes + * \param[in] len Length of \a tch_data in bytes or 0 to generate a bad frame * \param[in] codec_mode_req Use CMR (1) or FT (0) * \param[in] codec Array of codecs (active codec set) * \param[in] codecs Number of entries in \a codec @@ -2870,7 +3007,7 @@ out: * \param[in] cmr Codec Mode Request (used in codec_mode_req = 1 only) * \returns 0 in case of success; negative on error */ int gsm0503_tch_ahs_encode(ubit_t *bursts, const uint8_t *tch_data, int len, - int codec_mode_req, uint8_t *codec, int codecs, uint8_t ft, + int codec_mode_req, const uint8_t *codec, int codecs, uint8_t ft, uint8_t cmr) { ubit_t iB[912], cB[456], h; @@ -2897,28 +3034,27 @@ int gsm0503_tch_ahs_encode(ubit_t *bursts, const uint8_t *tch_data, int len, h = 0; - if (codec_mode_req) { - if (cmr >= codecs) { - /* FIXME: CMR ID %d not in codec list */ - return -1; - } - id = cmr; - } else { - if (ft >= codecs) { - /* FIXME: FT ID %d not in codec list */ - return -1; - } - id = ft; - } + id = codec_mode_req ? cmr : ft; + if (OSMO_UNLIKELY(id >= ARRAY_SIZE(gsm0503_ahs_ic_ubit))) + return -1; + if (OSMO_UNLIKELY(ft >= codecs)) + return -1; switch (codec[ft]) { case 5: /* TCH/AHS7.95 */ - if (len != 20) - goto invalid_length; - - tch_amr_disassemble(d, tch_data, 159); - - osmo_crc8gen_set_bits(&gsm0503_amr_crc6, d, 67, p); + if (!len) { + /* No data, induce BFI in the receiver by inverted CRC bits. + * The data bit are all 0, so the correct parity bits would be 111111. */ + memset(d, 0, 159); + memset(p, 0, 6); + } else { + if (len != 20) + goto invalid_length; + + 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); @@ -2928,12 +3064,18 @@ int gsm0503_tch_ahs_encode(ubit_t *bursts, const uint8_t *tch_data, int len, break; case 4: /* TCH/AHS7.4 */ - if (len != 19) - goto invalid_length; + if (!len) { + /* See comment above. */ + memset(d, 0, 148); + memset(p, 0, 6); + } else { + if (len != 19) + goto invalid_length; - tch_amr_disassemble(d, tch_data, 148); + tch_amr_disassemble(d, tch_data, 148); - osmo_crc8gen_set_bits(&gsm0503_amr_crc6, d, 61, p); + osmo_crc8gen_set_bits(&gsm0503_amr_crc6, d, 61, p); + } tch_amr_merge(conv, d, p, 120, 61); @@ -2943,12 +3085,18 @@ int gsm0503_tch_ahs_encode(ubit_t *bursts, const uint8_t *tch_data, int len, break; case 3: /* TCH/AHS6.7 */ - if (len != 17) - goto invalid_length; + if (!len) { + /* See comment above. */ + memset(d, 0, 134); + memset(p, 0, 6); + } else { + if (len != 17) + goto invalid_length; - tch_amr_disassemble(d, tch_data, 134); + tch_amr_disassemble(d, tch_data, 134); - osmo_crc8gen_set_bits(&gsm0503_amr_crc6, d, 55, p); + osmo_crc8gen_set_bits(&gsm0503_amr_crc6, d, 55, p); + } tch_amr_merge(conv, d, p, 110, 55); @@ -2958,12 +3106,18 @@ int gsm0503_tch_ahs_encode(ubit_t *bursts, const uint8_t *tch_data, int len, break; case 2: /* TCH/AHS5.9 */ - if (len != 15) - goto invalid_length; + if (!len) { + /* See comment above. */ + memset(d, 0, 118); + memset(p, 0, 6); + } else { + if (len != 15) + goto invalid_length; - tch_amr_disassemble(d, tch_data, 118); + tch_amr_disassemble(d, tch_data, 118); - osmo_crc8gen_set_bits(&gsm0503_amr_crc6, d, 55, p); + osmo_crc8gen_set_bits(&gsm0503_amr_crc6, d, 55, p); + } tch_amr_merge(conv, d, p, 102, 55); @@ -2973,12 +3127,18 @@ int gsm0503_tch_ahs_encode(ubit_t *bursts, const uint8_t *tch_data, int len, break; case 1: /* TCH/AHS5.15 */ - if (len != 13) - goto invalid_length; + if (!len) { + /* See comment above. */ + memset(d, 0, 103); + memset(p, 0, 6); + } else { + if (len != 13) + goto invalid_length; - tch_amr_disassemble(d, tch_data, 103); + tch_amr_disassemble(d, tch_data, 103); - osmo_crc8gen_set_bits(&gsm0503_amr_crc6, d, 49, p); + osmo_crc8gen_set_bits(&gsm0503_amr_crc6, d, 49, p); + } tch_amr_merge(conv, d, p, 91, 49); @@ -2988,12 +3148,18 @@ int gsm0503_tch_ahs_encode(ubit_t *bursts, const uint8_t *tch_data, int len, break; case 0: /* TCH/AHS4.75 */ - if (len != 12) - goto invalid_length; + if (!len) { + /* See comment above. */ + memset(d, 0, 95); + memset(p, 0, 6); + } else { + if (len != 12) + goto invalid_length; - tch_amr_disassemble(d, tch_data, 95); + tch_amr_disassemble(d, tch_data, 95); - osmo_crc8gen_set_bits(&gsm0503_amr_crc6, d, 39, p); + osmo_crc8gen_set_bits(&gsm0503_amr_crc6, d, 39, p); + } tch_amr_merge(conv, d, p, 83, 39); @@ -3007,7 +3173,7 @@ int gsm0503_tch_ahs_encode(ubit_t *bursts, const uint8_t *tch_data, int len, return -1; } - memcpy(cB, gsm0503_afs_ic_ubit[id], 4); + memcpy(cB, gsm0503_ahs_ic_ubit[id], 4); gsm0503_tch_hr_interleave(cB, iB); @@ -3212,4 +3378,491 @@ int gsm0503_sch_encode(ubit_t *burst, const uint8_t *sb_info) return 0; } +/* + * GSM CSD transcoding + */ + +static inline void _tch_csd_burst_map(ubit_t *burst, const ubit_t *iB) +{ + unsigned int i; + + /* hu(B): copy *even* numbered bits if not stolen by FACCH */ + if (burst[58] == 0) { + for (i = 0; i < 57; i += 2) + burst[i] |= iB[i]; + for (i = 58; i < 114; i += 2) + burst[i + 2] |= iB[i]; + } + + /* hl(B): copy *odd* numbered bits if not stolen by FACCH */ + if (burst[57] == 0) { + for (i = 1; i < 57; i += 2) + burst[i] |= iB[i]; + for (i = 57; i < 114; i += 2) + burst[i + 2] |= iB[i]; + } +} + +/*! Perform channel encoding of a TCH/F9.6 channel as per section 3.3. + * \param[out] bursts Caller-allocated buffer for symbols of 22 bursts, + * 22 * 2 * 58 == 2552 bits total. + * \param[in] data Data to be encoded (240 unpacked bits). + * \returns 0 in case of success; negative on error. */ +int gsm0503_tch_fr96_encode(ubit_t *bursts, const ubit_t *data) +{ + ubit_t iB[22 * 114], cB[4 * 114]; + ubit_t conv[4 * 60 + 4]; + + /* 3.3.2 Block code: b1(60) + b2(60) + b3(60) + b4(60) + pad(4) */ + memcpy(&conv[0], &data[0], 4 * 60); + /* pad(4) is set to 0 by osmo_conv_encode() below */ + + /* 3.3.3 Convolutional encoder */ + osmo_conv_encode(&gsm0503_tch_f96, &conv[0], &cB[0]); + + /* 3.3.4 Interleaving */ + memset(&iB[0], 0, sizeof(iB)); + gsm0503_tch_f96_interleave(&cB[0], &iB[0]); + + /* 3.3.5 Mapping on a burst: as specified for TCH/FS in subclause 3.1.4 */ + for (unsigned int i = 0; i < 22; i++) + _tch_csd_burst_map(&bursts[i * 116], &iB[i * 114]); + + return 0; +} + +/*! Perform channel decoding of a TCH/F9.6 channel as per section 3.3. + * \param[out] data Caller-allocated buffer for decoded data (240 unpacked bits). + * \param[in] bursts Buffer containing the symbols of 22 bursts, + * 22 * 2 * 58 == 2552 bits total. + * \param[out] n_errors Number of detected bit errors. + * \param[out] n_bits_total Total number of bits. + * \returns Number of unpacked bits used in the output buffer; negative on error. */ +int gsm0503_tch_fr96_decode(ubit_t *data, const sbit_t *bursts, + int *n_errors, int *n_bits_total) +{ + sbit_t iB[22 * 114], cB[4 * 114]; + ubit_t conv[4 * 60 + 4]; + + /* 3.3.5 Mapping on a burst: as specified for TCH/FS in subclause 3.1.4 */ + for (unsigned int i = 0; i < 22; i++) { + memcpy(&iB[i * 114], &bursts[i * 116], 57); + memcpy(&iB[i * 114 + 57], &bursts[i * 116 + 59], 57); + } + + /* 3.3.4 Interleaving */ + gsm0503_tch_f96_deinterleave(&cB[0], &iB[0]); + + /* 3.3.3 Convolutional encoder */ + osmo_conv_decode_ber(&gsm0503_tch_f96, &cB[0], &conv[0], n_errors, n_bits_total); + + /* 3.3.2 Block code: b1(60) + b2(60) + b3(60) + b4(60) + pad(4) */ + memcpy(&data[0], &conv[0], 4 * 60); + + return 4 * 60; +} + +/*! Perform channel encoding of a TCH/F4.8 channel as per section 3.4. + * \param[out] bursts Caller-allocated buffer for symbols of 22 bursts, + * 22 * 2 * 58 == 2552 bits total. + * \param[in] data Data to be encoded (120 unpacked bits). + * \returns 0 in case of success; negative on error */ +int gsm0503_tch_fr48_encode(ubit_t *bursts, const ubit_t *data) +{ + ubit_t iB[22 * 114], cB[4 * 114]; + ubit_t conv[2 * 60 + 32]; + + /* 3.4.2 Block code: + * + * Sixteen bits equal to 0 are added to the 60 information bits, the result + * being a block of 76 bits, {u(0),u(1),...,u(75)}, with: + * + * u(19k+p) = d(15k+p) for k = 0,1,2,3 and p = 0,1,...,14; + * u(19k+p) = 0 for k = 0,1,2,3 and p = 15,16,17,18. + * + * Two such blocks forming a block of 152 bits: u1 + u2. */ + for (unsigned int k = 0; k < 2 * 4; k++) { + memcpy(&conv[19 * k], &data[15 * k], 15); + memset(&conv[19 * k + 15], 0, 4); + } + + /* 3.4.3 Convolutional encoder */ + osmo_conv_encode(&gsm0503_tch_f48, &conv[0], &cB[0]); + + /* 3.4.4 Interleaving: as specified for the TCH/F9.6 in subclause 3.3.4 */ + memset(&iB[0], 0, sizeof(iB)); + gsm0503_tch_f96_interleave(&cB[0], &iB[0]); + + /* 3.4.5 Mapping on a burst: as specified for TCH/FS in subclause 3.1.4 */ + for (unsigned int i = 0; i < 22; i++) + _tch_csd_burst_map(&bursts[i * 116], &iB[i * 114]); + + return 0; +} + +/*! Perform channel decoding of a TCH/F4.8 channel as per section 3.4. + * \param[out] data Caller-allocated buffer for decoded data (120 unpacked bits). + * \param[in] bursts Buffer containing the symbols of 22 bursts, + * 22 * 2 * 58 == 2552 bits total. + * \param[out] n_errors Number of detected bit errors. + * \param[out] n_bits_total Total number of bits. + * \returns Number of unpacked bits used in the output buffer; negative on error. */ +int gsm0503_tch_fr48_decode(ubit_t *data, const sbit_t *bursts, + int *n_errors, int *n_bits_total) +{ + sbit_t iB[22 * 114], cB[4 * 114]; + ubit_t conv[2 * 60 + 32]; + + /* 3.4.5 Mapping on a burst: as specified for TCH/FS in subclause 3.1.4 */ + for (unsigned int i = 0; i < 22; i++) { + memcpy(&iB[i * 114], &bursts[i * 116], 57); + memcpy(&iB[i * 114 + 57], &bursts[i * 116 + 59], 57); + } + + /* 3.4.4 Interleaving: as specified for the TCH/F9.6 in subclause 3.3.4 */ + gsm0503_tch_f96_deinterleave(&cB[0], &iB[0]); + + /* 3.4.3 Convolutional encoder */ + osmo_conv_decode_ber(&gsm0503_tch_f48, &cB[0], &conv[0], n_errors, n_bits_total); + + /* 3.4.2 Block code: + * + * Sixteen bits equal to 0 are added to the 60 information bits, the result + * being a block of 76 bits, {u(0),u(1),...,u(75)}, with: + * + * u(19k+p) = d(15k+p) for k = 0,1,2,3 and p = 0,1,...,14; + * u(19k+p) = 0 for k = 0,1,2,3 and p = 15,16,17,18. + * + * Two such blocks forming a block of 152 bits: u1 + u2. */ + for (unsigned int k = 0; k < 2 * 4; k++) + memcpy(&data[15 * k], &conv[19 * k], 15); + + return 2 * 60; +} + +/*! Perform channel encoding of a TCH/H4.8 channel as per section 3.5. + * The algorithm is identical to TCH/F9.6, so it's just a wrapper. + * \param[out] bursts Caller-allocated buffer for symbols of 22 bursts, + * 22 * 2 * 58 == 2552 bits total. + * \param[in] data Data to be encoded (240 unpacked bits). + * \returns 0 in case of success; negative on error */ +int gsm0503_tch_hr48_encode(ubit_t *bursts, const ubit_t *data) +{ + return gsm0503_tch_fr96_encode(bursts, data); +} + +/*! Perform channel decoding of a TCH/H4.8 channel as per section 3.5. + * The algorithm is identical to TCH/F9.6, so it's just a wrapper. + * \param[out] data Caller-allocated buffer for decoded data (240 unpacked bits). + * \param[in] bursts Buffer containing the symbols of 22 bursts, + * 22 * 2 * 58 == 2552 bits total. + * \param[out] n_errors Number of detected bit errors. + * \param[out] n_bits_total Total number of bits. + * \returns Number of unpacked bits used in the output buffer; negative on error. */ +int gsm0503_tch_hr48_decode(ubit_t *data, const sbit_t *bursts, + int *n_errors, int *n_bits_total) +{ + return gsm0503_tch_fr96_decode(data, bursts, n_errors, n_bits_total); +} + +/*! Perform channel encoding of a TCH/F2.4 channel as per section 3.6. + * \param[out] bursts Caller-allocated buffer for symbols of 8 bursts, + * 8 * 2 * 58 == 928 bits total. + * \param[in] data Data to be encoded (72 unpacked bits). + * \returns 0 in case of success; negative on error */ +int gsm0503_tch_fr24_encode(ubit_t *bursts, const ubit_t *data) +{ + ubit_t iB[8 * 114], cB[4 * 114]; + const ubit_t h = 0; + + /* 3.6.{1-3} Block code and Convolutional encoder */ + osmo_conv_encode(&gsm0503_tch_f24, &data[0], &cB[0]); + + /* 3.6.4 Interleaving: as specified for the TCH/FS in subclause 3.1.3 */ + gsm0503_tch_fr_interleave(&cB[0], &iB[0]); + + /* 3.6.5 Mapping on a burst: as specified for TCH/FS in subclause 3.1.4 */ + 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 TCH/F2.4 channel as per section 3.6. + * \param[out] data Caller-allocated buffer for decoded data (72 unpacked bits). + * \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 unpacked bits used in the output buffer; negative on error. */ +int gsm0503_tch_fr24_decode(ubit_t *data, const sbit_t *bursts, + int *n_errors, int *n_bits_total) +{ + sbit_t iB[8 * 114], cB[4 * 114]; + + /* 3.6.5 Mapping on a burst: as specified for TCH/FS in subclause 3.1.4 */ + for (unsigned int i = 0; i < 8; i++) + gsm0503_tch_burst_unmap(&iB[i * 114], &bursts[i * 116], NULL, i >> 2); + + /* 3.6.4 Interleaving: as specified for the TCH/FS in subclause 3.1.3 */ + gsm0503_tch_fr_deinterleave(&cB[0], &iB[0]); + + /* 3.6.{1-3} Block code and Convolutional encoder */ + osmo_conv_decode_ber(&gsm0503_tch_f24, &cB[0], &data[0], n_errors, n_bits_total); + + return 72; +} + +/*! Perform channel encoding of a TCH/H2.4 channel as per section 3.7. + * \param[out] bursts Caller-allocated buffer for symbols of 22 bursts, + * 22 * 2 * 58 == 2552 bits total. + * \param[in] data Data to be encoded (144 unpacked bits). + * \returns 0 in case of success; negative on error */ +int gsm0503_tch_hr24_encode(ubit_t *bursts, const ubit_t *data) +{ + ubit_t iB[22 * 114], cB[4 * 114]; + + /* 3.7.{1-3} Block code and Convolutional encoder */ + osmo_conv_encode(&gsm0503_tch_h24, &data[ 0], &cB[ 0]); + osmo_conv_encode(&gsm0503_tch_h24, &data[72], &cB[228]); + + /* 3.7.4 Interleaving: as specified for the TCH/F9.6 in subclause 3.3.4 */ + memset(&iB[0], 0, sizeof(iB)); + gsm0503_tch_f96_interleave(&cB[0], &iB[0]); + + /* 3.7.5 Mapping on a burst: as specified for TCH/FS in subclause 3.1.4 */ + for (unsigned int i = 0; i < 22; i++) + _tch_csd_burst_map(&bursts[i * 116], &iB[i * 114]); + + return 0; +} + +/*! Perform channel decoding of a TCH/H2.4 channel as per section 3.7. + * \param[out] data Caller-allocated buffer for decoded data (144 unpacked bits). + * \param[in] bursts Buffer containing the symbols of 22 bursts, + * 22 * 2 * 58 == 2552 bits total. + * \param[out] n_errors Number of detected bit errors. + * \param[out] n_bits_total Total number of bits. + * \returns Number of unpacked bits used in the output buffer; negative on error. */ +int gsm0503_tch_hr24_decode(ubit_t *data, const sbit_t *bursts, + int *n_errors, int *n_bits_total) +{ + int n_errors_l[2], n_bits_total_l[2]; + sbit_t iB[22 * 114], cB[4 * 114]; + + /* 3.7.5 Mapping on a burst: as specified for TCH/FS in subclause 3.1.4 */ + for (unsigned int i = 0; i < 22; i++) { + memcpy(&iB[i * 114], &bursts[i * 116], 57); + memcpy(&iB[i * 114 + 57], &bursts[i * 116 + 59], 57); + } + + /* 3.7.4 Interleaving: as specified for the TCH/F9.6 in subclause 3.3.4 */ + gsm0503_tch_f96_deinterleave(&cB[0], &iB[0]); + + /* 3.7.{1-3} Block code and Convolutional encoder */ + osmo_conv_decode_ber(&gsm0503_tch_h24, &cB[ 0], &data[ 0], &n_errors_l[0], &n_bits_total_l[0]); + osmo_conv_decode_ber(&gsm0503_tch_h24, &cB[228], &data[72], &n_errors_l[1], &n_bits_total_l[1]); + + if (n_errors) + *n_errors = n_errors_l[0] + n_errors_l[1]; + + if (n_bits_total) + *n_bits_total = n_bits_total_l[0] + n_bits_total_l[1]; + + return 2 * 72; +} + +/*! Perform channel encoding of a TCH/F14.4 channel as per section 3.8. + * \param[out] bursts Caller-allocated buffer for symbols of 22 bursts, + * 22 * 2 * 58 == 2552 bits total. + * \param[in] data Data to be encoded (290 unpacked bits). + * \returns 0 in case of success; negative on error */ +int gsm0503_tch_fr144_encode(ubit_t *bursts, const ubit_t *data) +{ + ubit_t iB[22 * 114], cB[4 * 114]; + ubit_t conv[290 + 4]; + + /* 3.8.2 Block code: b(290) + pad(4) */ + memcpy(&conv[0], &data[0], 290); + /* pad(4) is set to 0 by osmo_conv_encode() below */ + + /* 3.8.3 Convolutional encoder */ + osmo_conv_encode(&gsm0503_tch_f144, &conv[0], &cB[0]); + + /* 3.8.4 Interleaving */ + memset(&iB[0], 0, sizeof(iB)); + gsm0503_tch_f96_interleave(&cB[0], &iB[0]); + + /* 3.8.5 Mapping on a burst: as specified for TCH/FS in subclause 3.1.4 */ + for (unsigned int i = 0; i < 22; i++) + _tch_csd_burst_map(&bursts[i * 116], &iB[i * 114]); + + return 0; +} + +/*! Perform channel decoding of a TCH/14.4 channel as per section 3.8. + * \param[out] data Caller-allocated buffer for decoded data (290 unpacked bits). + * \param[in] bursts Buffer containing the symbols of 22 bursts, + * 22 * 2 * 58 == 2552 bits total. + * \param[out] n_errors Number of detected bit errors. + * \param[out] n_bits_total Total number of bits. + * \returns Number of unpacked bits used in the output buffer; negative on error. */ +int gsm0503_tch_fr144_decode(ubit_t *data, const sbit_t *bursts, + int *n_errors, int *n_bits_total) +{ + sbit_t iB[22 * 114], cB[4 * 114]; + ubit_t conv[294]; + + /* 3.8.5 Mapping on a burst: as specified for TCH/FS in subclause 3.1.4 */ + for (unsigned int i = 0; i < 22; i++) { + memcpy(&iB[i * 114], &bursts[i * 116], 57); + memcpy(&iB[i * 114 + 57], &bursts[i * 116 + 59], 57); + } + + /* 3.8.4 Interleaving: as specified for the TCH/F9.6 in subclause 3.3.4 */ + gsm0503_tch_f96_deinterleave(&cB[0], &iB[0]); + + /* 3.8.3 Convolutional encoder */ + osmo_conv_decode_ber(&gsm0503_tch_f144, &cB[0], &conv[0], n_errors, n_bits_total); + + /* 3.8.2 Block code: b(290) + pad(4) */ + memcpy(&data[0], &conv[0], 290); + + 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; +} + /*! @} */ diff --git a/src/coding/gsm0503_interleaving.c b/src/coding/gsm0503_interleaving.c index d5008d07..570d65aa 100644 --- a/src/coding/gsm0503_interleaving.c +++ b/src/coding/gsm0503_interleaving.c @@ -16,10 +16,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include <stdint.h> @@ -682,4 +678,56 @@ void gsm0503_tch_hr_interleave(const ubit_t *cB, ubit_t *iB) } } +/* 3GPP TS 45.003 Section 3.3.4 + * The coded bits are reordered and interleaved according to the following rule: + * i(B,j) = c(n,k) for k = 0,1,...,455 + * n = 0,1,...,N,N + 1,... + * B = B0 +4n + (k mod 19) + (k div 114) + * j = (k mod 19) + 19 (k mod 6) + * + * The result of the interleaving is a distribution of the reordered 114 + * bit of a given data block, n = N, over 19 blocks, 6 bits equally + * distributed in each block, in a diagonal way over consecutive blocks. + * + * Or in other words the interleaving is a distribution of the encoded, + * reordered 456 bits from four given input data blocks, which taken + * together give n = N, over 22 bursts, 6 bits equally distributed in + * the first and 22 nd bursts, 12 bits distributed in the second and 21 + * st bursts, 18 bits distributed in the third and 20 th bursts and 24 + * bits distributed in the other 16 bursts. + * + * The block of coded data is interleaved "diagonal", where a new block + * of coded data starts with every fourth burst and is distributed over + * 22 bursts. + * + * Also used for TCH/F4.8, TCH/H4.8, and TCH/H2.4 and TCH/F14.4 */ +void gsm0503_tch_f96_interleave(const ubit_t *cB, ubit_t *iB) +{ + int j, k, B; + + for (k = 0; k < 456; k++) { + /* upper bound for B: 4*n + 18 + 4 = 4*n + 22 */ + B = /* B0 + 4n + */ (k % 19) + (k / 114); + /* upper bound for j: 18 + 19*5 = 113 */ + j = (k % 19) + 19 * (k % 6); + /* upper iB index: 4*n+23*114-1 */ + iB[B * 114 + j] = cB[k]; + } +} + +void gsm0503_tch_f96_deinterleave(sbit_t *cB, const sbit_t *iB) +{ + int j, k, B; + + for (k = 0; k < 456; k++) { + /* upper bound for B: 4*n + 18 + 4 = 4*n + 22 */ + B = /* B0 + 4n + */ (k % 19) + (k / 114); + /* upper bound for j: 18 + 19*5 = 113 */ + j = (k % 19) + 19 * (k % 6); + /* upper iB index: 4*n+23*114-1 */ + cB[k] = iB[B * 114 + j]; + } +} + + /*! @} */ diff --git a/src/coding/gsm0503_mapping.c b/src/coding/gsm0503_mapping.c index f7532eb2..04acfd07 100644 --- a/src/coding/gsm0503_mapping.c +++ b/src/coding/gsm0503_mapping.c @@ -15,10 +15,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include <stdint.h> diff --git a/src/coding/gsm0503_parity.c b/src/coding/gsm0503_parity.c index a8daacc7..ef71d351 100644 --- a/src/coding/gsm0503_parity.c +++ b/src/coding/gsm0503_parity.c @@ -15,10 +15,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include <stdint.h> diff --git a/src/coding/gsm0503_tables.c b/src/coding/gsm0503_tables.c index df0abeed..25ea2fa3 100644 --- a/src/coding/gsm0503_tables.c +++ b/src/coding/gsm0503_tables.c @@ -15,10 +15,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include <stdint.h> diff --git a/src/coding/libosmocoding.map b/src/coding/libosmocoding.map index 325b6d80..0444690e 100644 --- a/src/coding/libosmocoding.map +++ b/src/coding/libosmocoding.map @@ -76,6 +76,8 @@ gsm0503_xcch_deinterleave; gsm0503_xcch_interleave; gsm0503_tch_fr_deinterleave; gsm0503_tch_fr_interleave; +gsm0503_tch_f96_deinterleave; +gsm0503_tch_f96_interleave; gsm0503_tch_hr_deinterleave; gsm0503_tch_hr_interleave; gsm0503_mcs1_ul_deinterleave; @@ -105,6 +107,7 @@ gsm0503_tch_fr_encode; gsm0503_tch_fr_decode; gsm0503_tch_hr_encode; gsm0503_tch_hr_decode; +gsm0503_tch_hr_decode2; gsm0503_tch_afs_encode; gsm0503_tch_afs_decode; gsm0503_tch_afs_decode_dtx; @@ -123,6 +126,26 @@ gsm0503_amr_dtx_frame_names; gsm0503_amr_dtx_frame_name; gsm0503_detect_afs_dtx_frame; gsm0503_detect_ahs_dtx_frame; +gsm0503_detect_afs_dtx_frame2; +gsm0503_detect_ahs_dtx_frame2; + +gsm0503_tch_fr96_encode; +gsm0503_tch_fr96_decode; +gsm0503_tch_fr48_encode; +gsm0503_tch_fr48_decode; +gsm0503_tch_hr48_encode; +gsm0503_tch_hr48_decode; +gsm0503_tch_fr24_encode; +gsm0503_tch_fr24_decode; +gsm0503_tch_hr24_encode; +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: *; }; |