changeset 593:fd6a394ab4cd default tip

amrconv: new program tw5c-dump
author Mychaela Falconia <falcon@freecalypso.org>
date Tue, 18 Nov 2025 07:34:23 +0000
parents 24aba0e7aa35
children
files .hgignore amrconv/Makefile amrconv/tw5c-dump.c
diffstat 3 files changed, 197 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Fri Nov 07 00:41:56 2025 +0000
+++ b/.hgignore	Tue Nov 18 07:34:23 2025 +0000
@@ -13,6 +13,7 @@
 ^amrconv/amr-ietf2hexoa$
 ^amrconv/gsm-amr2efr$
 ^amrconv/gsm-efr2amr$
+^amrconv/tw5c-dump$
 
 ^amrefr/amrefr-decode-r$
 ^amrefr/amrefr-encode-r$
--- a/amrconv/Makefile	Fri Nov 07 00:41:56 2025 +0000
+++ b/amrconv/Makefile	Tue Nov 18 07:34:23 2025 +0000
@@ -1,5 +1,6 @@
 PROGS=	amr-cod-parse amr-cod2ietf amr-hex-bwe2oa amr-hex-oa2bwe amr-hexoa2ietf\
-	amr-ietf-parse amr-ietf2cod amr-ietf2hexoa gsm-amr2efr gsm-efr2amr
+	amr-ietf-parse amr-ietf2cod amr-ietf2hexoa gsm-amr2efr gsm-efr2amr \
+	tw5c-dump
 LIBTEST=../libtest/libtest.a
 
 include ../config.defs
@@ -22,6 +23,10 @@
 BWE2OA_OBJS=	bwe2oa.o bwe_conv_common.o
 OA2BWE_OBJS=	oa2bwe.o bwe_conv_common.o
 
+TW5C_DUMP_OBJS=	amr122bits.o amr_bits.o amr_common_tbl.o bitmanip.o \
+		bwe_conv_common.o if1_unpack.o param_asm.o param_dump.o \
+		tw5c-dump.o
+
 all:	${PROGS}
 
 amr-cod-parse:	${COD_PARSE_OBJS}
@@ -54,6 +59,9 @@
 gsm-efr2amr:	${EFR2AMR_OBJS} ${LIBTEST}
 	${CC} ${CFLAGS} -o $@ ${EFR2AMR_OBJS} ${LIBTEST}
 
+tw5c-dump:	${TW5C_DUMP_OBJS} ${LIBTEST}
+	${CC} ${CFLAGS} -o $@ ${TW5C_DUMP_OBJS} ${LIBTEST}
+
 install:
 	mkdir -p ${DESTDIR}${bindir}
 	install -c ${PROGS} ${DESTDIR}${bindir}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/amrconv/tw5c-dump.c	Tue Nov 18 07:34:23 2025 +0000
@@ -0,0 +1,187 @@
+/*
+ * 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);
+}