FreeCalypso > hg > freecalypso-reveng
diff hr-bits/sid-count.c @ 407:183e81c8f6c0
hr-bits: sid-count program written
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Mon, 22 Jul 2024 10:00:58 +0000 |
parents | |
children | 14302e075f37 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hr-bits/sid-count.c Mon Jul 22 10:00:58 2024 +0000 @@ -0,0 +1,181 @@ +/* + * This program reads a TCH/HS DL capture file made with FC tools + * and analyzes the hex string of payload bits in every frame. + * For each frame, this program counts how many bits in the SID field + * are set (both class 1 and class 2. All input lines are passed + * through to the output, but at the end of each line this program + * appends bit counts that match the conventions used in GSM 06.06 + * swSidDetection() function. + */ + +#include <ctype.h> +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> + +static const uint8_t class1_mask[12] = {0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, + 0x3F, 0xC0, 0x0F, 0x78, 0x0E, 0x06}; +static const uint8_t class2_mask[3] = {0x1F, 0xFF, 0xF0}; + +static char *infname, *outfname; +static FILE *inf, *outf; +static int lineno; +static char linebuf[80]; +static uint8_t frame[15]; + +static int +is_hex_string_spc(str, expect_len) + char *str; + unsigned expect_len; +{ + char *cp, *endp; + + endp = str + expect_len; + for (cp = str; cp < endp; cp++) { + if (!isxdigit(*cp)) + return 0; + } + if (*cp == ' ') + return 1; + else + return 0; +} + +static int +decode_hex_digit(c) +{ + int d; + + if (isdigit(c)) + d = c - '0'; + else if (isupper(c)) + d = c - 'A' + 10; + else + d = c - 'a' + 10; + return d; +} + +static void +frame_from_hex() +{ + char *cp; + uint8_t *dp; + unsigned n, u, l; + + cp = linebuf + 18; + dp = frame; + for (n = 0; n < 15; n++) { + u = decode_hex_digit(*cp++); + l = decode_hex_digit(*cp++); + *dp++ = (u << 4) | l; + } +} + +static unsigned +ones_in_byte(byte) + unsigned byte; +{ + unsigned count; + + count = 0; + for (; byte; byte >>= 1) { + if (byte & 1) + count++; + } + return count; +} + +static unsigned +count_1_bits(data, mask, nbytes) + uint8_t *data, *mask; + unsigned nbytes; +{ + unsigned n, and, accum; + + accum = 0; + for (n = 0; n < nbytes; n++) { + and = *data++ & *mask++; + accum += ones_in_byte(and); + } + return accum; +} + +static void +process_line() +{ + char *cp; + unsigned class1_ones, class1_zeros; + unsigned class2_ones, class2_zeros; + unsigned n1n2; + + cp = index(linebuf, '\n'); + if (!cp) { + fprintf(stderr, "%s line %d: too long or missing newline\n", + infname, lineno); + exit(1); + } + *cp = '\0'; + if (strncmp(linebuf, "HR ", 3)) { +inv: fprintf(stderr, + "%s line %d: format does not match HR DL capture\n", + infname, lineno); + exit(1); + } + if (!is_hex_string_spc(linebuf + 3, 4)) + goto inv; + if (!is_hex_string_spc(linebuf + 8, 4)) + goto inv; + if (!is_hex_string_spc(linebuf + 13, 4)) + goto inv; + if (!is_hex_string_spc(linebuf + 18, 30)) + goto inv; + frame_from_hex(); + + class1_ones = count_1_bits(frame, class1_mask, 12); + class1_zeros = 62 - class1_ones; + class2_ones = count_1_bits(frame + 12, class2_mask, 3); + class2_zeros = 17 - class2_ones; + n1n2 = class1_zeros + class2_zeros; + + fprintf(outf, "%s %u %u", linebuf, class1_zeros, n1n2); + if (n1n2 >= 11 && n1n2 < 16) + fputs(" SID-1-diff", outf); + if (n1n2 >= 16 && n1n2 <= 25) + fputs(" BCI-to-BFI", outf); + putc('\n', outf); +} + +main(argc, argv) + char **argv; +{ + if (argc >= 2) { + infname = argv[1]; + inf = fopen(infname, "r"); + if (!inf) { + perror(infname); + exit(1); + } + } else { + inf = stdin; + infname = "stdin"; + } + + if (argc >= 3) { + outfname = argv[2]; + outf = fopen(outfname, "w"); + if (!outf) { + perror(outfname); + exit(1); + } + } else { + outf = stdout; + outfname = "stdout"; + } + + for (lineno = 1; fgets(linebuf, sizeof linebuf, inf); lineno++) + process_line(); + + exit(0); +}