view ater/out_frame.c @ 22:bacc590ec839

ater: implement EFR CRC inversion option
author Mychaela Falconia <falcon@freecalypso.org>
date Mon, 24 Jun 2024 09:28:28 +0000
parents 2ee910aa03c3
children
line wrap: on
line source

/*
 * Here we implement our TRAU-UL bit filling function.
 *
 * This code is based on trau_rtp_conv.c in libosmo-abis.
 */

#include <stdint.h>
#include <stdbool.h>
#include <string.h>

#include <osmocom/core/bits.h>
#include <osmocom/core/crc8gen.h>
#include <osmocom/trau/trau_frame.h>

#include "out_frame.h"

/* this corresponds to the bit-lengths of the individual codec
 * parameters as indicated in Table 1.1 of TS 46.010 */
static const uint8_t gsm_fr_map[] = {
	6, 6, 5, 5, 4, 4, 3, 3,
	7, 2, 2, 6, 3, 3, 3, 3,
	3, 3, 3, 3, 3, 3, 3, 3,
	3, 7, 2, 2, 6, 3, 3, 3,
	3, 3, 3, 3, 3, 3, 3, 3,
	3, 3, 7, 2, 2, 6, 3, 3,
	3, 3, 3, 3, 3, 3, 3, 3,
	3, 3, 3, 7, 2, 2, 6, 3,
	3, 3, 3, 3, 3, 3, 3, 3,
	3, 3, 3, 3
};

/*
 * EFR TRAU parity
 *
 * g(x) = x^3 + x^1 + 1
 */
static const struct osmo_crc8gen_code gsm0860_efr_crc3 = {
	.bits = 3,
	.poly = 0x3,
	.init = 0x0,
	.remainder = 0x7,
};

/* re-combine EFR parity bits */
static inline void efr_parity_bits_1(ubit_t *check_bits, const ubit_t *d_bits)
{
	memcpy(check_bits + 0 , d_bits + 0, 22);
	memcpy(check_bits + 22 , d_bits + 24, 3);
	check_bits[25] = d_bits[28];
}

static inline void efr_parity_bits_2(ubit_t *check_bits, const ubit_t *d_bits)
{
	memcpy(check_bits + 0 , d_bits + 42, 10);
	memcpy(check_bits + 10 , d_bits + 90, 2);
}

static inline void efr_parity_bits_3(ubit_t *check_bits, const ubit_t *d_bits)
{
	memcpy(check_bits + 0 , d_bits + 98, 5);
	check_bits[5] = d_bits[104];
	memcpy(check_bits + 6 , d_bits + 143, 2);
}

static inline void efr_parity_bits_4(ubit_t *check_bits, const ubit_t *d_bits)
{
	memcpy(check_bits + 0 , d_bits + 151, 10);
	memcpy(check_bits + 10 , d_bits + 199, 2);
}

static inline void efr_parity_bits_5(ubit_t *check_bits, const ubit_t *d_bits)
{
	memcpy(check_bits + 0 , d_bits + 207, 5);
	check_bits[5] = d_bits[213];
	memcpy(check_bits + 6 , d_bits + 252, 2);
}

static void fill_data_fr(const uint8_t *data, struct osmo_trau_frame *tf)
{
	int i, j, k, l, o;

	/* reassemble d-bits */
	i = 0; /* counts bits */
	j = 4; /* counts input bits */
	k = gsm_fr_map[0]-1; /* current number bit in element */
	l = 0; /* counts element bits */
	o = 0; /* offset output bits */
	while (i < 260) {
		tf->d_bits[k+o] = (data[j/8] >> (7-(j%8))) & 1;
		/* to avoid out-of-bounds access in gsm_fr_map[++l] */
		if (i == 259)
			break;
		if (--k < 0) {
			o += gsm_fr_map[l];
			k = gsm_fr_map[++l]-1;
		}
		i++;
		j++;
	}
}

static void invert_crc3(ubit_t *crc)
{
	crc[0] = !crc[0];
	crc[1] = !crc[1];
	crc[2] = !crc[2];
}

static void fill_data_efr(const uint8_t *data, struct osmo_trau_frame *tf)
{
	int i, j;
	ubit_t check_bits[26];
	uint8_t crc_inv;

	/* reassemble d-bits */
	tf->d_bits[0] = 1;
	for (i = 1, j = 4; i < 39; i++, j++)
		tf->d_bits[i] = (data[j/8] >> (7-(j%8))) & 1;
	efr_parity_bits_1(check_bits, tf->d_bits);
	osmo_crc8gen_set_bits(&gsm0860_efr_crc3, check_bits, 26,
			tf->d_bits + 39);
	for (i = 42, j = 42; i < 95; i++, j++)
		tf->d_bits[i] = (data[j/8] >> (7-(j%8))) & 1;
	efr_parity_bits_2(check_bits, tf->d_bits);
	osmo_crc8gen_set_bits(&gsm0860_efr_crc3, check_bits, 12,
			tf->d_bits + 95);
	for (i = 98, j = 95; i < 148; i++, j++)
		tf->d_bits[i] = (data[j/8] >> (7-(j%8))) & 1;
	efr_parity_bits_3(check_bits, tf->d_bits);
	osmo_crc8gen_set_bits(&gsm0860_efr_crc3, check_bits, 8,
			tf->d_bits + 148);
	for (i = 151, j = 145; i < 204; i++, j++)
		tf->d_bits[i] = (data[j/8] >> (7-(j%8))) & 1;
	efr_parity_bits_4(check_bits, tf->d_bits);
	osmo_crc8gen_set_bits(&gsm0860_efr_crc3, check_bits, 12,
			tf->d_bits + 204);
	for (i = 207, j = 198; i < 257; i++, j++)
		tf->d_bits[i] = (data[j/8] >> (7-(j%8))) & 1;
	efr_parity_bits_5(check_bits, tf->d_bits);
	osmo_crc8gen_set_bits(&gsm0860_efr_crc3, check_bits, 8,
			tf->d_bits + 257);

	/* inverted CRC option */
	crc_inv = data[31];
	if (crc_inv & 0x80)
		invert_crc3(tf->d_bits + 39);
	if (crc_inv & 0x40)
		invert_crc3(tf->d_bits + 95);
	if (crc_inv & 0x20)
		invert_crc3(tf->d_bits + 148);
	if (crc_inv & 0x10)
		invert_crc3(tf->d_bits + 204);
	if (crc_inv & 0x08)
		invert_crc3(tf->d_bits + 257);
}

void trau_frame_from_record(const uint8_t *rec, bool is_efr,
			    struct osmo_trau_frame *tf)
{
	if (is_efr)
		fill_data_efr(rec, tf);
	else
		fill_data_fr(rec, tf);
	/* set BFI and SID flags */
	tf->c_bits[11] = (rec[33] & 0x80) >> 7;
	tf->c_bits[12] = (rec[33] & 0x02) >> 1;
	tf->c_bits[13] = (rec[33] & 0x01) >> 0;
}