FreeCalypso > hg > freecalypso-tools
view ffstools/caltools/c1xx-calextr.c @ 760:e1c8c5bcb233
ARFCN conversion tools documented
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sat, 28 Nov 2020 00:32:41 +0000 |
parents | 7de38a7e1fa5 |
children |
line wrap: on
line source
/* * This program parses Compal's proprietary data structure that contains * the factory RF calibration values among other data, locates those RF * calibration records, extracts their essential content (Rx GMagic and * Tx APC values), converts this distilled content into TCS211 RF calibration * tables (Rx agcparams and Tx levels) and writes these tables out in either * FreeCalypso ASCII or FFS binary format. */ #include <sys/types.h> #include <sys/param.h> #include <sys/file.h> #include <string.h> #include <strings.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #define COMPAL_SECTOR_LENGTH 0x2000 u_char sector[COMPAL_SECTOR_LENGTH]; u_char endmarker[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; u_char record_magic[4] = {0xAA, 0x00, 0x00, 0x00}; char *ascii_output_dir, *bin_output_dir; struct rx_calchan_map { unsigned upper_bound; unsigned compal_start; unsigned compal_num; }; #define RF_RX_CAL_CHAN_SIZE 10 /* TI/FC canonical version */ struct rx_calchan_map rx_calchan_map_850[RF_RX_CAL_CHAN_SIZE] = { {140, 0, 2}, {152, 2, 2}, {164, 4, 2}, {176, 6, 2}, {188, 8, 2}, {200, 10, 2}, {212, 12, 2}, {224, 14, 2}, {236, 16, 2}, {251, 18, 3} }; struct rx_calchan_map rx_calchan_map_900[RF_RX_CAL_CHAN_SIZE] = { { 18, 0, 3}, { 36, 3, 3}, { 54, 6, 3}, { 72, 9, 3}, { 90, 12, 3}, { 108, 15, 3}, { 124, 18, 3}, { 987, 21, 3}, {1005, 24, 3}, {1023, 27, 3} }; struct rx_calchan_map rx_calchan_map_1800[RF_RX_CAL_CHAN_SIZE] = { {548, 0, 6}, {584, 6, 6}, {620, 12, 6}, {656, 18, 6}, {692, 24, 6}, {728, 30, 6}, {764, 36, 6}, {806, 42, 7}, {848, 49, 7}, {885, 56, 7} }; struct rx_calchan_map rx_calchan_map_1900[RF_RX_CAL_CHAN_SIZE] = { {542, 0, 5}, {572, 5, 5}, {602, 10, 5}, {632, 15, 5}, {662, 20, 5}, {692, 25, 5}, {722, 30, 5}, {752, 35, 5}, {782, 40, 5}, {810, 45, 5} }; struct band { char *name; unsigned compal_record_id; unsigned record_length; unsigned magic2_offset; struct rx_calchan_map *rx_calchan_map; unsigned start_plnum; unsigned end_plnum; } bands[] = { {"900", 0x00, 0x94, 0x54, rx_calchan_map_900, 5, 19}, {"1800", 0x01, 0xC8, 0x74, rx_calchan_map_1800, 0, 15}, {"1900", 0x02, 0xB4, 0x68, rx_calchan_map_1900, 0, 15}, {"850", 0x18, 0x88, 0x4C, rx_calchan_map_850, 5, 19}, {0, 0, 0, 0, 0, 0, 0} }; read_binfile(filename, offset_arg) char *filename, *offset_arg; { int fd, cc; u_long offset; char *endp; fd = open(filename, O_RDONLY); if (fd < 0) { perror(filename); exit(1); } offset = strtoul(offset_arg, &endp, 0); if (*endp) { fprintf(stderr, "error: invalid offset argument \"%s\"\n", offset_arg); exit(1); } lseek(fd, offset, SEEK_SET); cc = read(fd, sector, COMPAL_SECTOR_LENGTH); if (cc != COMPAL_SECTOR_LENGTH) { fprintf(stderr, "error: unable to read Compal sector of %d bytes from %s at offset %s\n", COMPAL_SECTOR_LENGTH, filename, offset_arg); exit(1); } close(fd); } write_rx_agcparams_ascii(band, table) struct band *band; u_char *table; { char pathname[MAXPATHLEN]; FILE *of; sprintf(pathname, "%s/rx-agcparams.%s", ascii_output_dir, band->name); of = fopen(pathname, "w"); if (!of) { perror(pathname); exit(1); } write_rx_agcparams_table(table, of); fclose(of); } write_rx_agcparams_bin(band, table) struct band *band; u_char *table; { char pathname[MAXPATHLEN]; int fd; sprintf(pathname, "%s/rx", bin_output_dir); mkdir_existok(pathname); sprintf(pathname, "%s/rx/agcparams.%s", bin_output_dir, band->name); fd = open(pathname, O_WRONLY|O_CREAT|O_TRUNC, 0666); if (fd < 0) { perror(pathname); exit(1); } write(fd, table, 8); close(fd); } write_rx_calchan_ascii(band, table) struct band *band; u_char *table; { char pathname[MAXPATHLEN]; FILE *of; sprintf(pathname, "%s/rx-calchan.%s", ascii_output_dir, band->name); of = fopen(pathname, "w"); if (!of) { perror(pathname); exit(1); } write_rx_calchan_table(table, of); fclose(of); } write_rx_calchan_bin(band, table) struct band *band; u_char *table; { char pathname[MAXPATHLEN]; int fd; sprintf(pathname, "%s/rx", bin_output_dir); mkdir_existok(pathname); sprintf(pathname, "%s/rx/calchan.%s", bin_output_dir, band->name); fd = open(pathname, O_WRONLY|O_CREAT|O_TRUNC, 0666); if (fd < 0) { perror(pathname); exit(1); } write(fd, table, 40); close(fd); } write_tx_levels_ascii(band, table) struct band *band; u_char *table; { char pathname[MAXPATHLEN]; FILE *of; sprintf(pathname, "%s/tx-levels.%s", ascii_output_dir, band->name); of = fopen(pathname, "w"); if (!of) { perror(pathname); exit(1); } write_tx_levels_table(table, of); fclose(of); } write_tx_levels_bin(band, table) struct band *band; u_char *table; { char pathname[MAXPATHLEN]; int fd; sprintf(pathname, "%s/tx", bin_output_dir); mkdir_existok(pathname); sprintf(pathname, "%s/tx/levels.%s", bin_output_dir, band->name); fd = open(pathname, O_WRONLY|O_CREAT|O_TRUNC, 0666); if (fd < 0) { perror(pathname); exit(1); } write(fd, table, 128); close(fd); } do_rx_agcparams(band, compal_data) struct band *band; u_char *compal_data; { u_char rx_agcparams_table[8]; bcopy(compal_data, rx_agcparams_table, 2); /* the remaining fields are constants unchanged from TI */ rx_agcparams_table[2] = 40; rx_agcparams_table[3] = 0; rx_agcparams_table[4] = 40; rx_agcparams_table[5] = 0; rx_agcparams_table[6] = 44; rx_agcparams_table[7] = 0; if (ascii_output_dir) write_rx_agcparams_ascii(band, rx_agcparams_table); if (bin_output_dir) write_rx_agcparams_bin(band, rx_agcparams_table); } do_rx_calchan(band, compal_data) struct band *band; signed char *compal_data; { u_char rx_calchan_table[40], *dp; struct rx_calchan_map *map; unsigned i, j; int accum, average; dp = rx_calchan_table; for (i = 0; i < RF_RX_CAL_CHAN_SIZE; i++) { map = band->rx_calchan_map + i; *dp++ = map->upper_bound; *dp++ = map->upper_bound >> 8; accum = 0; for (j = 0; j < map->compal_num; j++) accum += compal_data[map->compal_start + j]; average = accum / (int)map->compal_num; *dp++ = average; *dp++ = average >> 8; } if (ascii_output_dir) write_rx_calchan_ascii(band, rx_calchan_table); if (bin_output_dir) write_rx_calchan_bin(band, rx_calchan_table); } do_tx_levels(band, compal_data) struct band *band; u_char *compal_data; { u_char tx_levels_table[128], *sp, *dp; unsigned num_levels, n; bzero(tx_levels_table, sizeof tx_levels_table); num_levels = band->end_plnum - band->start_plnum + 1; sp = compal_data; dp = tx_levels_table + band->start_plnum * 4; for (n = 0; n < num_levels; n++) { *dp++ = *sp++; *dp++ = *sp++; *dp++ = n; *dp++ = 0; } if (ascii_output_dir) write_tx_levels_ascii(band, tx_levels_table); if (bin_output_dir) write_tx_levels_bin(band, tx_levels_table); } process_band_record(band, offset) struct band *band; unsigned offset; { u_char *record; record = sector + offset + 8; if (bcmp(record, record_magic, 4)) { printf("bad magic1, skipping\n"); return(-1); } if (bcmp(record + band->magic2_offset, record_magic, 4)) { printf("bad magic2, skipping\n"); return(-1); } if (bcmp(record + band->magic2_offset + 8, record_magic, 4)) { printf("bad magic3, skipping\n"); return(-1); } do_rx_agcparams(band, record + 4); do_rx_calchan(band, record + 6); do_tx_levels(band, record + band->magic2_offset + 12); return(0); } process_sector_data() { unsigned offset, next_offset; u_char *header; unsigned hdr_words[4]; struct band *band; int i; for (offset = 0; ; offset = next_offset) { if (offset > COMPAL_SECTOR_LENGTH - 12) break; header = sector + offset; if (!bcmp(header, endmarker, 8)) break; for (i = 0; i < 4; i++) hdr_words[i] = header[i*2] | (header[i*2+1] << 8); if (!hdr_words[3]) { fprintf(stderr, "error at offset 0x%X: rounded record length word is 0\n", offset); exit(1); } if (hdr_words[3] & 3) { fprintf(stderr, "error at offset 0x%X: rounded record length word is not aligned to 4\n", offset); exit(1); } if (hdr_words[3] > COMPAL_SECTOR_LENGTH - offset - 8) { fprintf(stderr, "error at offset 0x%X: rounded record length spills past end of sector\n", offset); exit(1); } if (hdr_words[2] > hdr_words[3]) { fprintf(stderr, "error at offset 0x%X: native record length is greater than rounded\n", offset); exit(1); } next_offset = offset + 8 + hdr_words[3]; if (hdr_words[0] != 0x000C) continue; for (band = bands; band->name; band++) if (hdr_words[1] == band->compal_record_id) break; if (!band->name) continue; printf("Found %s MHz calibration record at offset 0x%X\n", band->name, offset); if (hdr_words[2] != band->record_length) { printf("Oops, wrong length, skipping\n"); continue; } process_band_record(band, offset); } } main(argc, argv) char **argv; { int c; extern char *optarg; extern int optind; while ((c = getopt(argc, argv, "a:b:")) != EOF) switch (c) { case 'a': ascii_output_dir = optarg; continue; case 'b': bin_output_dir = optarg; continue; case '?': default: usage: fprintf(stderr, "usage: %s [-a ascii_outdir] [-b bin_outdir] c1xx-binfile offset\n", argv[0]); exit(1); } if (argc - optind != 2) goto usage; read_binfile(argv[optind], argv[optind+1]); if (ascii_output_dir) mkdir_existok(ascii_output_dir); if (bin_output_dir) mkdir_existok(bin_output_dir); process_sector_data(); exit(0); }