view amrconv/tw5c-dump.c @ 608:d4e42ec4a688 default tip

hrutil: new program gsmhr-decode-r
author Mychaela Falconia <falcon@freecalypso.org>
date Fri, 05 Dec 2025 09:01:14 +0000
parents fd6a394ab4cd
children
line wrap: on
line source

/*
 * This program reads a TW-TS-005 Annex C hexadecimal file
 * and dumps all frames in human-readable form.
 */

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include "../libtest/tw5reader.h"
#include "amr_defs.h"

extern char *amr_mode_names[16];
extern const uint8_t pl_total_bytes_oa[9], pl_total_bytes_bwe[9];

static char *infname;
static int is_bwe;

static void
process_cmdline(argc, argv)
	char **argv;
{
	int opt;
	extern int optind;

	while ((opt = getopt(argc, argv, "b")) != EOF) {
		switch (opt) {
		case 'b':
			is_bwe = 1;
			continue;
		default:
		usage:
			fprintf(stderr, "usage: %s [-b] hex-file\n", argv[0]);
			exit(1);
		}
	}
	if (argc != optind + 1)
		goto usage;
	infname = argv[optind];
}

static void
if1_bwe_to_oa(in, out, mode)
	uint8_t *in, *out;
	unsigned mode;
{
	unsigned out_len, n;

	out_len = pl_total_bytes_oa[mode] - 2;
	for (n = 0; n < out_len; n++)
		out[n] = (in[n+1] << 2) | (in[n+2] >> 6);
}

static void
process_file()
{
	FILE *hexf;
	unsigned lineno;
	uint8_t frame[TWTS005_MAX_FRAME];
	unsigned frame_len, base_len, cmr, ft, q, sid_byte, sti, sid_mode;
	const uint8_t *pl_len_table;
	uint8_t frm_to_oa[MAX_IF1_BYTES];
	uint8_t ser_bits[MAX_SERIAL_SIZE];
	uint16_t params[MAX_PRM_SIZE];
	unsigned ptr;
	int rc;

	hexf = fopen(infname, "r");
	if (!hexf) {
		perror(infname);
		exit(1);
	}
	lineno = 0;
	for (;;) {
		rc = twts005_read_frame(hexf, &lineno, frame, &frame_len);
		if (rc < 0) {
			fprintf(stderr, "%s line %u: not valid TW-TS-005\n",
				infname, lineno);
			exit(1);
		}
		if (!rc)
			break;
		if (frame_len == 0) {
			printf("line %u: NULL frame\n", lineno);
			continue;
		}
		if (frame_len < 2) {
inv_payload:		fprintf(stderr,
				"%s line %u: payload is not valid AMR %s\n",
				infname, lineno, is_bwe ? "BWE" : "OA");
			exit(1);
		}
		cmr = frame[0] >> 4;
		if (cmr > MR122 && cmr != MODE_NO_DATA)
			goto inv_payload;
		if (is_bwe) {
			if (frame[0] & 0x08)
				goto inv_payload;
			ft = ((frame[0] & 0x07) << 1) |
			     ((frame[1] & 0x80) >> 7);
			q = (frame[1] & 0x40) >> 6;
			pl_len_table = pl_total_bytes_bwe;
		} else {
			if (frame[1] & 0x80)
				goto inv_payload;
			ft = (frame[1] & 0x78) >> 3;
			q = (frame[1] & 0x04) >> 2;
			pl_len_table = pl_total_bytes_oa;
		}
		if (ft <= MRDTX)
			base_len = pl_len_table[ft];
		else if (ft == MODE_NO_DATA)
			base_len = 2;
		else
			goto inv_payload;
		if (frame_len < base_len)
			goto inv_payload;
		printf("line %u: CMR=%u (%s) FT=%u (%s) Q=%u\n", lineno, cmr,
			amr_mode_names[cmr], ft, amr_mode_names[ft], q);
		if (ft != MODE_NO_DATA) {
			if (is_bwe) {
				if1_bwe_to_oa(frame, frm_to_oa, ft);
				amr_if1_unpack(frm_to_oa, ser_bits, ft);
			} else {
				amr_if1_unpack(frame + 2, ser_bits, ft);
			}
			reassemble_amr_params(ser_bits, params, ft);
			dump_amr_params(params, ft);
		}
		if (ft == MRDTX) {
			sid_byte = is_bwe ? frm_to_oa[4] : frame[6];
			sti = (sid_byte & 0x10) >> 4;
			sid_mode = 0;
			if (sid_byte & 0x08)
				sid_mode |= 1;
			if (sid_byte & 0x04)
				sid_mode |= 2;
			if (sid_byte & 0x02)
				sid_mode |= 4;
			printf("  SID_%s Mode=%u (%s)\n",
				sti ? "UPDATE" : "FIRST", sid_mode,
				amr_mode_names[sid_mode]);
		}
		if (is_bwe)
			continue;
		/* TW-TS-006 extensions */
		if (frame[0] & 0x08)
			printf("  RIF=%u\n", (frame[0] & 0x04) >> 2);
		ptr = base_len;
		if ((ft == MODE_NO_DATA) && (frame[1] & 0x02)) {
			fputs("  FT15 ext octet: ", stdout);
			if (ptr >= frame_len) {
				puts("indicated, but not present");
				continue;
			}
			/* repurpose sti and sid_mode vars */
			sti = (frame[ptr] & 0x80) >> 7;
			sid_mode = frame[ptr] & 7;
			printf("%s, Mode=%u (%s)\n", sti ? "Onset" : "No_Data",
				sid_mode, amr_mode_names[sid_mode]);
			ptr++;
		}
		if (frame[0] & 0x02) {
			if (ptr >= frame_len) {
				puts("  TA+DTXd+TFOE octet missing!");
				continue;
			}
			printf("  TA=%u DTXd=%u TFOE=%u\n", frame[ptr] >> 2,
				(frame[ptr] & 0x02) >> 1, frame[ptr] & 0x01);
			ptr++;
		}
		if (frame[0] & 0x01)
			puts("  Rel4 Config_Prot present, not decoded");
		if ((ft == MODE_NO_DATA) && (frame[1] & 0x01))
			puts("  Rel5 GCF, not decoded");
	}
}

main(argc, argv)
	char **argv;
{
	process_cmdline(argc, argv);
	process_file();
	exit(0);
}