view efrtest/dlcap-sync.c @ 537:f9eefb61fb2f

frtest: new program gsmfr-decode-tw5
author Mychaela Falconia <falcon@freecalypso.org>
date Sat, 21 Sep 2024 23:31:25 +0000
parents d80ccb3c3970
children
line wrap: on
line source

/*
 * This program reads a TCH/EFS downlink capture file from a FreeCalypso GSM MS
 * that was produced in a session in which seqsync PCMA or PCMU input was fed
 * into the test call from IP-PSTN side.  It looks for EFR DHF followed by
 * specific frame patterns indicating how the seqsync input was transcoded
 * by the alien GSM network, and reports its findings.
 */

#include <ctype.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include "../libgsmefr/gsm_efr.h"

static const uint8_t mr122_dhf[31] = {
0xC0,0x85,0x4D,0xB9,0x6A,0xAA,0xD6,0x00,0x00,0x00,0x00,0x01,0xB5,0x87,0xF6,0x68,
0x37,0x94,0x09,0x00,0x41,0x58,0x54,0xF1,0x0F,0x6B,0x02,0x40,0x3C,0x7E,0xA0,
};

extern const uint8_t sync_from_pcma[320*31];
extern const uint8_t sync_from_pcmu[320*31];

static int
check_for_match(input, table)
	const uint8_t *input, *table;
{
	unsigned n;

	for (n = 0; n < 320; n++) {
		if (!bcmp(input, table + n * 31, 31))
			return n;
	}
	return -1;
}

main(argc, argv)
	char **argv;
{
	FILE *inf;
	char linebuf[128];
	int lineno, rc;
	uint16_t status_words[3];
	uint8_t tidsp_bytes[33], efr_bytes[31];
	const uint8_t *match_table;
	int dhf_state;
	char *dhf_name;

	if (argc != 3) {
usage:		fprintf(stderr, "usage: %s dlcap-file alaw|ulaw\n", argv[0]);
		exit(1);
	}
	inf = fopen(argv[1], "r");
	if (!inf) {
		perror(argv[1]);
		exit(1);
	}
	if (!strcmp(argv[2], "alaw"))
		match_table = sync_from_pcma;
	else if (!strcmp(argv[2], "ulaw"))
		match_table = sync_from_pcmu;
	else
		goto usage;
	dhf_state = 0;
	for (lineno = 1; fgets(linebuf, sizeof linebuf, inf); lineno++) {
		/* support both old and new formats */
		if (isxdigit(linebuf[0]) && isxdigit(linebuf[1]) &&
		    isxdigit(linebuf[2]) && isxdigit(linebuf[3])) {
			rc = parse_dlcap_common(linebuf, status_words,
						tidsp_bytes);
			if (rc < 0) {
invalid:			fprintf(stderr,
				"error: %s is not in the expected format\n",
					argv[1]);
				exit(1);
			}
		} else if (!strncmp(linebuf, "EFR ", 4)) {
			rc = parse_dlcap_common(linebuf + 4, status_words,
						tidsp_bytes);
			if (rc < 0)
				goto invalid;
			if (linebuf[85] != ' ')
				goto invalid;
			if (!isdigit(linebuf[86]))
				goto invalid;
		} else
			goto invalid;
		if ((status_words[0] & 0xC204) != 0xC000) {
			dhf_state = 0;
			continue;
		}
		efr_tidsp_to_std(tidsp_bytes, efr_bytes);
		if (!bcmp(efr_bytes, EFR_decoder_homing_frame, 31)) {
			dhf_state = 1;
			continue;
		}
		if (!bcmp(efr_bytes, mr122_dhf, 31)) {
			dhf_state = 2;
			continue;
		}
		if (!dhf_state)
			continue;
		rc = check_for_match(efr_bytes, match_table);
		if (rc >= 0 && rc <= 159) {
			printf(
			    "line %d: match to standard EFR with offset %d\n",
				lineno, rc);
			if (dhf_state == 2)
				printf("... but preceded by MR122 DHF!\n");
		} else if (rc >= 160 && rc <= 279) {
			printf("line %d: match to AMR-EFR with offset %d\n",
				lineno, rc - 160);
			if (dhf_state == 2)
				printf("... but preceded by MR122 DHF!\n");
		} else if (rc >= 280 && rc <= 319) {
			printf("line %d: match to AMR-EFR with offset %d\n",
				lineno, rc - 160);
			switch (dhf_state) {
			case 1:
				dhf_name = "EFR";
				break;
			case 2:
				dhf_name = "MR122";
				break;
			default:
				dhf_name = "???";
			}
			printf("previous frame was %s DHF\n", dhf_name);
		}
		dhf_state = 0;
	}
	exit(0);
}