Implement -u option: update ContactsCSV database.
This commit is contained in:
parent
24b6bafcaf
commit
5144316fb9
61
dfu.c
61
dfu.c
@ -261,7 +261,7 @@ static void set_address(uint32_t address)
|
||||
wait_dfu_idle();
|
||||
}
|
||||
|
||||
static void erase_block(uint32_t address)
|
||||
static void erase_block(uint32_t address, int progress_flag)
|
||||
{
|
||||
unsigned char cmd[5] = { 0x41,
|
||||
(uint8_t)address,
|
||||
@ -285,8 +285,10 @@ static void erase_block(uint32_t address)
|
||||
get_status();
|
||||
wait_dfu_idle();
|
||||
|
||||
fprintf(stderr, "#");
|
||||
fflush(stderr);
|
||||
if (progress_flag) {
|
||||
fprintf(stderr, "#");
|
||||
fflush(stderr);
|
||||
}
|
||||
}
|
||||
|
||||
static const char *identify()
|
||||
@ -369,7 +371,7 @@ void dfu_close()
|
||||
}
|
||||
}
|
||||
|
||||
void dfu_erase(int nbytes)
|
||||
void dfu_erase(unsigned start, unsigned finish)
|
||||
{
|
||||
// Enter Programming Mode.
|
||||
get_status();
|
||||
@ -377,25 +379,36 @@ void dfu_erase(int nbytes)
|
||||
md380_command(0x91, 0x01);
|
||||
usleep(100000);
|
||||
|
||||
erase_block(0x00000000);
|
||||
erase_block(0x00010000);
|
||||
erase_block(0x00020000);
|
||||
erase_block(0x00030000);
|
||||
if (start == 0) {
|
||||
// Erase 256kbytes of configuration memory.
|
||||
erase_block(0x00000000, 1);
|
||||
erase_block(0x00010000, 1);
|
||||
erase_block(0x00020000, 1);
|
||||
erase_block(0x00030000, 1);
|
||||
|
||||
if (nbytes > 256*1024) {
|
||||
erase_block(0x00110000);
|
||||
erase_block(0x00120000);
|
||||
erase_block(0x00130000);
|
||||
erase_block(0x00140000);
|
||||
erase_block(0x00150000);
|
||||
erase_block(0x00160000);
|
||||
erase_block(0x00170000);
|
||||
erase_block(0x00180000);
|
||||
erase_block(0x00190000);
|
||||
erase_block(0x001a0000);
|
||||
erase_block(0x001b0000);
|
||||
erase_block(0x001c0000);
|
||||
erase_block(0x001d0000);
|
||||
if (finish > 256*1024) {
|
||||
// Erase 768kbytes of extended configuration memory.
|
||||
erase_block(0x00110000, 1);
|
||||
erase_block(0x00120000, 1);
|
||||
erase_block(0x00130000, 1);
|
||||
erase_block(0x00140000, 1);
|
||||
erase_block(0x00150000, 1);
|
||||
erase_block(0x00160000, 1);
|
||||
erase_block(0x00170000, 1);
|
||||
erase_block(0x00180000, 1);
|
||||
erase_block(0x00190000, 1);
|
||||
erase_block(0x001a0000, 1);
|
||||
erase_block(0x001b0000, 1);
|
||||
erase_block(0x001c0000, 1);
|
||||
erase_block(0x001d0000, 1);
|
||||
}
|
||||
} else {
|
||||
// Erase callsign database.
|
||||
int addr;
|
||||
|
||||
for (addr=start; addr<finish; addr+=0x00010000) {
|
||||
erase_block(addr, (addr & 0x00070000) == 0x00070000);
|
||||
}
|
||||
}
|
||||
|
||||
// Zero address.
|
||||
@ -404,7 +417,7 @@ void dfu_erase(int nbytes)
|
||||
|
||||
void dfu_read_block(int bno, uint8_t *data, int nbytes)
|
||||
{
|
||||
if (bno >= 256)
|
||||
if (bno >= 256 && bno < 2048)
|
||||
bno += 832;
|
||||
|
||||
if (trace_flag) {
|
||||
@ -427,7 +440,7 @@ void dfu_read_block(int bno, uint8_t *data, int nbytes)
|
||||
|
||||
void dfu_write_block(int bno, uint8_t *data, int nbytes)
|
||||
{
|
||||
if (bno >= 256)
|
||||
if (bno >= 256 && bno < 2048)
|
||||
bno += 832;
|
||||
|
||||
if (trace_flag) {
|
||||
|
29
main.c
29
main.c
@ -53,6 +53,8 @@ void usage()
|
||||
fprintf(stderr, _(" Store modified copy to a file 'device.img'.\n"));
|
||||
fprintf(stderr, _(" dmrconfig file.img\n"));
|
||||
fprintf(stderr, _(" Display configuration from the codeplug image.\n"));
|
||||
fprintf(stderr, _(" dmrconfig -u [-t] file.csv\n"));
|
||||
fprintf(stderr, _(" Update contacts database.\n"));
|
||||
fprintf(stderr, _("Options:\n"));
|
||||
fprintf(stderr, _(" -r Read codeplug from the radio.\n"));
|
||||
fprintf(stderr, _(" -w Write codeplug to the radio.\n"));
|
||||
@ -63,7 +65,7 @@ void usage()
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int read_flag = 0, write_flag = 0, config_flag = 0;
|
||||
int read_flag = 0, write_flag = 0, config_flag = 0, csv_flag = 0;
|
||||
|
||||
// Set locale and message catalogs.
|
||||
setlocale(LC_ALL, "");
|
||||
@ -79,11 +81,12 @@ int main(int argc, char **argv)
|
||||
copyright = _("Copyright (C) 2018 Serge Vakulenko KK6ABQ");
|
||||
trace_flag = 0;
|
||||
for (;;) {
|
||||
switch (getopt(argc, argv, "tcwr")) {
|
||||
case 't': ++trace_flag; continue;
|
||||
case 'r': ++read_flag; continue;
|
||||
case 'w': ++write_flag; continue;
|
||||
case 'c': ++config_flag; continue;
|
||||
switch (getopt(argc, argv, "tcwru")) {
|
||||
case 't': ++trace_flag; continue;
|
||||
case 'r': ++read_flag; continue;
|
||||
case 'w': ++write_flag; continue;
|
||||
case 'c': ++config_flag; continue;
|
||||
case 'u': ++csv_flag; continue;
|
||||
default:
|
||||
usage();
|
||||
case EOF:
|
||||
@ -93,8 +96,8 @@ int main(int argc, char **argv)
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
if (write_flag + config_flag > 1) {
|
||||
fprintf(stderr, "Only one of -w or -c options is allowed.\n");
|
||||
if (read_flag + write_flag + config_flag + csv_flag > 1) {
|
||||
fprintf(stderr, "Only one of -r, -w, -c or -u options is allowed.\n");
|
||||
usage();
|
||||
}
|
||||
setvbuf(stdout, 0, _IOLBF, 0);
|
||||
@ -156,6 +159,16 @@ int main(int argc, char **argv)
|
||||
}
|
||||
radio_print_config(conf, 1);
|
||||
fclose(conf);
|
||||
|
||||
} else if (csv_flag) {
|
||||
// Update contacts database on the device.
|
||||
if (argc != 1)
|
||||
usage();
|
||||
|
||||
radio_connect();
|
||||
radio_write_csv(argv[0]);
|
||||
radio_disconnect();
|
||||
|
||||
} else {
|
||||
if (argc != 1)
|
||||
usage();
|
||||
|
2
md380.c
2
md380.c
@ -384,7 +384,7 @@ static void md380_upload(radio_device_t *radio, int cont_flag)
|
||||
{
|
||||
int bno;
|
||||
|
||||
dfu_erase(MEMSZ);
|
||||
dfu_erase(0, MEMSZ);
|
||||
|
||||
for (bno=0; bno<MEMSZ/1024; bno++) {
|
||||
dfu_write_block(bno, &radio_mem[bno*1024], 1024);
|
||||
|
31
radio.c
31
radio.c
@ -67,7 +67,6 @@ void radio_connect()
|
||||
{
|
||||
// Only TYT MD family for now.
|
||||
const char *ident = dfu_init(0x0483, 0xdf11);
|
||||
fprintf(stderr, "Connect to %s.\n", ident);
|
||||
|
||||
if (strcasecmp(ident, "DR780") == 0) { // TYT MD-380, Retevis RT3, RT8
|
||||
device = &radio_md380;
|
||||
@ -91,6 +90,7 @@ void radio_connect()
|
||||
ident);
|
||||
exit(-1);
|
||||
}
|
||||
fprintf(stderr, "Connect to %s.\n", device->name);
|
||||
}
|
||||
|
||||
//
|
||||
@ -132,7 +132,7 @@ void radio_upload(int cont_flag)
|
||||
//
|
||||
// Read firmware image from the binary file.
|
||||
//
|
||||
void radio_read_image(char *filename)
|
||||
void radio_read_image(const char *filename)
|
||||
{
|
||||
FILE *img;
|
||||
struct stat st;
|
||||
@ -171,7 +171,7 @@ void radio_read_image(char *filename)
|
||||
//
|
||||
// Save firmware image to the binary file.
|
||||
//
|
||||
void radio_save_image(char *filename)
|
||||
void radio_save_image(const char *filename)
|
||||
{
|
||||
FILE *img;
|
||||
|
||||
@ -188,7 +188,7 @@ void radio_save_image(char *filename)
|
||||
//
|
||||
// Read the configuration from text file, and modify the firmware.
|
||||
//
|
||||
void radio_parse_config(char *filename)
|
||||
void radio_parse_config(const char *filename)
|
||||
{
|
||||
FILE *conf;
|
||||
char line [256], *p, *v;
|
||||
@ -300,3 +300,26 @@ void radio_verify_config()
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Update contacts database on the device.
|
||||
//
|
||||
void radio_write_csv(const char *filename)
|
||||
{
|
||||
FILE *csv;
|
||||
|
||||
if (!device->write_csv) {
|
||||
fprintf(stderr, "%s does not support CSV database.\n", device->name);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
csv = fopen(filename, "rb");
|
||||
if (! csv) {
|
||||
perror(filename);
|
||||
exit(-1);
|
||||
}
|
||||
fprintf(stderr, "Read file '%s'.\n", filename);
|
||||
|
||||
device->write_csv(device, csv);
|
||||
fclose(csv);
|
||||
}
|
||||
|
14
radio.h
14
radio.h
@ -60,22 +60,27 @@ void radio_print_config(FILE *out, int verbose);
|
||||
//
|
||||
// Read firmware image from the binary file.
|
||||
//
|
||||
void radio_read_image(char *filename);
|
||||
void radio_read_image(const char *filename);
|
||||
|
||||
//
|
||||
// Save firmware image to the binary file.
|
||||
//
|
||||
void radio_save_image(char *filename);
|
||||
void radio_save_image(const char *filename);
|
||||
|
||||
//
|
||||
// Read the configuration from text file, and modify the firmware.
|
||||
//
|
||||
void radio_parse_config(char *filename);
|
||||
void radio_parse_config(const char *filename);
|
||||
|
||||
//
|
||||
// Check the configuration.
|
||||
//
|
||||
void radio_verify_config();
|
||||
void radio_verify_config(void);
|
||||
|
||||
//
|
||||
// Update CSV contacts database.
|
||||
//
|
||||
void radio_write_csv(const char *filename);
|
||||
|
||||
//
|
||||
// Device-dependent interface to the radio.
|
||||
@ -95,6 +100,7 @@ struct _radio_device_t {
|
||||
int (*parse_header)(radio_device_t *radio, char *line);
|
||||
int (*parse_row)(radio_device_t *radio, int table_id, int first_row, char *line);
|
||||
void (*update_timestamp)(radio_device_t *radio);
|
||||
void (*write_csv)(radio_device_t *radio, FILE *csv);
|
||||
int channel_count;
|
||||
};
|
||||
|
||||
|
2
util.h
2
util.h
@ -60,7 +60,7 @@ void print_hex(const unsigned char *data, int len);
|
||||
//
|
||||
const char *dfu_init(unsigned vid, unsigned pid);
|
||||
void dfu_close(void);
|
||||
void dfu_erase(int nbytes);
|
||||
void dfu_erase(unsigned start, unsigned finish);
|
||||
void dfu_read_block(int bno, unsigned char *data, int nbytes);
|
||||
void dfu_write_block(int bno, unsigned char *data, int nbytes);
|
||||
void dfu_reboot(void);
|
||||
|
114
uv380.c
114
uv380.c
@ -52,6 +52,9 @@
|
||||
#define OFFSET_CHANNELS 0x40000
|
||||
#define OFFSET_CONTACTS 0x70000
|
||||
|
||||
#define CALLSIGN_START 0x00200000 // Start of callsign database
|
||||
#define CALLSIGN_FINISH 0x01000000 // End of callsign database
|
||||
|
||||
#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])
|
||||
@ -61,6 +64,7 @@
|
||||
#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])
|
||||
#define GET_CALLSIGN(m,i) ((callsign_t*) ((m) + 0x4003 + (i)*120))
|
||||
|
||||
#define VALID_TEXT(txt) (*(txt) != 0 && *(txt) != 0xffff)
|
||||
#define VALID_CHANNEL(ch) VALID_TEXT((ch)->name)
|
||||
@ -343,6 +347,16 @@ typedef struct {
|
||||
uint16_t radio_name[16];
|
||||
} general_settings_t;
|
||||
|
||||
//
|
||||
// Callsign database (CSV).
|
||||
//
|
||||
typedef struct {
|
||||
unsigned dmrid : 24; // DMR id
|
||||
unsigned _unused : 8; // 0xff
|
||||
char callsign[16]; // ascii zero terminated
|
||||
char name[100]; // name, nickname, city, state, country
|
||||
} callsign_t;
|
||||
|
||||
static const char *POWER_NAME[] = { "Low", "Low", "Mid", "High" };
|
||||
static const char *BANDWIDTH[] = { "12.5", "20", "25", "25" };
|
||||
static const char *CONTACT_TYPE[] = { "-", "Group", "Private", "All" };
|
||||
@ -402,7 +416,7 @@ static void uv380_upload(radio_device_t *radio, int cont_flag)
|
||||
{
|
||||
int bno;
|
||||
|
||||
dfu_erase(MEMSZ);
|
||||
dfu_erase(0, MEMSZ);
|
||||
|
||||
for (bno=0; bno<MEMSZ/1024; bno++) {
|
||||
dfu_write_block(bno, &radio_mem[bno*1024], 1024);
|
||||
@ -2383,6 +2397,103 @@ static int uv380_verify_config(radio_device_t *radio)
|
||||
return 1;
|
||||
}
|
||||
|
||||
//
|
||||
// Write CSV file to contacts database.
|
||||
//
|
||||
static void uv380_write_csv(radio_device_t *radio, FILE *csv)
|
||||
{
|
||||
uint8_t *mem;
|
||||
char line[256], *callsign, *name;
|
||||
int id, bno, nbytes, nrecords = 0;
|
||||
callsign_t *cs;
|
||||
|
||||
// Allocate 14Mbytes of memory.
|
||||
nbytes = CALLSIGN_FINISH - CALLSIGN_START;
|
||||
mem = malloc(nbytes);
|
||||
if (!mem) {
|
||||
fprintf(stderr, "Out of memory!\n");
|
||||
return;
|
||||
}
|
||||
memset(mem, 0xff, nbytes);
|
||||
|
||||
// Parse CSV file.
|
||||
while (fgets(line, sizeof(line), csv)) {
|
||||
if (line[0] < '0' || line[0] > '9') {
|
||||
// Skip header.
|
||||
continue;
|
||||
}
|
||||
|
||||
id = strtoul(line, 0, 10);
|
||||
if (id < 1 || id > 0xffffff) {
|
||||
fprintf(stderr, "Bad id: %d\n", id);
|
||||
fprintf(stderr, "Line: '%s'\n", line);
|
||||
return;
|
||||
}
|
||||
|
||||
callsign = strchr(line, ',');
|
||||
if (! callsign) {
|
||||
fprintf(stderr, "Cannot find callsign!\n");
|
||||
fprintf(stderr, "Line: '%s'\n", line);
|
||||
return;
|
||||
}
|
||||
*callsign++ = 0;
|
||||
|
||||
name = strchr(callsign, ',');
|
||||
if (! name) {
|
||||
fprintf(stderr, "Cannot find name!\n");
|
||||
fprintf(stderr, "Line: '%s,%s'\n", line, callsign);
|
||||
return;
|
||||
}
|
||||
*name++ = 0;
|
||||
|
||||
//printf("%-10d%-10s%s", id, callsign, name);
|
||||
cs = GET_CALLSIGN(mem, nrecords);
|
||||
nrecords++;
|
||||
|
||||
// Fill callsign structure.
|
||||
cs->dmrid = id;
|
||||
strncpy(cs->callsign, callsign, sizeof(cs->callsign));
|
||||
strncpy(cs->name, name, sizeof(cs->name));
|
||||
}
|
||||
fprintf(stderr, "Total %d contacts.\n", nrecords);
|
||||
|
||||
// Preserve 1kbyte at 0x0200000-0x02003ff.
|
||||
//dfu_read_block(CALLSIGN_START/1024, &mem[0], 1024);
|
||||
|
||||
// Number of contacts.
|
||||
mem[0] = nrecords >> 16;
|
||||
mem[1] = nrecords >> 8;
|
||||
mem[2] = nrecords;
|
||||
|
||||
radio_progress = 0;
|
||||
if (! trace_flag) {
|
||||
fprintf(stderr, "Erase contacts: ");
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
// Erase whole region.
|
||||
dfu_erase(CALLSIGN_START, CALLSIGN_FINISH);
|
||||
if (! trace_flag) {
|
||||
fprintf(stderr, " done.\n");
|
||||
fprintf(stderr, "Write contacts: ");
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
// Write callsigns.
|
||||
for (bno = CALLSIGN_START/1024; bno < CALLSIGN_FINISH/1024; bno++) {
|
||||
dfu_write_block(bno, &mem[bno*1024 - CALLSIGN_START], 1024);
|
||||
|
||||
++radio_progress;
|
||||
if (radio_progress % 512 == 0) {
|
||||
fprintf(stderr, "#");
|
||||
fflush(stderr);
|
||||
}
|
||||
}
|
||||
if (! trace_flag)
|
||||
fprintf(stderr, " done.\n");
|
||||
free(mem);
|
||||
}
|
||||
|
||||
//
|
||||
// TYT MD-UV380
|
||||
//
|
||||
@ -2400,6 +2511,7 @@ radio_device_t radio_uv380 = {
|
||||
uv380_parse_header,
|
||||
uv380_parse_row,
|
||||
uv380_update_timestamp,
|
||||
uv380_write_csv,
|
||||
};
|
||||
|
||||
//
|
||||
|
Loading…
Reference in New Issue
Block a user