view ater/out_frame.c @ 37:26c9535df39e

rm abis subdir: moved to e1-fake-trau repository The present code repository is meant to contain code for talking to a TRAU DUT, hence the name ice1-trau-tester. The different and separate function of talking to an E1 BTS (Abis instead of Ater, and in the opposite role) was never in scope for this project, but that code got added here in a haste when the InSite BTS arrived while the TRAU bring-up was still blocked. Now that we have our Nokia TCSM2 system working and are doing TRAU experiments, let's keep the code clean.
author Mychaela Falconia <falcon@freecalypso.org>
date Thu, 29 Aug 2024 19:02:02 +0000
parents bacc590ec839
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;
}