changeset 6:d57f68d0568d

fc-tch2fr utility written, added under miscutil
author Mychaela Falconia <falcon@freecalypso.org>
date Tue, 14 Jun 2016 02:45:09 +0000
parents 7eaa3307e5df
children 08804864172a
files .hgignore miscutil/Makefile miscutil/fc-tch2fr.c
diffstat 3 files changed, 100 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Tue Jun 14 01:40:14 2016 +0000
+++ b/.hgignore	Tue Jun 14 02:45:09 2016 +0000
@@ -19,6 +19,7 @@
 ^miscutil/fc-fr2tch$
 ^miscutil/fc-rgbconv$
 ^miscutil/fc-serterm$
+^miscutil/fc-tch2fr$
 ^miscutil/imei-luhn$
 
 ^rvinterf/asyncshell/fc-shell$
--- a/miscutil/Makefile	Tue Jun 14 01:40:14 2016 +0000
+++ b/miscutil/Makefile	Tue Jun 14 02:45:09 2016 +0000
@@ -1,11 +1,12 @@
 CC=	gcc
 CFLAGS=	-O2
-PROGS=	fc-fr2tch fc-rgbconv fc-serterm imei-luhn
+PROGS=	fc-fr2tch fc-rgbconv fc-serterm fc-tch2fr imei-luhn
 INSTBIN=/usr/local/bin
 
 all:	${PROGS}
 
 FR2TCH_OBJS=	fc-fr2tch.o gsm0610.o
+TCH2FR_OBJS=	fc-tch2fr.o gsm0610.o
 SERTERM_OBJS=	fc-serterm.o openport.o ttypassthru.o
 
 fc-fr2tch:	${FR2TCH_OBJS}
@@ -20,6 +21,9 @@
 ttypassthru.o:	../loadtools/ttypassthru.c
 	${CC} ${CFLAGS} -c -o $@ $<
 
+fc-tch2fr:	${TCH2FR_OBJS}
+	${CC} ${CFLAGS} -o $@ ${TCH2FR_OBJS}
+
 imei-luhn:	imei-luhn.c
 	${CC} ${CFLAGS} -o $@ $@.c
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/miscutil/fc-tch2fr.c	Tue Jun 14 02:45:09 2016 +0000
@@ -0,0 +1,94 @@
+/*
+ * Our experimental Calypso firmware enables us to capture the output of
+ * the GSM 05.03 channel decoder in the DSP, i.e., the bits leaving the
+ * channel decoder and going into the speech decoder.  Our fc-shell utility
+ * allows saving this capture to a file; the captured booty includes not only
+ * the expected 260 bits per frame, but also some DSP status words which are
+ * not fully understood, but which are believed to contain indications as to
+ * whether the decoded speech frame is good or bad.
+ *
+ * My first naive thought was to save the captured speech frames in libgsm
+ * format so I could then play them with the 'play' command (SoX package)
+ * under Linux, but the problem with this naive approach is that the bad frames
+ * indication is lost, and some of the saved "speech" frames will contain
+ * utter garbage, resulting in very unkind-on-ears noises if that file is
+ * then played.  I don't know what the proper solution should be; I don't know
+ * what the commercial cellphone implementations of the GSM 06.10 speech decoder
+ * (buried in black box DSPs) do when they get bad frames from the channel
+ * decoder.
+ *
+ * The present utility reproduces the naive behaviour of my previous
+ * implementation of fc-shell's tch record command: it takes hex files written
+ * by the current implementation of tch record in fc-shell, DISREGARDS the
+ * DSP status words, and blindly converts each 260-bit frame (good or bad)
+ * into libgsm format.
+ */
+
+#include <sys/types.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static
+decode_hex_digit(ch)
+{
+	if (isdigit(ch))
+		return(ch - '0');
+	else if (isupper(ch))
+		return(ch - 'A' + 10);
+	else
+		return(ch - 'a' + 10);
+}
+
+main(argc, argv)
+	char **argv;
+{
+	FILE *inf, *outf;
+	char linebuf[128];
+	int lineno;
+	char *cp;
+	int i, j;
+	u_char tidsp_bytes[33], libgsm_bytes[33];
+
+	if (argc != 3) {
+		fprintf(stderr, "usage: %s infile outfile\n", argv[0]);
+		exit(1);
+	}
+	inf = fopen(argv[1], "r");
+	if (!inf) {
+		perror(argv[1]);
+		exit(1);
+	}
+	outf = fopen(argv[2], "w");
+	if (!outf) {
+		perror(argv[2]);
+		exit(1);
+	}
+	for (lineno = 1; fgets(linebuf, sizeof linebuf, inf); lineno++) {
+		/* skip DSP status words */
+		cp = linebuf;
+		for (i = 0; i < 3; i++) {
+			for (j = 0; j < 4; j++) {
+				if (!isxdigit(*cp++)) {
+invalid:				fprintf(stderr,
+				    "error: %s is not in the expected format\n",
+						argv[1]);
+					exit(1);
+				}
+			}
+			if (*cp++ != ' ')
+				goto invalid;
+		}
+		/* read the frame bits */
+		for (i = 0; i < 33; i++) {
+			if (!isxdigit(cp[0]) || !isxdigit(cp[1]))
+				goto invalid;
+			tidsp_bytes[i] = (decode_hex_digit(cp[0]) << 4) |
+					  decode_hex_digit(cp[1]);
+			cp += 2;
+		}
+		gsm0610_tidsp_to_libgsm(tidsp_bytes, libgsm_bytes);
+		fwrite(libgsm_bytes, 1, 33, outf);
+	}
+	exit(0);
+}