/* * Configuration Utility for DMR radios. * * Copyright (C) 2018 Serge Vakulenko, KK6ABQ * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include "radio.h" #include "util.h" /* typedef struct { char* ident; radio_device_t* device; } radio_tab_t; static radio_tab_t radio_tab[] = { { "DR780", &radio_md380 }, // TYT MD-380, Retevis RT3, RT8 { "MD390", &radio_md390 }, // TYT MD-390 { "MD-UV380", &radio_uv380 }, // TYT MD-UV380 { "MD-UV390", &radio_uv390 }, // TYT MD-UV390, Retevis RT3S { "2017", &radio_md2017 }, // TYT MD-2017, Retevis RT82 { "MD9600", &radio_md9600 }, // TYT MD-9600 { "BF-5R", &radio_rd5r }, // Baofeng RD-5R, TD-5R { "1801", &radio_dm1801 }, // Baofeng DM-1801 { "DM-1701", &radio_rt84 }, // Baofeng DM-1701, Retevis RT84 { "MD-760P", &radio_gd77 }, // Radioddity GD-77, version 3.1.1 and later { "D868UVE", &radio_d868uv }, // Anytone AT-D868UV { "D878UV", &radio_d878uv }, // Anytone AT-D878UV { "D6X2UV", &radio_dmr6x2 }, // BTECH DMR-6x2 { "ZD3688", &radio_d900 }, // Zastone D900 { "TP660", &radio_dp880 }, // Zastone DP880 { "ZN><:", &radio_rt27d }, // Radtel RT-27D { 0, 0 } }; */ static radio_device_t *active_device; // Device-dependent interface radio_device_t* get_active_device() { return active_device; } void set_active_device(radio_device_t* d) { active_device = d; } unsigned char radio_mem [1024*1024*2]; // Radio memory contents, up to 2 Mbytes // // Read the configuration from text file, and modify the firmware. // void radio_parse_config(radio_device_t* device, const char *filename) { FILE *conf; char line [256], *p, *v; int table_id = 0, table_dirty = 0; fprintf(stderr, "Read configuration from file '%s'.\n", filename); conf = fopen(filename, "r"); if (! conf) { perror(filename); exit(-1); } device->channel_count = 0; while (fgets(line, sizeof(line), conf)) { line[sizeof(line)-1] = 0; // Strip comments. v = strchr(line, '#'); if (v) *v = 0; // Strip trailing spaces and newline. v = line + strlen(line) - 1; while (v >= line && (*v=='\n' || *v=='\r' || *v==' ' || *v=='\t')) *v-- = 0; // Ignore comments and empty lines. p = line; if (*p == 0) continue; if (*p != ' ') { // Table finished. table_id = 0; // Find the value. v = strchr(p, ':'); if (! v) { // Table header: get table type. table_id = device->parse_header(device, p); if (! table_id) { badline: fprintf(stderr, "Invalid line: '%s'\n", line); exit(-1); } table_dirty = 0; continue; } // Parameter. *v++ = 0; // Skip spaces. while (*v == ' ' || *v == '\t') v++; device->parse_parameter(device, p, v); } else { // Table row or comment. // Skip spaces. // Ignore comments and empty lines. while (*p == ' ' || *p == '\t') p++; if (*p == '#' || *p == 0) continue; if (! table_id) { goto badline; } if (! device->parse_row(device, table_id, ! table_dirty, p)) { goto badline; } table_dirty = 1; } } fclose(conf); device->update_timestamp(device); } // // Print full information about the device configuration. // void radio_print_config(radio_device_t* device, FILE *out, int verbose) { if (verbose) { char buf [40]; time_t t; struct tm *tmp; t = time(NULL); tmp = localtime(&t); if (! tmp || ! strftime(buf, sizeof(buf), "%Y/%m/%d ", tmp)) buf[0] = 0; fprintf(out, "#\n"); fprintf(out, "# Configuration generated %sby dmrconfig, version %s\n", buf, version); fprintf(out, "#\n"); } device->print_config(device, out, verbose); } // // Update contacts database on the device. // void radio_write_csv(radio_device_t* device, const char *filename) { FILE *csv; if (!device->write_csv) { fprintf(stderr, "%s does not support CSV database.\n", device->name); return; } csv = fopen(filename, "r"); if (! csv) { perror(filename); return; } fprintf(stderr, "Read file '%s'.\n", filename); device->write_csv(device, csv); fclose(csv); }