Parse Name and ID.
Update timestamp.
This commit is contained in:
parent
7c8c7148a5
commit
6212fac6af
209
md380.c
209
md380.c
@ -42,9 +42,8 @@
|
|||||||
#define NMESSAGES 50
|
#define NMESSAGES 50
|
||||||
|
|
||||||
#define MEMSZ 0x40000
|
#define MEMSZ 0x40000
|
||||||
#define OFFSET_VERSION 0x02001
|
#define OFFSET_TIMESTMP 0x02001
|
||||||
#define OFFSET_ID 0x02084
|
#define OFFSET_SETTINGS 0x02040
|
||||||
#define OFFSET_NAME 0x020b0
|
|
||||||
#define OFFSET_MSG 0x02180
|
#define OFFSET_MSG 0x02180
|
||||||
#define OFFSET_CONTACTS 0x05f80
|
#define OFFSET_CONTACTS 0x05f80
|
||||||
#define OFFSET_GLISTS 0x0ec20
|
#define OFFSET_GLISTS 0x0ec20
|
||||||
@ -227,6 +226,86 @@ typedef struct {
|
|||||||
uint16_t member[31]; // Channels
|
uint16_t member[31]; // Channels
|
||||||
} scanlist_t;
|
} scanlist_t;
|
||||||
|
|
||||||
|
//
|
||||||
|
// General settings.
|
||||||
|
// TODO: verify the general settings with CPS
|
||||||
|
//
|
||||||
|
typedef struct {
|
||||||
|
|
||||||
|
// Bytes 0-19
|
||||||
|
uint16_t intro_screen_line1[10];
|
||||||
|
|
||||||
|
// Bytes 20-39
|
||||||
|
uint16_t intro_screen_line2[10];
|
||||||
|
|
||||||
|
// Bytes 40-63
|
||||||
|
uint8_t _unused40[24];
|
||||||
|
|
||||||
|
// Byte 64
|
||||||
|
uint8_t _unused64_0 : 3,
|
||||||
|
monitor_type : 1,
|
||||||
|
_unused64_4 : 1,
|
||||||
|
disable_all_leds : 1,
|
||||||
|
_unused64_6 : 2;
|
||||||
|
|
||||||
|
// Byte 65
|
||||||
|
uint8_t talk_permit_tone : 2,
|
||||||
|
pw_and_lock_enable : 1,
|
||||||
|
ch_free_indication_tone : 1,
|
||||||
|
_unused65_4 : 1,
|
||||||
|
disable_all_tones : 1,
|
||||||
|
save_mode_receive : 1,
|
||||||
|
save_preamble : 1;
|
||||||
|
|
||||||
|
// Byte 66
|
||||||
|
uint8_t _unused66_0 : 2,
|
||||||
|
keypad_tones : 1,
|
||||||
|
intro_screen : 1,
|
||||||
|
_unused66_4 : 4;
|
||||||
|
|
||||||
|
// Byte 67
|
||||||
|
uint8_t _unused67;
|
||||||
|
|
||||||
|
// Bytes 68-71
|
||||||
|
uint8_t radio_id[3];
|
||||||
|
uint8_t _unused71;
|
||||||
|
|
||||||
|
// Bytes 72-84
|
||||||
|
uint8_t tx_preamble_duration;
|
||||||
|
uint8_t group_call_hang_time;
|
||||||
|
uint8_t private_call_hang_time;
|
||||||
|
uint8_t vox_sensitivity;
|
||||||
|
uint8_t _unused76[2];
|
||||||
|
uint8_t rx_low_battery_interval;
|
||||||
|
uint8_t call_alert_tone_duration;
|
||||||
|
uint8_t lone_worker_response_time;
|
||||||
|
uint8_t lone_worker_reminder_time;
|
||||||
|
uint8_t _unused82;
|
||||||
|
uint8_t scan_digital_hang_time;
|
||||||
|
uint8_t scan_analog_hang_time;
|
||||||
|
|
||||||
|
// Byte 85
|
||||||
|
uint8_t _unused85_0 : 6,
|
||||||
|
backlight_time : 2;
|
||||||
|
|
||||||
|
// Bytes 86-87
|
||||||
|
uint8_t set_keypad_lock_time;
|
||||||
|
uint8_t mode;
|
||||||
|
|
||||||
|
// Bytes 88-95
|
||||||
|
uint32_t power_on_password;
|
||||||
|
uint32_t radio_prog_password;
|
||||||
|
|
||||||
|
// Bytes 96-103
|
||||||
|
uint8_t pc_prog_password[8];
|
||||||
|
|
||||||
|
// Bytes 104-111
|
||||||
|
uint8_t _unused104[8];
|
||||||
|
|
||||||
|
// Bytes 112-143
|
||||||
|
uint16_t radio_name[16];
|
||||||
|
} general_settings_t;
|
||||||
|
|
||||||
static const char *POWER_NAME[] = { "Low", "High" };
|
static const char *POWER_NAME[] = { "Low", "High" };
|
||||||
static const char *SQUELCH_NAME[] = { "Tight", "Normal" };
|
static const char *SQUELCH_NAME[] = { "Tight", "Normal" };
|
||||||
static const char *BANDWIDTH[] = { "12.5", "20", "25" };
|
static const char *BANDWIDTH[] = { "12.5", "20", "25" };
|
||||||
@ -502,25 +581,27 @@ static void print_chanlist(FILE *out, uint16_t *unsorted, int nchan)
|
|||||||
|
|
||||||
static void print_id(FILE *out)
|
static void print_id(FILE *out)
|
||||||
{
|
{
|
||||||
const unsigned char *data = &radio_mem[OFFSET_VERSION];
|
general_settings_t *gs = (general_settings_t*) &radio_mem[OFFSET_SETTINGS];
|
||||||
|
unsigned id = gs->radio_id[0] | (gs->radio_id[1] << 8) | (gs->radio_id[2] << 16);
|
||||||
|
unsigned char *timestamp = &radio_mem[OFFSET_TIMESTMP];
|
||||||
|
|
||||||
fprintf(out, "Name: ");
|
fprintf(out, "Name: ");
|
||||||
if (radio_mem[OFFSET_NAME] != 0 && *(uint16_t*)&radio_mem[OFFSET_NAME] != 0xffff) {
|
if (gs->radio_name[0] != 0 && gs->radio_name[0] != 0xffff) {
|
||||||
print_unicode(out, (uint16_t*) &radio_mem[OFFSET_NAME], 16, 0);
|
print_unicode(out, gs->radio_name, 16, 0);
|
||||||
} else {
|
} else {
|
||||||
fprintf(out, "-");
|
fprintf(out, "-");
|
||||||
}
|
}
|
||||||
fprintf(out, "\nID: %u\n", *(uint32_t*) &radio_mem[OFFSET_ID] & 0xffffff);
|
fprintf(out, "\nID: %u\n", id);
|
||||||
|
|
||||||
if (*data != 0xff) {
|
if (*timestamp != 0xff) {
|
||||||
fprintf(out, "Last Programmed Date: %d%d%d%d-%d%d-%d%d",
|
fprintf(out, "Last Programmed Date: %d%d%d%d-%d%d-%d%d",
|
||||||
data[0] >> 4, data[0] & 15, data[1] >> 4, data[1] & 15,
|
timestamp[0] >> 4, timestamp[0] & 15, timestamp[1] >> 4, timestamp[1] & 15,
|
||||||
data[2] >> 4, data[2] & 15, data[3] >> 4, data[3] & 15);
|
timestamp[2] >> 4, timestamp[2] & 15, timestamp[3] >> 4, timestamp[3] & 15);
|
||||||
fprintf(out, " %d%d:%d%d:%d%d\n",
|
fprintf(out, " %d%d:%d%d:%d%d\n",
|
||||||
data[4] >> 4, data[4] & 15, data[5] >> 4, data[5] & 15,
|
timestamp[4] >> 4, timestamp[4] & 15, timestamp[5] >> 4, timestamp[5] & 15,
|
||||||
data[6] >> 4, data[6] & 15);
|
timestamp[6] >> 4, timestamp[6] & 15);
|
||||||
fprintf(out, "CPS Software Version: V%x%x.%x%x\n",
|
fprintf(out, "CPS Software Version: V%x%x.%x%x\n",
|
||||||
data[7], data[8], data[9], data[10]);
|
timestamp[7], timestamp[8], timestamp[9], timestamp[10]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1078,6 +1159,8 @@ static void md380_save_image(radio_device_t *radio, FILE *img)
|
|||||||
//
|
//
|
||||||
static void md380_parse_parameter(radio_device_t *radio, char *param, char *value)
|
static void md380_parse_parameter(radio_device_t *radio, char *param, char *value)
|
||||||
{
|
{
|
||||||
|
general_settings_t *gs = (general_settings_t*) &radio_mem[OFFSET_SETTINGS];
|
||||||
|
|
||||||
if (strcasecmp("Radio", param) == 0) {
|
if (strcasecmp("Radio", param) == 0) {
|
||||||
if (strcasecmp(radio->name, value) != 0) {
|
if (strcasecmp(radio->name, value) != 0) {
|
||||||
fprintf(stderr, "Bad value for %s: %s\n", param, value);
|
fprintf(stderr, "Bad value for %s: %s\n", param, value);
|
||||||
@ -1085,6 +1168,29 @@ static void md380_parse_parameter(radio_device_t *radio, char *param, char *valu
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (strcasecmp ("Name", param) == 0) {
|
||||||
|
// Decode utf8 text to ucs2.
|
||||||
|
utf8_decode(gs->radio_name, value, 16);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcasecmp ("ID", param) == 0) {
|
||||||
|
uint32_t id = strtoul(value, 0, 0);
|
||||||
|
gs->radio_id[0] = id;
|
||||||
|
gs->radio_id[1] = id >> 8;
|
||||||
|
gs->radio_id[2] = id >> 16;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcasecmp ("Last Programmed Date", param) == 0) {
|
||||||
|
// Ignore.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (strcasecmp ("CPS Software Version", param) == 0) {
|
||||||
|
// Ignore.
|
||||||
|
return;
|
||||||
|
}
|
||||||
fprintf(stderr, "Unknown parameter: %s = %s\n", param, value);
|
fprintf(stderr, "Unknown parameter: %s = %s\n", param, value);
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
@ -1096,7 +1202,21 @@ static void md380_parse_parameter(radio_device_t *radio, char *param, char *valu
|
|||||||
//
|
//
|
||||||
static int parse_digital_channel(int first_row, char *line)
|
static int parse_digital_channel(int first_row, char *line)
|
||||||
{
|
{
|
||||||
//TODO: parse digital channel
|
//TODO: parse digital channel Name
|
||||||
|
//TODO: parse digital channel Receive
|
||||||
|
//TODO: parse digital channel Transmit
|
||||||
|
//TODO: parse digital channel Power
|
||||||
|
//TODO: parse digital channel Scan
|
||||||
|
//TODO: parse digital channel AS
|
||||||
|
//TODO: parse digital channel Sq
|
||||||
|
//TODO: parse digital channel TOT
|
||||||
|
//TODO: parse digital channel RO
|
||||||
|
//TODO: parse digital channel Admit
|
||||||
|
//TODO: parse digital channel Color
|
||||||
|
//TODO: parse digital channel Slot
|
||||||
|
//TODO: parse digital channel InCall
|
||||||
|
//TODO: parse digital channel RxGL
|
||||||
|
//TODO: parse digital channel TxContact
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1108,7 +1228,19 @@ static int parse_digital_channel(int first_row, char *line)
|
|||||||
static int parse_analog_channel(int first_row, char *line)
|
static int parse_analog_channel(int first_row, char *line)
|
||||||
{
|
{
|
||||||
#if 1
|
#if 1
|
||||||
//TODO: parse analog channel
|
//TODO: parse analog channel Name
|
||||||
|
//TODO: parse analog channel Receive
|
||||||
|
//TODO: parse analog channel Transmit
|
||||||
|
//TODO: parse analog channel Power
|
||||||
|
//TODO: parse analog channel Scan
|
||||||
|
//TODO: parse analog channel AS
|
||||||
|
//TODO: parse analog channel Sq
|
||||||
|
//TODO: parse analog channel TOT
|
||||||
|
//TODO: parse analog channel RO
|
||||||
|
//TODO: parse analog channel Admit
|
||||||
|
//TODO: parse analog channel RxTone
|
||||||
|
//TODO: parse analog channel TxTone
|
||||||
|
//TODO: parse analog channel Width
|
||||||
return 0;
|
return 0;
|
||||||
#else
|
#else
|
||||||
char num_str[256], name_str[256], rxfreq_str[256], offset_str[256];
|
char num_str[256], name_str[256], rxfreq_str[256], offset_str[256];
|
||||||
@ -1272,7 +1404,11 @@ static int parse_zones(int first_row, char *line)
|
|||||||
//
|
//
|
||||||
static int parse_scanlist(int first_row, char *line)
|
static int parse_scanlist(int first_row, char *line)
|
||||||
{
|
{
|
||||||
//TODO: parse scanlist
|
//TODO: parse scanlist Name
|
||||||
|
//TODO: parse scanlist PCh1
|
||||||
|
//TODO: parse scanlist PCh2
|
||||||
|
//TODO: parse scanlist TxCh
|
||||||
|
//TODO: parse scanlist Channels
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1282,7 +1418,10 @@ static int parse_scanlist(int first_row, char *line)
|
|||||||
//
|
//
|
||||||
static int parse_contact(int first_row, char *line)
|
static int parse_contact(int first_row, char *line)
|
||||||
{
|
{
|
||||||
//TODO: parse contact
|
//TODO: parse contact Name
|
||||||
|
//TODO: parse contact Type
|
||||||
|
//TODO: parse contact ID
|
||||||
|
//TODO: parse contact RxTone
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1292,7 +1431,7 @@ static int parse_contact(int first_row, char *line)
|
|||||||
//
|
//
|
||||||
static int parse_grouplist(int first_row, char *line)
|
static int parse_grouplist(int first_row, char *line)
|
||||||
{
|
{
|
||||||
//TODO: parse grouplist
|
//TODO: parse grouplist Contacts
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1334,6 +1473,39 @@ static int md380_parse_row(radio_device_t *radio, int table_id, int first_row, c
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Update timestamp.
|
||||||
|
//
|
||||||
|
static void md380_update_timestamp(radio_device_t *radio)
|
||||||
|
{
|
||||||
|
unsigned char *timestamp = &radio_mem[OFFSET_TIMESTMP];
|
||||||
|
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; // D means Dmrconfig
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// TYT MD-380
|
// TYT MD-380
|
||||||
//
|
//
|
||||||
@ -1349,4 +1521,5 @@ radio_device_t radio_md380 = {
|
|||||||
md380_parse_parameter,
|
md380_parse_parameter,
|
||||||
md380_parse_header,
|
md380_parse_header,
|
||||||
md380_parse_row,
|
md380_parse_row,
|
||||||
|
md380_update_timestamp,
|
||||||
};
|
};
|
||||||
|
1
radio.c
1
radio.c
@ -257,6 +257,7 @@ badline: fprintf(stderr, "Invalid line: '%s'\n", line);
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
fclose(conf);
|
fclose(conf);
|
||||||
|
device->update_timestamp(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
1
radio.h
1
radio.h
@ -88,6 +88,7 @@ struct _radio_device_t {
|
|||||||
void (*parse_parameter)(radio_device_t *radio, char *param, char *value);
|
void (*parse_parameter)(radio_device_t *radio, char *param, char *value);
|
||||||
int (*parse_header)(radio_device_t *radio, char *line);
|
int (*parse_header)(radio_device_t *radio, char *line);
|
||||||
int (*parse_row)(radio_device_t *radio, int table_id, int first_row, char *line);
|
int (*parse_row)(radio_device_t *radio, int table_id, int first_row, char *line);
|
||||||
|
void (*update_timestamp)(radio_device_t *radio);
|
||||||
};
|
};
|
||||||
|
|
||||||
extern radio_device_t radio_md380; // TYT MD-380
|
extern radio_device_t radio_md380; // TYT MD-380
|
||||||
|
52
util.c
52
util.c
@ -30,6 +30,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <time.h>
|
||||||
#ifdef MINGW32
|
#ifdef MINGW32
|
||||||
# include <windows.h>
|
# include <windows.h>
|
||||||
#else
|
#else
|
||||||
@ -231,3 +232,54 @@ void print_unicode(FILE *out, const unsigned short *text, unsigned nchars, int f
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Get local time in format: YYYYMMDDhhmmss
|
||||||
|
//
|
||||||
|
void get_timestamp(char p[16])
|
||||||
|
{
|
||||||
|
time_t now = time(NULL);
|
||||||
|
struct tm *local = localtime(&now);
|
||||||
|
|
||||||
|
if (! local) {
|
||||||
|
perror("localtime");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
if (!strftime(p, 16, "%Y%m%d%H%M%S", local)) {
|
||||||
|
perror("strftime");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Fetch Unicode symbol from UTF-8 string.
|
||||||
|
// Advance string pointer.
|
||||||
|
//
|
||||||
|
int utf8_to_unicode(const char **p)
|
||||||
|
{
|
||||||
|
int c1, c2, c3;
|
||||||
|
|
||||||
|
c1 = (unsigned char) *(*p)++;
|
||||||
|
if (! (c1 & 0x80))
|
||||||
|
return c1;
|
||||||
|
c2 = (unsigned char) *(*p)++;
|
||||||
|
if (! (c1 & 0x20))
|
||||||
|
return (c1 & 0x1f) << 6 | (c2 & 0x3f);
|
||||||
|
c3 = (unsigned char) *(*p)++;
|
||||||
|
return (c1 & 0x0f) << 12 | (c2 & 0x3f) << 6 | (c3 & 0x3f);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Decode UTF-8 string into UCS-2 string, at most nsym characters.
|
||||||
|
//
|
||||||
|
void utf8_decode(unsigned short *dst, const char *src, unsigned nsym)
|
||||||
|
{
|
||||||
|
for (; nsym > 0; nsym--) {
|
||||||
|
if ((*dst++ = utf8_to_unicode(&src)) == 0) {
|
||||||
|
// Clear the remaining bytes.
|
||||||
|
while (--nsym > 0)
|
||||||
|
*dst++ = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
16
util.h
16
util.h
@ -129,3 +129,19 @@ void putc_utf8(unsigned short ch, FILE *out);
|
|||||||
// Print utf16 text as utf8.
|
// Print utf16 text as utf8.
|
||||||
//
|
//
|
||||||
void print_unicode(FILE *out, const unsigned short *text, unsigned nchars, int fill_flag);
|
void print_unicode(FILE *out, const unsigned short *text, unsigned nchars, int fill_flag);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Fetch Unicode symbol from UTF-8 string.
|
||||||
|
// Advance string pointer.
|
||||||
|
//
|
||||||
|
int utf8_to_unicode(const char **p);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Decode UTF-8 string into UCS-2 string, at most nsym characters.
|
||||||
|
//
|
||||||
|
void utf8_decode(unsigned short *dst, const char *src, unsigned nsym);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Get local time in format: YYYYMMDDhhmmss
|
||||||
|
//
|
||||||
|
void get_timestamp(char p[16]);
|
||||||
|
210
uv380.c
210
uv380.c
@ -42,9 +42,8 @@
|
|||||||
#define NMESSAGES 50
|
#define NMESSAGES 50
|
||||||
|
|
||||||
#define MEMSZ 0xd0000
|
#define MEMSZ 0xd0000
|
||||||
#define OFFSET_VERSION 0x02001
|
#define OFFSET_TIMESTMP 0x02001
|
||||||
#define OFFSET_ID 0x02084
|
#define OFFSET_SETTINGS 0x02040
|
||||||
#define OFFSET_NAME 0x020b0
|
|
||||||
#define OFFSET_MSG 0x02180
|
#define OFFSET_MSG 0x02180
|
||||||
#define OFFSET_GLISTS 0x0ec20
|
#define OFFSET_GLISTS 0x0ec20
|
||||||
#define OFFSET_ZONES 0x149e0
|
#define OFFSET_ZONES 0x149e0
|
||||||
@ -245,6 +244,86 @@ typedef struct {
|
|||||||
uint16_t member[31]; // Channels
|
uint16_t member[31]; // Channels
|
||||||
} scanlist_t;
|
} scanlist_t;
|
||||||
|
|
||||||
|
//
|
||||||
|
// General settings.
|
||||||
|
// TODO: verify the general settings with CPS
|
||||||
|
//
|
||||||
|
typedef struct {
|
||||||
|
|
||||||
|
// Bytes 0-19
|
||||||
|
uint16_t intro_screen_line1[10];
|
||||||
|
|
||||||
|
// Bytes 20-39
|
||||||
|
uint16_t intro_screen_line2[10];
|
||||||
|
|
||||||
|
// Bytes 40-63
|
||||||
|
uint8_t _unused40[24];
|
||||||
|
|
||||||
|
// Byte 64
|
||||||
|
uint8_t _unused64_0 : 3,
|
||||||
|
monitor_type : 1,
|
||||||
|
_unused64_4 : 1,
|
||||||
|
disable_all_leds : 1,
|
||||||
|
_unused64_6 : 2;
|
||||||
|
|
||||||
|
// Byte 65
|
||||||
|
uint8_t talk_permit_tone : 2,
|
||||||
|
pw_and_lock_enable : 1,
|
||||||
|
ch_free_indication_tone : 1,
|
||||||
|
_unused65_4 : 1,
|
||||||
|
disable_all_tones : 1,
|
||||||
|
save_mode_receive : 1,
|
||||||
|
save_preamble : 1;
|
||||||
|
|
||||||
|
// Byte 66
|
||||||
|
uint8_t _unused66_0 : 2,
|
||||||
|
keypad_tones : 1,
|
||||||
|
intro_screen : 1,
|
||||||
|
_unused66_4 : 4;
|
||||||
|
|
||||||
|
// Byte 67
|
||||||
|
uint8_t _unused67;
|
||||||
|
|
||||||
|
// Bytes 68-71
|
||||||
|
uint8_t radio_id[3];
|
||||||
|
uint8_t _unused71;
|
||||||
|
|
||||||
|
// Bytes 72-84
|
||||||
|
uint8_t tx_preamble_duration;
|
||||||
|
uint8_t group_call_hang_time;
|
||||||
|
uint8_t private_call_hang_time;
|
||||||
|
uint8_t vox_sensitivity;
|
||||||
|
uint8_t _unused76[2];
|
||||||
|
uint8_t rx_low_battery_interval;
|
||||||
|
uint8_t call_alert_tone_duration;
|
||||||
|
uint8_t lone_worker_response_time;
|
||||||
|
uint8_t lone_worker_reminder_time;
|
||||||
|
uint8_t _unused82;
|
||||||
|
uint8_t scan_digital_hang_time;
|
||||||
|
uint8_t scan_analog_hang_time;
|
||||||
|
|
||||||
|
// Byte 85
|
||||||
|
uint8_t _unused85_0 : 6,
|
||||||
|
backlight_time : 2;
|
||||||
|
|
||||||
|
// Bytes 86-87
|
||||||
|
uint8_t set_keypad_lock_time;
|
||||||
|
uint8_t mode;
|
||||||
|
|
||||||
|
// Bytes 88-95
|
||||||
|
uint32_t power_on_password;
|
||||||
|
uint32_t radio_prog_password;
|
||||||
|
|
||||||
|
// Bytes 96-103
|
||||||
|
uint8_t pc_prog_password[8];
|
||||||
|
|
||||||
|
// Bytes 104-111
|
||||||
|
uint8_t _unused104[8];
|
||||||
|
|
||||||
|
// Bytes 112-143
|
||||||
|
uint16_t radio_name[16];
|
||||||
|
} general_settings_t;
|
||||||
|
|
||||||
static const char *POWER_NAME[] = { "Low", "???", "Mid", "High" };
|
static const char *POWER_NAME[] = { "Low", "???", "Mid", "High" };
|
||||||
static const char *BANDWIDTH[] = { "12.5", "20", "25" };
|
static const char *BANDWIDTH[] = { "12.5", "20", "25" };
|
||||||
static const char *CONTACT_TYPE[] = { "-", "Group", "Private", "All" };
|
static const char *CONTACT_TYPE[] = { "-", "Group", "Private", "All" };
|
||||||
@ -518,25 +597,27 @@ static void print_chanlist(FILE *out, uint16_t *unsorted, int nchan)
|
|||||||
|
|
||||||
static void print_id(FILE *out)
|
static void print_id(FILE *out)
|
||||||
{
|
{
|
||||||
const unsigned char *data = &radio_mem[OFFSET_VERSION];
|
general_settings_t *gs = (general_settings_t*) &radio_mem[OFFSET_SETTINGS];
|
||||||
|
unsigned id = gs->radio_id[0] | (gs->radio_id[1] << 8) | (gs->radio_id[2] << 16);
|
||||||
|
unsigned char *timestamp = &radio_mem[OFFSET_TIMESTMP];
|
||||||
|
|
||||||
fprintf(out, "Name: ");
|
fprintf(out, "Name: ");
|
||||||
if (radio_mem[OFFSET_NAME] != 0 && *(uint16_t*)&radio_mem[OFFSET_NAME] != 0xffff) {
|
if (gs->radio_name[0] != 0 && gs->radio_name[0] != 0xffff) {
|
||||||
print_unicode(out, (uint16_t*) &radio_mem[OFFSET_NAME], 16, 0);
|
print_unicode(out, gs->radio_name, 16, 0);
|
||||||
} else {
|
} else {
|
||||||
fprintf(out, "-");
|
fprintf(out, "-");
|
||||||
}
|
}
|
||||||
fprintf(out, "\nID: %u\n", *(uint32_t*) &radio_mem[OFFSET_ID] & 0xffffff);
|
fprintf(out, "\nID: %u\n", id);
|
||||||
|
|
||||||
if (*data != 0xff) {
|
if (*timestamp != 0xff) {
|
||||||
fprintf(out, "Last Programmed Date: %d%d%d%d-%d%d-%d%d",
|
fprintf(out, "Last Programmed Date: %d%d%d%d-%d%d-%d%d",
|
||||||
data[0] >> 4, data[0] & 15, data[1] >> 4, data[1] & 15,
|
timestamp[0] >> 4, timestamp[0] & 15, timestamp[1] >> 4, timestamp[1] & 15,
|
||||||
data[2] >> 4, data[2] & 15, data[3] >> 4, data[3] & 15);
|
timestamp[2] >> 4, timestamp[2] & 15, timestamp[3] >> 4, timestamp[3] & 15);
|
||||||
fprintf(out, " %d%d:%d%d:%d%d\n",
|
fprintf(out, " %d%d:%d%d:%d%d\n",
|
||||||
data[4] >> 4, data[4] & 15, data[5] >> 4, data[5] & 15,
|
timestamp[4] >> 4, timestamp[4] & 15, timestamp[5] >> 4, timestamp[5] & 15,
|
||||||
data[6] >> 4, data[6] & 15);
|
timestamp[6] >> 4, timestamp[6] & 15);
|
||||||
fprintf(out, "CPS Software Version: V%x%x.%x%x\n",
|
fprintf(out, "CPS Software Version: V%x%x.%x%x\n",
|
||||||
data[7], data[8], data[9], data[10]);
|
timestamp[7], timestamp[8], timestamp[9], timestamp[10]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1119,6 +1200,8 @@ static void uv380_save_image(radio_device_t *radio, FILE *img)
|
|||||||
//
|
//
|
||||||
static void uv380_parse_parameter(radio_device_t *radio, char *param, char *value)
|
static void uv380_parse_parameter(radio_device_t *radio, char *param, char *value)
|
||||||
{
|
{
|
||||||
|
general_settings_t *gs = (general_settings_t*) &radio_mem[OFFSET_SETTINGS];
|
||||||
|
|
||||||
if (strcasecmp("Radio", param) == 0) {
|
if (strcasecmp("Radio", param) == 0) {
|
||||||
// Accept either MD-2017 or MD-UV380.
|
// Accept either MD-2017 or MD-UV380.
|
||||||
if (strcasecmp("TYT MD-2017", value) != 0 &&
|
if (strcasecmp("TYT MD-2017", value) != 0 &&
|
||||||
@ -1128,6 +1211,29 @@ static void uv380_parse_parameter(radio_device_t *radio, char *param, char *valu
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (strcasecmp ("Name", param) == 0) {
|
||||||
|
// Decode utf8 text to ucs2.
|
||||||
|
utf8_decode(gs->radio_name, value, 16);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcasecmp ("ID", param) == 0) {
|
||||||
|
uint32_t id = strtoul(value, 0, 0);
|
||||||
|
gs->radio_id[0] = id;
|
||||||
|
gs->radio_id[1] = id >> 8;
|
||||||
|
gs->radio_id[2] = id >> 16;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcasecmp ("Last Programmed Date", param) == 0) {
|
||||||
|
// Ignore.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (strcasecmp ("CPS Software Version", param) == 0) {
|
||||||
|
// Ignore.
|
||||||
|
return;
|
||||||
|
}
|
||||||
fprintf(stderr, "Unknown parameter: %s = %s\n", param, value);
|
fprintf(stderr, "Unknown parameter: %s = %s\n", param, value);
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
@ -1139,7 +1245,21 @@ static void uv380_parse_parameter(radio_device_t *radio, char *param, char *valu
|
|||||||
//
|
//
|
||||||
static int parse_digital_channel(int first_row, char *line)
|
static int parse_digital_channel(int first_row, char *line)
|
||||||
{
|
{
|
||||||
//TODO: parse digital channel
|
//TODO: parse digital channel Name
|
||||||
|
//TODO: parse digital channel Receive
|
||||||
|
//TODO: parse digital channel Transmit
|
||||||
|
//TODO: parse digital channel Power
|
||||||
|
//TODO: parse digital channel Scan
|
||||||
|
//TODO: parse digital channel AS
|
||||||
|
//TODO: parse digital channel Sq
|
||||||
|
//TODO: parse digital channel TOT
|
||||||
|
//TODO: parse digital channel RO
|
||||||
|
//TODO: parse digital channel Admit
|
||||||
|
//TODO: parse digital channel Color
|
||||||
|
//TODO: parse digital channel Slot
|
||||||
|
//TODO: parse digital channel InCall
|
||||||
|
//TODO: parse digital channel RxGL
|
||||||
|
//TODO: parse digital channel TxContact
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1151,7 +1271,19 @@ static int parse_digital_channel(int first_row, char *line)
|
|||||||
static int parse_analog_channel(int first_row, char *line)
|
static int parse_analog_channel(int first_row, char *line)
|
||||||
{
|
{
|
||||||
#if 1
|
#if 1
|
||||||
//TODO: parse analog channel
|
//TODO: parse analog channel Name
|
||||||
|
//TODO: parse analog channel Receive
|
||||||
|
//TODO: parse analog channel Transmit
|
||||||
|
//TODO: parse analog channel Power
|
||||||
|
//TODO: parse analog channel Scan
|
||||||
|
//TODO: parse analog channel AS
|
||||||
|
//TODO: parse analog channel Sq
|
||||||
|
//TODO: parse analog channel TOT
|
||||||
|
//TODO: parse analog channel RO
|
||||||
|
//TODO: parse analog channel Admit
|
||||||
|
//TODO: parse analog channel RxTone
|
||||||
|
//TODO: parse analog channel TxTone
|
||||||
|
//TODO: parse analog channel Width
|
||||||
return 0;
|
return 0;
|
||||||
#else
|
#else
|
||||||
char num_str[256], name_str[256], rxfreq_str[256], offset_str[256];
|
char num_str[256], name_str[256], rxfreq_str[256], offset_str[256];
|
||||||
@ -1315,7 +1447,11 @@ static int parse_zones(int first_row, char *line)
|
|||||||
//
|
//
|
||||||
static int parse_scanlist(int first_row, char *line)
|
static int parse_scanlist(int first_row, char *line)
|
||||||
{
|
{
|
||||||
//TODO: parse scanlist
|
//TODO: parse scanlist Name
|
||||||
|
//TODO: parse scanlist PCh1
|
||||||
|
//TODO: parse scanlist PCh2
|
||||||
|
//TODO: parse scanlist TxCh
|
||||||
|
//TODO: parse scanlist Channels
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1325,7 +1461,10 @@ static int parse_scanlist(int first_row, char *line)
|
|||||||
//
|
//
|
||||||
static int parse_contact(int first_row, char *line)
|
static int parse_contact(int first_row, char *line)
|
||||||
{
|
{
|
||||||
//TODO: parse contact
|
//TODO: parse contact Name
|
||||||
|
//TODO: parse contact Type
|
||||||
|
//TODO: parse contact ID
|
||||||
|
//TODO: parse contact RxTone
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1335,7 +1474,7 @@ static int parse_contact(int first_row, char *line)
|
|||||||
//
|
//
|
||||||
static int parse_grouplist(int first_row, char *line)
|
static int parse_grouplist(int first_row, char *line)
|
||||||
{
|
{
|
||||||
//TODO: parse grouplist
|
//TODO: parse grouplist Contacts
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1377,6 +1516,39 @@ static int uv380_parse_row(radio_device_t *radio, int table_id, int first_row, c
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Update timestamp.
|
||||||
|
//
|
||||||
|
static void uv380_update_timestamp(radio_device_t *radio)
|
||||||
|
{
|
||||||
|
unsigned char *timestamp = &radio_mem[OFFSET_TIMESTMP];
|
||||||
|
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; // D means Dmrconfig
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// TYT MD-UV380
|
// TYT MD-UV380
|
||||||
//
|
//
|
||||||
@ -1392,6 +1564,7 @@ radio_device_t radio_uv380 = {
|
|||||||
uv380_parse_parameter,
|
uv380_parse_parameter,
|
||||||
uv380_parse_header,
|
uv380_parse_header,
|
||||||
uv380_parse_row,
|
uv380_parse_row,
|
||||||
|
uv380_update_timestamp,
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -1409,4 +1582,5 @@ radio_device_t radio_md2017 = {
|
|||||||
uv380_parse_parameter,
|
uv380_parse_parameter,
|
||||||
uv380_parse_header,
|
uv380_parse_header,
|
||||||
uv380_parse_row,
|
uv380_parse_row,
|
||||||
|
uv380_update_timestamp,
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user