diff --git a/dfu.c b/dfu.c index bf55e0e..4b96d87 100644 --- a/dfu.c +++ b/dfu.c @@ -284,6 +284,9 @@ static void erase_block(uint32_t address) } get_status(); wait_dfu_idle(); + + fprintf(stderr, "#"); + fflush(stderr); } static const char *identify() @@ -369,6 +372,8 @@ void dfu_close() void dfu_erase(int nbytes) { // Enter Programming Mode. + get_status(); + wait_dfu_idle(); md380_command(0x91, 0x01); usleep(100000); diff --git a/main.c b/main.c index 83c67b9..eb5068a 100644 --- a/main.c +++ b/main.c @@ -120,6 +120,7 @@ int main(int argc, char **argv) radio_read_image(argv[0]); radio_print_version(stdout); radio_parse_config(argv[1]); + radio_verify_config(); radio_save_image("device.img"); } else { @@ -129,6 +130,7 @@ int main(int argc, char **argv) radio_print_version(stdout); radio_save_image("backup.img"); radio_parse_config(argv[0]); + radio_verify_config(); radio_upload(1); radio_disconnect(); } diff --git a/md380.c b/md380.c index d937e6d..8ca8ef5 100644 --- a/md380.c +++ b/md380.c @@ -51,6 +51,16 @@ #define OFFSET_SCANL 0x18860 #define OFFSET_CHANNELS 0x1ee00 +#define GET_TIMESTAMP() (&radio_mem[OFFSET_TIMESTMP]) +#define GET_SETTINGS() ((general_settings_t*) &radio_mem[OFFSET_SETTINGS]) +#define GET_CHANNEL(i) ((channel_t*) &radio_mem[OFFSET_CHANNELS + (i)*64]) +#define GET_ZONE(i) ((zone_t*) &radio_mem[OFFSET_ZONES + (i)*64]) +#define GET_ZONEXT(i) ((zone_ext_t*) &radio_mem[OFFSET_ZONEXT + (i)*224]) +#define GET_SCANLIST(i) ((scanlist_t*) &radio_mem[OFFSET_SCANL + (i)*104]) +#define GET_CONTACT(i) ((contact_t*) &radio_mem[OFFSET_CONTACTS + (i)*36]) +#define GET_GROUPLIST(i) ((grouplist_t*) &radio_mem[OFFSET_GLISTS + (i)*96]) +#define GET_MESSAGE(i) ((uint16_t*) &radio_mem[OFFSET_MSG + (i)*288]) + // // Channel data. // @@ -325,7 +335,7 @@ static const char *SIGNALING_SYSTEM[] = { "-", "DTMF-1", "DTMF-2", "DTMF-3", "DT // static void md380_print_version(radio_device_t *radio, FILE *out) { - unsigned char *timestamp = &radio_mem[OFFSET_TIMESTMP]; + unsigned char *timestamp = GET_TIMESTAMP(); static const char charmap[16] = "0123456789:;<=>?"; if (*timestamp != 0xff) { @@ -368,8 +378,6 @@ static void md380_upload(radio_device_t *radio, int cont_flag) dfu_erase(MEMSZ); - fprintf(stderr, "Sending data... "); - fflush(stderr); for (bno=0; bnoname, name, 16); } @@ -403,9 +411,9 @@ static void setup_zone(int index, const char *name) // Add channel to a zone. // Return 0 on failure. // -static int zone_append(int zone_index, int cnum) +static int zone_append(int index, int cnum) { - zone_t *z = (zone_t*) &radio_mem[OFFSET_ZONES + zone_index*64]; + zone_t *z = GET_ZONE(index); int i; for (i=0; i<16; i++) { @@ -419,9 +427,9 @@ static int zone_append(int zone_index, int cnum) return 0; } -static void erase_zone(int zone_index) +static void erase_zone(int index) { - zone_t *z = (zone_t*) &radio_mem[OFFSET_ZONES + zone_index*64]; + zone_t *z = GET_ZONE(index); memset(z, 0, 64); } @@ -432,7 +440,7 @@ static void erase_zone(int zone_index) static void setup_scanlist(int index, const char *name, int prio1, int prio2, int txchan) { - scanlist_t *sl = (scanlist_t*) &radio_mem[OFFSET_SCANL + index*104]; + scanlist_t *sl = GET_SCANLIST(index); // Bytes 0-31 utf8_decode(sl->name, name, 16); @@ -445,7 +453,7 @@ static void setup_scanlist(int index, const char *name, static void erase_scanlist(int index) { - scanlist_t *sl = (scanlist_t*) &radio_mem[OFFSET_SCANL + index*104]; + scanlist_t *sl = GET_SCANLIST(index); memset(sl, 0, 104); @@ -465,9 +473,9 @@ static void erase_scanlist(int index) // Add channel to a zone. // Return 0 on failure. // -static int scanlist_append(int list_index, int cnum) +static int scanlist_append(int index, int cnum) { - scanlist_t *sl = (scanlist_t*) &radio_mem[OFFSET_SCANL + list_index*104]; + scanlist_t *sl = GET_SCANLIST(index); int i; for (i=0; i<31; i++) { @@ -483,7 +491,7 @@ static int scanlist_append(int list_index, int cnum) static void erase_contact(int index) { - contact_t *ct = (contact_t*) &radio_mem[OFFSET_CONTACTS + index*36]; + contact_t *ct = GET_CONTACT(index); memset(ct, 0, 36); *(uint32_t*)ct = 0xffffffff; @@ -491,7 +499,7 @@ static void erase_contact(int index) static void setup_contact(int index, const char *name, int type, int id, int rxtone) { - contact_t *ct = (contact_t*) &radio_mem[OFFSET_CONTACTS + index*36]; + contact_t *ct = GET_CONTACT(index); ct->id = id; ct->type = type; @@ -502,7 +510,7 @@ static void setup_contact(int index, const char *name, int type, int id, int rxt static void setup_grouplist(int index, const char *name) { - grouplist_t *gl = (grouplist_t*) &radio_mem[OFFSET_GLISTS + index*96]; + grouplist_t *gl = GET_GROUPLIST(index); utf8_decode(gl->name, name, 16); } @@ -513,7 +521,7 @@ static void setup_grouplist(int index, const char *name) // static int grouplist_append(int index, int cnum) { - grouplist_t *gl = (grouplist_t*) &radio_mem[OFFSET_GLISTS + index*96]; + grouplist_t *gl = GET_GROUPLIST(index); int i; for (i=0; i<32; i++) { @@ -532,7 +540,7 @@ static int grouplist_append(int index, int cnum) // static void setup_message(int index, const char *text) { - uint16_t *msg = (uint16_t*) &radio_mem[OFFSET_MSG + index*288]; + uint16_t *msg = GET_MESSAGE(index); // Skip spaces and tabs. while (*text == ' ' || *text == '\t') @@ -560,7 +568,7 @@ static void setup_channel(int i, int mode, char *name, double rx_mhz, double tx_ int admit, int colorcode, int timeslot, int incall, int grouplist, int contact, int rxtone, int txtone, int width) { - channel_t *ch = (channel_t*) &radio_mem[OFFSET_CHANNELS + i*64]; + channel_t *ch = GET_CHANNEL(i); ch->channel_mode = mode; ch->bandwidth = width; @@ -590,7 +598,7 @@ static void setup_channel(int i, int mode, char *name, double rx_mhz, double tx_ // static void erase_channel(int i) { - channel_t *ch = (channel_t*) &radio_mem[OFFSET_CHANNELS + i*64]; + channel_t *ch = GET_CHANNEL(i); // Byte 0 ch->channel_mode = MODE_ANALOG; @@ -706,7 +714,7 @@ static void print_chanlist(FILE *out, uint16_t *unsorted, int nchan) static void print_id(FILE *out, int verbose) { - general_settings_t *gs = (general_settings_t*) &radio_mem[OFFSET_SETTINGS]; + general_settings_t *gs = GET_SETTINGS(); unsigned id = gs->radio_id[0] | (gs->radio_id[1] << 8) | (gs->radio_id[2] << 16); if (verbose) @@ -722,7 +730,7 @@ static void print_id(FILE *out, int verbose) static void print_intro(FILE *out, int verbose) { - general_settings_t *gs = (general_settings_t*) &radio_mem[OFFSET_SETTINGS]; + general_settings_t *gs = GET_SETTINGS(); if (verbose) fprintf(out, "\n# Text displayed when the radio powers up.\n"); @@ -749,7 +757,7 @@ static int have_channels(int mode) int i; for (i=0; iname[0] != 0 && ch->channel_mode == mode) return 1; @@ -850,7 +858,7 @@ static void print_digital_channels(FILE *out, int verbose) #endif fprintf(out, "\n"); for (i=0; iname[0] == 0 || ch->channel_mode != MODE_DIGITAL) { // Select digital channels @@ -939,7 +947,7 @@ static void print_analog_channels(FILE *out, int verbose) #endif fprintf(out, "\n"); for (i=0; iname[0] == 0 || ch->channel_mode != MODE_ANALOG) { // Select analog channels @@ -975,37 +983,66 @@ static void print_analog_channels(FILE *out, int verbose) static int have_zones() { - zone_t *z = (zone_t*) &radio_mem[OFFSET_ZONES]; + int i; - return z->name[0] != 0 && z->name[0] != 0xffff; + for (i=0; iname[0] != 0 && z->name[0] != 0xffff) + return 1; + } + return 0; } static int have_scanlists() { - scanlist_t *sl = (scanlist_t*) &radio_mem[OFFSET_SCANL]; + int i; - return sl->name[0] != 0 && sl->name[0] != 0xffff; + for (i=0; iname[0] != 0 && sl->name[0] != 0xffff) + return 1; + } + return 0; } static int have_contacts() { - contact_t *ct = (contact_t*) &radio_mem[OFFSET_CONTACTS]; + int i; - return ct->name[0] != 0 && ct->name[0] != 0xffff; + for (i=0; iname[0] != 0 && ct->name[0] != 0xffff) + return 1; + } + return 0; } static int have_grouplists() { - grouplist_t *gl = (grouplist_t*) &radio_mem[OFFSET_GLISTS]; + int i; - return gl->name[0] != 0 && gl->name[0] != 0xffff; + for (i=0; iname[0] != 0 && gl->name[0] != 0xffff) + return 1; + } + return 0; } static int have_messages() { - uint16_t *msg = (uint16_t*) &radio_mem[OFFSET_MSG]; + int i; - return msg[0] != 0 && msg[0] != 0xffff; + for (i=0; iname[0] == 0 || z->name[0] == 0xffff) { // Zone is disabled. @@ -1085,7 +1122,7 @@ static void md380_print_config(radio_device_t *radio, FILE *out, int verbose) #endif fprintf(out, "Channels\n"); for (i=0; iname[0] == 0 || sl->name[0] == 0xffff) { // Scan list is disabled. @@ -1144,7 +1181,7 @@ static void md380_print_config(radio_device_t *radio, FILE *out, int verbose) } fprintf(out, "Contact Name Type ID RxTone\n"); for (i=0; iname[0] == 0 || ct->name[0] == 0xffff) { // Contact is disabled @@ -1172,7 +1209,7 @@ static void md380_print_config(radio_device_t *radio, FILE *out, int verbose) } fprintf(out, "Grouplist Name Contacts\n"); for (i=0; iname[0] == 0 || gl->name[0] == 0xffff) { // Group list is disabled. @@ -1204,7 +1241,7 @@ static void md380_print_config(radio_device_t *radio, FILE *out, int verbose) } fprintf(out, "Message Text\n"); for (i=0; iname, value) != 0) { @@ -2057,7 +2094,7 @@ static int md380_parse_row(radio_device_t *radio, int table_id, int first_row, c // static void md380_update_timestamp(radio_device_t *radio) { - unsigned char *timestamp = &radio_mem[OFFSET_TIMESTMP]; + unsigned char *timestamp = GET_TIMESTAMP(); char p[16]; // Last Programmed Date @@ -2085,6 +2122,146 @@ static void md380_update_timestamp(radio_device_t *radio) } } +// +// Check that configuration is correct. +// Return 0 on error. +// +static int md380_verify_config(radio_device_t *radio) +{ + int i, k, nchannels = 0, nzones = 0, nscanlists = 0, ngrouplists = 0; + int ncontacts = 0, nerrors = 0; + + // Channels: check references to scanlists, contacts and grouplists. + for (i=0; iname[0] == 0 || ch->name[0] == 0xffff) + continue; + + nchannels++; + if (ch->scan_list_index != 0) { + scanlist_t *sl = GET_SCANLIST(ch->scan_list_index - 1); + + if (sl->name[0] == 0 || sl->name[0] == 0xffff) { + fprintf(stderr, "Channel %d '", i+1); + print_unicode(stderr, ch->name, 16, 0); + fprintf(stderr, "': scanlist %d not found.\n", ch->scan_list_index); + nerrors++; + } + } + if (ch->contact_name_index != 0) { + contact_t *ct = GET_CONTACT(ch->contact_name_index - 1); + + if (ct->name[0] == 0 || ct->name[0] == 0xffff) { + fprintf(stderr, "Channel %d '", i+1); + print_unicode(stderr, ch->name, 16, 0); + fprintf(stderr, "': contact %d not found.\n", ch->contact_name_index); + nerrors++; + } + } + if (ch->group_list_index != 0) { + grouplist_t *gl = GET_GROUPLIST(ch->group_list_index - 1); + + if (gl->name[0] == 0 || gl->name[0] == 0xffff) { + fprintf(stderr, "Channel %d '", i+1); + print_unicode(stderr, ch->name, 16, 0); + fprintf(stderr, "': grouplist %d not found.\n", ch->group_list_index); + nerrors++; + } + } + } + + // Zones: check references to channels. + for (i=0; iname[0] == 0 || z->name[0] == 0xffff) + continue; + + nzones++; + for (k=0; k<16; k++) { + int cnum = z->member[k]; + + if (cnum != 0) { + channel_t *ch = GET_CHANNEL(cnum - 1); + + if (ch->name[0] == 0 || ch->name[0] == 0xffff) { + fprintf(stderr, "Zone %da '", i+1); + print_unicode(stderr, z->name, 16, 0); + fprintf(stderr, "': channel %d not found.\n", cnum); + nerrors++; + } + } + } + } + + // Scanlists: check references to channels. + for (i=0; iname[0] == 0 || sl->name[0] == 0xffff) + continue; + + nscanlists++; + for (k=0; k<31; k++) { + int cnum = sl->member[k]; + + if (cnum != 0) { + channel_t *ch = GET_CHANNEL(cnum - 1); + + if (ch->name[0] == 0 || ch->name[0] == 0xffff) { + fprintf(stderr, "Scanlist %d '", i+1); + print_unicode(stderr, sl->name, 16, 0); + fprintf(stderr, "': channel %d not found.\n", cnum); + nerrors++; + } + } + } + } + + // Grouplists: check references to contacts. + for (i=0; iname[0] == 0 || gl->name[0] == 0xffff) + continue; + + ngrouplists++; + for (k=0; k<32; k++) { + int cnum = gl->member[k]; + + if (cnum != 0) { + contact_t *ct = GET_CONTACT(cnum - 1); + + if (ct->name[0] == 0 || ct->name[0] == 0xffff) { + fprintf(stderr, "Grouplist %d '", i+1); + print_unicode(stderr, gl->name, 16, 0); + fprintf(stderr, "': contact %d not found.\n", cnum); + nerrors++; + } + } + } + } + + // Count contacts. + for (i=0; iname[0] == 0 || ct->name[0] == 0xffff) + continue; + + ncontacts++; + } + + if (nerrors > 0) { + fprintf(stderr, "Total %d errors.\n", nerrors); + return 0; + } + fprintf(stderr, "Total %d channels, %d zones, %d scanlists, %d contacts, %d grouplists.\n", + nchannels, nzones, nscanlists, ncontacts, ngrouplists); + return 1; +} + // // TYT MD-380 // @@ -2097,6 +2274,7 @@ radio_device_t radio_md380 = { md380_save_image, md380_print_version, md380_print_config, + md380_verify_config, md380_parse_parameter, md380_parse_header, md380_parse_row, diff --git a/radio.c b/radio.c index a72a228..a4f417a 100644 --- a/radio.c +++ b/radio.c @@ -282,3 +282,14 @@ void radio_print_config(FILE *out, int verbose) } device->print_config(device, out, verbose); } + +// +// Check the configuration is correct. +// +void radio_verify_config() +{ + if (!device->verify_config(device)) { + // Message should be already printed. + exit(-1); + } +} diff --git a/radio.h b/radio.h index 1de546b..4b3cc16 100644 --- a/radio.h +++ b/radio.h @@ -72,6 +72,11 @@ void radio_save_image(char *filename); // void radio_parse_config(char *filename); +// +// Check the configuration. +// +void radio_verify_config(); + // // Device-dependent interface to the radio. // @@ -85,6 +90,7 @@ struct _radio_device_t { void (*save_image)(radio_device_t *radio, FILE *img); void (*print_version)(radio_device_t *radio, FILE *out); void (*print_config)(radio_device_t *radio, FILE *out, int verbose); + int (*verify_config)(radio_device_t *radio); void (*parse_parameter)(radio_device_t *radio, char *param, char *value); int (*parse_header)(radio_device_t *radio, char *line); int (*parse_row)(radio_device_t *radio, int table_id, int first_row, char *line); diff --git a/uv380.c b/uv380.c index d080098..980cf45 100644 --- a/uv380.c +++ b/uv380.c @@ -52,6 +52,16 @@ #define OFFSET_CHANNELS 0x40000 #define OFFSET_CONTACTS 0x70000 +#define GET_TIMESTAMP() (&radio_mem[OFFSET_TIMESTMP]) +#define GET_SETTINGS() ((general_settings_t*) &radio_mem[OFFSET_SETTINGS]) +#define GET_CHANNEL(i) ((channel_t*) &radio_mem[OFFSET_CHANNELS + (i)*64]) +#define GET_ZONE(i) ((zone_t*) &radio_mem[OFFSET_ZONES + (i)*64]) +#define GET_ZONEXT(i) ((zone_ext_t*) &radio_mem[OFFSET_ZONEXT + (i)*224]) +#define GET_SCANLIST(i) ((scanlist_t*) &radio_mem[OFFSET_SCANL + (i)*104]) +#define GET_CONTACT(i) ((contact_t*) &radio_mem[OFFSET_CONTACTS + (i)*36]) +#define GET_GROUPLIST(i) ((grouplist_t*) &radio_mem[OFFSET_GLISTS + (i)*96]) +#define GET_MESSAGE(i) ((uint16_t*) &radio_mem[OFFSET_MSG + (i)*288]) + // // Channel data. // @@ -343,7 +353,7 @@ static const char *TURNOFF_FREQ[] = { "259.2", "55.2", "???", "-" }; // static void uv380_print_version(radio_device_t *radio, FILE *out) { - unsigned char *timestamp = &radio_mem[OFFSET_TIMESTMP]; + unsigned char *timestamp = GET_TIMESTAMP(); static const char charmap[16] = "0123456789:;<=>?"; if (*timestamp != 0xff) { @@ -410,7 +420,7 @@ static int uv380_is_compatible(radio_device_t *radio) // static void setup_zone(int index, const char *name) { - zone_t *z = (zone_t*) &radio_mem[OFFSET_ZONES + index*64]; + zone_t *z = GET_ZONE(index); utf8_decode(z->name, name, 16); } @@ -419,10 +429,10 @@ static void setup_zone(int index, const char *name) // Add channel to a zone. // Return 0 on failure. // -static int zone_append(int zone_index, int b_flag, int cnum) +static int zone_append(int index, int b_flag, int cnum) { - zone_t *z = (zone_t*) &radio_mem[OFFSET_ZONES + zone_index*64]; - zone_ext_t *zext = (zone_ext_t*) &radio_mem[OFFSET_ZONEXT + zone_index*224]; + zone_t *z = GET_ZONE(index); + zone_ext_t *zext = GET_ZONEXT(index); int i; if (b_flag) { @@ -455,10 +465,10 @@ static int zone_append(int zone_index, int b_flag, int cnum) return 0; } -static void erase_zone(int zone_index) +static void erase_zone(int index) { - zone_t *z = (zone_t*) &radio_mem[OFFSET_ZONES + zone_index*64]; - zone_ext_t *zext = (zone_ext_t*) &radio_mem[OFFSET_ZONEXT + zone_index*224]; + zone_t *z = GET_ZONE(index); + zone_ext_t *zext = GET_ZONEXT(index); memset(z, 0, 64); memset(zext, 0, 224); @@ -470,7 +480,7 @@ static void erase_zone(int zone_index) static void setup_scanlist(int index, const char *name, int prio1, int prio2, int txchan) { - scanlist_t *sl = (scanlist_t*) &radio_mem[OFFSET_SCANL + index*104]; + scanlist_t *sl = GET_SCANLIST(index); // Bytes 0-31 utf8_decode(sl->name, name, 16); @@ -483,7 +493,7 @@ static void setup_scanlist(int index, const char *name, static void erase_scanlist(int index) { - scanlist_t *sl = (scanlist_t*) &radio_mem[OFFSET_SCANL + index*104]; + scanlist_t *sl = GET_SCANLIST(index); memset(sl, 0, 104); @@ -503,9 +513,9 @@ static void erase_scanlist(int index) // Add channel to a zone. // Return 0 on failure. // -static int scanlist_append(int list_index, int cnum) +static int scanlist_append(int index, int cnum) { - scanlist_t *sl = (scanlist_t*) &radio_mem[OFFSET_SCANL + list_index*104]; + scanlist_t *sl = GET_SCANLIST(index); int i; for (i=0; i<31; i++) { @@ -521,7 +531,7 @@ static int scanlist_append(int list_index, int cnum) static void erase_contact(int index) { - contact_t *ct = (contact_t*) &radio_mem[OFFSET_CONTACTS + index*36]; + contact_t *ct = GET_CONTACT(index); memset(ct, 0, 36); *(uint32_t*)ct = 0xffffffff; @@ -529,7 +539,7 @@ static void erase_contact(int index) static void setup_contact(int index, const char *name, int type, int id, int rxtone) { - contact_t *ct = (contact_t*) &radio_mem[OFFSET_CONTACTS + index*36]; + contact_t *ct = GET_CONTACT(index); ct->id = id; ct->type = type; @@ -540,7 +550,7 @@ static void setup_contact(int index, const char *name, int type, int id, int rxt static void setup_grouplist(int index, const char *name) { - grouplist_t *gl = (grouplist_t*) &radio_mem[OFFSET_GLISTS + index*96]; + grouplist_t *gl = GET_GROUPLIST(index); utf8_decode(gl->name, name, 16); } @@ -551,7 +561,7 @@ static void setup_grouplist(int index, const char *name) // static int grouplist_append(int index, int cnum) { - grouplist_t *gl = (grouplist_t*) &radio_mem[OFFSET_GLISTS + index*96]; + grouplist_t *gl = GET_GROUPLIST(index); int i; for (i=0; i<32; i++) { @@ -570,7 +580,7 @@ static int grouplist_append(int index, int cnum) // static void setup_message(int index, const char *text) { - uint16_t *msg = (uint16_t*) &radio_mem[OFFSET_MSG + index*288]; + uint16_t *msg = GET_MESSAGE(index); // Skip spaces and tabs. while (*text == ' ' || *text == '\t') @@ -598,7 +608,7 @@ static void setup_channel(int i, int mode, char *name, double rx_mhz, double tx_ int admit, int colorcode, int timeslot, int incall, int grouplist, int contact, int rxtone, int txtone, int width) { - channel_t *ch = (channel_t*) &radio_mem[OFFSET_CHANNELS + i*64]; + channel_t *ch = GET_CHANNEL(i); ch->channel_mode = mode; ch->bandwidth = width; @@ -628,7 +638,7 @@ static void setup_channel(int i, int mode, char *name, double rx_mhz, double tx_ // static void erase_channel(int i) { - channel_t *ch = (channel_t*) &radio_mem[OFFSET_CHANNELS + i*64]; + channel_t *ch = GET_CHANNEL(i); // Byte 0 ch->channel_mode = MODE_ANALOG; @@ -748,7 +758,7 @@ static void print_chanlist(FILE *out, uint16_t *unsorted, int nchan) static void print_id(FILE *out, int verbose) { - general_settings_t *gs = (general_settings_t*) &radio_mem[OFFSET_SETTINGS]; + general_settings_t *gs = GET_SETTINGS(); unsigned id = gs->radio_id[0] | (gs->radio_id[1] << 8) | (gs->radio_id[2] << 16); if (verbose) @@ -764,7 +774,7 @@ static void print_id(FILE *out, int verbose) static void print_intro(FILE *out, int verbose) { - general_settings_t *gs = (general_settings_t*) &radio_mem[OFFSET_SETTINGS]; + general_settings_t *gs = GET_SETTINGS(); if (verbose) fprintf(out, "\n# Text displayed when the radio powers up.\n"); @@ -791,7 +801,7 @@ static int have_channels(int mode) int i; for (i=0; iname[0] != 0 && ch->channel_mode == mode) return 1; @@ -894,7 +904,7 @@ static void print_digital_channels(FILE *out, int verbose) #endif fprintf(out, "\n"); for (i=0; iname[0] == 0 || ch->channel_mode != MODE_DIGITAL) { // Select digital channels @@ -987,7 +997,7 @@ static void print_analog_channels(FILE *out, int verbose) #endif fprintf(out, "\n"); for (i=0; iname[0] == 0 || ch->channel_mode != MODE_ANALOG) { // Select analog channels @@ -1024,37 +1034,66 @@ static void print_analog_channels(FILE *out, int verbose) static int have_zones() { - zone_t *z = (zone_t*) &radio_mem[OFFSET_ZONES]; + int i; - return z->name[0] != 0 && z->name[0] != 0xffff; + for (i=0; iname[0] != 0 && z->name[0] != 0xffff) + return 1; + } + return 0; } static int have_scanlists() { - scanlist_t *sl = (scanlist_t*) &radio_mem[OFFSET_SCANL]; + int i; - return sl->name[0] != 0 && sl->name[0] != 0xffff; + for (i=0; iname[0] != 0 && sl->name[0] != 0xffff) + return 1; + } + return 0; } static int have_contacts() { - contact_t *ct = (contact_t*) &radio_mem[OFFSET_CONTACTS]; + int i; - return ct->name[0] != 0 && ct->name[0] != 0xffff; + for (i=0; iname[0] != 0 && ct->name[0] != 0xffff) + return 1; + } + return 0; } static int have_grouplists() { - grouplist_t *gl = (grouplist_t*) &radio_mem[OFFSET_GLISTS]; + int i; - return gl->name[0] != 0 && gl->name[0] != 0xffff; + for (i=0; iname[0] != 0 && gl->name[0] != 0xffff) + return 1; + } + return 0; } static int have_messages() { - uint16_t *msg = (uint16_t*) &radio_mem[OFFSET_MSG]; + int i; - return msg[0] != 0 && msg[0] != 0xffff; + for (i=0; iname[0] == 0 || z->name[0] == 0xffff) { // Zone is disabled. @@ -1147,7 +1186,7 @@ static void uv380_print_config(radio_device_t *radio, FILE *out, int verbose) #endif fprintf(out, "Channels\n"); for (i=0; iname[0] == 0 || sl->name[0] == 0xffff) { // Scan list is disabled. @@ -1206,7 +1245,7 @@ static void uv380_print_config(radio_device_t *radio, FILE *out, int verbose) } fprintf(out, "Contact Name Type ID RxTone\n"); for (i=0; iname[0] == 0 || ct->name[0] == 0xffff) { // Contact is disabled @@ -1234,7 +1273,7 @@ static void uv380_print_config(radio_device_t *radio, FILE *out, int verbose) } fprintf(out, "Grouplist Name Contacts\n"); for (i=0; iname[0] == 0 || gl->name[0] == 0xffff) { // Group list is disabled. @@ -1266,7 +1305,7 @@ static void uv380_print_config(radio_device_t *radio, FILE *out, int verbose) } fprintf(out, "Message Text\n"); for (i=0; iname[0] == 0 || ch->name[0] == 0xffff) + continue; + + nchannels++; + if (ch->scan_list_index != 0) { + scanlist_t *sl = GET_SCANLIST(ch->scan_list_index - 1); + + if (sl->name[0] == 0 || sl->name[0] == 0xffff) { + fprintf(stderr, "Channel %d '", i+1); + print_unicode(stderr, ch->name, 16, 0); + fprintf(stderr, "': scanlist %d not found.\n", ch->scan_list_index); + nerrors++; + } + } + if (ch->contact_name_index != 0) { + contact_t *ct = GET_CONTACT(ch->contact_name_index - 1); + + if (ct->name[0] == 0 || ct->name[0] == 0xffff) { + fprintf(stderr, "Channel %d '", i+1); + print_unicode(stderr, ch->name, 16, 0); + fprintf(stderr, "': contact %d not found.\n", ch->contact_name_index); + nerrors++; + } + } + if (ch->group_list_index != 0) { + grouplist_t *gl = GET_GROUPLIST(ch->group_list_index - 1); + + if (gl->name[0] == 0 || gl->name[0] == 0xffff) { + fprintf(stderr, "Channel %d '", i+1); + print_unicode(stderr, ch->name, 16, 0); + fprintf(stderr, "': grouplist %d not found.\n", ch->group_list_index); + nerrors++; + } + } + } + + // Zones: check references to channels. + for (i=0; iname[0] == 0 || z->name[0] == 0xffff) + continue; + + nzones++; + + // Zone A + for (k=0; k<16; k++) { + int cnum = z->member_a[k]; + + if (cnum != 0) { + channel_t *ch = GET_CHANNEL(cnum - 1); + + if (ch->name[0] == 0 || ch->name[0] == 0xffff) { + fprintf(stderr, "Zone %da '", i+1); + print_unicode(stderr, z->name, 16, 0); + fprintf(stderr, "': channel %d not found.\n", cnum); + nerrors++; + } + } + } + for (k=0; k<48; k++) { + int cnum = zext->ext_a[k]; + + if (cnum != 0) { + channel_t *ch = GET_CHANNEL(cnum - 1); + + if (ch->name[0] == 0 || ch->name[0] == 0xffff) { + fprintf(stderr, "Zone %da '", i+1); + print_unicode(stderr, z->name, 16, 0); + fprintf(stderr, "': channel %d not found.\n", cnum); + nerrors++; + } + } + } + + // Zone B + for (k=0; k<64; k++) { + int cnum = zext->member_b[k]; + + if (cnum != 0) { + channel_t *ch = GET_CHANNEL(cnum - 1); + + if (ch->name[0] == 0 || ch->name[0] == 0xffff) { + fprintf(stderr, "Zone %db '", i+1); + print_unicode(stderr, z->name, 16, 0); + fprintf(stderr, "': channel %d not found.\n", cnum); + nerrors++; + } + } + } + } + + // Scanlists: check references to channels. + for (i=0; iname[0] == 0 || sl->name[0] == 0xffff) + continue; + + nscanlists++; + for (k=0; k<31; k++) { + int cnum = sl->member[k]; + + if (cnum != 0) { + channel_t *ch = GET_CHANNEL(cnum - 1); + + if (ch->name[0] == 0 || ch->name[0] == 0xffff) { + fprintf(stderr, "Scanlist %d '", i+1); + print_unicode(stderr, sl->name, 16, 0); + fprintf(stderr, "': channel %d not found.\n", cnum); + nerrors++; + } + } + } + } + + // Grouplists: check references to contacts. + for (i=0; iname[0] == 0 || gl->name[0] == 0xffff) + continue; + + ngrouplists++; + for (k=0; k<32; k++) { + int cnum = gl->member[k]; + + if (cnum != 0) { + contact_t *ct = GET_CONTACT(cnum - 1); + + if (ct->name[0] == 0 || ct->name[0] == 0xffff) { + fprintf(stderr, "Grouplist %d '", i+1); + print_unicode(stderr, gl->name, 16, 0); + fprintf(stderr, "': contact %d not found.\n", cnum); + nerrors++; + } + } + } + } + + // Count contacts. + for (i=0; iname[0] == 0 || ct->name[0] == 0xffff) + continue; + + ncontacts++; + } + + if (nerrors > 0) { + fprintf(stderr, "Total %d errors.\n", nerrors); + return 0; + } + fprintf(stderr, "Total %d channels, %d zones, %d scanlists, %d contacts, %d grouplists.\n", + nchannels, nzones, nscanlists, ncontacts, ngrouplists); + return 1; +} + // // TYT MD-UV380 // @@ -2168,6 +2380,7 @@ radio_device_t radio_uv380 = { uv380_save_image, uv380_print_version, uv380_print_config, + uv380_verify_config, uv380_parse_parameter, uv380_parse_header, uv380_parse_row, @@ -2186,6 +2399,7 @@ radio_device_t radio_md2017 = { uv380_save_image, uv380_print_version, uv380_print_config, + uv380_verify_config, uv380_parse_parameter, uv380_parse_header, uv380_parse_row,