view trau-decode/parse-main.c @ 49:e579784e5578

trau-parse: restore FR-like display for unknown frames
author Mychaela Falconia <falcon@freecalypso.org>
date Tue, 24 Sep 2024 19:49:45 +0000
parents 3d8cb2631812
children f77a48a01ff0
line wrap: on
line source

/*
 * This program reads a 64 kbit/s timeslot recording file, examines one
 * of the four 16 kbit/s subslots (selected), looks for GSM 08.60 TRAU
 * frames, and dumps whatever it finds.
 */

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>

static unsigned file_offset;
static int include_raw;

static enum {
	HUNT_FOR_0,
	HUNT_FOUND_0,
	GOT_8_ZEROS,
	SYNCED
} state;
static enum {
	NOT_D144,
	D144_SYNC,
	D144_EDATA,
} d144_state;
static unsigned hunt_for_0_count, frame_pos_count;
static uint8_t in_frame_2bit[160], frame_bits[320], d_bits[260];

static void
unpack_dibits()
{
	int i, inb;
	uint8_t *op;

	op = frame_bits;
	for (i = 0; i < 160; i++) {
		inb = in_frame_2bit[i];
		if (inb & 2)
			*op++ = 1;
		else
			*op++ = 0;
		if (inb & 1)
			*op++ = 1;
		else
			*op++ = 0;
	}
}

static unsigned
bits_to_num(bits, nbits)
	uint8_t *bits;
	unsigned nbits;
{
	unsigned accum;
	unsigned n;

	accum = 0;
	for (n = 0; n < nbits; n++) {
		accum <<= 1;
		if (*bits)
			accum |= 1;
		bits++;
	}
	return accum;
}

static void
collect_d_bits()
{
	bcopy(frame_bits + 33, d_bits, 15);
	bcopy(frame_bits + 49, d_bits + 15, 15);
	bcopy(frame_bits + 65, d_bits + 30, 15);
	bcopy(frame_bits + 81, d_bits + 45, 15);
	bcopy(frame_bits + 97, d_bits + 60, 15);
	bcopy(frame_bits + 113, d_bits + 75, 15);
	bcopy(frame_bits + 129, d_bits + 90, 15);
	bcopy(frame_bits + 145, d_bits + 105, 15);
	bcopy(frame_bits + 161, d_bits + 120, 15);
	bcopy(frame_bits + 177, d_bits + 135, 15);
	bcopy(frame_bits + 193, d_bits + 150, 15);
	bcopy(frame_bits + 209, d_bits + 165, 15);
	bcopy(frame_bits + 225, d_bits + 180, 15);
	bcopy(frame_bits + 241, d_bits + 195, 15);
	bcopy(frame_bits + 257, d_bits + 210, 15);
	bcopy(frame_bits + 273, d_bits + 225, 15);
	bcopy(frame_bits + 289, d_bits + 240, 15);
	bcopy(frame_bits + 305, d_bits + 255, 5);
}

static void
print_fr_efr_frame(c1_5)
	unsigned c1_5;
{
	switch (c1_5) {
	case 0x02:
	case 0x1C:
		collect_d_bits();
		print_fr_frame(d_bits);
		break;
	case 0x1A:
		collect_d_bits();
		check_efr_crc(d_bits);
		print_efr_frame(d_bits);
		break;
	}
}

static void
print_data_subframe(nf, bits)
	uint8_t *bits;
{
	unsigned nb;

	printf("  Data frame %d:", nf);
	for (nb = 0; nb < 9; nb++) {
		printf(" %02X", bits_to_num(bits, 8));
		bits += 8;
	}
	putchar('\n');
}

static void
print_data_frame()
{
	print_data_subframe(0, frame_bits + 4 * 8);
	print_data_subframe(1, frame_bits + 13 * 8);
	print_data_subframe(2, frame_bits + 22 * 8);
	print_data_subframe(3, frame_bits + 31 * 8);
}

static void
dump_raw_frame()
{
	uint8_t *sp = frame_bits;
	unsigned n, m, d;

	for (n = 0; n < 80; n++) {
		d = 0;
		for (m = 0; m < 4; m++) {
			d <<= 1;
			d |= *sp++;
		}
		printf("%x", d);
	}
	putchar('\n');
}

static void
process_frame()
{
	unsigned c1_5, c6_11;

	printf("Frame at 0x%x:\n", file_offset - 159);
	if (include_raw)
		dump_raw_frame();
	printf("  C1-C5: %u%u%u%u%u", frame_bits[17], frame_bits[18],
		frame_bits[19], frame_bits[20], frame_bits[21]);
	c1_5 = bits_to_num(frame_bits + 17, 5);
	switch (c1_5) {
	case 0x02:
		fputs(" (FR UL)", stdout);
		break;
	case 0x1C:
		fputs(" (FR DL)", stdout);
		break;
	case 0x1A:
		fputs(" (EFR)", stdout);
		break;
	case 0x10:
		fputs(" (idle UL)", stdout);
		break;
	case 0x0E:
		fputs(" (idle DL)", stdout);
		break;
	case 0x08:
		fputs(" (data UL)", stdout);
		break;
	case 0x16:
		fputs(" (data DL)", stdout);
		break;
	case 0x09:
		fputs(" (HR data UL)", stdout);
		break;
	case 0x17:
		fputs(" (HR data DL)", stdout);
		break;
	case 0x14:
		fputs(" (D144 sync)", stdout);
		break;
	case 0x1F:
		fputs(" (E-TRAU)", stdout);
		break;
	case 0x06:
		fputs(" (AMR)", stdout);
		break;
	}
	putchar('\n');
	if (c1_5 == 0x14)
		d144_state = D144_SYNC;
	else if (c1_5 == 0x1F &&
		 (d144_state == D144_SYNC || d144_state == D144_EDATA))
		d144_state = D144_EDATA;
	else
		d144_state = NOT_D144;
	switch (c1_5) {
	case 0x02:
	case 0x1C:
	case 0x1A:
	case 0x10:
	case 0x0E:
		c6_11 = bits_to_num(frame_bits + 22, 6);
		printf("  C6-C11: %u\n", c6_11);
		printf("  C12=%u C13=%u C14=%u C15=%u\n", frame_bits[28],
			frame_bits[29], frame_bits[30], frame_bits[31]);
		print_fr_efr_frame(c1_5);
		printf("  C16=%u C17=%u C18=%u C19=%u C20=%u C21=%u\n",
			frame_bits[310], frame_bits[311], frame_bits[312],
			frame_bits[313], frame_bits[314], frame_bits[315]);
		printf("  T1=%u T2=%u T3=%u T4=%u\n", frame_bits[316],
			frame_bits[317], frame_bits[318], frame_bits[319]);
		break;
	case 0x08:
	case 0x09:
	case 0x16:
	case 0x17:
	case 0x14:
		printf("  C6-C15: %u%u%u%u%u%u%u%u%u%u\n", frame_bits[22],
			frame_bits[23], frame_bits[24], frame_bits[25],
			frame_bits[26], frame_bits[27], frame_bits[28],
			frame_bits[29], frame_bits[30], frame_bits[31]);
		print_data_frame();
		break;
	case 0x1F:
		printf("  C6-C13: %u%u%u%u%u%u%u%u\n", frame_bits[22],
			frame_bits[23], frame_bits[24], frame_bits[25],
			frame_bits[26], frame_bits[27], frame_bits[28],
			frame_bits[29]);
		printf("  M1=%u M2=%u\n", frame_bits[30], frame_bits[31]);
		break;
	case 0x06:
		c6_11 = bits_to_num(frame_bits + 22, 6);
		printf("  C6-C11: %u\n", c6_11);
		printf("  RIF=%u C13=%u Config_Prot=%u%u%u Msg_No=%u%u\n",
			frame_bits[28], frame_bits[29], frame_bits[30],
			frame_bits[31], frame_bits[33], frame_bits[34],
			frame_bits[35]);
		printf("  DTXd=%u TFOE=%u FClass=%u%u CMI/CMR=%u%u%u\n",
			frame_bits[36], frame_bits[37], frame_bits[38],
			frame_bits[39], frame_bits[40], frame_bits[41],
			frame_bits[42]);
		if (!frame_bits[38] && !frame_bits[39])
			printf("  No_Spch_Class=%u%u%u CMI=%u%u%u CMR=%u%u%u\n",
				frame_bits[76], frame_bits[77], frame_bits[78],
				frame_bits[79], frame_bits[81], frame_bits[82],
				frame_bits[83], frame_bits[84], frame_bits[85]);
		printf("  T1=%u T2=%u T3=%u T4=%u\n", frame_bits[316],
			frame_bits[317], frame_bits[318], frame_bits[319]);
		break;
	default:
		printf("  C6-C15: %u%u%u%u%u%u%u%u%u%u\n", frame_bits[22],
			frame_bits[23], frame_bits[24], frame_bits[25],
			frame_bits[26], frame_bits[27], frame_bits[28],
			frame_bits[29], frame_bits[30], frame_bits[31]);
		printf("  C16=%u C17=%u C18=%u C19=%u C20=%u C21=%u\n",
			frame_bits[310], frame_bits[311], frame_bits[312],
			frame_bits[313], frame_bits[314], frame_bits[315]);
		printf("  T1=%u T2=%u T3=%u T4=%u\n", frame_bits[316],
			frame_bits[317], frame_bits[318], frame_bits[319]);
	}
}

static int
check_sync_zeros()
{
	int i;

	for (i = 0; i < 16; i++) {
		if (frame_bits[i])
			return 0;
	}
	return 1;
}

static int
check_sync_ones()
{
	int i;

	for (i = 1; i < 20; i++) {
		if (!frame_bits[i*16])
			return 0;
	}
	return 1;
}

static void
check_sync()
{
	int sync_res;

	if (d144_state == D144_EDATA)
		sync_res = check_sync_zeros() && frame_bits[16];
	else
		sync_res = check_sync_zeros() && check_sync_ones();
	if (sync_res)
		return;
	printf("Bad frame sync, returning to hunt state\n");
	state = HUNT_FOR_0;
}

static void
byte_input(inb)
{
	switch (state) {
	case HUNT_FOR_0:
		if (inb != 0)
			return;
		state = HUNT_FOUND_0;
		hunt_for_0_count = 1;
		return;
	case HUNT_FOUND_0:
		if (inb != 0) {
			state = HUNT_FOR_0;
			return;
		}
		hunt_for_0_count++;
		if (hunt_for_0_count >= 8)
			state = GOT_8_ZEROS;
		return;
	case GOT_8_ZEROS:
		if (inb & 2) {
			printf("Found frame sync at file offset 0x%x\n",
				file_offset - 8);
			bzero(in_frame_2bit, 8);
			in_frame_2bit[8] = inb;
			frame_pos_count = 9;
			state = SYNCED;
			return;
		}
		if (inb != 0)
			state = HUNT_FOR_0;
		return;
	case SYNCED:
		in_frame_2bit[frame_pos_count++] = inb;
		if (frame_pos_count < 160)
			return;
		frame_pos_count = 0;
		unpack_dibits();
		process_frame();
		check_sync();
		return;
	default:
		fprintf(stderr, "BUG: bad sync state\n");
		abort();
	}
}

main(argc, argv)
	char **argv;
{
	char *filename, *subslot_arg;
	FILE *inf;
	int subslot, right_shift;
	int inb;

	switch (argc) {
	case 3:
		filename = argv[1];
		subslot_arg = argv[2];
		include_raw = 0;
		break;
	case 4:
		if (strcmp(argv[1], "-r"))
			goto usage;
		filename = argv[2];
		subslot_arg = argv[3];
		include_raw = 1;
		break;
	default:
	usage:
		fprintf(stderr, "usage: %s [-r] binfile subslot\n", argv[0]);
		exit(1);
	}
	inf = fopen(filename, "r");
	if (!inf) {
		perror(filename);
		exit(1);
	}
	subslot = atoi(subslot_arg);
	if (subslot < 0 || subslot > 3) {
		fprintf(stderr, "error: invalid subslot argument\n");
		exit(1);
	}
	right_shift = (3 - subslot) * 2;
	state = HUNT_FOR_0;
	d144_state = NOT_D144;
	for (file_offset = 0; ; file_offset++) {
		inb = getc(inf);
		if (inb < 0)
			break;
		inb >>= right_shift;
		inb &= 3;
		byte_input(inb);
	}
	exit(0);
}