FreeCalypso > hg > gsm-codec-lib
comparison amrconv/tw5c-dump.c @ 593:fd6a394ab4cd
amrconv: new program tw5c-dump
| author | Mychaela Falconia <falcon@freecalypso.org> |
|---|---|
| date | Tue, 18 Nov 2025 07:34:23 +0000 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 592:24aba0e7aa35 | 593:fd6a394ab4cd |
|---|---|
| 1 /* | |
| 2 * This program reads a TW-TS-005 Annex C hexadecimal file | |
| 3 * and dumps all frames in human-readable form. | |
| 4 */ | |
| 5 | |
| 6 #include <stdio.h> | |
| 7 #include <stdint.h> | |
| 8 #include <stdlib.h> | |
| 9 #include <string.h> | |
| 10 #include <strings.h> | |
| 11 #include <unistd.h> | |
| 12 #include "../libtest/tw5reader.h" | |
| 13 #include "amr_defs.h" | |
| 14 | |
| 15 extern char *amr_mode_names[16]; | |
| 16 extern const uint8_t pl_total_bytes_oa[9], pl_total_bytes_bwe[9]; | |
| 17 | |
| 18 static char *infname; | |
| 19 static int is_bwe; | |
| 20 | |
| 21 static void | |
| 22 process_cmdline(argc, argv) | |
| 23 char **argv; | |
| 24 { | |
| 25 int opt; | |
| 26 extern int optind; | |
| 27 | |
| 28 while ((opt = getopt(argc, argv, "b")) != EOF) { | |
| 29 switch (opt) { | |
| 30 case 'b': | |
| 31 is_bwe = 1; | |
| 32 continue; | |
| 33 default: | |
| 34 usage: | |
| 35 fprintf(stderr, "usage: %s [-b] hex-file\n", argv[0]); | |
| 36 exit(1); | |
| 37 } | |
| 38 } | |
| 39 if (argc != optind + 1) | |
| 40 goto usage; | |
| 41 infname = argv[optind]; | |
| 42 } | |
| 43 | |
| 44 static void | |
| 45 if1_bwe_to_oa(in, out, mode) | |
| 46 uint8_t *in, *out; | |
| 47 unsigned mode; | |
| 48 { | |
| 49 unsigned out_len, n; | |
| 50 | |
| 51 out_len = pl_total_bytes_oa[mode] - 2; | |
| 52 for (n = 0; n < out_len; n++) | |
| 53 out[n] = (in[n+1] << 2) | (in[n+2] >> 6); | |
| 54 } | |
| 55 | |
| 56 static void | |
| 57 process_file() | |
| 58 { | |
| 59 FILE *hexf; | |
| 60 unsigned lineno; | |
| 61 uint8_t frame[TWTS005_MAX_FRAME]; | |
| 62 unsigned frame_len, base_len, cmr, ft, q, sid_byte, sti, sid_mode; | |
| 63 const uint8_t *pl_len_table; | |
| 64 uint8_t frm_to_oa[MAX_IF1_BYTES]; | |
| 65 uint8_t ser_bits[MAX_SERIAL_SIZE]; | |
| 66 uint16_t params[MAX_PRM_SIZE]; | |
| 67 unsigned ptr; | |
| 68 int rc; | |
| 69 | |
| 70 hexf = fopen(infname, "r"); | |
| 71 if (!hexf) { | |
| 72 perror(infname); | |
| 73 exit(1); | |
| 74 } | |
| 75 lineno = 0; | |
| 76 for (;;) { | |
| 77 rc = twts005_read_frame(hexf, &lineno, frame, &frame_len); | |
| 78 if (rc < 0) { | |
| 79 fprintf(stderr, "%s line %u: not valid TW-TS-005\n", | |
| 80 infname, lineno); | |
| 81 exit(1); | |
| 82 } | |
| 83 if (!rc) | |
| 84 break; | |
| 85 if (frame_len == 0) { | |
| 86 printf("line %u: NULL frame\n", lineno); | |
| 87 continue; | |
| 88 } | |
| 89 if (frame_len < 2) { | |
| 90 inv_payload: fprintf(stderr, | |
| 91 "%s line %u: payload is not valid AMR %s\n", | |
| 92 infname, lineno, is_bwe ? "BWE" : "OA"); | |
| 93 exit(1); | |
| 94 } | |
| 95 cmr = frame[0] >> 4; | |
| 96 if (cmr > MR122 && cmr != MODE_NO_DATA) | |
| 97 goto inv_payload; | |
| 98 if (is_bwe) { | |
| 99 if (frame[0] & 0x08) | |
| 100 goto inv_payload; | |
| 101 ft = ((frame[0] & 0x07) << 1) | | |
| 102 ((frame[1] & 0x80) >> 7); | |
| 103 q = (frame[1] & 0x40) >> 6; | |
| 104 pl_len_table = pl_total_bytes_bwe; | |
| 105 } else { | |
| 106 if (frame[1] & 0x80) | |
| 107 goto inv_payload; | |
| 108 ft = (frame[1] & 0x78) >> 3; | |
| 109 q = (frame[1] & 0x04) >> 2; | |
| 110 pl_len_table = pl_total_bytes_oa; | |
| 111 } | |
| 112 if (ft <= MRDTX) | |
| 113 base_len = pl_len_table[ft]; | |
| 114 else if (ft == MODE_NO_DATA) | |
| 115 base_len = 2; | |
| 116 else | |
| 117 goto inv_payload; | |
| 118 if (frame_len < base_len) | |
| 119 goto inv_payload; | |
| 120 printf("line %u: CMR=%u (%s) FT=%u (%s) Q=%u\n", lineno, cmr, | |
| 121 amr_mode_names[cmr], ft, amr_mode_names[ft], q); | |
| 122 if (ft != MODE_NO_DATA) { | |
| 123 if (is_bwe) { | |
| 124 if1_bwe_to_oa(frame, frm_to_oa, ft); | |
| 125 amr_if1_unpack(frm_to_oa, ser_bits, ft); | |
| 126 } else { | |
| 127 amr_if1_unpack(frame + 2, ser_bits, ft); | |
| 128 } | |
| 129 reassemble_amr_params(ser_bits, params, ft); | |
| 130 dump_amr_params(params, ft); | |
| 131 } | |
| 132 if (ft == MRDTX) { | |
| 133 sid_byte = is_bwe ? frm_to_oa[4] : frame[6]; | |
| 134 sti = (sid_byte & 0x10) >> 4; | |
| 135 sid_mode = 0; | |
| 136 if (sid_byte & 0x08) | |
| 137 sid_mode |= 1; | |
| 138 if (sid_byte & 0x04) | |
| 139 sid_mode |= 2; | |
| 140 if (sid_byte & 0x02) | |
| 141 sid_mode |= 4; | |
| 142 printf(" SID_%s Mode=%u (%s)\n", | |
| 143 sti ? "UPDATE" : "FIRST", sid_mode, | |
| 144 amr_mode_names[sid_mode]); | |
| 145 } | |
| 146 if (is_bwe) | |
| 147 continue; | |
| 148 /* TW-TS-006 extensions */ | |
| 149 if (frame[0] & 0x08) | |
| 150 printf(" RIF=%u\n", (frame[0] & 0x04) >> 2); | |
| 151 ptr = base_len; | |
| 152 if ((ft == MODE_NO_DATA) && (frame[1] & 0x02)) { | |
| 153 fputs(" FT15 ext octet: ", stdout); | |
| 154 if (ptr >= frame_len) { | |
| 155 puts("indicated, but not present"); | |
| 156 continue; | |
| 157 } | |
| 158 /* repurpose sti and sid_mode vars */ | |
| 159 sti = (frame[ptr] & 0x80) >> 7; | |
| 160 sid_mode = frame[ptr] & 7; | |
| 161 printf("%s, Mode=%u (%s)\n", sti ? "Onset" : "No_Data", | |
| 162 sid_mode, amr_mode_names[sid_mode]); | |
| 163 ptr++; | |
| 164 } | |
| 165 if (frame[0] & 0x02) { | |
| 166 if (ptr >= frame_len) { | |
| 167 puts(" TA+DTXd+TFOE octet missing!"); | |
| 168 continue; | |
| 169 } | |
| 170 printf(" TA=%u DTXd=%u TFOE=%u\n", frame[ptr] >> 2, | |
| 171 (frame[ptr] & 0x02) >> 1, frame[ptr] & 0x01); | |
| 172 ptr++; | |
| 173 } | |
| 174 if (frame[0] & 0x01) | |
| 175 puts(" Rel4 Config_Prot present, not decoded"); | |
| 176 if ((ft == MODE_NO_DATA) && (frame[1] & 0x01)) | |
| 177 puts(" Rel5 GCF, not decoded"); | |
| 178 } | |
| 179 } | |
| 180 | |
| 181 main(argc, argv) | |
| 182 char **argv; | |
| 183 { | |
| 184 process_cmdline(argc, argv); | |
| 185 process_file(); | |
| 186 exit(0); | |
| 187 } |
