changeset 4:d9c095357c32

trau-parse: check and report EFR CRC
author Mychaela Falconia <falcon@freecalypso.org>
date Fri, 24 May 2024 09:16:35 +0000
parents 64b15810dc4c
children bf5c9fb431b8
files trau-decode/Makefile trau-decode/crc8gen.c trau-decode/osmo_bits.h trau-decode/parse-efr.c trau-decode/parse-main.c
diffstat 5 files changed, 232 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/trau-decode/Makefile	Fri May 24 08:31:52 2024 +0000
+++ b/trau-decode/Makefile	Fri May 24 09:16:35 2024 +0000
@@ -4,7 +4,7 @@
 
 all:	${PROGS}
 
-trau-parse:	parse-fr.o parse-main.o
+trau-parse:	crc8gen.o parse-fr.o parse-efr.o parse-main.o
 	${CC} ${CFLAGS} -o $@ $^ -lgsmfr2
 
 clean:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/trau-decode/crc8gen.c	Fri May 24 09:16:35 2024 +0000
@@ -0,0 +1,115 @@
+/*! \file crc8gen.c
+ * Osmocom generic CRC routines (for max 8 bits poly). */
+/*
+ * Copyright (C) 2011  Sylvain Munaut <tnt@246tNt.com>
+ *
+ * All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 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.
+ */
+
+/*! \addtogroup crc
+ *  @{
+ *  Osmocom generic CRC routines (for max 8 bits poly).
+ *
+ *  \file crc8gen.c.tpl */
+
+#include <stdint.h>
+#include "osmo_bits.h"
+
+/*! Compute the CRC value of a given array of hard-bits
+ *  \param[in] code The CRC code description to apply
+ *  \param[in] in Array of hard bits
+ *  \param[in] len Length of the array of hard bits
+ *  \returns The CRC value
+ */
+uint8_t
+osmo_crc8gen_compute_bits(const struct osmo_crc8gen_code *code,
+                           const ubit_t *in, int len)
+{
+	const uint8_t poly = code->poly;
+	uint8_t crc = code->init;
+	int i, n = code->bits-1;
+
+	for (i=0; i<len; i++) {
+		uint8_t bit = in[i] & 1;
+		crc ^= (bit << n);
+		if (crc & ((uint8_t)1 << n)) {
+			crc <<= 1;
+			crc ^= poly;
+		} else {
+			crc <<= 1;
+		}
+		crc &= ((uint8_t)1 << code->bits) - 1;
+	}
+
+	crc ^= code->remainder;
+
+	return crc;
+}
+
+
+/*! Checks the CRC value of a given array of hard-bits
+ *  \param[in] code The CRC code description to apply
+ *  \param[in] in Array of hard bits
+ *  \param[in] len Length of the array of hard bits
+ *  \param[in] crc_bits Array of hard bits with the alleged CRC
+ *  \returns 0 if CRC matches. 1 in case of error.
+ *
+ * The crc_bits array must have a length of code->len
+ */
+int
+osmo_crc8gen_check_bits(const struct osmo_crc8gen_code *code,
+                         const ubit_t *in, int len, const ubit_t *crc_bits)
+{
+	uint8_t crc;
+	int i;
+
+	crc = osmo_crc8gen_compute_bits(code, in, len);
+
+	for (i=0; i<code->bits; i++)
+		if (crc_bits[i] ^ ((crc >> (code->bits-i-1)) & 1))
+			return 1;
+
+	return 0;
+}
+
+
+/*! Computes and writes the CRC value of a given array of bits
+ *  \param[in] code The CRC code description to apply
+ *  \param[in] in Array of hard bits
+ *  \param[in] len Length of the array of hard bits
+ *  \param[in] crc_bits Array of hard bits to write the computed CRC to
+ *
+ * The crc_bits array must have a length of code->len
+ */
+void
+osmo_crc8gen_set_bits(const struct osmo_crc8gen_code *code,
+                       const ubit_t *in, int len, ubit_t *crc_bits)
+{
+	uint8_t crc;
+	int i;
+
+	crc = osmo_crc8gen_compute_bits(code, in, len);
+
+	for (i=0; i<code->bits; i++)
+		crc_bits[i] = ((crc >> (code->bits-i-1)) & 1);
+}
+
+/*! @} */
+
+/* vim: set syntax=c: */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/trau-decode/osmo_bits.h	Fri May 24 09:16:35 2024 +0000
@@ -0,0 +1,27 @@
+/*
+ * This include file has been put together from Osmocom (specifically
+ * libosmocore) header files, containing definitions for bit vector
+ * manipulation and CRC functions.
+ */
+
+/* from bits.h */
+
+/*! unpacked bit (0 or 1): 1 bit per byte */
+typedef uint8_t ubit_t;
+
+/* from crc8gen.h */
+
+/*! structure describing a given CRC code of max 8 bits */
+struct osmo_crc8gen_code {
+	int bits;          /*!< Actual number of bits of the CRC */
+	uint8_t poly;      /*!< Polynom (normal representation, MSB omitted */
+	uint8_t init;      /*!< Initialization value of the CRC state */
+	uint8_t remainder; /*!< Remainder of the CRC (final XOR) */
+};
+
+uint8_t osmo_crc8gen_compute_bits(const struct osmo_crc8gen_code *code,
+                                  const ubit_t *in, int len);
+int osmo_crc8gen_check_bits(const struct osmo_crc8gen_code *code,
+                            const ubit_t *in, int len, const ubit_t *crc_bits);
+void osmo_crc8gen_set_bits(const struct osmo_crc8gen_code *code,
+                           const ubit_t *in, int len, ubit_t *crc_bits);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/trau-decode/parse-efr.c	Fri May 24 09:16:35 2024 +0000
@@ -0,0 +1,85 @@
+/*
+ * This module implements the EFR decoding part of trau-parse.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <gsm_efr.h>
+#include "osmo_bits.h"
+
+/*
+ * 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);
+}
+
+void
+check_efr_crc(d_bits)
+	ubit_t *d_bits;
+{
+	ubit_t check_bits[26];
+	int rc1, rc2, rc3, rc4, rc5;
+
+	efr_parity_bits_1(check_bits, d_bits);
+	rc1 = osmo_crc8gen_check_bits(&gsm0860_efr_crc3, check_bits, 26,
+					d_bits + 39);
+	efr_parity_bits_2(check_bits, d_bits);
+	rc2 = osmo_crc8gen_check_bits(&gsm0860_efr_crc3, check_bits, 12,
+					d_bits + 95);
+	efr_parity_bits_3(check_bits, d_bits);
+	rc3 = osmo_crc8gen_check_bits(&gsm0860_efr_crc3, check_bits, 8,
+					d_bits + 148);
+	efr_parity_bits_4(check_bits, d_bits);
+	rc4 = osmo_crc8gen_check_bits(&gsm0860_efr_crc3, check_bits, 12,
+					d_bits + 204);
+	efr_parity_bits_5(check_bits, d_bits);
+	rc5 = osmo_crc8gen_check_bits(&gsm0860_efr_crc3, check_bits, 8,
+					d_bits + 257);
+	printf("  D1=%u CRC: %s %s %s %s %s\n", d_bits[0],
+		rc1 ? "bad" : "good", rc2 ? "bad" : "good",
+		rc3 ? "bad" : "good", rc4 ? "bad" : "good",
+		rc5 ? "bad" : "good");
+}
--- a/trau-decode/parse-main.c	Fri May 24 08:31:52 2024 +0000
+++ b/trau-decode/parse-main.c	Fri May 24 09:16:35 2024 +0000
@@ -119,6 +119,10 @@
 		collect_d_bits();
 		print_fr_frame(d_bits);
 		break;
+	case 0x1A:
+		collect_d_bits();
+		check_efr_crc(d_bits);
+		break;
 	}
 	printf("  C16=%u C17=%u C18=%u C19=%u C20=%u C21=%u\n",
 		frame_bits[310], frame_bits[311], frame_bits[312],