diff --git a/DVAPDongle.cpp b/DVAPDongle.cpp new file mode 100644 index 0000000..2e15647 --- /dev/null +++ b/DVAPDongle.cpp @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include "DVAPDongle.h" + + extern std::atomic 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; +} diff --git a/DVAPDongle.h b/DVAPDongle.h new file mode 100644 index 0000000..f498e8d --- /dev/null +++ b/DVAPDongle.h @@ -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,...); +}; diff --git a/Makefile b/Makefile index 1938874..ba5da27 100644 --- a/Makefile +++ b/Makefile @@ -35,8 +35,8 @@ g2_ircddb : g2_ircddb.cpp $(IRCDDBOBJS) versions.h g2_link : g2_link.cpp versions.h g++ $(CPPFLAGS) -o g2_link g2_link.cpp -lrt -lconfig++ -pthread -dvap_rptr : dvap_rptr.cpp dstar_dv.o golay23.o versions.h - g++ $(CPPFLAGS) -o dvap_rptr dvap_rptr.cpp golay23.o dstar_dv.o -I/usr/include -L/usr/lib -lrt -lconfig++ -pthread +dvap_rptr : dvap_rptr.cpp DVAPDongle.o dstar_dv.o golay23.o DVAPDongle.h versions.h + g++ $(CPPFLAGS) -o dvap_rptr dvap_rptr.cpp DVAPDongle.o golay23.o dstar_dv.o -I/usr/include -L/usr/lib -lrt -lconfig++ -pthread dvrptr : dvrptr.cpp dstar_dv.o golay23.o g++ $(CPPFLAGS) -o dvrptr dvrptr.cpp golay23.o dstar_dv.o -I/usr/include -L/usr/lib -lconfig++ -lrt @@ -68,6 +68,9 @@ IRCDDBApp.o : IRCDDBApp.cpp IRCDDBApp.h IRCutils.h aprs.o : aprs.cpp aprs.h g++ -c $(CPPFLAGS) aprs.cpp +DVAPDongle.o : DVAPDongle.cpp DVAPDongle.h + g++ -c $(CPPFLAGS) DVAPDongle.cpp + golay23.o : golay23.cpp golay23.h g++ -c $(CPPFLAGS) golay23.cpp diff --git a/dvap_rptr.cpp b/dvap_rptr.cpp index 45c8341..2f3bfde 100644 --- a/dvap_rptr.cpp +++ b/dvap_rptr.cpp @@ -47,6 +47,8 @@ #include using namespace libconfig; +#include "DVAPDongle.h" + #define VERSION DVAP_VERSION #define CALL_SIZE 8 #define RPTR_SIZE 8 @@ -54,31 +56,6 @@ using namespace libconfig; // we need to be sure these structures don't have any dead space #pragma pack(push, 1) -/* data from dvap */ -typedef struct dvap_hdr_tag { - unsigned char hdr0; // 0 = 0x2f - unsigned char hdr1; // 1 = 0xa0 - uint16_t streamid; // 2 - unsigned char framepos; // 4 - unsigned char seq; // 5 - unsigned char flag[3]; // 6 - unsigned char rpt1[8]; // 9 - unsigned char rpt2[8]; // 17 - unsigned char urcall[8];// 25 - unsigned char mycall[8];// 33 - unsigned char sfx[4]; // 41 - unsigned char pfcs[2]; // 45 -} SDVAP_HDR; // total: 47 - -typedef struct dvap_data_tag { - unsigned char hdr0; // 0 = 0x12 - unsigned char hdr1; // 1 = 0xc0 - uint16_t streamid; // 2 - unsigned char framepos; // 4 - unsigned char seq; // 5 - unsigned char audio[12];// 6 -} SDVAP_DATA; // total: 18 - // for communicating with the g2 gateway typedef struct pkt_tag { unsigned char pkt_id[4]; @@ -154,58 +131,10 @@ static int insock = -1; static struct sockaddr_in outaddr; static int serfd = -1; static bool busy20000 = false; -static std::atomic keep_running(true); -static const unsigned char DVP_RQST_NAME[] = {0x04, 0x20, 0x01, 0x00}; -static const unsigned char DVP_REPL_NAME[] = {0x10, 0x00, 0x01, 0x00, 'D', 'V', 'A', 'P', ' ', 'D', 'o', 'n', 'g', 'l', 'e', 0x00}; -static const unsigned char DVP_RQST_SER[] = {0x04, 0x20, 0x02, 0x00}; -static const unsigned char DVP_REPL_SER[] = {0x0C, 0x00, 0x02, 0x00}; -static const unsigned char DVP_RQST_FW[] = {0x05, 0x20, 0x04, 0x00, 0x01}; -static const unsigned char DVP_REPL_FW[] = {0x07, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00}; -static const unsigned char DVP_RQST_MODU[] = {0x05, 0x00, 0x28, 0x00, 0x01}; -static const unsigned char DVP_REPL_MODU[] = {0x05, 0x00, 0x28, 0x00, 0x01}; -static const unsigned char DVP_RQST_MODE[] = {0x05, 0x00, 0x2A, 0x00, 0x00}; -static const unsigned char DVP_REPL_MODE[] = {0x05, 0x00, 0x2A, 0x00, 0x00}; -static const unsigned char DVP_RQST_SQL[] = {0x05, 0x00, 0x80, 0x00, 0x00}; -static const unsigned char DVP_REPL_SQL[] = {0x05, 0x00, 0x80, 0x00, 0x00}; -static const unsigned char DVP_RQST_PWR[] = {0x06, 0x00, 0x38, 0x01, 0x00, 0x00}; -static const unsigned char DVP_REPL_PWR[] = {0x06, 0x00, 0x38, 0x01, 0x00, 0x00}; -static const unsigned char DVP_RQST_OFF[] = {0x06, 0x00, 0x00, 0x04, 0x00, 0x00}; -static const unsigned char DVP_REPL_OFF[] = {0x06, 0x00, 0x00, 0x04, 0x00, 0x00}; -static const unsigned char DVP_RQST_FREQ[] = {0x08, 0x00, 0x20, 0x02, 0x00, 0x00, 0x00, 0x00}; -static const unsigned char DVP_REPL_FREQ[] = {0x08, 0x00, 0x20, 0x02, 0x00, 0x00, 0x00, 0x00}; -static const unsigned char DVP_RQST_START[] = {0x05, 0x00, 0x18, 0x00, 0x01}; -static const unsigned char DVP_REPL_START[] = {0x05, 0x00, 0x18, 0x00, 0x01}; -static const unsigned char DVP_RQST_STOP[] = {0x05, 0x00, 0x18, 0x00, 0x00}; -static const unsigned char DVP_REPL_STOP[] = {0x05, 0x00, 0x18, 0x00, 0x00}; -static const unsigned char DVP_HDR[] = { 0x2F, 0xA0 }; +std::atomic keep_running(true); static const unsigned char DVP_REPL_HDR[] = { 0x2F, 0x60 }; static const unsigned char DVP_REPL_PTT[] = {0x05, 0x20, 0x18, 0x01, 0x00}; -static const unsigned char DVP_DAT[] = { 0x12, 0xC0 }; static const unsigned char DVP_STS[] = {0x07, 0x20, 0x90, 0x00, 0x00, 0x00, 0x00}; -static const unsigned char DVP_ACK[] = {0x03, 0x60, 0x00}; -static const unsigned int MAX_REPL_CNT = 20; -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_STS, - RT_PTT, - RT_ACK, - RT_HDR, - RT_HDR_ACK, - RT_DAT -}; static unsigned int space = 0; static unsigned int aseed = 0; @@ -215,23 +144,7 @@ static void traceit(const char *fmt,...); static int read_config(const char *cfgFile); static void sig_catch(int signum); static int open_sock(); -static bool open_ser(char *dvp); -static bool open_dvp(); -static int read_from_dvp(unsigned char* buf, unsigned int len); -static int write_to_dvp(const unsigned char* buf, const unsigned int len); -static bool get_name(); -static bool get_fw(); -static bool get_ser(char *dvp); -static bool set_modu(); -static bool set_mode(); -static bool set_sql(); -static bool set_pwr(); -static bool set_off(); -static bool set_freq(); -static bool start_dvap(); static void readFrom20000(); -static REPLY_TYPE get_reply(unsigned char *buf, unsigned int *len); -static void syncit(); static void calcPFCS(unsigned char *packet, unsigned char *pfcs); static void ReadDVAPThread(); static void RptrAckThread(SDVAP_ACK_ARG *parg); @@ -240,6 +153,8 @@ static void RptrAckThread(SDVAP_ACK_ARG *parg); extern void dstar_dv_init(); extern int dstar_dv_decode(const unsigned char *d, int data[3]); +CDVAPDongle dongle; + static void calcPFCS(unsigned char *packet, unsigned char *pfcs) { unsigned short crc_dstar_ffff = 0xffff; @@ -520,615 +435,6 @@ static int open_sock() return 0; } -static bool open_ser(char *dvp) -{ - static termios t; - - serfd = open(dvp, O_RDWR | O_NOCTTY | O_NDELAY, 0); - if (serfd < 0) { - traceit("Failed to open device [%s], error=%d, message=%s\n", dvp, errno, strerror(errno)); - return false; - } - - if (isatty(serfd) == 0) { - traceit("Device %s is not a tty device\n", dvp); - close(serfd); - serfd = -1; - return false; - } - - if (tcgetattr(serfd, &t) < 0) { - traceit("tcgetattr failed for %s, error=%d\n", dvp, 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=%d\n", dvp, errno); - close(serfd); - serfd = -1; - return false; - } - - return true; -} - -static bool open_dvp() -{ - bool ok = false; - char dvp_device[128]; - - do { - for (int i = 0; i < 32; i++) { - sprintf(dvp_device, "/dev/ttyUSB%d", i); - - if (access(dvp_device, R_OK | W_OK) != 0) - continue; - - ok = open_ser(dvp_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 by other dvap_rptr\n", dvp_device); - continue; - } - traceit("Device %s now locked for exclusive use\n", dvp_device); - - ok = get_ser(dvp_device); - 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(); - if (!ok) - break; - - ok = set_pwr(); - if (!ok) - break; - - ok = set_off(); - if (!ok) - break; - - ok = set_freq(); - if (!ok) - break; - - ok = start_dvap(); - if (!ok) - break; - - } while (false); - - if (!ok) { - if (serfd != -1) { - (void)write_to_dvp(DVP_RQST_STOP, 5); - close(serfd); - serfd = -1; - } - return false; - } - return true; -} - -static int read_from_dvp(unsigned char *buf, unsigned int len) -{ - unsigned int off = 0; - fd_set fds; - int n; - struct timeval tv; - ssize_t temp_len; - - 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; -} - -static int write_to_dvp(const unsigned char *buf, const unsigned int len) -{ - unsigned int ptr = 0; - - if (len == 0) - return 0; - - while (ptr < len) { - ssize_t n = write(serfd, buf + ptr, len - ptr); - if (n < 0) { - traceit("Error %d writing to dvap\n", errno); - return -1; - } - - if (n > 0) - ptr += n; - } - - return len; -} - -static REPLY_TYPE get_reply(unsigned char *buf, unsigned int *len) -{ - unsigned int off = 2; - int rc = read_from_dvp(buf, 2); - if (rc == 0) - return RT_TIMEOUT; - if (rc != 2) - return RT_ERR; - - *len = buf[0] + (buf[1] & 0x1f) * 256; - if (*len > 50) { - syncit(); - return RT_TIMEOUT; - } - - while (off < *len) { - rc = read_from_dvp(buf + off, *len - off); - if (rc < 0) - return RT_TIMEOUT; - if (rc > 0) - off += rc; - } - - if (memcmp(buf, DVP_STS, 4) == 0) - return RT_STS; - else if (memcmp(buf, DVP_DAT, 2) == 0) - return RT_DAT; - else if (memcmp(buf, DVP_HDR, 2) == 0) - return RT_HDR; - else if (memcmp(buf, DVP_REPL_HDR, 2) == 0) - return RT_HDR_ACK; - else if (memcmp(buf, DVP_REPL_PTT, 4) == 0) - return RT_PTT; - else if (memcmp(buf, DVP_REPL_START, 5) == 0) - return RT_START; - else if (memcmp(buf, DVP_REPL_STOP, 5) == 0) - return RT_STOP; - else if (memcmp(buf, DVP_REPL_OFF, 4) == 0) - return RT_OFF; - else if (memcmp(buf, DVP_REPL_NAME, 4) == 0) - return RT_NAME; - else if (memcmp(buf + 1, DVP_REPL_SER + 1, 3) == 0) - return RT_SER; - else if (memcmp(buf, DVP_REPL_FW, 5) == 0) - return RT_FW; - else if (memcmp(buf, DVP_REPL_FREQ, 4) == 0) - return RT_FREQ; - else if (memcmp(buf, DVP_REPL_MODU, 5) == 0) - return RT_MODU; - else if (memcmp(buf, DVP_REPL_MODE, 5) == 0) - return RT_MODE; - else if (memcmp(buf, DVP_REPL_PWR, 4) == 0) - return RT_PWR; - else if (memcmp(buf, DVP_REPL_SQL, 4) == 0) - return RT_SQL; - else { - syncit(); - return RT_TIMEOUT; - } - - /* It should never get here */ - return RT_TIMEOUT; -} - -static void syncit() -{ - unsigned char data[7]; - struct timeval tv; - fd_set fds; - short cnt = 0; - - traceit("Starting syncing dvap\n"); - memset(data, 0x00, 7); - - while (memcmp(data, DVP_STS, 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; -} - -static bool get_name() -{ - unsigned cnt = 0; - unsigned int len = 0; - REPLY_TYPE reply; - unsigned char dvp_buf[200]; - - int rc = write_to_dvp(DVP_RQST_NAME, 4); - if (rc != 4) { - traceit("Failed to send request to get dvap name\n"); - return false; - } - - do { - usleep(5000); - - reply = get_reply(dvp_buf, &len); - cnt ++; - if (cnt >= MAX_REPL_CNT) { - traceit("Reached max number of requests to receive dvap name\n"); - return false; - } - } while (reply != RT_NAME); - - bool testit = (memcmp(dvp_buf, DVP_REPL_NAME, len) == 0); - - if (!testit) { - traceit("Failed to receive dvap name\n"); - return false; - } - - traceit("Device name: %.*s\n", 11, dvp_buf + 4); - return true; -} - -static bool get_fw() -{ - unsigned cnt = 0; - unsigned int len = 0; - REPLY_TYPE reply; - unsigned char dvp_buf[200]; - - int rc = write_to_dvp(DVP_RQST_FW, 5); - if (rc != 5) { - traceit("Failed to send request to get dvap fw\n"); - return false; - } - - do { - usleep(5000); - - reply = get_reply(dvp_buf, &len); - 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 = dvp_buf[6] * 256 + dvp_buf[5]; - traceit("dvap fw ver: %u.%u\n", ver / 100, ver % 100); - - return true; -} - -static bool get_ser(char *dvp) -{ - unsigned cnt = 0; - unsigned int len = 0; - REPLY_TYPE reply; - unsigned char dvp_buf[200]; - - int rc = write_to_dvp(DVP_RQST_SER, 4); - if (rc != 4) { - traceit("Failed to send request to get dvap serial#\n"); - return false; - } - - do { - usleep(5000); - - reply = get_reply(dvp_buf, &len); - cnt ++; - if (cnt >= MAX_REPL_CNT) { - traceit("Reached max number of requests to receive dvap serial#\n"); - return false; - } - } while (reply != RT_SER); - - if (strcmp((char *)(dvp_buf + 4), DVP_SERIAL) == 0) { - traceit("Using %s: %s, because serial number matches your dvap_rptr.cfg\n", - dvp, DVP_SERIAL); - return true; - } else { - traceit("Device %s has serial %s, but does not match your config value %s\n", dvp, dvp_buf + 4, DVP_SERIAL); - return false; - } -} - -static bool set_modu() -{ - unsigned cnt = 0; - unsigned int len = 0; - REPLY_TYPE reply; - unsigned char dvp_buf[200]; - - int rc = write_to_dvp(DVP_RQST_MODU, 5); - if (rc != 5) { - traceit("Failed to send request to set dvap modulation\n"); - return false; - } - - do { - usleep(5000); - - reply = get_reply(dvp_buf, &len); - - 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; -} - -static bool set_mode() -{ - unsigned cnt = 0; - unsigned int len = 0; - REPLY_TYPE reply; - unsigned char dvp_buf[200]; - - int rc = write_to_dvp(DVP_RQST_MODE, 5); - if (rc != 5) { - traceit("Failed to send request to set dvap mode\n"); - return false; - } - - do { - usleep(5000); - - reply = get_reply(dvp_buf, &len); - - 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; -} - -static bool set_sql() -{ - unsigned cnt = 0; - unsigned int len = 0; - REPLY_TYPE reply; - unsigned char buf[10]; - unsigned char dvp_buf[200]; - - memcpy(buf, DVP_RQST_SQL, 5); - memcpy(buf + 4, &DVP_SQL, 1); - - int rc = write_to_dvp(buf, 5); - if (rc != 5) { - traceit("Failed to send request to set dvap sql\n"); - return false; - } - - do { - usleep(5000); - - reply = get_reply(dvp_buf, &len); - - cnt ++; - if (cnt >= MAX_REPL_CNT) { - traceit("Reached max number of requests to set dvap sql\n"); - return false; - } - } while (reply != RT_SQL); - - return true; -} - -static bool set_pwr() -{ - unsigned cnt = 0; - unsigned int len = 0; - REPLY_TYPE reply; - unsigned char buf[10]; - unsigned char dvp_buf[200]; - - memcpy(buf, DVP_RQST_PWR, 6); - memcpy(buf + 4, &DVP_PWR, sizeof(int16_t)); - - int rc = write_to_dvp(buf, 6); - if (rc != 6) { - traceit("Failed to send request to set dvap pwr\n"); - return false; - } - - do { - usleep(5000); - - reply = get_reply(dvp_buf, &len); - - cnt ++; - if (cnt >= MAX_REPL_CNT) { - traceit("Reached max number of requests to set dvap pwr\n"); - return false; - } - } while (reply != RT_PWR); - - return true; -} - -static bool set_off() -{ - unsigned cnt = 0; - unsigned int len = 0; - REPLY_TYPE reply; - unsigned char buf[10]; - unsigned char dvp_buf[200]; - - memcpy(buf, DVP_RQST_OFF, 6); - memcpy(buf + 4, &DVP_OFF, sizeof(int16_t)); - - int rc = write_to_dvp(buf, 6); - if (rc != 6) { - traceit("Failed to send request to set dvap offset\n"); - return false; - } - - do { - usleep(5000); - - reply = get_reply(dvp_buf, &len); - - cnt ++; - if (cnt >= MAX_REPL_CNT) { - traceit("Reached max number of requests to set dvap offset\n"); - return false; - } - } while (reply != RT_OFF); - - return true; -} - -static bool set_freq() -{ - unsigned cnt = 0; - unsigned int len = 0; - REPLY_TYPE reply; - unsigned char buf[10]; - unsigned char dvp_buf[200]; - - memcpy(buf, DVP_RQST_FREQ, 8); - memcpy(buf + 4, &DVP_FREQ, sizeof(u_int32_t)); - - int rc = write_to_dvp(buf, 8); - if (rc != 8) { - traceit("Failed to send request to set dvap frequency\n"); - return false; - } - - do { - usleep(5000); - - reply = get_reply(dvp_buf, &len); - - cnt ++; - if (cnt >= MAX_REPL_CNT) { - traceit("Reached max number of requests to set dvap frequency\n"); - return false; - } - } while (reply != RT_FREQ); - - return true; -} - -static bool start_dvap() -{ - unsigned cnt = 0; - unsigned int len = 0; - REPLY_TYPE reply; - unsigned char dvp_buf[200]; - - int rc = write_to_dvp(DVP_RQST_START, 5); - if (rc != 5) { - traceit("Failed to send request to start the dvap dongle\n"); - return false; - } - - do { - usleep(5000); - - reply = get_reply(dvp_buf, &len); - - 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; -} - static void readFrom20000() { struct sockaddr_in from; @@ -1160,7 +466,7 @@ static void readFrom20000() select(insock + 1, &readfd, NULL, NULL, &tv); if (FD_ISSET(insock, &readfd)) { - len = recvfrom (insock, (char *)&net_buf, 58, 0, (struct sockaddr *)&from, &fromlen); + len = recvfrom(insock, (char *)&net_buf, 58, 0, (struct sockaddr *)&from, &fromlen); if (len == 58) { if (busy20000) { FD_CLR (insock, &readfd); @@ -1169,7 +475,7 @@ static void readFrom20000() /* check the module and gateway */ if (net_buf.vpkt.hdr.rpt1[7] != RPTR_MOD) { - FD_CLR (insock, &readfd); + FD_CLR(insock, &readfd); break; } memcpy(net_buf.vpkt.hdr.rpt2, OWNER, 7); @@ -1192,7 +498,7 @@ static void readFrom20000() (net_buf.vpkt.hdr.flag[0] != 0x20) && (net_buf.vpkt.hdr.flag[0] != 0x28) && (net_buf.vpkt.hdr.flag[0] != 0x40)) { - FD_CLR (insock, &readfd); + FD_CLR(insock, &readfd); break; } @@ -1200,7 +506,7 @@ static void readFrom20000() (net_buf.flag[0] != 0x73) || (net_buf.flag[1] != 0x12) || (net_buf.vpkt.myicm.icm_id != 0x20)) { /* voice type */ - FD_CLR (insock, &readfd); + FD_CLR(insock, &readfd); break; } @@ -1231,30 +537,29 @@ static void readFrom20000() else net_buf.vpkt.hdr.flag[0] = 0x40; } - net_buf.vpkt.hdr.flag[1] = 0x00; - net_buf.vpkt.hdr.flag[2] = 0x00; + net_buf.vpkt.hdr.flag[1] = net_buf.vpkt.hdr.flag[2] = 0x00; // write the header packet to the dvap here while ((space < 1) && keep_running) usleep(5); - SDVAP_HDR dh; + SDVAP_REGISTER dr; stream_id_to_dvap = (rand_r(&aseed) % 65535U) + 1U; - memcpy(&dh, DVP_HDR, 2); - dh.streamid = stream_id_to_dvap; - dh.framepos = 0x80; - dh.seq = 0; + dr.header = 0xa02f; + dr.frame.streamid = stream_id_to_dvap; + dr.frame.framepos = 0x80; + dr.frame.seq = 0; //memset(dvp_buf + 6, ' ', 41); for (int f=0; f<3; f++) - dh.flag[f] = net_buf.vpkt.hdr.flag[0]; - memcpy(dh.rpt1, net_buf.vpkt.hdr.rpt2, 8); - memcpy(dh.rpt2, net_buf.vpkt.hdr.rpt1, 8); - memcpy(dh.urcall, net_buf.vpkt.hdr.urcall, 8); - memcpy(dh.mycall, net_buf.vpkt.hdr.mycall, 8); - memcpy(dh.sfx, net_buf.vpkt.hdr.sfx, 4); - calcPFCS(dh.flag, dh.pfcs); + dr.frame.hdr.flag[f] = net_buf.vpkt.hdr.flag[0]; + memcpy(dr.frame.hdr.rpt1, net_buf.vpkt.hdr.rpt2, 8); + memcpy(dr.frame.hdr.rpt2, net_buf.vpkt.hdr.rpt1, 8); + memcpy(dr.frame.hdr.urcall, net_buf.vpkt.hdr.urcall, 8); + memcpy(dr.frame.hdr.mycall, net_buf.vpkt.hdr.mycall, 8); + memcpy(dr.frame.hdr.sfx, net_buf.vpkt.hdr.sfx, 4); + calcPFCS(dr.frame.hdr.flag, dr.frame.hdr.pfcs); frame_pos_to_dvap = 0; seq_to_dvap = 0; - (void)write_to_dvp((unsigned char *)&dh, 47); + dongle.SendRegister(dr); inactive = 0; seq_no = 0; @@ -1285,17 +590,17 @@ static void readFrom20000() // write the audio packet to the dvap here while ((space < 1) && keep_running) usleep(5); - SDVAP_DATA dd; - memcpy(&dd, DVP_DAT, 2); + SDVAP_REGISTER dr; + dr.header = 0xc012u; if (memcmp(net_buf.vpkt.vasd.text, sync_codes, 3) == 0) frame_pos_to_dvap = 0; - dd.streamid = stream_id_to_dvap; - dd.framepos = frame_pos_to_dvap; + dr.frame.streamid = stream_id_to_dvap; + dr.frame.framepos = frame_pos_to_dvap; if ((net_buf.vpkt.myicm.ctrl & 0x40) != 0) - dd.framepos |= 0x40U; - dd.seq = seq_to_dvap; - memcpy(dd.audio, net_buf.vpkt.vasd.voice, 12); - (void)write_to_dvp((unsigned char *)&dd, 18); + dr.frame.framepos |= 0x40U; + dr.frame.seq = seq_to_dvap; + memcpy(&dr.frame.vad.voice, net_buf.vpkt.vasd.voice, 12); + dongle.SendRegister(dr); frame_pos_to_dvap ++; seq_to_dvap ++; @@ -1358,15 +663,15 @@ static void readFrom20000() silence[11] = 0x93; } - SDVAP_DATA dd; - memcpy(&dd, DVP_DAT, 2); + SDVAP_REGISTER dr; + dr.header = 0xc012u; if (memcmp(silence + 9, sync_codes, 3) == 0) frame_pos_to_dvap = 0; - dd.streamid = stream_id_to_dvap; - dd.framepos = frame_pos_to_dvap; - dd.seq = seq_to_dvap; - memcpy(dd.audio, silence, 12); - (void)write_to_dvp((unsigned char *)&dd, 18); + dr.frame.streamid = stream_id_to_dvap; + dr.frame.framepos = frame_pos_to_dvap; + dr.frame.seq = seq_to_dvap; + memcpy(&dr.frame.vad.voice, silence, 12); + dongle.SendRegister(dr); frame_pos_to_dvap ++; seq_to_dvap++; @@ -1445,12 +750,12 @@ int main(int argc, const char **argv) } /* open dvp */ - if (!open_dvp()) + if (!dongle.Initialize(DVP_SERIAL, DVP_FREQ, DVP_OFF, DVP_PWR, DVP_SQL)) return 1; rc = open_sock(); if (rc != 0) { - (void)write_to_dvp(DVP_RQST_STOP, 5); + dongle.Stop(); close(serfd); return 1; } @@ -1469,7 +774,7 @@ int main(int argc, const char **argv) while (keep_running) { time(&tnow); if ((tnow - ackpoint) > 2) { - rc = write_to_dvp(DVP_ACK, 3); + rc = dongle.KeepAlive(); if (rc < 0) { cnt ++; if (cnt > 5) { @@ -1531,34 +836,31 @@ static void RptrAckThread(SDVAP_ACK_ARG *parg) // HEADER while ((space < 1) && keep_running) usleep(5); - SDVAP_HDR dvh; - dvh.hdr0 = 0x2f; - dvh.hdr1 = 0xa0; - dvh.streamid = stream_id_to_dvap; - dvh.framepos = 0x80; - dvh.seq = 0; - dvh.flag[0] = 0x01; - dvh.flag[1] = dvh.flag[2] = 0x00; - memcpy(dvh.rpt1, RPTR_and_MOD, 8); - memcpy(dvh.rpt2, RPTR_and_G, 8); - memcpy(dvh.urcall, mycall, 8); - memcpy(dvh.mycall, RPTR_and_MOD, 8); - memcpy(dvh.sfx, (unsigned char *)" ", 4); - calcPFCS(dvh.flag, dvh.pfcs); - (void)write_to_dvp(&dvh.hdr0, 47); + SDVAP_REGISTER dr; + dr.header = 0xa02fu; + dr.frame.streamid = stream_id_to_dvap; + dr.frame.framepos = 0x80; + dr.frame.seq = 0; + dr.frame.hdr.flag[0] = 0x01; + dr.frame.hdr.flag[1] = dr.frame.hdr.flag[2] = 0x00; + memcpy(dr.frame.hdr.rpt1, RPTR_and_MOD, 8); + memcpy(dr.frame.hdr.rpt2, RPTR_and_G, 8); + memcpy(dr.frame.hdr.urcall, mycall, 8); + memcpy(dr.frame.hdr.mycall, RPTR_and_MOD, 8); + memcpy(dr.frame.hdr.sfx, (unsigned char *)" ", 4); + calcPFCS(dr.frame.hdr.flag, dr.frame.hdr.pfcs); + dongle.SendRegister(dr); nanos.tv_sec = 0; nanos.tv_nsec = DELAY_BETWEEN * 1000000; nanosleep(&nanos,0); // SYNC - SDVAP_DATA dvd; - dvd.hdr0 = 0x12; - dvd.hdr1 = 0xc0; - dvd.streamid = stream_id_to_dvap; + dr.header = 0xc012u; + dr.frame.streamid = stream_id_to_dvap; for (int i=0; i<10; i++) { while ((space < 1) && keep_running) usleep(5); - dvd.framepos = dvd.seq = i; + dr.frame.framepos = dr.frame.seq = i; switch (i) { case 0: silence[9] = 0x55; @@ -1612,11 +914,11 @@ static void RptrAckThread(SDVAP_ACK_ARG *parg) silence[9] = 0x55; silence[10] = 0x55; silence[11] = 0x55; - dvd.framepos |= 0x40; + dr.frame.framepos |= 0x40; break; } - memcpy(dvd.audio, silence, 12); - (void)write_to_dvp(&dvd.hdr0, 18); + memcpy(&dr.frame.vad.voice, silence, 12); + dongle.SendRegister(dr); if (i < 9) { nanos.tv_sec = 0; nanos.tv_nsec = DELAY_BETWEEN * 1000000; @@ -1629,10 +931,9 @@ static void RptrAckThread(SDVAP_ACK_ARG *parg) static void ReadDVAPThread() { REPLY_TYPE reply; - unsigned int len = 0; - unsigned char dvp_buf[200]; SPKT net_buf; SPKT spack; + SDVAP_REGISTER dr; time_t tnow = 0; time_t S_ctrl_msg_time = 0; unsigned short C_COUNTER = 0; @@ -1641,8 +942,6 @@ static void ReadDVAPThread() bool dvap_busy = false; // bool ptt = false; bool the_end = true; - SDVAP_HDR *from_dvap_hdr = (SDVAP_HDR *)dvp_buf; - // dvap_voice *from_dvap_voice = (dvap_voice *)dvp_buf; bool ok = true; int i = 0; u_int16_t streamid_raw = 0; @@ -1706,7 +1005,7 @@ static void ReadDVAPThread() } // read from the dvap and process - reply = get_reply(dvp_buf, &len); + reply = dongle.get_reply(dr); if (reply == RT_ERR) { traceit("Detected ERROR event from DVAP dongle, stopping...n"); break; @@ -1719,7 +1018,7 @@ static void ReadDVAPThread() // ptt = (dvp_buf[4] == 0x01); // traceit("Detected PTT=%s\n", ptt?"on":"off"); } else if (reply == RT_STS) { - space = dvp_buf[6]; + space = (unsigned int)dr.param.sstr[2]; if (status_cntr < 3000) status_cntr += 20; } else if (reply == RT_HDR) { @@ -1727,40 +1026,40 @@ static void ReadDVAPThread() num_bit_errors = 0; traceit("From DVAP: flags=%02x:%02x:%02x, my=%.8s, sfx=%.4s, ur=%.8s, rpt1=%.8s, rpt2=%.8s\n", - from_dvap_hdr->flag[0], from_dvap_hdr->flag[1], from_dvap_hdr->flag[2], - from_dvap_hdr->mycall, from_dvap_hdr->sfx, from_dvap_hdr->urcall, - from_dvap_hdr->rpt2, from_dvap_hdr->rpt1); + dr.frame.hdr.flag[0], dr.frame.hdr.flag[1], dr.frame.hdr.flag[2], + dr.frame.hdr.mycall, dr.frame.hdr.sfx, dr.frame.hdr.urcall, + dr.frame.hdr.rpt2, dr.frame.hdr.rpt1); ok = true; /* Accept valid flags only */ if (ok) { - if ((from_dvap_hdr->flag[0] != 0x00) && (from_dvap_hdr->flag[0] != 0x08) && // net - (from_dvap_hdr->flag[0] != 0x20) && (from_dvap_hdr->flag[0] != 0x28) && // flags + if ((dr.frame.hdr.flag[0] != 0x00) && (dr.frame.hdr.flag[0] != 0x08) && // net + (dr.frame.hdr.flag[0] != 0x20) && (dr.frame.hdr.flag[0] != 0x28) && // flags - (from_dvap_hdr->flag[0] != 0x40) && (from_dvap_hdr->flag[0] != 0x48) && // rptr - (from_dvap_hdr->flag[0] != 0x60) && (from_dvap_hdr->flag[0] != 0x68)) // flags + (dr.frame.hdr.flag[0] != 0x40) && (dr.frame.hdr.flag[0] != 0x48) && // rptr + (dr.frame.hdr.flag[0] != 0x60) && (dr.frame.hdr.flag[0] != 0x68)) // flags ok = false; } /* Reject those stupid STN stations */ if (ok) { - memcpy(temp_yrcall, from_dvap_hdr->urcall, CALL_SIZE); + memcpy(temp_yrcall, dr.frame.hdr.urcall, CALL_SIZE); temp_yrcall[CALL_SIZE] = '\0'; temp_ptr = strstr(temp_yrcall, INVALID_YRCALL_KEY); if (temp_ptr == temp_yrcall) { // found it at first position traceit("YRCALL value [%s] starts with the INVALID_YRCALL_KEY [%s], resetting to CQCQCQ\n", temp_yrcall, INVALID_YRCALL_KEY); - memcpy(from_dvap_hdr->urcall, "CQCQCQ ", 8); + memcpy(dr.frame.hdr.urcall, "CQCQCQ ", 8); } } - memcpy(&net_buf.vpkt.hdr, from_dvap_hdr->flag, 41); // copy the header + memcpy(&net_buf.vpkt.hdr, dr.frame.hdr.flag, 41); // copy the header /* RPT1 must always be the repeater + module */ memcpy(net_buf.vpkt.hdr.rpt2, RPTR_and_MOD, 8); /* copy RPT2 */ - memcpy(net_buf.vpkt.hdr.rpt1, from_dvap_hdr->rpt1, 8); + memcpy(net_buf.vpkt.hdr.rpt1, dr.frame.hdr.rpt1, 8); /* RPT2 must also be valid */ if ((net_buf.vpkt.hdr.rpt1[7] == 'A') || @@ -1831,13 +1130,13 @@ static void ReadDVAPThread() memcpy(net_buf.vpkt.hdr.urcall, "CQCQCQ ", 8); /* change the rptr flags to net flags */ - if (from_dvap_hdr->flag[0] == 0x40) + if (dr.frame.hdr.flag[0] == 0x40) net_buf.vpkt.hdr.flag[0] = 0x00; - else if (from_dvap_hdr->flag[0] == 0x48) + else if (dr.frame.hdr.flag[0] == 0x48) net_buf.vpkt.hdr.flag[0] = 0x08; - else if (from_dvap_hdr->flag[0] == 0x60) + else if (dr.frame.hdr.flag[0] == 0x60) net_buf.vpkt.hdr.flag[0] = 0x20; - else if (from_dvap_hdr->flag[0] == 0x68) + else if (dr.frame.hdr.flag[0] == 0x68) net_buf.vpkt.hdr.flag[0] = 0x28; else net_buf.vpkt.hdr.flag[0] = 0x00; @@ -1882,13 +1181,13 @@ static void ReadDVAPThread() time(&last_RF_time); // save mycall for the ack later - memcpy(mycall, from_dvap_hdr->mycall, 8); + memcpy(mycall, dr.frame.hdr.mycall, 8); } } else if (reply == RT_DAT) { /* have we already received a header ? */ if (dvap_busy) { - the_end = ((dvp_buf[4] & 0x40) == 0x40); + the_end = ((dr.frame.hdr.flag[0] & 0x40) == 0x40); net_buf.nothing1[0] = ((C_COUNTER >> 8) & 0xff); net_buf.nothing1[1] = (unsigned char)(C_COUNTER & 0xff); @@ -1896,7 +1195,7 @@ static void ReadDVAPThread() net_buf.vpkt.myicm.ctrl = sequence++; if (the_end) net_buf.vpkt.myicm.ctrl = sequence | 0x40; - memcpy(&net_buf.vpkt.vasd, dvp_buf + 6, 12); + memcpy(&net_buf.vpkt.vasd, &dr.frame.vad.voice, 12); sendto(insock, &net_buf, 29, 0, (struct sockaddr *)&outaddr, sizeof(outaddr)); int ber_data[3]; @@ -1937,7 +1236,7 @@ static void ReadDVAPThread() } /* stop dvap */ - (void)write_to_dvp(DVP_RQST_STOP, 5); + dongle.Stop(); close(serfd); traceit("ReadDVAPThread exiting\n");