view trau-decode/trau-hr-dump.c @ 28:9bcdb091c24d

trau-decode: new program trau-hr-dump
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 18 Aug 2024 08:37:02 +0000
parents trau-decode/trau-sync8.c@f508dacf2cf9
children 61181373875d
line wrap: on
line source

/*
 * This program reads a 64 kbit/s timeslot recording file, examines one
 * of the eight 8 kbit/s subslots (selected), looks for the sync pattern of
 * GSM 08.61, decodes each frame as HRv1 speech and dumps everything it
 * decodes.
 */

#include <sys/types.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include "gsmhr_unpack.h"
#include "osmo_bits.h"

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

static uint8_t *filebuf;
static unsigned total_size;

static void
read_ts_file(filename, subslot_arg)
	char *filename, *subslot_arg;
{
	FILE *inf;
	struct stat st;
	int subslot, right_shift;
	unsigned n;
	uint8_t *dp;
	int b;

	inf = fopen(filename, "r");
	if (!inf) {
		perror(filename);
		exit(1);
	}
	fstat(fileno(inf), &st);
	if (!S_ISREG(st.st_mode)) {
		fprintf(stderr, "error: %s is not a regular file\n", filename);
		exit(1);
	}
	total_size = st.st_size;
	if (total_size < 160) {
		fprintf(stderr, "error: %s is too short\n", filename);
		exit(1);
	}
	filebuf = malloc(total_size);
	if (!filebuf) {
		perror("malloc of file size");
		exit(1);
	}
	subslot = atoi(subslot_arg);
	if (subslot < 0 || subslot > 7) {
		fprintf(stderr, "error: invalid subslot argument\n");
		exit(1);
	}
	right_shift = 7 - subslot;
	dp = filebuf;
	for (n = 0; n < total_size; n++) {
		b = getc(inf);
		if (b < 0) {
			fprintf(stderr,
			"error: getc() returned EOF contrary to st_size\n");
			exit(1);
		}
		*dp++ = (b >> right_shift) & 1;
	}
	fclose(inf);
}

static int
check_sync(pos)
	unsigned pos;
{
	uint8_t *cand = filebuf + pos;
	unsigned n;

	for (n = 0; n < 8; n++) {
		if (cand[n])
			return 0;
	}
	if (!cand[8])
		return 0;
	if (cand[16])
		return 0;
	if (!cand[17])
		return 0;
	for (n = 3; n < 20; n++) {
		if (!cand[n * 8])
			return 0;
	}
	return 1;
}

static int
bit_parity(bits, nbits)
	ubit_t *bits;
	unsigned nbits;
{
	unsigned n, sum;

	sum = 0;
	for (n = 0; n < nbits; n++)
		sum += bits[n];
	return sum & 1;
}

static void
bits2bytes(bits, bytes, nbytes)
	ubit_t *bits;
	uint8_t *bytes;
	unsigned nbytes;
{
	unsigned n, m, acc;

	for (n = 0; n < nbytes; n++) {
		acc = 0;
		for (m = 0; m < 8; m++) {
			acc <<= 1;
			acc |= *bits++;
		}
		*bytes++ = acc;
	}
}

static void
process_frame(pos)
	unsigned pos;
{
	ubit_t *frame = filebuf + pos;
	ubit_t xc_bits[6], dbits[112];
	uint8_t hr_bytes[14];
	int16_t params[18];
	int crc_stat;

	printf("Frame at 0x%x:\n", pos);
	printf("  C1-C4: %u%u%u%u OP %s\n", frame[9], frame[10], frame[11],
		frame[12], bit_parity(frame + 9, 5) ? "good" : "bad");
	bcopy(frame + 14, xc_bits, 2);
	bcopy(frame + 18, xc_bits + 2, 4);
	printf("  XC1-XC5: %u%u%u%u%u OP %s\n", xc_bits[0], xc_bits[1],
		xc_bits[2], xc_bits[3], xc_bits[4],
		bit_parity(xc_bits, 6) ? "good" : "bad");
	bcopy(frame + 22, dbits, 2);
	bcopy(frame + 25, dbits + 2, 7);
	bcopy(frame + 33, dbits + 9, 7);
	bcopy(frame + 41, dbits + 16, 7);
	bcopy(frame + 49, dbits + 23, 7);
	bcopy(frame + 57, dbits + 30, 7);
	bcopy(frame + 65, dbits + 37, 7);
	bcopy(frame + 76, dbits + 44, 4);
	bcopy(frame + 81, dbits + 48, 7);
	bcopy(frame + 89, dbits + 55, 7);
	bcopy(frame + 97, dbits + 62, 7);
	bcopy(frame + 105, dbits + 69, 7);
	bcopy(frame + 113, dbits + 76, 7);
	bcopy(frame + 121, dbits + 83, 7);
	bcopy(frame + 129, dbits + 90, 7);
	bcopy(frame + 137, dbits + 97, 7);
	bcopy(frame + 145, dbits + 104, 7);
	dbits[111] = frame[153];
	crc_stat = osmo_crc8gen_check_bits(&gsm0860_efr_crc3, dbits, 44,
					   frame + 73);
	printf("  CRC %s\n", crc_stat ? "bad" : "good");
	bits2bytes(dbits, hr_bytes, 14);
	gsmhr_unpack_ts101318(hr_bytes, params);
	printf("  R0=%02x LPC=%03x,%03x,%02x Int=%x Mode=%x\n", params[0],
		params[1], params[2], params[3], params[4], params[5]);
	printf(params[5] ? "  s1=%02x,%03x,%02x" : "  s1=%02x,%02x,%02x",
		params[6], params[7], params[8]);
	printf(params[5] ? " s2=%x,%03x,%02x" : " s2=%02x,%02x,%02x",
		params[9], params[10], params[11]);
	printf(params[5] ? " s3=%x,%03x,%02x" : " s3=%02x,%02x,%02x",
		params[12], params[13], params[14]);
	printf(params[5] ? " s4=%x,%03x,%02x\n" : " s4=%02x,%02x,%02x\n",
		params[15], params[16], params[17]);
	printf("  C6-C9: %u%u%u%u\n", frame[154], frame[155], frame[156],
		frame[157]);
	printf("  T1=%u T2=%u\n", frame[158], frame[159]);
}

static void
process_filebuf()
{
	unsigned p, endp;
	int sync = 0, match;

	endp = total_size - 160;
	for (p = 0; p < endp; ) {
		match = check_sync(p);
		if (match != sync) {
			printf("# %s frame sync at file offset 0x%x\n",
				match ? "Acquired" : "Lost", p);
		}
		if (match) {
			process_frame(p);
			if (!filebuf[p+158] && !filebuf[p+159]) {
				printf(
			  "# both T bits equal 0, shifting frame alignment\n");
				p += 158;
			} else
				p += 160;
		} else
			p++;
		sync = match;
	}
}

main(argc, argv)
	char **argv;
{
	if (argc != 3) {
		fprintf(stderr, "usage: %s binfile subslot\n", argv[0]);
		exit(1);
	}
	read_ts_file(argv[1], argv[2]);
	process_filebuf();
	exit(0);
}