Recognize the D868UV radio.
This commit is contained in:
parent
2f2acc20e0
commit
3607c41562
4
Makefile
4
Makefile
@ -6,7 +6,7 @@ UNAME = $(shell uname)
|
|||||||
CFLAGS = -g -O -Wall -Werror -DVERSION='"$(VERSION).$(GITCOUNT)"'
|
CFLAGS = -g -O -Wall -Werror -DVERSION='"$(VERSION).$(GITCOUNT)"'
|
||||||
LDFLAGS = -g
|
LDFLAGS = -g
|
||||||
|
|
||||||
OBJS = main.o util.o radio.o dfu-libusb.o uv380.o md380.o rd5r.o gd77.o hid.o serial.o
|
OBJS = main.o util.o radio.o dfu-libusb.o uv380.o md380.o rd5r.o gd77.o hid.o serial.o d868uv.o
|
||||||
LIBS = -lusb-1.0
|
LIBS = -lusb-1.0
|
||||||
|
|
||||||
# Linux
|
# Linux
|
||||||
@ -37,6 +37,7 @@ dmrconfig.linux: dmrconfig
|
|||||||
strip $@
|
strip $@
|
||||||
|
|
||||||
###
|
###
|
||||||
|
d868uv.o: d868uv.c radio.h util.h
|
||||||
dfu-libusb.o: dfu-libusb.c util.h
|
dfu-libusb.o: dfu-libusb.c util.h
|
||||||
dfu-windows.o: dfu-windows.c util.h
|
dfu-windows.o: dfu-windows.c util.h
|
||||||
gd77.o: gd77.c radio.h util.h
|
gd77.o: gd77.c radio.h util.h
|
||||||
@ -48,5 +49,6 @@ main.o: main.c radio.h util.h
|
|||||||
md380.o: md380.c radio.h util.h
|
md380.o: md380.c radio.h util.h
|
||||||
radio.o: radio.c radio.h util.h
|
radio.o: radio.c radio.h util.h
|
||||||
rd5r.o: rd5r.c radio.h util.h
|
rd5r.o: rd5r.c radio.h util.h
|
||||||
|
serial.o: serial.c util.h
|
||||||
util.o: util.c util.h
|
util.o: util.c util.h
|
||||||
uv380.o: uv380.c radio.h util.h
|
uv380.o: uv380.c radio.h util.h
|
||||||
|
@ -5,7 +5,7 @@ GITCOUNT = $(shell git rev-list HEAD --count)
|
|||||||
CFLAGS = -g -O -Wall -Werror -DVERSION='"$(VERSION).$(GITCOUNT)"'
|
CFLAGS = -g -O -Wall -Werror -DVERSION='"$(VERSION).$(GITCOUNT)"'
|
||||||
LDFLAGS = -g -s
|
LDFLAGS = -g -s
|
||||||
|
|
||||||
OBJS = main.o util.o radio.o dfu-windows.o uv380.o md380.o rd5r.o gd77.o hid.o hid-windows.o serial.o
|
OBJS = main.o util.o radio.o dfu-windows.o uv380.o md380.o rd5r.o gd77.o hid.o hid-windows.o serial.o d868uv.o
|
||||||
LIBS = -lhid -lsetupapi
|
LIBS = -lhid -lsetupapi
|
||||||
|
|
||||||
# Compiling Windows binary from Linux
|
# Compiling Windows binary from Linux
|
||||||
@ -33,6 +33,7 @@ install: dmrconfig
|
|||||||
install -c -s dmrconfig /usr/local/bin/dmrconfig
|
install -c -s dmrconfig /usr/local/bin/dmrconfig
|
||||||
|
|
||||||
###
|
###
|
||||||
|
d868uv.o: d868uv.c radio.h util.h
|
||||||
dfu-libusb.o: dfu-libusb.c util.h
|
dfu-libusb.o: dfu-libusb.c util.h
|
||||||
dfu-windows.o: dfu-windows.c util.h
|
dfu-windows.o: dfu-windows.c util.h
|
||||||
gd77.o: gd77.c radio.h util.h
|
gd77.o: gd77.c radio.h util.h
|
||||||
@ -44,5 +45,6 @@ main.o: main.c radio.h util.h
|
|||||||
md380.o: md380.c radio.h util.h
|
md380.o: md380.c radio.h util.h
|
||||||
radio.o: radio.c radio.h util.h
|
radio.o: radio.c radio.h util.h
|
||||||
rd5r.o: rd5r.c radio.h util.h
|
rd5r.o: rd5r.c radio.h util.h
|
||||||
|
serial.o: serial.c util.h
|
||||||
util.o: util.c util.h
|
util.o: util.c util.h
|
||||||
uv380.o: uv380.c radio.h util.h
|
uv380.o: uv380.c radio.h util.h
|
||||||
|
466
d868uv.c
Normal file
466
d868uv.c
Normal file
@ -0,0 +1,466 @@
|
|||||||
|
/*
|
||||||
|
* Interface to Anytone D868UV.
|
||||||
|
*
|
||||||
|
* 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 <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include "radio.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#define NCHAN 4000
|
||||||
|
#define NCONTACTS 10000
|
||||||
|
#define NZONES 250
|
||||||
|
#define NGLISTS 250
|
||||||
|
#define NSCANL 250
|
||||||
|
#define NMESSAGES 100
|
||||||
|
|
||||||
|
#define MEMSZ 0xd0000
|
||||||
|
|
||||||
|
//
|
||||||
|
// Print a generic information about the device.
|
||||||
|
//
|
||||||
|
static void d868uv_print_version(radio_device_t *radio, FILE *out)
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
#if 0
|
||||||
|
unsigned char *timestamp = GET_TIMESTAMP();
|
||||||
|
static const char charmap[16] = "0123456789:;<=>?";
|
||||||
|
|
||||||
|
if (*timestamp != 0xff) {
|
||||||
|
fprintf(out, "Last Programmed Date: %d%d%d%d-%d%d-%d%d",
|
||||||
|
timestamp[0] >> 4, timestamp[0] & 15, timestamp[1] >> 4, timestamp[1] & 15,
|
||||||
|
timestamp[2] >> 4, timestamp[2] & 15, timestamp[3] >> 4, timestamp[3] & 15);
|
||||||
|
fprintf(out, " %d%d:%d%d:%d%d\n",
|
||||||
|
timestamp[4] >> 4, timestamp[4] & 15, timestamp[5] >> 4, timestamp[5] & 15,
|
||||||
|
timestamp[6] >> 4, timestamp[6] & 15);
|
||||||
|
fprintf(out, "CPS Software Version: V%c%c.%c%c\n",
|
||||||
|
charmap[timestamp[7] & 15], charmap[timestamp[8] & 15],
|
||||||
|
charmap[timestamp[9] & 15], charmap[timestamp[10] & 15]);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Read memory image from the device.
|
||||||
|
//
|
||||||
|
static void d868uv_download(radio_device_t *radio)
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
#if 0
|
||||||
|
int bno;
|
||||||
|
|
||||||
|
for (bno=0; bno<MEMSZ/1024; bno++) {
|
||||||
|
dfu_read_block(bno, &radio_mem[bno*1024], 1024);
|
||||||
|
|
||||||
|
++radio_progress;
|
||||||
|
if (radio_progress % 32 == 0) {
|
||||||
|
fprintf(stderr, "#");
|
||||||
|
fflush(stderr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Write memory image to the device.
|
||||||
|
//
|
||||||
|
static void d868uv_upload(radio_device_t *radio, int cont_flag)
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
#if 0
|
||||||
|
int bno;
|
||||||
|
|
||||||
|
dfu_erase(0, MEMSZ);
|
||||||
|
|
||||||
|
for (bno=0; bno<MEMSZ/1024; bno++) {
|
||||||
|
dfu_write_block(bno, &radio_mem[bno*1024], 1024);
|
||||||
|
|
||||||
|
++radio_progress;
|
||||||
|
if (radio_progress % 32 == 0) {
|
||||||
|
fprintf(stderr, "#");
|
||||||
|
fflush(stderr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Check whether the memory image is compatible with this device.
|
||||||
|
//
|
||||||
|
static int d868uv_is_compatible(radio_device_t *radio)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Print full information about the device configuration.
|
||||||
|
//
|
||||||
|
static void d868uv_print_config(radio_device_t *radio, FILE *out, int verbose)
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Read memory image from the binary file.
|
||||||
|
//
|
||||||
|
static void d868uv_read_image(radio_device_t *radio, FILE *img)
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
#if 0
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
// Guess device type by file size.
|
||||||
|
if (fstat(fileno(img), &st) < 0) {
|
||||||
|
fprintf(stderr, "Cannot get file size.\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
switch (st.st_size) {
|
||||||
|
case MEMSZ:
|
||||||
|
// IMG file.
|
||||||
|
if (fread(&radio_mem[0], 1, MEMSZ, img) != MEMSZ) {
|
||||||
|
fprintf(stderr, "Error reading image data.\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MEMSZ + 0x225 + 0x10:
|
||||||
|
// RTD file.
|
||||||
|
// Header 0x225 bytes and footer 0x10 bytes at 0x40225.
|
||||||
|
fseek(img, 0x225, SEEK_SET);
|
||||||
|
if (fread(&radio_mem[0], 1, 0x40000, img) != 0x40000) {
|
||||||
|
fprintf(stderr, "Error reading image data.\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
fseek(img, 0x10, SEEK_CUR);
|
||||||
|
if (fread(&radio_mem[0x40000], 1, MEMSZ - 0x40000, img) != MEMSZ - 0x40000) {
|
||||||
|
fprintf(stderr, "Error reading image data.\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "Unrecognized file size %u bytes.\n", (int) st.st_size);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Save memory image to the binary file.
|
||||||
|
//
|
||||||
|
static void d868uv_save_image(radio_device_t *radio, FILE *img)
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
#if 0
|
||||||
|
fwrite(&radio_mem[0], 1, MEMSZ, img);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Parse the scalar parameter.
|
||||||
|
//
|
||||||
|
static void d868uv_parse_parameter(radio_device_t *radio, char *param, char *value)
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
fprintf(stderr, "Unknown parameter: %s = %s\n", param, value);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Parse table header.
|
||||||
|
// Return table id, or 0 in case of error.
|
||||||
|
//
|
||||||
|
static int d868uv_parse_header(radio_device_t *radio, char *line)
|
||||||
|
{
|
||||||
|
if (strncasecmp(line, "Digital", 7) == 0)
|
||||||
|
return 'D';
|
||||||
|
if (strncasecmp(line, "Analog", 6) == 0)
|
||||||
|
return 'A';
|
||||||
|
if (strncasecmp(line, "Zone", 4) == 0)
|
||||||
|
return 'Z';
|
||||||
|
if (strncasecmp(line, "Scanlist", 8) == 0)
|
||||||
|
return 'S';
|
||||||
|
if (strncasecmp(line, "Contact", 7) == 0)
|
||||||
|
return 'C';
|
||||||
|
if (strncasecmp(line, "Grouplist", 9) == 0)
|
||||||
|
return 'G';
|
||||||
|
if (strncasecmp(line, "Message", 7) == 0)
|
||||||
|
return 'M';
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Parse one line of table data.
|
||||||
|
// Return 0 on failure.
|
||||||
|
//
|
||||||
|
static int d868uv_parse_row(radio_device_t *radio, int table_id, int first_row, char *line)
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
#if 0
|
||||||
|
switch (table_id) {
|
||||||
|
case 'D': return parse_digital_channel(radio, first_row, line);
|
||||||
|
case 'A': return parse_analog_channel(radio, first_row, line);
|
||||||
|
case 'Z': return parse_zones(first_row, line);
|
||||||
|
case 'S': return parse_scanlist(first_row, line);
|
||||||
|
case 'C': return parse_contact(first_row, line);
|
||||||
|
case 'G': return parse_grouplist(first_row, line);
|
||||||
|
case 'M': return parse_messages(first_row, line);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Update timestamp.
|
||||||
|
//
|
||||||
|
static void d868uv_update_timestamp(radio_device_t *radio)
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
#if 0
|
||||||
|
unsigned char *timestamp = GET_TIMESTAMP();
|
||||||
|
char p[16];
|
||||||
|
|
||||||
|
// Last Programmed Date
|
||||||
|
get_timestamp(p);
|
||||||
|
timestamp[0] = ((p[0] & 0xf) << 4) | (p[1] & 0xf); // year upper
|
||||||
|
timestamp[1] = ((p[2] & 0xf) << 4) | (p[3] & 0xf); // year lower
|
||||||
|
timestamp[2] = ((p[4] & 0xf) << 4) | (p[5] & 0xf); // month
|
||||||
|
timestamp[3] = ((p[6] & 0xf) << 4) | (p[7] & 0xf); // day
|
||||||
|
timestamp[4] = ((p[8] & 0xf) << 4) | (p[9] & 0xf); // hour
|
||||||
|
timestamp[5] = ((p[10] & 0xf) << 4) | (p[11] & 0xf); // minute
|
||||||
|
timestamp[6] = ((p[12] & 0xf) << 4) | (p[13] & 0xf); // second
|
||||||
|
|
||||||
|
// CPS Software Version: Vdx.xx
|
||||||
|
const char *dot = strchr(VERSION, '.');
|
||||||
|
if (dot) {
|
||||||
|
timestamp[7] = 0x0d; // Prints as '='
|
||||||
|
timestamp[8] = dot[-1] & 0x0f;
|
||||||
|
if (dot[2] == '.') {
|
||||||
|
timestamp[9] = 0;
|
||||||
|
timestamp[10] = dot[1] & 0x0f;
|
||||||
|
} else {
|
||||||
|
timestamp[9] = dot[1] & 0x0f;
|
||||||
|
timestamp[10] = dot[2] & 0x0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Check that configuration is correct.
|
||||||
|
// Return 0 on error.
|
||||||
|
//
|
||||||
|
static int d868uv_verify_config(radio_device_t *radio)
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
#if 0
|
||||||
|
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; i<NCHAN; i++) {
|
||||||
|
channel_t *ch = GET_CHANNEL(i);
|
||||||
|
|
||||||
|
if (!VALID_CHANNEL(ch))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
nchannels++;
|
||||||
|
if (ch->scan_list_index != 0) {
|
||||||
|
scanlist_t *sl = GET_SCANLIST(ch->scan_list_index - 1);
|
||||||
|
|
||||||
|
if (!VALID_SCANLIST(sl)) {
|
||||||
|
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 (!VALID_CONTACT(ct)) {
|
||||||
|
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 (!VALID_GROUPLIST(gl)) {
|
||||||
|
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; i<NZONES; i++) {
|
||||||
|
zone_t *z = GET_ZONE(i);
|
||||||
|
zone_ext_t *zext = GET_ZONEXT(i);
|
||||||
|
|
||||||
|
if (!VALID_ZONE(z))
|
||||||
|
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 (!VALID_CHANNEL(ch)) {
|
||||||
|
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 (!VALID_CHANNEL(ch)) {
|
||||||
|
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 (!VALID_CHANNEL(ch)) {
|
||||||
|
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; i<NSCANL; i++) {
|
||||||
|
scanlist_t *sl = GET_SCANLIST(i);
|
||||||
|
|
||||||
|
if (!VALID_SCANLIST(sl))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
nscanlists++;
|
||||||
|
for (k=0; k<31; k++) {
|
||||||
|
int cnum = sl->member[k];
|
||||||
|
|
||||||
|
if (cnum != 0) {
|
||||||
|
channel_t *ch = GET_CHANNEL(cnum - 1);
|
||||||
|
|
||||||
|
if (!VALID_CHANNEL(ch)) {
|
||||||
|
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; i<NGLISTS; i++) {
|
||||||
|
grouplist_t *gl = GET_GROUPLIST(i);
|
||||||
|
|
||||||
|
if (!VALID_GROUPLIST(gl))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ngrouplists++;
|
||||||
|
for (k=0; k<32; k++) {
|
||||||
|
int cnum = gl->member[k];
|
||||||
|
|
||||||
|
if (cnum != 0) {
|
||||||
|
contact_t *ct = GET_CONTACT(cnum - 1);
|
||||||
|
|
||||||
|
if (!VALID_CONTACT(ct)) {
|
||||||
|
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; i<NCONTACTS; i++) {
|
||||||
|
contact_t *ct = GET_CONTACT(i);
|
||||||
|
|
||||||
|
if (VALID_CONTACT(ct))
|
||||||
|
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);
|
||||||
|
#endif
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// TYT MD-UV380
|
||||||
|
//
|
||||||
|
radio_device_t radio_d868uv = {
|
||||||
|
"Anytone AT-D868UV",
|
||||||
|
d868uv_download,
|
||||||
|
d868uv_upload,
|
||||||
|
d868uv_is_compatible,
|
||||||
|
d868uv_read_image,
|
||||||
|
d868uv_save_image,
|
||||||
|
d868uv_print_version,
|
||||||
|
d868uv_print_config,
|
||||||
|
d868uv_verify_config,
|
||||||
|
d868uv_parse_parameter,
|
||||||
|
d868uv_parse_header,
|
||||||
|
d868uv_parse_row,
|
||||||
|
d868uv_update_timestamp,
|
||||||
|
//d868uv_write_csv,
|
||||||
|
};
|
1
radio.c
1
radio.c
@ -49,6 +49,7 @@ static struct {
|
|||||||
{ "ZN><:", &radio_rt27d }, // Radtel RT-27D
|
{ "ZN><:", &radio_rt27d }, // Radtel RT-27D
|
||||||
{ "BF-5R", &radio_rd5r }, // Baofeng RD-5R
|
{ "BF-5R", &radio_rd5r }, // Baofeng RD-5R
|
||||||
{ "MD-760P", &radio_gd77 }, // Radioddity GD-77, version 3.1.1 and later
|
{ "MD-760P", &radio_gd77 }, // Radioddity GD-77, version 3.1.1 and later
|
||||||
|
{ "D868UVE", &radio_d868uv }, // Anytone AT-D868UV
|
||||||
{ 0, 0 }
|
{ 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
1
radio.h
1
radio.h
@ -124,6 +124,7 @@ extern radio_device_t radio_dp880; // Zastone DP880
|
|||||||
extern radio_device_t radio_rt27d; // Radtel RT-27D
|
extern radio_device_t radio_rt27d; // Radtel RT-27D
|
||||||
extern radio_device_t radio_rd5r; // Baofeng RD-5R
|
extern radio_device_t radio_rd5r; // Baofeng RD-5R
|
||||||
extern radio_device_t radio_gd77; // Radioddity GD-77, version 3.1.1 and later
|
extern radio_device_t radio_gd77; // Radioddity GD-77, version 3.1.1 and later
|
||||||
|
extern radio_device_t radio_d868uv; // Anytone AT-D868UV
|
||||||
|
|
||||||
//
|
//
|
||||||
// Radio: memory contents.
|
// Radio: memory contents.
|
||||||
|
60
serial.c
60
serial.c
@ -59,8 +59,10 @@
|
|||||||
static char *dev_path;
|
static char *dev_path;
|
||||||
|
|
||||||
static const unsigned char CMD_PRG[] = "PROGRAM";
|
static const unsigned char CMD_PRG[] = "PROGRAM";
|
||||||
|
static const unsigned char CMD_PRG2[] = "\2";
|
||||||
static const unsigned char CMD_QX[] = "QX\6";
|
static const unsigned char CMD_QX[] = "QX\6";
|
||||||
static const unsigned char CMD_ACK2[] = "\2";
|
static const unsigned char CMD_ACK[] = "\6";
|
||||||
|
static const unsigned char CMD_END[] = "END";
|
||||||
|
|
||||||
//
|
//
|
||||||
// Encode the speed in bits per second into bit value
|
// Encode the speed in bits per second into bit value
|
||||||
@ -250,26 +252,6 @@ again:
|
|||||||
return got;
|
return got;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Close the serial port.
|
|
||||||
//
|
|
||||||
void serial_close()
|
|
||||||
{
|
|
||||||
#if defined(__WIN32__) || defined(WIN32)
|
|
||||||
if (fd != INVALID_HANDLE_VALUE) {
|
|
||||||
SetCommState(fd, &saved_mode);
|
|
||||||
CloseHandle(fd);
|
|
||||||
fd = INVALID_HANDLE_VALUE;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if (fd >= 0) {
|
|
||||||
tcsetattr(fd, TCSANOW, &saved_mode);
|
|
||||||
close(fd);
|
|
||||||
fd = -1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Open the serial port.
|
// Open the serial port.
|
||||||
// Return -1 on error.
|
// Return -1 on error.
|
||||||
@ -601,8 +583,33 @@ static int send_recv(const unsigned char *cmd, int cmdlen,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Close the serial port.
|
||||||
|
//
|
||||||
|
void serial_close()
|
||||||
|
{
|
||||||
|
#if defined(__WIN32__) || defined(WIN32)
|
||||||
|
if (fd != INVALID_HANDLE_VALUE) {
|
||||||
|
SetCommState(fd, &saved_mode);
|
||||||
|
CloseHandle(fd);
|
||||||
|
fd = INVALID_HANDLE_VALUE;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (fd >= 0) {
|
||||||
|
unsigned char ack[1];
|
||||||
|
|
||||||
|
send_recv(CMD_END, 3, ack, 1);
|
||||||
|
|
||||||
|
tcsetattr(fd, TCSANOW, &saved_mode);
|
||||||
|
close(fd);
|
||||||
|
fd = -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Query and return the device identification string.
|
// Query and return the device identification string.
|
||||||
|
// On error, return NULL.
|
||||||
//
|
//
|
||||||
const char *serial_identify()
|
const char *serial_identify()
|
||||||
{
|
{
|
||||||
@ -614,7 +621,7 @@ const char *serial_identify()
|
|||||||
}
|
}
|
||||||
|
|
||||||
send_recv(CMD_PRG, 7, ack, 3);
|
send_recv(CMD_PRG, 7, ack, 3);
|
||||||
if (ack[0] != CMD_QX[0] || ack[1] != CMD_QX[1] || ack[2] != CMD_QX[2]) {
|
if (memcmp(ack, CMD_QX, 3) != 0) {
|
||||||
fprintf(stderr, "%s: Wrong PRG acknowledge %02x-%02x-%02x, expected %02x-%02x-%02x\n",
|
fprintf(stderr, "%s: Wrong PRG acknowledge %02x-%02x-%02x, expected %02x-%02x-%02x\n",
|
||||||
__func__, ack[0], ack[1], ack[2], CMD_QX[0], CMD_QX[1], CMD_QX[2]);
|
__func__, ack[0], ack[1], ack[2], CMD_QX[0], CMD_QX[1], CMD_QX[2]);
|
||||||
return 0;
|
return 0;
|
||||||
@ -623,9 +630,14 @@ const char *serial_identify()
|
|||||||
// Reply:
|
// Reply:
|
||||||
// 49 44 38 36 38 55 56 45 00 56 31 30 32 00 00 06
|
// 49 44 38 36 38 55 56 45 00 56 31 30 32 00 00 06
|
||||||
// I D 8 6 8 U V E V 1 0 2
|
// I D 8 6 8 U V E V 1 0 2
|
||||||
send_recv(CMD_ACK2, 1, reply, 16);
|
send_recv(CMD_PRG2, 1, reply, 16);
|
||||||
|
if (reply[0] != 'I' || reply[15] != CMD_ACK[0]) {
|
||||||
|
fprintf(stderr, "%s: Wrong PRG2 reply %02x-...-%02x, expected %02x-...-%02x\n",
|
||||||
|
__func__, reply[0], reply[15], 'I', CMD_ACK[0]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Terminate the string.
|
// Terminate the string.
|
||||||
reply[8] = 0;
|
reply[8] = 0;
|
||||||
return (char*)reply;
|
return (char*)&reply[1];
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user