view tfo/tfo-trace-msg.c @ 64:0364d77aca58 default tip

d144: generate hex version of Nokia TCSM2 A-TRAU capture
author Mychaela Falconia <falcon@freecalypso.org>
date Wed, 25 Sep 2024 18:57:54 +0000
parents f6bb790e186a
children
line wrap: on
line source

/*
 * This program reads a raw binary file that contains a recording of
 * a T1/E1 timeslot on the MSC side of a TRAU, analyzes it looking for
 * TFO IS messages, and prints whatever it finds.
 */

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

#define	MAX_EXT_WORDS	5

static uint8_t is_hunt_buf[320];
static int is_state;
static unsigned is_hunt_fill;
static unsigned is_offset;
static unsigned is_file_offset;
static unsigned is_bit_count;
static uint32_t is_rx_word, is_cmd, is_ext_words[MAX_EXT_WORDS];
static unsigned is_ext_count;

static const u_char hdr_pattern[20] =	{0, 1, 0, 1, 0, 1, 1, 0, 1, 0,
					 0, 1, 1, 0, 1, 0, 1, 0, 0, 1};

static void
is_rx_hunt(cur_file_offset)
	unsigned cur_file_offset;
{
	unsigned offset, n;

	for (offset = 0; offset < 16; offset++) {
		for (n = 0; n < 20; n++)
			if ((is_hunt_buf[offset + n*16] & 1) != hdr_pattern[n])
				break;
		if (n == 20)
			break;
	}
	if (n != 20)
		return;
	is_offset = offset;
	is_file_offset = cur_file_offset - 19*16 + offset;
	is_state = 1;
	is_bit_count = 0;
	is_rx_word = 0;
	is_hunt_fill = 0;
}

static void
is_process_cmd()
{
	int cont;

	printf("0x%x: ", is_file_offset);
	is_cmd = is_rx_word;
	switch (is_cmd) {
	case 0x05D:
		printf("IS_REQ\n");
		cont = 1;
		break;
	case 0x0BA:
		printf("IS_ACK\n");
		cont = 1;
		break;
	case 0x0E7:
		printf("IS_IPE\n");
		cont = 1;
		break;
	case 0x129:
		printf("IS_FILL\n");
		cont = 0;
		break;
	case 0x174:
		printf("IS_DUP\n");
		cont = 0;
		break;
	case 0x193:
		printf("IS_SYL\n");
		cont = 0;
		break;
	default:
		printf("unknown IS_Command 0x%03X\n", (unsigned) is_cmd);
		cont = 0;
	}
	if (cont) {
		is_state = 2;
		is_bit_count = 0;
		is_rx_word = 0;
		is_ext_count = 0;
	} else
		is_state = 0;
}

static void
process_tfo_req_ack(reqack)
	char *reqack;
{
	if (is_ext_count < 2)
		return;
	if (is_ext_words[0] != 0x5394B)		/* GSM System ID */
		return;
	printf("  TFO_%s: List_Ind=%u Sig=0x%02X CoID=0x%X CRC=%u\n", reqack,
		(is_ext_words[1] >> 18) & 1, (is_ext_words[1] >> 10) & 0xFF,
		(is_ext_words[1] >> 5) & 0xF, (is_ext_words[1] >> 2) & 7);
}

static void
is_process_high_level()
{
	switch (is_cmd) {
	case 0x05D:
		process_tfo_req_ack("REQ");
		break;
	case 0x0BA:
		process_tfo_req_ack("ACK");
		break;
	}
}

static void
is_process_ext()
{
	printf("  IS_Extension: 0x%05X", (unsigned) is_rx_word);
	if (is_rx_word & 0x80200) {
		printf(" (bad sync)\n");
		is_state = 0;
		return;
	}
	if (is_ext_count < MAX_EXT_WORDS)
		is_ext_words[is_ext_count++] = is_rx_word;
	switch (is_rx_word & 3) {
	case 0:
		printf(" (final)\n");
		is_state = 0;
		is_process_high_level();
		return;
	case 3:
		printf(" (continue)\n");
		is_state = 2;
		is_bit_count = 0;
		is_rx_word = 0;
		return;
	default:
		printf(" (bad EX)\n");
		is_state = 0;
	}
}

static void
is_rx_process(input, cur_file_offset)
	uint8_t *input;
	unsigned cur_file_offset;
{
	unsigned new_bit;

	memmove(is_hunt_buf, is_hunt_buf + 16, 304);
	memcpy(is_hunt_buf + 304, input, 16);
	if (!is_state) {
		if (is_hunt_fill < 20)
			is_hunt_fill++;
		if (is_hunt_fill == 20)
			is_rx_hunt(cur_file_offset);
		return;
	}
	new_bit = input[is_offset] & 1;
	is_rx_word <<= 1;
	is_rx_word |= new_bit;
	is_bit_count++;
	if (is_state == 1 && is_bit_count == 10)
		is_process_cmd();
	else if (is_state == 2 && is_bit_count == 20)
		is_process_ext();
}

main(argc, argv)
	char **argv;
{
	FILE *inf;
	uint8_t chunk[16];
	unsigned file_offset;
	int cc;

	if (argc != 2) {
		fprintf(stderr, "usage: %s pcm-capture-file\n", argv[0]);
		exit(1);
	}
	inf = fopen(argv[1], "r");
	if (!inf) {
		perror(argv[1]);
		exit(1);
	}
	for (file_offset = 0; ; file_offset += 16) {
		cc = fread(chunk, 1, 16, inf);
		if (cc == 0)
			break;
		if (cc != 16) {
			fprintf(stderr,
				"error: read of 16 bytes returned %d\n", cc);
			exit(1);
		}
		is_rx_process(chunk, file_offset);
	}
	exit(0);
}