FreeCalypso > hg > freecalypso-tools
changeset 902:8ddb16a37273
tree org: move TCH and VM utils from miscutil to tchtools
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Wed, 28 Dec 2022 07:52:30 +0000 |
parents | 2e6764022292 |
children | a7ad6b39e01b |
files | .hgignore Makefile miscutil/Makefile miscutil/fc-fr2tch.c miscutil/fc-gsm2vm.c miscutil/fc-tch2fr.c miscutil/fc-vm2hex.c miscutil/gsm0610.c tchtools/Makefile tchtools/fc-fr2tch.c tchtools/fc-gsm2vm.c tchtools/fc-tch2fr.c tchtools/fc-vm2hex.c tchtools/gsm0610.c |
diffstat | 14 files changed, 674 insertions(+), 657 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgignore Tue Dec 13 03:24:36 2022 +0000 +++ b/.hgignore Wed Dec 28 07:52:30 2022 +0000 @@ -34,14 +34,10 @@ ^loadtools/fc-xram$ ^miscutil/arfcn2ti$ -^miscutil/fc-fr2tch$ -^miscutil/fc-gsm2vm$ ^miscutil/fc-pulse-dtr$ ^miscutil/fc-pulse-rts$ ^miscutil/fc-rgbconv$ ^miscutil/fc-serterm$ -^miscutil/fc-tch2fr$ -^miscutil/fc-vm2hex$ ^miscutil/imei-luhn$ ^miscutil/make-imeisv$ ^miscutil/mokosrec2bin$ @@ -72,6 +68,11 @@ ^target-utils/tf-breakin/embed\.c$ ^target-utils/tf-breakin/mkembed$ +^tchtools/fc-fr2tch$ +^tchtools/fc-gsm2vm$ +^tchtools/fc-tch2fr$ +^tchtools/fc-vm2hex$ + ^toolchain/binutils-2\.21\.1/ ^toolchain/binutils-build/ ^toolchain/gcc-4\.5\.4/
--- a/Makefile Tue Dec 13 03:24:36 2022 +0000 +++ b/Makefile Wed Dec 28 07:52:30 2022 +0000 @@ -1,6 +1,6 @@ CC= gcc CFLAGS= -O2 -PROGDIR=ffstools loadtools miscutil ringtools rvinterf uptools +PROGDIR=ffstools loadtools miscutil ringtools rvinterf tchtools uptools LIBDIR= libpwon librftab libserial SUBDIR= ${PROGDIR} ${LIBDIR}
--- a/miscutil/Makefile Tue Dec 13 03:24:36 2022 +0000 +++ b/miscutil/Makefile Wed Dec 28 07:52:30 2022 +0000 @@ -1,8 +1,7 @@ CC= gcc CFLAGS= -O2 -PROGS= arfcn2ti fc-fr2tch fc-gsm2vm fc-pulse-dtr fc-pulse-rts fc-rgbconv \ - fc-serterm fc-tch2fr fc-vm2hex imei-luhn make-imeisv mokosrec2bin \ - srec-regions ti2arfcn +PROGS= arfcn2ti fc-pulse-dtr fc-pulse-rts fc-rgbconv fc-serterm imei-luhn \ + make-imeisv mokosrec2bin srec-regions ti2arfcn SCRIPTS=c139explore pirexplore INSTALL_PREFIX= /opt/freecalypso @@ -11,20 +10,11 @@ all: ${PROGS} -FR2TCH_OBJS= fc-fr2tch.o gsm0610.o -GSM2VM_OBJS= fc-gsm2vm.o gsm0610.o -TCH2FR_OBJS= fc-tch2fr.o gsm0610.o SERTERM_OBJS= fc-serterm.o ttypassthru.o ../libserial/libserial.a arfcn2ti: arfcn2ti.c ${CC} ${CFLAGS} -o $@ $@.c -fc-fr2tch: ${FR2TCH_OBJS} - ${CC} ${CFLAGS} -o $@ ${FR2TCH_OBJS} - -fc-gsm2vm: ${GSM2VM_OBJS} - ${CC} ${CFLAGS} -o $@ ${GSM2VM_OBJS} - fc-pulse-dtr: fc-pulse-dtr.c ${CC} ${CFLAGS} -o $@ $@.c @@ -40,12 +30,6 @@ ttypassthru.o: ../loadtools/ttypassthru.c ${CC} ${CFLAGS} -c -o $@ $< -fc-tch2fr: ${TCH2FR_OBJS} - ${CC} ${CFLAGS} -o $@ ${TCH2FR_OBJS} - -fc-vm2hex: fc-vm2hex.c - ${CC} ${CFLAGS} -o $@ $@.c - imei-luhn: imei-luhn.c ${CC} ${CFLAGS} -o $@ $@.c
--- a/miscutil/fc-fr2tch.c Tue Dec 13 03:24:36 2022 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -/* - * This utility converts a GSM 06.10 speech recording from the format that is - * commonly accepted as standard in the Unix/Linux world (libgsm format) into - * hex strings of TCH bits to be fed to the GSM 05.03 channel encoder by way - * of a TI Calypso GSM device, a FreeCalypso GSM firmware version with the - * TCH rerouting feature, and fc-shell's tch play command. - */ - -#include <sys/types.h> -#include <stdio.h> -#include <stdlib.h> - -main(argc, argv) - char **argv; -{ - FILE *inf, *outf; - u_char libgsm_bytes[33], tidsp_bytes[33]; - int cc, i, gotsome = 0; - - 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 (;;) { - cc = fread(libgsm_bytes, 1, 33, inf); - if (cc < 33) - break; - if ((libgsm_bytes[0] & 0xF0) != 0xD0) { -invalid: fprintf(stderr, "error: %s is not in libgsm format\n", - argv[1]); - exit(1); - } - gsm0610_libgsm_to_tidsp(libgsm_bytes, tidsp_bytes); - for (i = 0; i < 33; i++) - fprintf(outf, "%02X", tidsp_bytes[i]); - putc('\n', outf); - gotsome = 1; - } - fclose(outf); - if (cc) { - if (gotsome) - fprintf(stderr, - "warning: extra non-33 bytes at the end of %s\n", - argv[1]); - else - goto invalid; - } - exit(0); -}
--- a/miscutil/fc-gsm2vm.c Tue Dec 13 03:24:36 2022 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +0,0 @@ -/* - * This utility converts a GSM 06.10 speech recording from the format that is - * commonly accepted as standard in the Unix/Linux world (libgsm format) into - * a voice memo file that can be uploaded into the FFS of a FreeCalypso device - * and played with the audio_vm_play_start() API or the AT@VMP command that - * invokes the latter. - */ - -#include <sys/types.h> -#include <stdio.h> -#include <stdlib.h> - -main(argc, argv) - char **argv; -{ - FILE *inf, *outf; - u_char libgsm_bytes[33], tidsp_bytes[34], arm_bytes[34]; - static u_char header_bytes[6] = {0x00, 0xC4, 0x00, 0x00, 0x00, 0x00}; - static u_char endmarker[2] = {0xFF, 0xFB}; - int cc, i, gotsome = 0; - - 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); - } - tidsp_bytes[33] = 0; - for (;;) { - cc = fread(libgsm_bytes, 1, 33, inf); - if (cc < 33) - break; - if ((libgsm_bytes[0] & 0xF0) != 0xD0) { -invalid: fprintf(stderr, "error: %s is not in libgsm format\n", - argv[1]); - exit(1); - } - gsm0610_libgsm_to_tidsp(libgsm_bytes, tidsp_bytes); - for (i = 0; i < 34; i += 2) { - arm_bytes[i] = tidsp_bytes[i+1]; - arm_bytes[i+1] = tidsp_bytes[i]; - } - fwrite(header_bytes, 1, 6, outf); - fwrite(arm_bytes, 1, 34, outf); - gotsome = 1; - } - fwrite(endmarker, 1, 2, outf); - fclose(outf); - if (cc) { - if (gotsome) - fprintf(stderr, - "warning: extra non-33 bytes at the end of %s\n", - argv[1]); - else - goto invalid; - } - exit(0); -}
--- a/miscutil/fc-tch2fr.c Tue Dec 13 03:24:36 2022 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,94 +0,0 @@ -/* - * 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); -}
--- a/miscutil/fc-vm2hex.c Tue Dec 13 03:24:36 2022 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,86 +0,0 @@ -/* - * This utility converts the old-fashioned (non-AMR) voice memo files - * read out of FFS into hex strings that can be analyzed by a human - * or further fed to fc-tch2fr. - */ - -#include <sys/types.h> -#include <stdio.h> -#include <stdlib.h> - -char *infname; -FILE *inf, *outf; - -static unsigned -get_word() -{ - u_char b[2]; - int i, c; - - for (i = 0; i < 2; i++) { - c = getc(inf); - if (c < 0) { - fprintf(stderr, "error: premature EOF in %s\n", - infname); - exit(1); - } - b[i] = c; - } - return((b[1] << 8) | b[0]); -} - -convert_speech_sample() -{ - u_char bytes[34]; - int i, dp; - unsigned word; - - dp = 0; - for (i = 0; i < 17; i++) { - word = get_word(); - bytes[dp++] = word >> 8; - bytes[dp++] = word; - } - for (i = 0; i < 33; i++) - fprintf(outf, "%02X", bytes[i]); -} - -main(argc, argv) - char **argv; -{ - unsigned first_word; - - if (argc < 2 || argc > 3) { - fprintf(stderr, "usage: %s infile [outfile]\n", argv[0]); - exit(1); - } - infname = argv[1]; - inf = fopen(infname, "r"); - if (!inf) { - perror(infname); - exit(1); - } - if (argc > 2) { - outf = fopen(argv[2], "w"); - if (!outf) { - perror(argv[2]); - exit(1); - } - } else - outf = stdout; - - for (;;) { - first_word = get_word(); - if (first_word == 0xFBFF) /* SC_VM_END_MASK */ - break; - fprintf(outf, "%04X", first_word); - if (first_word & 0x8000) { /* B_VM_SPEECH */ - fprintf(outf, " %04X", get_word()); - fprintf(outf, " %04X", get_word()); - putc(' ', outf); - convert_speech_sample(); - } - putc('\n', outf); - } - exit(0); -}
--- a/miscutil/gsm0610.c Tue Dec 13 03:24:36 2022 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,329 +0,0 @@ -/* - * This code (lifted from OsmocomBB) facilitates the conversion of 33-byte - * GSM 06.10 encoded speech frames between the bit order at the 06.10 interface - * in the de facto standard libgsm implementation and the bit order at the - * 05.03 channel encoder interface, as realized in TI's Calypso DSP. - */ - -#include <sys/types.h> -#include <string.h> -#include <strings.h> - -/* GSM FR - subjective importance bit ordering */ - /* This array encodes GSM 05.03 Table 2. - * It's also GSM 06.10 Table A.2.1a - * - * It converts between serial parameter output by the encoder and the - * order needed before channel encoding. - */ -const u_short gsm0610_bitorder[260] = { - 0, /* LARc0:5 */ - 47, /* Xmaxc0:5 */ - 103, /* Xmaxc1:5 */ - 159, /* Xmaxc2:5 */ - 215, /* Xmaxc3:5 */ - 1, /* LARc0:4 */ - 6, /* LARc1:5 */ - 12, /* LARc2:4 */ - 2, /* LARc0:3 */ - 7, /* LARc1:4 */ - 13, /* LARc2:3 */ - 17, /* LARc3:4 */ - 36, /* Nc0:6 */ - 92, /* Nc1:6 */ - 148, /* Nc2:6 */ - 204, /* Nc3:6 */ - 48, /* Xmaxc0:4 */ - 104, /* Xmaxc1:4 */ - 160, /* Xmaxc2:4 */ - 216, /* Xmaxc3:4 */ - 8, /* LARc1:3 */ - 22, /* LARc4:3 */ - 26, /* LARc5:3 */ - 37, /* Nc0:5 */ - 93, /* Nc1:5 */ - 149, /* Nc2:5 */ - 205, /* Nc3:5 */ - 38, /* Nc0:4 */ - 94, /* Nc1:4 */ - 150, /* Nc2:4 */ - 206, /* Nc3:4 */ - 39, /* Nc0:3 */ - 95, /* Nc1:3 */ - 151, /* Nc2:3 */ - 207, /* Nc3:3 */ - 40, /* Nc0:2 */ - 96, /* Nc1:2 */ - 152, /* Nc2:2 */ - 208, /* Nc3:2 */ - 49, /* Xmaxc0:3 */ - 105, /* Xmaxc1:3 */ - 161, /* Xmaxc2:3 */ - 217, /* Xmaxc3:3 */ - 3, /* LARc0:2 */ - 18, /* LARc3:3 */ - 30, /* LARc6:2 */ - 41, /* Nc0:1 */ - 97, /* Nc1:1 */ - 153, /* Nc2:1 */ - 209, /* Nc3:1 */ - 23, /* LARc4:2 */ - 27, /* LARc5:2 */ - 43, /* bc0:1 */ - 99, /* bc1:1 */ - 155, /* bc2:1 */ - 211, /* bc3:1 */ - 42, /* Nc0:0 */ - 98, /* Nc1:0 */ - 154, /* Nc2:0 */ - 210, /* Nc3:0 */ - 45, /* Mc0:1 */ - 101, /* Mc1:1 */ - 157, /* Mc2:1 */ - 213, /* Mc3:1 */ - 4, /* LARc0:1 */ - 9, /* LARc1:2 */ - 14, /* LARc2:2 */ - 33, /* LARc7:2 */ - 19, /* LARc3:2 */ - 24, /* LARc4:1 */ - 31, /* LARc6:1 */ - 44, /* bc0:0 */ - 100, /* bc1:0 */ - 156, /* bc2:0 */ - 212, /* bc3:0 */ - 50, /* Xmaxc0:2 */ - 106, /* Xmaxc1:2 */ - 162, /* Xmaxc2:2 */ - 218, /* Xmaxc3:2 */ - 53, /* xmc0_0:2 */ - 56, /* xmc0_1:2 */ - 59, /* xmc0_2:2 */ - 62, /* xmc0_3:2 */ - 65, /* xmc0_4:2 */ - 68, /* xmc0_5:2 */ - 71, /* xmc0_6:2 */ - 74, /* xmc0_7:2 */ - 77, /* xmc0_8:2 */ - 80, /* xmc0_9:2 */ - 83, /* xmc0_10:2 */ - 86, /* xmc0_11:2 */ - 89, /* xmc0_12:2 */ - 109, /* xmc1_0:2 */ - 112, /* xmc1_1:2 */ - 115, /* xmc1_2:2 */ - 118, /* xmc1_3:2 */ - 121, /* xmc1_4:2 */ - 124, /* xmc1_5:2 */ - 127, /* xmc1_6:2 */ - 130, /* xmc1_7:2 */ - 133, /* xmc1_8:2 */ - 136, /* xmc1_9:2 */ - 139, /* xmc1_10:2 */ - 142, /* xmc1_11:2 */ - 145, /* xmc1_12:2 */ - 165, /* xmc2_0:2 */ - 168, /* xmc2_1:2 */ - 171, /* xmc2_2:2 */ - 174, /* xmc2_3:2 */ - 177, /* xmc2_4:2 */ - 180, /* xmc2_5:2 */ - 183, /* xmc2_6:2 */ - 186, /* xmc2_7:2 */ - 189, /* xmc2_8:2 */ - 192, /* xmc2_9:2 */ - 195, /* xmc2_10:2 */ - 198, /* xmc2_11:2 */ - 201, /* xmc2_12:2 */ - 221, /* xmc3_0:2 */ - 224, /* xmc3_1:2 */ - 227, /* xmc3_2:2 */ - 230, /* xmc3_3:2 */ - 233, /* xmc3_4:2 */ - 236, /* xmc3_5:2 */ - 239, /* xmc3_6:2 */ - 242, /* xmc3_7:2 */ - 245, /* xmc3_8:2 */ - 248, /* xmc3_9:2 */ - 251, /* xmc3_10:2 */ - 254, /* xmc3_11:2 */ - 257, /* xmc3_12:2 */ - 46, /* Mc0:0 */ - 102, /* Mc1:0 */ - 158, /* Mc2:0 */ - 214, /* Mc3:0 */ - 51, /* Xmaxc0:1 */ - 107, /* Xmaxc1:1 */ - 163, /* Xmaxc2:1 */ - 219, /* Xmaxc3:1 */ - 54, /* xmc0_0:1 */ - 57, /* xmc0_1:1 */ - 60, /* xmc0_2:1 */ - 63, /* xmc0_3:1 */ - 66, /* xmc0_4:1 */ - 69, /* xmc0_5:1 */ - 72, /* xmc0_6:1 */ - 75, /* xmc0_7:1 */ - 78, /* xmc0_8:1 */ - 81, /* xmc0_9:1 */ - 84, /* xmc0_10:1 */ - 87, /* xmc0_11:1 */ - 90, /* xmc0_12:1 */ - 110, /* xmc1_0:1 */ - 113, /* xmc1_1:1 */ - 116, /* xmc1_2:1 */ - 119, /* xmc1_3:1 */ - 122, /* xmc1_4:1 */ - 125, /* xmc1_5:1 */ - 128, /* xmc1_6:1 */ - 131, /* xmc1_7:1 */ - 134, /* xmc1_8:1 */ - 137, /* xmc1_9:1 */ - 140, /* xmc1_10:1 */ - 143, /* xmc1_11:1 */ - 146, /* xmc1_12:1 */ - 166, /* xmc2_0:1 */ - 169, /* xmc2_1:1 */ - 172, /* xmc2_2:1 */ - 175, /* xmc2_3:1 */ - 178, /* xmc2_4:1 */ - 181, /* xmc2_5:1 */ - 184, /* xmc2_6:1 */ - 187, /* xmc2_7:1 */ - 190, /* xmc2_8:1 */ - 193, /* xmc2_9:1 */ - 196, /* xmc2_10:1 */ - 199, /* xmc2_11:1 */ - 202, /* xmc2_12:1 */ - 222, /* xmc3_0:1 */ - 225, /* xmc3_1:1 */ - 228, /* xmc3_2:1 */ - 231, /* xmc3_3:1 */ - 234, /* xmc3_4:1 */ - 237, /* xmc3_5:1 */ - 240, /* xmc3_6:1 */ - 243, /* xmc3_7:1 */ - 246, /* xmc3_8:1 */ - 249, /* xmc3_9:1 */ - 252, /* xmc3_10:1 */ - 255, /* xmc3_11:1 */ - 258, /* xmc3_12:1 */ - 5, /* LARc0:0 */ - 10, /* LARc1:1 */ - 15, /* LARc2:1 */ - 28, /* LARc5:1 */ - 32, /* LARc6:0 */ - 34, /* LARc7:1 */ - 35, /* LARc7:0 */ - 16, /* LARc2:0 */ - 20, /* LARc3:1 */ - 21, /* LARc3:0 */ - 25, /* LARc4:0 */ - 52, /* Xmaxc0:0 */ - 108, /* Xmaxc1:0 */ - 164, /* Xmaxc2:0 */ - 220, /* Xmaxc3:0 */ - 55, /* xmc0_0:0 */ - 58, /* xmc0_1:0 */ - 61, /* xmc0_2:0 */ - 64, /* xmc0_3:0 */ - 67, /* xmc0_4:0 */ - 70, /* xmc0_5:0 */ - 73, /* xmc0_6:0 */ - 76, /* xmc0_7:0 */ - 79, /* xmc0_8:0 */ - 82, /* xmc0_9:0 */ - 85, /* xmc0_10:0 */ - 88, /* xmc0_11:0 */ - 91, /* xmc0_12:0 */ - 111, /* xmc1_0:0 */ - 114, /* xmc1_1:0 */ - 117, /* xmc1_2:0 */ - 120, /* xmc1_3:0 */ - 123, /* xmc1_4:0 */ - 126, /* xmc1_5:0 */ - 129, /* xmc1_6:0 */ - 132, /* xmc1_7:0 */ - 135, /* xmc1_8:0 */ - 138, /* xmc1_9:0 */ - 141, /* xmc1_10:0 */ - 144, /* xmc1_11:0 */ - 147, /* xmc1_12:0 */ - 167, /* xmc2_0:0 */ - 170, /* xmc2_1:0 */ - 173, /* xmc2_2:0 */ - 176, /* xmc2_3:0 */ - 179, /* xmc2_4:0 */ - 182, /* xmc2_5:0 */ - 185, /* xmc2_6:0 */ - 188, /* xmc2_7:0 */ - 191, /* xmc2_8:0 */ - 194, /* xmc2_9:0 */ - 197, /* xmc2_10:0 */ - 200, /* xmc2_11:0 */ - 203, /* xmc2_12:0 */ - 223, /* xmc3_0:0 */ - 226, /* xmc3_1:0 */ - 229, /* xmc3_2:0 */ - 232, /* xmc3_3:0 */ - 235, /* xmc3_4:0 */ - 238, /* xmc3_5:0 */ - 241, /* xmc3_6:0 */ - 244, /* xmc3_7:0 */ - 247, /* xmc3_8:0 */ - 250, /* xmc3_9:0 */ - 253, /* xmc3_10:0 */ - 256, /* xmc3_11:0 */ - 259, /* xmc3_12:0 */ - 11, /* LARc1:0 */ - 29, /* LARc5:0 */ -}; - -static int -msb_get_bit(buf, bn) - u_char *buf; -{ - int pos_byte = bn >> 3; - int pos_bit = 7 - (bn & 7); - - return (buf[pos_byte] >> pos_bit) & 1; -} - -static void -msb_set_bit(buf, bn, bit) - u_char *buf; -{ - int pos_byte = bn >> 3; - int pos_bit = 7 - (bn & 7); - - buf[pos_byte] |= (bit << pos_bit); -} - -void -gsm0610_tidsp_to_libgsm(inbytes, outbytes) - u_char *inbytes, *outbytes; -{ - int i, di, si; - - bzero(outbytes, 33); - outbytes[0] = 0xD0; - for (i = 0; i < 260; i++) { - di = gsm0610_bitorder[i]; - si = (i > 181) ? i + 4 : i; - msb_set_bit(outbytes, 4 + di, msb_get_bit(inbytes, si)); - } -} - -void -gsm0610_libgsm_to_tidsp(inbytes, outbytes) - u_char *inbytes, *outbytes; -{ - int i, di, si; - - bzero(outbytes, 33); - for (i = 0; i < 260; i++) { - si = gsm0610_bitorder[i]; - di = (i > 181) ? i + 4 : i; - msb_set_bit(outbytes, di, msb_get_bit(inbytes, 4 + si)); - } -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tchtools/Makefile Wed Dec 28 07:52:30 2022 +0000 @@ -0,0 +1,32 @@ +CC= gcc +CFLAGS= -O2 +PROGS= fc-fr2tch fc-gsm2vm fc-tch2fr fc-vm2hex + +INSTALL_PREFIX= /opt/freecalypso + +INSTBIN=${INSTALL_PREFIX}/bin + +all: ${PROGS} + +FR2TCH_OBJS= fc-fr2tch.o gsm0610.o +GSM2VM_OBJS= fc-gsm2vm.o gsm0610.o +TCH2FR_OBJS= fc-tch2fr.o gsm0610.o + +fc-fr2tch: ${FR2TCH_OBJS} + ${CC} ${CFLAGS} -o $@ ${FR2TCH_OBJS} + +fc-gsm2vm: ${GSM2VM_OBJS} + ${CC} ${CFLAGS} -o $@ ${GSM2VM_OBJS} + +fc-tch2fr: ${TCH2FR_OBJS} + ${CC} ${CFLAGS} -o $@ ${TCH2FR_OBJS} + +fc-vm2hex: fc-vm2hex.c + ${CC} ${CFLAGS} -o $@ $@.c + +install: + mkdir -p ${INSTBIN} + install -c ${PROGS} ${INSTBIN} + +clean: + rm -f ${PROGS} *.o *errs *.out
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tchtools/fc-fr2tch.c Wed Dec 28 07:52:30 2022 +0000 @@ -0,0 +1,59 @@ +/* + * This utility converts a GSM 06.10 speech recording from the format that is + * commonly accepted as standard in the Unix/Linux world (libgsm format) into + * hex strings of TCH bits to be fed to the GSM 05.03 channel encoder by way + * of a TI Calypso GSM device, a FreeCalypso GSM firmware version with the + * TCH rerouting feature, and fc-shell's tch play command. + */ + +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> + +main(argc, argv) + char **argv; +{ + FILE *inf, *outf; + u_char libgsm_bytes[33], tidsp_bytes[33]; + int cc, i, gotsome = 0; + + 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 (;;) { + cc = fread(libgsm_bytes, 1, 33, inf); + if (cc < 33) + break; + if ((libgsm_bytes[0] & 0xF0) != 0xD0) { +invalid: fprintf(stderr, "error: %s is not in libgsm format\n", + argv[1]); + exit(1); + } + gsm0610_libgsm_to_tidsp(libgsm_bytes, tidsp_bytes); + for (i = 0; i < 33; i++) + fprintf(outf, "%02X", tidsp_bytes[i]); + putc('\n', outf); + gotsome = 1; + } + fclose(outf); + if (cc) { + if (gotsome) + fprintf(stderr, + "warning: extra non-33 bytes at the end of %s\n", + argv[1]); + else + goto invalid; + } + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tchtools/fc-gsm2vm.c Wed Dec 28 07:52:30 2022 +0000 @@ -0,0 +1,66 @@ +/* + * This utility converts a GSM 06.10 speech recording from the format that is + * commonly accepted as standard in the Unix/Linux world (libgsm format) into + * a voice memo file that can be uploaded into the FFS of a FreeCalypso device + * and played with the audio_vm_play_start() API or the AT@VMP command that + * invokes the latter. + */ + +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> + +main(argc, argv) + char **argv; +{ + FILE *inf, *outf; + u_char libgsm_bytes[33], tidsp_bytes[34], arm_bytes[34]; + static u_char header_bytes[6] = {0x00, 0xC4, 0x00, 0x00, 0x00, 0x00}; + static u_char endmarker[2] = {0xFF, 0xFB}; + int cc, i, gotsome = 0; + + 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); + } + tidsp_bytes[33] = 0; + for (;;) { + cc = fread(libgsm_bytes, 1, 33, inf); + if (cc < 33) + break; + if ((libgsm_bytes[0] & 0xF0) != 0xD0) { +invalid: fprintf(stderr, "error: %s is not in libgsm format\n", + argv[1]); + exit(1); + } + gsm0610_libgsm_to_tidsp(libgsm_bytes, tidsp_bytes); + for (i = 0; i < 34; i += 2) { + arm_bytes[i] = tidsp_bytes[i+1]; + arm_bytes[i+1] = tidsp_bytes[i]; + } + fwrite(header_bytes, 1, 6, outf); + fwrite(arm_bytes, 1, 34, outf); + gotsome = 1; + } + fwrite(endmarker, 1, 2, outf); + fclose(outf); + if (cc) { + if (gotsome) + fprintf(stderr, + "warning: extra non-33 bytes at the end of %s\n", + argv[1]); + else + goto invalid; + } + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tchtools/fc-tch2fr.c Wed Dec 28 07:52:30 2022 +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); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tchtools/fc-vm2hex.c Wed Dec 28 07:52:30 2022 +0000 @@ -0,0 +1,86 @@ +/* + * This utility converts the old-fashioned (non-AMR) voice memo files + * read out of FFS into hex strings that can be analyzed by a human + * or further fed to fc-tch2fr. + */ + +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> + +char *infname; +FILE *inf, *outf; + +static unsigned +get_word() +{ + u_char b[2]; + int i, c; + + for (i = 0; i < 2; i++) { + c = getc(inf); + if (c < 0) { + fprintf(stderr, "error: premature EOF in %s\n", + infname); + exit(1); + } + b[i] = c; + } + return((b[1] << 8) | b[0]); +} + +convert_speech_sample() +{ + u_char bytes[34]; + int i, dp; + unsigned word; + + dp = 0; + for (i = 0; i < 17; i++) { + word = get_word(); + bytes[dp++] = word >> 8; + bytes[dp++] = word; + } + for (i = 0; i < 33; i++) + fprintf(outf, "%02X", bytes[i]); +} + +main(argc, argv) + char **argv; +{ + unsigned first_word; + + if (argc < 2 || argc > 3) { + fprintf(stderr, "usage: %s infile [outfile]\n", argv[0]); + exit(1); + } + infname = argv[1]; + inf = fopen(infname, "r"); + if (!inf) { + perror(infname); + exit(1); + } + if (argc > 2) { + outf = fopen(argv[2], "w"); + if (!outf) { + perror(argv[2]); + exit(1); + } + } else + outf = stdout; + + for (;;) { + first_word = get_word(); + if (first_word == 0xFBFF) /* SC_VM_END_MASK */ + break; + fprintf(outf, "%04X", first_word); + if (first_word & 0x8000) { /* B_VM_SPEECH */ + fprintf(outf, " %04X", get_word()); + fprintf(outf, " %04X", get_word()); + putc(' ', outf); + convert_speech_sample(); + } + putc('\n', outf); + } + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tchtools/gsm0610.c Wed Dec 28 07:52:30 2022 +0000 @@ -0,0 +1,329 @@ +/* + * This code (lifted from OsmocomBB) facilitates the conversion of 33-byte + * GSM 06.10 encoded speech frames between the bit order at the 06.10 interface + * in the de facto standard libgsm implementation and the bit order at the + * 05.03 channel encoder interface, as realized in TI's Calypso DSP. + */ + +#include <sys/types.h> +#include <string.h> +#include <strings.h> + +/* GSM FR - subjective importance bit ordering */ + /* This array encodes GSM 05.03 Table 2. + * It's also GSM 06.10 Table A.2.1a + * + * It converts between serial parameter output by the encoder and the + * order needed before channel encoding. + */ +const u_short gsm0610_bitorder[260] = { + 0, /* LARc0:5 */ + 47, /* Xmaxc0:5 */ + 103, /* Xmaxc1:5 */ + 159, /* Xmaxc2:5 */ + 215, /* Xmaxc3:5 */ + 1, /* LARc0:4 */ + 6, /* LARc1:5 */ + 12, /* LARc2:4 */ + 2, /* LARc0:3 */ + 7, /* LARc1:4 */ + 13, /* LARc2:3 */ + 17, /* LARc3:4 */ + 36, /* Nc0:6 */ + 92, /* Nc1:6 */ + 148, /* Nc2:6 */ + 204, /* Nc3:6 */ + 48, /* Xmaxc0:4 */ + 104, /* Xmaxc1:4 */ + 160, /* Xmaxc2:4 */ + 216, /* Xmaxc3:4 */ + 8, /* LARc1:3 */ + 22, /* LARc4:3 */ + 26, /* LARc5:3 */ + 37, /* Nc0:5 */ + 93, /* Nc1:5 */ + 149, /* Nc2:5 */ + 205, /* Nc3:5 */ + 38, /* Nc0:4 */ + 94, /* Nc1:4 */ + 150, /* Nc2:4 */ + 206, /* Nc3:4 */ + 39, /* Nc0:3 */ + 95, /* Nc1:3 */ + 151, /* Nc2:3 */ + 207, /* Nc3:3 */ + 40, /* Nc0:2 */ + 96, /* Nc1:2 */ + 152, /* Nc2:2 */ + 208, /* Nc3:2 */ + 49, /* Xmaxc0:3 */ + 105, /* Xmaxc1:3 */ + 161, /* Xmaxc2:3 */ + 217, /* Xmaxc3:3 */ + 3, /* LARc0:2 */ + 18, /* LARc3:3 */ + 30, /* LARc6:2 */ + 41, /* Nc0:1 */ + 97, /* Nc1:1 */ + 153, /* Nc2:1 */ + 209, /* Nc3:1 */ + 23, /* LARc4:2 */ + 27, /* LARc5:2 */ + 43, /* bc0:1 */ + 99, /* bc1:1 */ + 155, /* bc2:1 */ + 211, /* bc3:1 */ + 42, /* Nc0:0 */ + 98, /* Nc1:0 */ + 154, /* Nc2:0 */ + 210, /* Nc3:0 */ + 45, /* Mc0:1 */ + 101, /* Mc1:1 */ + 157, /* Mc2:1 */ + 213, /* Mc3:1 */ + 4, /* LARc0:1 */ + 9, /* LARc1:2 */ + 14, /* LARc2:2 */ + 33, /* LARc7:2 */ + 19, /* LARc3:2 */ + 24, /* LARc4:1 */ + 31, /* LARc6:1 */ + 44, /* bc0:0 */ + 100, /* bc1:0 */ + 156, /* bc2:0 */ + 212, /* bc3:0 */ + 50, /* Xmaxc0:2 */ + 106, /* Xmaxc1:2 */ + 162, /* Xmaxc2:2 */ + 218, /* Xmaxc3:2 */ + 53, /* xmc0_0:2 */ + 56, /* xmc0_1:2 */ + 59, /* xmc0_2:2 */ + 62, /* xmc0_3:2 */ + 65, /* xmc0_4:2 */ + 68, /* xmc0_5:2 */ + 71, /* xmc0_6:2 */ + 74, /* xmc0_7:2 */ + 77, /* xmc0_8:2 */ + 80, /* xmc0_9:2 */ + 83, /* xmc0_10:2 */ + 86, /* xmc0_11:2 */ + 89, /* xmc0_12:2 */ + 109, /* xmc1_0:2 */ + 112, /* xmc1_1:2 */ + 115, /* xmc1_2:2 */ + 118, /* xmc1_3:2 */ + 121, /* xmc1_4:2 */ + 124, /* xmc1_5:2 */ + 127, /* xmc1_6:2 */ + 130, /* xmc1_7:2 */ + 133, /* xmc1_8:2 */ + 136, /* xmc1_9:2 */ + 139, /* xmc1_10:2 */ + 142, /* xmc1_11:2 */ + 145, /* xmc1_12:2 */ + 165, /* xmc2_0:2 */ + 168, /* xmc2_1:2 */ + 171, /* xmc2_2:2 */ + 174, /* xmc2_3:2 */ + 177, /* xmc2_4:2 */ + 180, /* xmc2_5:2 */ + 183, /* xmc2_6:2 */ + 186, /* xmc2_7:2 */ + 189, /* xmc2_8:2 */ + 192, /* xmc2_9:2 */ + 195, /* xmc2_10:2 */ + 198, /* xmc2_11:2 */ + 201, /* xmc2_12:2 */ + 221, /* xmc3_0:2 */ + 224, /* xmc3_1:2 */ + 227, /* xmc3_2:2 */ + 230, /* xmc3_3:2 */ + 233, /* xmc3_4:2 */ + 236, /* xmc3_5:2 */ + 239, /* xmc3_6:2 */ + 242, /* xmc3_7:2 */ + 245, /* xmc3_8:2 */ + 248, /* xmc3_9:2 */ + 251, /* xmc3_10:2 */ + 254, /* xmc3_11:2 */ + 257, /* xmc3_12:2 */ + 46, /* Mc0:0 */ + 102, /* Mc1:0 */ + 158, /* Mc2:0 */ + 214, /* Mc3:0 */ + 51, /* Xmaxc0:1 */ + 107, /* Xmaxc1:1 */ + 163, /* Xmaxc2:1 */ + 219, /* Xmaxc3:1 */ + 54, /* xmc0_0:1 */ + 57, /* xmc0_1:1 */ + 60, /* xmc0_2:1 */ + 63, /* xmc0_3:1 */ + 66, /* xmc0_4:1 */ + 69, /* xmc0_5:1 */ + 72, /* xmc0_6:1 */ + 75, /* xmc0_7:1 */ + 78, /* xmc0_8:1 */ + 81, /* xmc0_9:1 */ + 84, /* xmc0_10:1 */ + 87, /* xmc0_11:1 */ + 90, /* xmc0_12:1 */ + 110, /* xmc1_0:1 */ + 113, /* xmc1_1:1 */ + 116, /* xmc1_2:1 */ + 119, /* xmc1_3:1 */ + 122, /* xmc1_4:1 */ + 125, /* xmc1_5:1 */ + 128, /* xmc1_6:1 */ + 131, /* xmc1_7:1 */ + 134, /* xmc1_8:1 */ + 137, /* xmc1_9:1 */ + 140, /* xmc1_10:1 */ + 143, /* xmc1_11:1 */ + 146, /* xmc1_12:1 */ + 166, /* xmc2_0:1 */ + 169, /* xmc2_1:1 */ + 172, /* xmc2_2:1 */ + 175, /* xmc2_3:1 */ + 178, /* xmc2_4:1 */ + 181, /* xmc2_5:1 */ + 184, /* xmc2_6:1 */ + 187, /* xmc2_7:1 */ + 190, /* xmc2_8:1 */ + 193, /* xmc2_9:1 */ + 196, /* xmc2_10:1 */ + 199, /* xmc2_11:1 */ + 202, /* xmc2_12:1 */ + 222, /* xmc3_0:1 */ + 225, /* xmc3_1:1 */ + 228, /* xmc3_2:1 */ + 231, /* xmc3_3:1 */ + 234, /* xmc3_4:1 */ + 237, /* xmc3_5:1 */ + 240, /* xmc3_6:1 */ + 243, /* xmc3_7:1 */ + 246, /* xmc3_8:1 */ + 249, /* xmc3_9:1 */ + 252, /* xmc3_10:1 */ + 255, /* xmc3_11:1 */ + 258, /* xmc3_12:1 */ + 5, /* LARc0:0 */ + 10, /* LARc1:1 */ + 15, /* LARc2:1 */ + 28, /* LARc5:1 */ + 32, /* LARc6:0 */ + 34, /* LARc7:1 */ + 35, /* LARc7:0 */ + 16, /* LARc2:0 */ + 20, /* LARc3:1 */ + 21, /* LARc3:0 */ + 25, /* LARc4:0 */ + 52, /* Xmaxc0:0 */ + 108, /* Xmaxc1:0 */ + 164, /* Xmaxc2:0 */ + 220, /* Xmaxc3:0 */ + 55, /* xmc0_0:0 */ + 58, /* xmc0_1:0 */ + 61, /* xmc0_2:0 */ + 64, /* xmc0_3:0 */ + 67, /* xmc0_4:0 */ + 70, /* xmc0_5:0 */ + 73, /* xmc0_6:0 */ + 76, /* xmc0_7:0 */ + 79, /* xmc0_8:0 */ + 82, /* xmc0_9:0 */ + 85, /* xmc0_10:0 */ + 88, /* xmc0_11:0 */ + 91, /* xmc0_12:0 */ + 111, /* xmc1_0:0 */ + 114, /* xmc1_1:0 */ + 117, /* xmc1_2:0 */ + 120, /* xmc1_3:0 */ + 123, /* xmc1_4:0 */ + 126, /* xmc1_5:0 */ + 129, /* xmc1_6:0 */ + 132, /* xmc1_7:0 */ + 135, /* xmc1_8:0 */ + 138, /* xmc1_9:0 */ + 141, /* xmc1_10:0 */ + 144, /* xmc1_11:0 */ + 147, /* xmc1_12:0 */ + 167, /* xmc2_0:0 */ + 170, /* xmc2_1:0 */ + 173, /* xmc2_2:0 */ + 176, /* xmc2_3:0 */ + 179, /* xmc2_4:0 */ + 182, /* xmc2_5:0 */ + 185, /* xmc2_6:0 */ + 188, /* xmc2_7:0 */ + 191, /* xmc2_8:0 */ + 194, /* xmc2_9:0 */ + 197, /* xmc2_10:0 */ + 200, /* xmc2_11:0 */ + 203, /* xmc2_12:0 */ + 223, /* xmc3_0:0 */ + 226, /* xmc3_1:0 */ + 229, /* xmc3_2:0 */ + 232, /* xmc3_3:0 */ + 235, /* xmc3_4:0 */ + 238, /* xmc3_5:0 */ + 241, /* xmc3_6:0 */ + 244, /* xmc3_7:0 */ + 247, /* xmc3_8:0 */ + 250, /* xmc3_9:0 */ + 253, /* xmc3_10:0 */ + 256, /* xmc3_11:0 */ + 259, /* xmc3_12:0 */ + 11, /* LARc1:0 */ + 29, /* LARc5:0 */ +}; + +static int +msb_get_bit(buf, bn) + u_char *buf; +{ + int pos_byte = bn >> 3; + int pos_bit = 7 - (bn & 7); + + return (buf[pos_byte] >> pos_bit) & 1; +} + +static void +msb_set_bit(buf, bn, bit) + u_char *buf; +{ + int pos_byte = bn >> 3; + int pos_bit = 7 - (bn & 7); + + buf[pos_byte] |= (bit << pos_bit); +} + +void +gsm0610_tidsp_to_libgsm(inbytes, outbytes) + u_char *inbytes, *outbytes; +{ + int i, di, si; + + bzero(outbytes, 33); + outbytes[0] = 0xD0; + for (i = 0; i < 260; i++) { + di = gsm0610_bitorder[i]; + si = (i > 181) ? i + 4 : i; + msb_set_bit(outbytes, 4 + di, msb_get_bit(inbytes, si)); + } +} + +void +gsm0610_libgsm_to_tidsp(inbytes, outbytes) + u_char *inbytes, *outbytes; +{ + int i, di, si; + + bzero(outbytes, 33); + for (i = 0; i < 260; i++) { + si = gsm0610_bitorder[i]; + di = (i > 181) ? i + 4 : i; + msb_set_bit(outbytes, di, msb_get_bit(inbytes, 4 + si)); + } +}