parent
8036b7eca1
commit
1ace589916
@ -0,0 +1,748 @@
|
||||
/*
|
||||
* Copyright 2017 by Thomas Early, AC2IE
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <termios.h>
|
||||
#include <time.h>
|
||||
#include <sys/file.h>
|
||||
#include <atomic>
|
||||
#include "DVAPDongle.h"
|
||||
|
||||
extern std::atomic<bool> keep_running;
|
||||
|
||||
CDVAPDongle::CDVAPDongle() : MAX_REPL_CNT(20u)
|
||||
{
|
||||
}
|
||||
|
||||
CDVAPDongle::~CDVAPDongle()
|
||||
{
|
||||
}
|
||||
|
||||
bool CDVAPDongle::Initialize(char *serialno, int frequency, int offset, int power, int squelch)
|
||||
{
|
||||
bool ok = false;
|
||||
char device[128];
|
||||
|
||||
do {
|
||||
for (int i = 0; i < 32; i++) {
|
||||
sprintf(device, "/dev/ttyUSB%d", i);
|
||||
|
||||
if (access(device, R_OK | W_OK) != 0)
|
||||
continue;
|
||||
|
||||
ok = OpenSerial(device);
|
||||
if (!ok)
|
||||
continue;
|
||||
|
||||
if (flock(serfd, LOCK_EX | LOCK_NB) != 0) {
|
||||
close(serfd);
|
||||
serfd = -1;
|
||||
ok = false;
|
||||
traceit("Device %s is already locked/used\n", device);
|
||||
continue;
|
||||
}
|
||||
traceit("Device %s now locked for exclusive use\n", device);
|
||||
|
||||
ok = get_ser(device, serialno);
|
||||
if (!ok) {
|
||||
close(serfd);
|
||||
serfd = -1;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (!ok)
|
||||
break;
|
||||
|
||||
ok = get_name();
|
||||
if (!ok)
|
||||
break;
|
||||
|
||||
ok = get_fw();
|
||||
if (!ok)
|
||||
break;
|
||||
|
||||
|
||||
ok = set_modu();
|
||||
if (!ok)
|
||||
break;
|
||||
|
||||
ok = set_mode();
|
||||
if (!ok)
|
||||
break;
|
||||
|
||||
ok = set_sql(squelch);
|
||||
if (!ok)
|
||||
break;
|
||||
|
||||
ok = set_pwr(power);
|
||||
if (!ok)
|
||||
break;
|
||||
|
||||
ok = set_off(offset);
|
||||
if (!ok)
|
||||
break;
|
||||
|
||||
ok = set_freq(frequency);
|
||||
if (!ok)
|
||||
break;
|
||||
|
||||
ok = start_dvap();
|
||||
if (!ok)
|
||||
break;
|
||||
|
||||
} while (false);
|
||||
|
||||
if (!ok) {
|
||||
if (serfd != -1) {
|
||||
Stop();
|
||||
close(serfd);
|
||||
serfd = -1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
REPLY_TYPE CDVAPDongle::get_reply(SDVAP_REGISTER &dr)
|
||||
{
|
||||
dr.header = dr.param.control = 0;
|
||||
unsigned int off = 2;
|
||||
int rc = read_from_dvp(&dr.header, 2);
|
||||
if (rc == 0)
|
||||
return RT_TIMEOUT;
|
||||
if (rc != 2)
|
||||
return RT_ERR;
|
||||
|
||||
uint16_t len = dr.header & 0x1fff;
|
||||
if (len > 50) {
|
||||
syncit();
|
||||
return RT_TIMEOUT;
|
||||
}
|
||||
|
||||
while (off < len) {
|
||||
uint8_t *ptr = (uint8_t *)&dr;
|
||||
rc = read_from_dvp(ptr + off, len - off);
|
||||
if (rc < 0)
|
||||
return RT_TIMEOUT;
|
||||
if (rc > 0)
|
||||
off += rc;
|
||||
}
|
||||
|
||||
if (0x2007u==dr.header && 0x90u==dr.param.control)
|
||||
return RT_STS;
|
||||
else if (0xc012u==dr.header)
|
||||
return RT_DAT;
|
||||
else if (0xa02fu==dr.header)
|
||||
return RT_HDR;
|
||||
else if (0x602fu==dr.header)
|
||||
return RT_HDR_ACK;
|
||||
else if (0x2005u==dr.header && 0x118u==dr.param.control)
|
||||
return RT_PTT;
|
||||
else if (0x5u==dr.header && 0x18u==dr.param.control && 0x1==dr.param.byte)
|
||||
return RT_START;
|
||||
else if (0x5u==dr.header && 0x18u==dr.param.control && 0x0==dr.param.byte)
|
||||
return RT_STOP;
|
||||
else if (0x6u==dr.header && 0x400u==dr.param.control)
|
||||
return RT_OFF;
|
||||
else if (0x10u==dr.header && 0x1u==dr.param.control)
|
||||
return RT_NAME;
|
||||
else if (0xdu==dr.header && 0x2u==dr.param.control)
|
||||
return RT_SER;
|
||||
else if (0x7u==dr.header && 0x4u==dr.param.control && 0x1u==dr.param.ustr[0])
|
||||
return RT_FW;
|
||||
else if (0x8u==dr.header && 0x220u==dr.param.control)
|
||||
return RT_FREQ;
|
||||
else if (0xcu==dr.header && 0x230u==dr.param.control)
|
||||
return RT_FREQ_LIMIT;
|
||||
else if (0x5u==dr.header && 0x28u==dr.param.control && 0x1u==dr.param.ustr[0])
|
||||
return RT_MODU;
|
||||
else if (0x5u==dr.header && 0x2au==dr.param.control && 0x0u==dr.param.ustr[0])
|
||||
return RT_MODE;
|
||||
else if (0x6u==dr.header && 0x138u==dr.param.control)
|
||||
return RT_PWR;
|
||||
else if (0x5u== dr.header && 0x80u==dr.param.control)
|
||||
return RT_SQL;
|
||||
else {
|
||||
syncit();
|
||||
return RT_TIMEOUT;
|
||||
}
|
||||
|
||||
/* It should never get here */
|
||||
return RT_TIMEOUT;
|
||||
}
|
||||
|
||||
void CDVAPDongle::syncit()
|
||||
{
|
||||
unsigned char data[7];
|
||||
struct timeval tv;
|
||||
fd_set fds;
|
||||
short cnt = 0;
|
||||
|
||||
traceit("Starting syncing dvap\n");
|
||||
memset(data, 0x00, 7);
|
||||
dvapreg.header = 0x2007u;
|
||||
dvapreg.param.control = 0x90u;
|
||||
|
||||
while (memcmp(data, &dvapreg, 4) != 0) {
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(serfd, &fds);
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 1000;
|
||||
int n = select(serfd + 1, &fds, NULL, NULL, &tv);
|
||||
if (n <= 0) {
|
||||
cnt ++;
|
||||
if (cnt > 100) {
|
||||
traceit("dvap is not responding,...stopping\n");
|
||||
keep_running = false;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
unsigned char c;
|
||||
n = read_from_dvp(&c, 1);
|
||||
if (n > 0) {
|
||||
data[0] = data[1];
|
||||
data[1] = data[2];
|
||||
data[2] = data[3];
|
||||
data[3] = data[4];
|
||||
data[4] = data[5];
|
||||
data[5] = data[6];
|
||||
data[6] = c;
|
||||
|
||||
cnt = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
traceit("Stopping syncing dvap\n");
|
||||
return;
|
||||
}
|
||||
|
||||
bool CDVAPDongle::get_ser(char *dvp, char *dvap_serial_number)
|
||||
{
|
||||
unsigned cnt = 0;
|
||||
REPLY_TYPE reply;
|
||||
dvapreg.header = 0x2004u;
|
||||
dvapreg.param.control = 0x2u;
|
||||
|
||||
int rc = write_to_dvp(&dvapreg, 4);
|
||||
if (rc != 4) {
|
||||
traceit("Failed to send request to get dvap serial#\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
do {
|
||||
usleep(5000);
|
||||
|
||||
reply = get_reply(dvapreg);
|
||||
cnt ++;
|
||||
if (cnt >= MAX_REPL_CNT) {
|
||||
traceit("Reached max number of requests to receive dvap serial#\n");
|
||||
return false;
|
||||
}
|
||||
} while (reply != RT_SER);
|
||||
|
||||
if (0 == strcmp(dvapreg.param.sstr, dvap_serial_number)) {
|
||||
traceit("Using %s: %s, because serial number matches your dvap_rptr.cfg\n", dvp, dvap_serial_number);
|
||||
return true;
|
||||
}
|
||||
traceit("Device %s has serial %s, but does not match your config value %s\n", dvp, dvapreg.param.sstr, dvap_serial_number);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CDVAPDongle::get_name()
|
||||
{
|
||||
unsigned cnt = 0;
|
||||
REPLY_TYPE reply;
|
||||
dvapreg.header = 0x2004u;
|
||||
dvapreg.param.control = 0x1u;
|
||||
|
||||
int rc = write_to_dvp(&dvapreg, 4);
|
||||
if (rc != 4) {
|
||||
traceit("Failed to send request to get dvap name\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
do {
|
||||
usleep(5000);
|
||||
|
||||
reply = get_reply(dvapreg);
|
||||
cnt ++;
|
||||
if (cnt >= MAX_REPL_CNT) {
|
||||
traceit("Reached max number of requests to receive dvap name\n");
|
||||
return false;
|
||||
}
|
||||
} while (reply != RT_NAME);
|
||||
|
||||
if (0x10u!=dvapreg.header || 0x1u!=dvapreg.param.control || strncmp(dvapreg.param.sstr, "DVAP Dongle", 11)) {
|
||||
traceit("Failed to receive dvap name, got %s\n", dvapreg.param.sstr);
|
||||
return false;
|
||||
}
|
||||
|
||||
traceit("Device name: %.*s\n", 11, dvapreg.param.sstr);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDVAPDongle::get_fw()
|
||||
{
|
||||
unsigned cnt = 0;
|
||||
REPLY_TYPE reply;
|
||||
dvapreg.header = 0x2005u;
|
||||
dvapreg.param.control = 0x4u;
|
||||
dvapreg.param.ustr[0] = 0x1u;
|
||||
|
||||
int rc = write_to_dvp(&dvapreg, 5);
|
||||
if (rc != 5) {
|
||||
traceit("Failed to send request to get dvap fw\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
do {
|
||||
usleep(5000);
|
||||
|
||||
reply = get_reply(dvapreg);
|
||||
cnt ++;
|
||||
if (cnt >= MAX_REPL_CNT) {
|
||||
traceit("Reached max number of requests to receive dvap fw\n");
|
||||
return false;
|
||||
}
|
||||
} while (reply != RT_FW);
|
||||
|
||||
unsigned int ver = dvapreg.param.ustr[1] + 256 * dvapreg.param.ustr[2];
|
||||
traceit("dvap fw ver: %u.%u\n", ver / 100, ver % 100);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDVAPDongle::set_modu()
|
||||
{
|
||||
unsigned cnt = 0;
|
||||
REPLY_TYPE reply;
|
||||
dvapreg.header = 0x5u;
|
||||
dvapreg.param.control = 0x28u;
|
||||
dvapreg.param.ustr[0] = 0x1u;
|
||||
|
||||
int rc = write_to_dvp(&dvapreg, 5);
|
||||
if (rc != 5) {
|
||||
traceit("Failed to send request to set dvap modulation\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
do {
|
||||
usleep(5000);
|
||||
|
||||
reply = get_reply(dvapreg);
|
||||
|
||||
cnt ++;
|
||||
if (cnt >= MAX_REPL_CNT) {
|
||||
traceit("Reached max number of requests to set dvap modulation\n");
|
||||
return false;
|
||||
}
|
||||
} while (reply != RT_MODU);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDVAPDongle::set_mode()
|
||||
{
|
||||
unsigned cnt = 0;
|
||||
REPLY_TYPE reply;
|
||||
dvapreg.header = 0x5u;
|
||||
dvapreg.param.control = 0x2au;
|
||||
dvapreg.param.ustr[0] = 0x0u;
|
||||
|
||||
int rc = write_to_dvp(&dvapreg, 5);
|
||||
if (rc != 5) {
|
||||
traceit("Failed to send request to set dvap mode\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
do {
|
||||
usleep(5000);
|
||||
|
||||
reply = get_reply(dvapreg);
|
||||
|
||||
cnt ++;
|
||||
if (cnt >= MAX_REPL_CNT) {
|
||||
traceit("Reached max number of requests to set dvap mode\n");
|
||||
return false;
|
||||
}
|
||||
} while (reply != RT_MODE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDVAPDongle::set_sql(int squelch)
|
||||
{
|
||||
unsigned cnt = 0;
|
||||
REPLY_TYPE reply;
|
||||
|
||||
dvapreg.header = 0x5u;
|
||||
dvapreg.param.control = 0x80u;
|
||||
if (squelch < -128) {
|
||||
traceit("Squelch setting of %d too small, resetting...\n", squelch);
|
||||
squelch = -128;
|
||||
} else if (squelch > -45) {
|
||||
traceit("Squelch setting of %d too large, resetting...\n", squelch);
|
||||
squelch = -45;
|
||||
}
|
||||
dvapreg.param.byte = (int8_t)squelch;
|
||||
|
||||
int rc = write_to_dvp(&dvapreg, 5);
|
||||
if (rc != 5) {
|
||||
traceit("Failed to send request to set dvap sql\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
do {
|
||||
usleep(5000);
|
||||
|
||||
reply = get_reply(dvapreg);
|
||||
|
||||
cnt ++;
|
||||
if (cnt >= MAX_REPL_CNT) {
|
||||
traceit("Reached max number of requests to set dvap sql\n");
|
||||
return false;
|
||||
}
|
||||
} while (reply != RT_SQL);
|
||||
traceit("DVAP squelch is %d dB\n", (int)dvapreg.param.byte);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDVAPDongle::set_pwr(int power)
|
||||
{
|
||||
unsigned cnt = 0;
|
||||
REPLY_TYPE reply;
|
||||
|
||||
dvapreg.header = 0x6u;
|
||||
dvapreg.param.control = 0x138u;
|
||||
if (power < -12) {
|
||||
traceit("Power setting of %d is too low, resetting...\n", power);
|
||||
power = -12;
|
||||
} else if (power > 10) {
|
||||
traceit("Power setting of %d is too high, resetting...\n", power);
|
||||
power = 10;
|
||||
}
|
||||
dvapreg.param.word = (int16_t)power;
|
||||
|
||||
int rc = write_to_dvp(&dvapreg, 6);
|
||||
if (rc != 6) {
|
||||
traceit("Failed to send request to set dvap pwr\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
do {
|
||||
usleep(5000);
|
||||
|
||||
reply = get_reply(dvapreg);
|
||||
|
||||
cnt ++;
|
||||
if (cnt >= MAX_REPL_CNT) {
|
||||
traceit("Reached max number of requests to set dvap pwr\n");
|
||||
return false;
|
||||
}
|
||||
} while (reply != RT_PWR);
|
||||
traceit("DVAP power is %d dB\n", (int)dvapreg.param.word);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDVAPDongle::set_off(int offset)
|
||||
{
|
||||
unsigned cnt = 0;
|
||||
REPLY_TYPE reply;
|
||||
|
||||
dvapreg.header = 0x6u;
|
||||
dvapreg.param.control = 0x400u;
|
||||
if (offset < -2000) {
|
||||
traceit("Offset of %d is too low, resetting...\n", offset);
|
||||
offset = -2000;
|
||||
} else if (offset > 2000) {
|
||||
traceit("Offset of %d is too high, resetting...\n", offset);
|
||||
offset = 2000;
|
||||
}
|
||||
dvapreg.param.word = (int16_t)offset;
|
||||
|
||||
int rc = write_to_dvp(&dvapreg, 6);
|
||||
if (rc != 6) {
|
||||
traceit("Failed to send request to set dvap offset\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
do {
|
||||
usleep(5000);
|
||||
|
||||
reply = get_reply(dvapreg);
|
||||
|
||||
cnt ++;
|
||||
if (cnt >= MAX_REPL_CNT) {
|
||||
traceit("Reached max number of requests to set dvap offset\n");
|
||||
return false;
|
||||
}
|
||||
} while (reply != RT_OFF);
|
||||
traceit("DVAP offset is %d Hz\n", (int)dvapreg.param.word);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDVAPDongle::set_freq(int frequency)
|
||||
{
|
||||
unsigned cnt = 0;
|
||||
REPLY_TYPE reply;
|
||||
|
||||
// first get the frequency limits
|
||||
dvapreg.header = 0x2004u;
|
||||
dvapreg.param.control = 0x230u;
|
||||
|
||||
int rc = write_to_dvp(&dvapreg, 4);
|
||||
if (rc != 4) {
|
||||
traceit("Failed to send request for frequency limits\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
do {
|
||||
usleep(5000);
|
||||
|
||||
reply = get_reply(dvapreg);
|
||||
|
||||
cnt++;
|
||||
if (cnt >= MAX_REPL_CNT) {
|
||||
traceit("Reached max number of requests for dvap frequency limits\n");
|
||||
return false;
|
||||
}
|
||||
} while (reply != RT_FREQ_LIMIT);
|
||||
traceit("DVAP Frequency limits are from %d to %d Hz\n", dvapreg.param.twod[0], dvapreg.param.twod[1]);
|
||||
|
||||
// okay, now we know the frequency limits, get on with the show...
|
||||
if (frequency < dvapreg.param.twod[0]) {
|
||||
traceit("Frequency of %d is too small, resetting...\n", frequency);
|
||||
frequency = dvapreg.param.twod[0];
|
||||
} else if (frequency > dvapreg.param.twod[1]) {
|
||||
traceit("Frequency of %d is too large, resetting...\n", frequency);
|
||||
frequency = dvapreg.param.twod[1];
|
||||
}
|
||||
|
||||
cnt = 0;
|
||||
dvapreg.header = 0x8u;
|
||||
dvapreg.param.control = 0x220u;
|
||||
dvapreg.param.dword = frequency;
|
||||
|
||||
rc = write_to_dvp(&dvapreg, 8);
|
||||
if (rc != 8) {
|
||||
traceit("Failed to send request to set dvap frequency\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
do {
|
||||
usleep(5000);
|
||||
|
||||
reply = get_reply(dvapreg);
|
||||
|
||||
cnt ++;
|
||||
if (cnt >= MAX_REPL_CNT) {
|
||||
traceit("Reached max number of requests to set dvap frequency\n");
|
||||
return false;
|
||||
}
|
||||
} while (reply != RT_FREQ);
|
||||
traceit("DVAP frequency is %d Hz\n", dvapreg.param.dword);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDVAPDongle::start_dvap()
|
||||
{
|
||||
unsigned cnt = 0;
|
||||
REPLY_TYPE reply;
|
||||
|
||||
dvapreg.header = 0x5u;
|
||||
dvapreg.param.control = 0x18u;
|
||||
dvapreg.param.byte = 0x1;
|
||||
|
||||
int rc = write_to_dvp(&dvapreg, 5);
|
||||
if (rc != 5) {
|
||||
traceit("Failed to send request to start the dvap dongle\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
do {
|
||||
usleep(5000);
|
||||
|
||||
reply = get_reply(dvapreg);
|
||||
|
||||
cnt ++;
|
||||
if (cnt >= MAX_REPL_CNT) {
|
||||
traceit("Reached max number of requests to start the dvap dongle\n");
|
||||
return false;
|
||||
}
|
||||
} while (reply != RT_START);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CDVAPDongle::SendRegister(SDVAP_REGISTER &dr)
|
||||
{
|
||||
unsigned int len = dr.header & 0x1fff;
|
||||
write_to_dvp(&dr, len);
|
||||
return;
|
||||
}
|
||||
|
||||
int CDVAPDongle::write_to_dvp(const void *buffer, const unsigned int len)
|
||||
{
|
||||
unsigned int ptr = 0;
|
||||
|
||||
if (len == 0)
|
||||
return 0;
|
||||
|
||||
uint8_t *buf = (uint8_t *)buffer;
|
||||
while (ptr < len) {
|
||||
ssize_t n = write(serfd, buf + ptr, len - ptr);
|
||||
if (n < 0) {
|
||||
traceit("Error %d writing to dvap, message=%s\n", errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (n > 0)
|
||||
ptr += n;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int CDVAPDongle::read_from_dvp(void *buffer, unsigned int len)
|
||||
{
|
||||
unsigned int off = 0;
|
||||
fd_set fds;
|
||||
int n;
|
||||
struct timeval tv;
|
||||
ssize_t temp_len;
|
||||
uint8_t *buf = (uint8_t *)buffer;
|
||||
|
||||
if (len == 0)
|
||||
return 0;
|
||||
|
||||
while (off < len) {
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(serfd, &fds);
|
||||
|
||||
if (off == 0) {
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
n = select(serfd + 1, &fds, NULL, NULL, &tv);
|
||||
if (n == 0)
|
||||
return 0; // nothing to read from the dvap
|
||||
} else
|
||||
n = select(serfd + 1, &fds, NULL, NULL, NULL);
|
||||
|
||||
if (n < 0) {
|
||||
traceit("select error=%d on dvap\n", errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (n > 0) {
|
||||
temp_len = read(serfd, buf + off, len - off);
|
||||
if (temp_len > 0)
|
||||
off += temp_len;
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
bool CDVAPDongle::OpenSerial(char *device)
|
||||
{
|
||||
static termios t;
|
||||
|
||||
serfd = open(device, O_RDWR | O_NOCTTY | O_NDELAY, 0);
|
||||
if (serfd < 0) {
|
||||
traceit("Failed to open device [%s], error=%d, message=%s\n", device, errno, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isatty(serfd) == 0) {
|
||||
traceit("Device %s is not a tty device\n", device);
|
||||
close(serfd);
|
||||
serfd = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tcgetattr(serfd, &t) < 0) {
|
||||
traceit("tcgetattr failed for %s, error=%d, message-%s\n", device, errno, strerror(errno));
|
||||
close(serfd);
|
||||
serfd = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
t.c_lflag &= ~(ECHO | ECHOE | ICANON | IEXTEN | ISIG);
|
||||
t.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON | IXOFF | IXANY);
|
||||
t.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CRTSCTS);
|
||||
t.c_cflag |= CS8;
|
||||
t.c_oflag &= ~(OPOST);
|
||||
t.c_cc[VMIN] = 0;
|
||||
t.c_cc[VTIME] = 10;
|
||||
|
||||
cfsetospeed(&t, B230400);
|
||||
cfsetispeed(&t, B230400);
|
||||
|
||||
if (tcsetattr(serfd, TCSANOW, &t) < 0) {
|
||||
traceit("tcsetattr failed for %s, error=%dm message=%s\n", device, errno, strerror(errno));
|
||||
close(serfd);
|
||||
serfd = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CDVAPDongle::Stop()
|
||||
{
|
||||
dvapreg.header = 0x5u;
|
||||
dvapreg.param.control = 0x18u;
|
||||
dvapreg.param.byte = 0;
|
||||
write_to_dvp(&dvapreg, 5);
|
||||
return;
|
||||
}
|
||||
|
||||
int CDVAPDongle::KeepAlive()
|
||||
{
|
||||
dvapreg.header = 0x6003u;
|
||||
dvapreg.nul = 0x0u;
|
||||
return write_to_dvp(&dvapreg, 3);
|
||||
}
|
||||
|
||||
void CDVAPDongle::traceit(const char *fmt,...)
|
||||
{
|
||||
time_t ltime;
|
||||
struct tm mytm;
|
||||
const int TRACE_BFSZ = 256;
|
||||
char trace_buf[TRACE_BFSZ];
|
||||
|
||||
time(<ime);
|
||||
localtime_r(<ime,&mytm);
|
||||
|
||||
snprintf(trace_buf,TRACE_BFSZ - 1,"%02d/%02d/%02d %02d:%02d:%02d:",
|
||||
mytm.tm_mon+1,mytm.tm_mday,mytm.tm_year % 100,
|
||||
mytm.tm_hour,mytm.tm_min,mytm.tm_sec);
|
||||
|
||||
va_list args;
|
||||
va_start(args,fmt);
|
||||
vsnprintf(trace_buf + strlen(trace_buf), TRACE_BFSZ - strlen(trace_buf) - 1, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
fprintf(stdout, "%s", trace_buf);
|
||||
return;
|
||||
}
|
||||
@ -0,0 +1,119 @@
|
||||
#pragma once
|
||||
/*
|
||||
* Copyright 2017 by Thomas Early, AC2IE
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
enum REPLY_TYPE {
|
||||
RT_TIMEOUT,
|
||||
RT_ERR,
|
||||
RT_UNKNOWN,
|
||||
RT_NAME,
|
||||
RT_SER,
|
||||
RT_FW,
|
||||
RT_START,
|
||||
RT_STOP,
|
||||
RT_MODU,
|
||||
RT_MODE,
|
||||
RT_SQL,
|
||||
RT_PWR,
|
||||
RT_OFF,
|
||||
RT_FREQ,
|
||||
RT_FREQ_LIMIT,
|
||||
RT_STS,
|
||||
RT_PTT,
|
||||
RT_ACK,
|
||||
RT_HDR,
|
||||
RT_HDR_ACK,
|
||||
RT_DAT
|
||||
};
|
||||
|
||||
#pragma pack(push,1)
|
||||
typedef struct dvp_register_tag {
|
||||
uint16_t header;
|
||||
union {
|
||||
uint8_t nul;
|
||||
struct {
|
||||
uint16_t control;
|
||||
union {
|
||||
int8_t byte;
|
||||
int16_t word;
|
||||
int32_t dword;
|
||||
int32_t twod[2];
|
||||
char sstr[12];
|
||||
uint8_t ustr[12];
|
||||
};
|
||||
} param;
|
||||
struct {
|
||||
uint16_t streamid;
|
||||
uint8_t framepos;
|
||||
uint8_t seq;
|
||||
union {
|
||||
struct {
|
||||
unsigned char flag[3];
|
||||
unsigned char rpt1[8];
|
||||
unsigned char rpt2[8];
|
||||
unsigned char urcall[8];
|
||||
unsigned char mycall[8];
|
||||
unsigned char sfx[4];
|
||||
unsigned char pfcs[2];
|
||||
} hdr;
|
||||
struct {
|
||||
unsigned char voice;
|
||||
unsigned char sdata;
|
||||
} vad;
|
||||
};
|
||||
} frame;
|
||||
};
|
||||
} SDVAP_REGISTER;
|
||||
#pragma pack(pop)
|
||||
|
||||
class CDVAPDongle
|
||||
{
|
||||
public:
|
||||
CDVAPDongle();
|
||||
~CDVAPDongle();
|
||||
bool Initialize(char *serialno, int frequency, int offset, int power, int squelch);
|
||||
REPLY_TYPE get_reply(SDVAP_REGISTER &dr);
|
||||
void Stop();
|
||||
int KeepAlive();
|
||||
void SendRegister(SDVAP_REGISTER &dr);
|
||||
|
||||
private:
|
||||
// data
|
||||
int serfd;
|
||||
const unsigned int MAX_REPL_CNT;
|
||||
uint32_t frequency;
|
||||
int32_t offset;
|
||||
SDVAP_REGISTER dvapreg;
|
||||
|
||||
// functions
|
||||
bool OpenSerial(char *device);
|
||||
int read_from_dvp(void* buf, unsigned int len);
|
||||
int write_to_dvp(const void* buf, const unsigned int len);
|
||||
void syncit();
|
||||
bool get_ser(char *dvp, char *dvap_serial_number);
|
||||
bool get_name();
|
||||
bool get_fw();
|
||||
bool set_modu();
|
||||
bool set_mode();
|
||||
bool set_sql(int squelch);
|
||||
bool set_pwr(int power);
|
||||
bool set_off(int offset);
|
||||
bool set_freq(int frequency);
|
||||
bool start_dvap();
|
||||
void traceit(const char *fmt,...);
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue