view hr-bits/sid-count.c @ 407:183e81c8f6c0

hr-bits: sid-count program written
author Mychaela Falconia <falcon@freecalypso.org>
date Mon, 22 Jul 2024 10:00:58 +0000
parents
children 14302e075f37
line wrap: on
line source

/*
 * This program reads a TCH/HS DL capture file made with FC tools
 * and analyzes the hex string of payload bits in every frame.
 * For each frame, this program counts how many bits in the SID field
 * are set (both class 1 and class 2.  All input lines are passed
 * through to the output, but at the end of each line this program
 * appends bit counts that match the conventions used in GSM 06.06
 * swSidDetection() function.
 */

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

static const uint8_t class1_mask[12] = {0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9,
					0x3F, 0xC0, 0x0F, 0x78, 0x0E, 0x06};
static const uint8_t class2_mask[3]  = {0x1F, 0xFF, 0xF0};

static char *infname, *outfname;
static FILE *inf, *outf;
static int lineno;
static char linebuf[80];
static uint8_t frame[15];

static int
is_hex_string_spc(str, expect_len)
	char *str;
	unsigned expect_len;
{
	char *cp, *endp;

	endp = str + expect_len;
	for (cp = str; cp < endp; cp++) {
		if (!isxdigit(*cp))
			return 0;
	}
	if (*cp == ' ')
		return 1;
	else
		return 0;
}

static int
decode_hex_digit(c)
{
	int d;

	if (isdigit(c))
		d = c - '0';
	else if (isupper(c))
		d = c - 'A' + 10;
	else
		d = c - 'a' + 10;
	return d;
}

static void
frame_from_hex()
{
	char *cp;
	uint8_t *dp;
	unsigned n, u, l;

	cp = linebuf + 18;
	dp = frame;
	for (n = 0; n < 15; n++) {
		u = decode_hex_digit(*cp++);
		l = decode_hex_digit(*cp++);
		*dp++ = (u << 4) | l;
	}
}

static unsigned
ones_in_byte(byte)
	unsigned byte;
{
	unsigned count;

	count = 0;
	for (; byte; byte >>= 1) {
		if (byte & 1)
			count++;
	}
	return count;
}

static unsigned
count_1_bits(data, mask, nbytes)
	uint8_t *data, *mask;
	unsigned nbytes;
{
	unsigned n, and, accum;

	accum = 0;
	for (n = 0; n < nbytes; n++) {
		and = *data++ & *mask++;
		accum += ones_in_byte(and);
	}
	return accum;
}

static void
process_line()
{
	char *cp;
	unsigned class1_ones, class1_zeros;
	unsigned class2_ones, class2_zeros;
	unsigned n1n2;

	cp = index(linebuf, '\n');
	if (!cp) {
		fprintf(stderr, "%s line %d: too long or missing newline\n",
			infname, lineno);
		exit(1);
	}
	*cp = '\0';
	if (strncmp(linebuf, "HR ", 3)) {
inv:		fprintf(stderr,
			"%s line %d: format does not match HR DL capture\n",
			infname, lineno);
		exit(1);
	}
	if (!is_hex_string_spc(linebuf + 3, 4))
		goto inv;
	if (!is_hex_string_spc(linebuf + 8, 4))
		goto inv;
	if (!is_hex_string_spc(linebuf + 13, 4))
		goto inv;
	if (!is_hex_string_spc(linebuf + 18, 30))
		goto inv;
	frame_from_hex();

	class1_ones = count_1_bits(frame, class1_mask, 12);
	class1_zeros = 62 - class1_ones;
	class2_ones = count_1_bits(frame + 12, class2_mask, 3);
	class2_zeros = 17 - class2_ones;
	n1n2 = class1_zeros + class2_zeros;

	fprintf(outf, "%s %u %u", linebuf, class1_zeros, n1n2);
	if (n1n2 >= 11 && n1n2 < 16)
		fputs(" SID-1-diff", outf);
	if (n1n2 >= 16 && n1n2 <= 25)
		fputs(" BCI-to-BFI", outf);
	putc('\n', outf);
}

main(argc, argv)
	char **argv;
{
	if (argc >= 2) {
		infname = argv[1];
		inf = fopen(infname, "r");
		if (!inf) {
			perror(infname);
			exit(1);
		}
	} else {
		inf = stdin;
		infname = "stdin";
	}

	if (argc >= 3) {
		outfname = argv[2];
		outf = fopen(outfname, "w");
		if (!outf) {
			perror(outfname);
			exit(1);
		}
	} else {
		outf = stdout;
		outfname = "stdout";
	}

	for (lineno = 1; fgets(linebuf, sizeof linebuf, inf); lineno++)
		process_line();

	exit(0);
}