diff options
author | Sylvain Munaut <tnt@246tNt.com> | 2011-12-14 20:43:34 +0100 |
---|---|---|
committer | Sylvain Munaut <tnt@246tNt.com> | 2011-12-15 10:12:03 +0100 |
commit | ecceb996aab2c4365e0c972737046f9cd7b0c9dd (patch) | |
tree | 2a31c10aacb8ea2f24cd62a7d1beffa9b8c0fcfb /src/l1 | |
parent | 069fa2e094d13df3ce206794829b4a9b2832f0a8 (diff) |
l1/tch3: Add support for TCH3 (speech) channel coding
Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
Diffstat (limited to 'src/l1')
-rw-r--r-- | src/l1/Makefile.am | 2 | ||||
-rw-r--r-- | src/l1/tch3.c | 183 |
2 files changed, 184 insertions, 1 deletions
diff --git a/src/l1/Makefile.am b/src/l1/Makefile.am index 05e068c..0a03e5f 100644 --- a/src/l1/Makefile.am +++ b/src/l1/Makefile.am @@ -6,4 +6,4 @@ noinst_LIBRARIES = libgmr1-l1.a libgmr1_l1_a_SOURCES = \ conv.c crc.c interleave.c punct.c scramb.c \ - bcch.c ccch.c facch3.c + bcch.c ccch.c facch3.c tch3.c diff --git a/src/l1/tch3.c b/src/l1/tch3.c new file mode 100644 index 0000000..638819b --- /dev/null +++ b/src/l1/tch3.c @@ -0,0 +1,183 @@ +/* GMR-1 TCH3 channel coding */ +/* See GMR-1 05.003 (ETSI TS 101 376-5-3 V1.2.1) - Section 5.1 */ + +/* (C) 2011 by Sylvain Munaut <tnt@246tNt.com> + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/*! \addtogroup tch3 + * @{ + */ + +/*! \file l1/tch3.c + * \brief Osmocom GMR-1 TCH3 channel coding implementation + */ + +#include <stdint.h> +#include <string.h> + +#include <osmocom/gmr1/l1/conv.h> +#include <osmocom/gmr1/l1/crc.h> +#include <osmocom/gmr1/l1/punct.h> +#include <osmocom/gmr1/l1/scramb.h> + + +static struct osmo_conv_code gmr1_conv_tch3_speech; + +static void __attribute__ ((constructor)) +gmr1_tch3_init(void) +{ + /* Init convolutional coder */ + memcpy(&gmr1_conv_tch3_speech, &gmr1_conv_tch3, sizeof(struct osmo_conv_code)); + gmr1_conv_tch3_speech.len = 48; + gmr1_puncturer_generate(&gmr1_conv_tch3_speech, &gmr1_punct12_P12); +} + + +/*! \brief Stateless GMR-1 TCH3 channel coder + * \param[out] bits_e 212 encoded bits to be mapped on a burst + * \param[in] frame0 1st speech frame (10 byte / 80 bits, msb first) + * \param[in] frame1 2nd speech frame (10 byte / 80 bits, msb first) + * \param[in] bits_s 4 status bits to be multiplexed + * \param[in] ciph 208 bits of cipher stream (can be NULL) + * \param[in] m Multiplexing mode (0 or 1) + */ +void +gmr1_tch3_encode(ubit_t *bits_e, + const uint8_t *frame0, const uint8_t *frame1, + const ubit_t *bits_s, const ubit_t *ciph, int m) +{ + ubit_t bits_epp[208]; + ubit_t bits_xmy[208]; + int i, j; + + for (i=0; i<2; i++) + { + const uint8_t *frame = i ? frame1 : frame0; + + ubit_t bits_d[80]; + ubit_t bits_c[104]; + ubit_t bits_ep[104]; + + int kc; + + osmo_pbit2ubit(bits_d, frame, 80); + + osmo_conv_encode(&gmr1_conv_tch3_speech, bits_c, bits_d); + memcpy(bits_c+72, bits_d+48, 32); + + for (kc=0; kc<104; kc++) { + int ii, ij, kep; + ii = kc % 24; + ij = kc / 24; + kep = (ii < 8) ? (ij + 5*ii) : (ij + 4*ii + 8); + bits_ep[kep] = bits_c[kc]; + } + + if (m) { + for (j=0; j<104; j++) + bits_epp[(104*i)+j] = bits_ep[j]; + } else { + for (j=0; j<104; j++) + bits_epp[(j<<1)+i] = bits_ep[j]; + } + } + + gmr1_scramble_ubit(bits_xmy, bits_epp, 208); + + if (ciph) { + for (i=0; i<208; i++) + bits_xmy[i] ^= ciph[i]; + } + + memcpy(bits_e, bits_xmy, 52); + memcpy(bits_e+52, bits_s, 4); + memcpy(bits_e+56, bits_xmy+52, 156); +} + +/*! \brief Stateless GMR-1 TCH3 channel decoder + * \param[out] frame0 1st speech frame (10 byte / 80 bits, msb first) + * \param[out] frame1 2nd speech frame (10 byte / 80 bits, msb first) + * \param[out] bits_s 4 status bits that were demultiplexed + * \param[in] bits_e 212 softbits demodulated from a burst + * \param[in] ciph 208 bits of cipher stream (can be NULL) + * \param[in] m Multiplexing mode (0 or 1) + * \param[out] conv0_rv Return of the conv. decode of frame 0 (can be NULL) + * \param[out] conv1_rv Return of the conv. decode of frame 1 (can be NULL) + * \return 0 if CRC check pass, any other value for fail. + */ +void +gmr1_tch3_decode(uint8_t *frame0, uint8_t *frame1, ubit_t *bits_s, + const sbit_t *bits_e, const ubit_t *ciph, int m, + int *conv0_rv, int *conv1_rv) +{ + sbit_t bits_xmy[208]; + sbit_t bits_epp[208]; + int rv, i, j; + + for (i=0; i<4; i++) + bits_s[i] = bits_e[52+i] < 0; + + memcpy(bits_xmy, bits_e, 52); + memcpy(bits_xmy+52, bits_e+56, 156); + + if (ciph) { + for (i=0; i<208; i++) + if (ciph[i]) + bits_xmy[i] *= -1; + } + + gmr1_scramble_sbit(bits_epp, bits_xmy, 208); + + for (i=0; i<2; i++) + { + int *conv_rv = i ? conv1_rv : conv0_rv; + uint8_t *frame = i ? frame1 : frame0; + + sbit_t bits_ep[104]; + sbit_t bits_c[104]; + ubit_t bits_d[80]; + + int kc; + + if (m) { + for (j=0; j<104; j++) + bits_ep[j] = bits_epp[(104*i)+j]; + } else { + for (j=0; j<104; j++) + bits_ep[j] = bits_epp[(j<<1)+i]; + } + + for (kc=0; kc<104; kc++) { + int ii, ij, kep; + ii = kc % 24; + ij = kc / 24; + kep = (ii < 8) ? (ij + 5*ii) : (ij + 4*ii + 8); + bits_c[kc] = bits_ep[kep]; + } + + rv = osmo_conv_decode(&gmr1_conv_tch3_speech, bits_c, bits_d); + if (conv_rv) + *conv_rv = rv; + + for (j=48; j<80; j++) + bits_d[j] = bits_c[j+24] < 0; + + osmo_ubit2pbit(frame, bits_d, 80); + } +} + +/*! }@ */ |