Merge branch 'release/0.7'

master v0.7
Geoffrey Merck 3 years ago
commit 0c1dbb5bd4

@ -73,7 +73,25 @@
"typeindex": "cpp",
"variant": "cpp",
"iostream": "cpp",
"fstream": "cpp"
"fstream": "cpp",
"csignal": "cpp",
"cstdarg": "cpp",
"strstream": "cpp",
"codecvt": "cpp",
"numeric": "cpp",
"regex": "cpp",
"cfenv": "cpp",
"cinttypes": "cpp"
},
"files.exclude": {
"**/.DS_Store": true,
"**/.git": true,
"**/.hg": true,
"**/.svn": true,
"**/*.d": true,
"**/*.o": true,
"**/CVS": true,
"**/Thumbs.db": true
},
"editor.tokenColorCustomizations": {
"textMateRules": [

10
.vscode/tasks.json vendored

@ -13,10 +13,7 @@
"USE_GPSD=1",
"all"
],
"group": {
"kind": "build",
"isDefault": true
},
"group": "build",
"problemMatcher": []
},
{
@ -94,7 +91,10 @@
"ENABLE_DEBUG=1",
"USE_GPSD=1"
],
"group": "build",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": []
}
]

@ -138,6 +138,11 @@ bool CAPRSParser::parseInt(CAPRSFrame& frame)
type = APFT_TELEMETRY;
}
break;
case ';' :
if( body.length() >= 10 && (body[9] == '*' || body[9] == '_')) {
type = APFT_OBJECT;
}
break;
default:
type = APFT_UNKNOWN;
break;

@ -70,7 +70,7 @@ void CUtils::dump(const char* title, const bool* data, unsigned int length)
output += "*'";
CLog::logInfo("%04X: %s\n", offset / 8U, output.c_str());
CLog::logDebug("%04X: %s\n", offset / 8U, output.c_str());
offset += 128U;
}
@ -115,7 +115,7 @@ void CUtils::dumpRev(const char* title, const bool* data, unsigned int length)
output += "*";
CLog::logInfo("%04X: %s\n", offset / 8U, output.c_str());
CLog::logDebug("%04X: %s\n", offset / 8U, output.c_str());
offset += 128U;
}
@ -157,7 +157,7 @@ void CUtils::dump(const char* title, const unsigned char* data, unsigned int len
output += "*";
CLog::logInfo("%04X: %s\n", offset, output.c_str());
CLog::logDebug("%04X: %s\n", offset, output.c_str());
offset += 16U;

@ -51,10 +51,14 @@ CAPRSCollector::~CAPRSCollector()
m_collectors.clear();
}
void CAPRSCollector::writeHeader(const std::string& callsign)
void CAPRSCollector::writeHeader(const CHeaderData& header)
{
std::string mycall1 = header.getMyCall1();
std::string mycall2 = header.getMyCall2();
for(auto collector : m_collectors) {
collector->setMyCall(callsign);
collector->setMyCall1(mycall1);
collector->setMyCall2(mycall2);
}
}
@ -95,12 +99,12 @@ unsigned int CAPRSCollector::getData(unsigned char dataType, unsigned char* data
return 0U;
}
void CAPRSCollector::getData(std::function<void(const std::string&)> dataHandler)
void CAPRSCollector::getData(std::function<void(const std::string&, const std::string&)> dataHandler)
{
for(auto collector : m_collectors) {
std::string data;
if(collector->getData(data)) {
dataHandler(data);
dataHandler(data, collector->getMyCall1().append("/").append(collector->getMyCall2()));
collector->reset();
}
}

@ -24,6 +24,7 @@
#include <functional>
#include "SlowDataCollector.h"
#include "HeaderData.h"
#include "Defs.h"
enum APRS_STATE {
@ -39,7 +40,7 @@ public:
CAPRSCollector();
~CAPRSCollector();
void writeHeader(const std::string& callsign);
void writeHeader(const CHeaderData& callsign);
bool writeData(const unsigned char* data);
@ -49,7 +50,7 @@ public:
unsigned int getData(unsigned char dataType, unsigned char* data, unsigned int length);
void getData(std::function<void(const std::string&)> dataHandler);
void getData(std::function<void(const std::string&, const std::string&)> dataHandler);
void clock(unsigned int ms);

@ -23,13 +23,13 @@
#include "APRSFixedIdFrameProvider.h"
#include "StringUtils.h"
CAPRSFixedIdFrameProvider::CAPRSFixedIdFrameProvider() :
CAPRSIdFrameProvider(20U) // Initial timeout of 20 seconds
CAPRSFixedIdFrameProvider::CAPRSFixedIdFrameProvider(const std::string& gateway) :
CAPRSIdFrameProvider(gateway, 20U) // Initial timeout of 20 seconds
{
}
bool CAPRSFixedIdFrameProvider::buildAPRSFramesInt(const std::string& gateway, const CAPRSEntry * entry, std::vector<CAPRSFrame *>& frames)
bool CAPRSFixedIdFrameProvider::buildAPRSFramesInt(const CAPRSEntry * entry, std::vector<CAPRSFrame *>& frames)
{
if (entry == nullptr)
return false;
@ -114,9 +114,9 @@ bool CAPRSFixedIdFrameProvider::buildAPRSFramesInt(const std::string& gateway, c
lon.c_str(), (entry->getLongitude() < 0.0F) ? 'W' : 'E',
entry->getRange() * 0.6214, entry->getAGL() * 3.28, band.c_str(), desc.c_str());
CAPRSFrame * frame = new CAPRSFrame(gateway + "-S",
CAPRSFrame * frame = new CAPRSFrame(m_gateway + "-S",
"APD5T1",
{ "TCPIP*", "qAC" , gateway + "-GS" },
{ "TCPIP*", "qAC" , m_gateway + "-GS" },
body, APFT_OBJECT);
frames.push_back(frame);

@ -23,8 +23,8 @@
class CAPRSFixedIdFrameProvider : public CAPRSIdFrameProvider
{
public:
CAPRSFixedIdFrameProvider();
CAPRSFixedIdFrameProvider(const std::string& gateway);
protected:
virtual bool buildAPRSFramesInt(const std::string& gateway, const CAPRSEntry * aprsEntry, std::vector<CAPRSFrame *>& frames);
virtual bool buildAPRSFramesInt(const CAPRSEntry * aprsEntry, std::vector<CAPRSFrame *>& frames);
};

@ -24,8 +24,8 @@
#include "StringUtils.h"
#include "Log.h"
CAPRSGPSDIdFrameProvider::CAPRSGPSDIdFrameProvider(std::string address, std::string port) :
CAPRSIdFrameProvider(20U),
CAPRSGPSDIdFrameProvider::CAPRSGPSDIdFrameProvider(const std::string& gateway, const std::string& address, const std::string& port) :
CAPRSIdFrameProvider(gateway, 20U),
m_gpsdAddress(address),
m_gpsdPort(port),
m_gpsdData(),
@ -56,7 +56,7 @@ void CAPRSGPSDIdFrameProvider::close()
}
}
bool CAPRSGPSDIdFrameProvider::buildAPRSFramesInt(const std::string& gateway, const CAPRSEntry * entry, std::vector<CAPRSFrame *>& frames)
bool CAPRSGPSDIdFrameProvider::buildAPRSFramesInt(const CAPRSEntry * entry, std::vector<CAPRSFrame *>& frames)
{
if(!m_hasConnection) {
this->start();
@ -182,9 +182,9 @@ bool CAPRSGPSDIdFrameProvider::buildAPRSFramesInt(const std::string& gateway, co
body.append(CStringUtils::string_format("RNG%04.0lf %s %s\r\n", entry->getRange() * 0.6214, band.c_str(), desc.c_str()));
CAPRSFrame * frame = new CAPRSFrame(gateway + "-S",
CAPRSFrame * frame = new CAPRSFrame(m_gateway + "-S",
"APD5T1",
{ "TCPIP*", "qAC" , gateway + "-GS" },
{ "TCPIP*", "qAC" , m_gateway + "-GS" },
body, APFT_OBJECT);
@ -201,9 +201,9 @@ bool CAPRSGPSDIdFrameProvider::buildAPRSFramesInt(const std::string& gateway, co
lat.c_str(), (rawLatitude < 0.0) ? 'S' : 'N',
lon.c_str(), (rawLongitude < 0.0) ? 'W' : 'E');
frame = new CAPRSFrame(gateway,
frame = new CAPRSFrame(m_gateway,
"APD5T2",
{ "TCPIP*", "qAC" , gateway + "-GS" },
{ "TCPIP*", "qAC" , m_gateway + "-GS" },
body, APFT_POSITION);
frames.push_back(frame);

@ -29,13 +29,13 @@
class CAPRSGPSDIdFrameProvider : public CAPRSIdFrameProvider
{
public:
CAPRSGPSDIdFrameProvider(std::string address, std::string port);
CAPRSGPSDIdFrameProvider(const std::string& gateway, const std::string& address, const std::string& port);
virtual void start();
virtual void close();
protected:
virtual bool buildAPRSFramesInt(const std::string& gateway, const CAPRSEntry * aprsEntry, std::vector<CAPRSFrame *>& frames);
virtual bool buildAPRSFramesInt(const CAPRSEntry * aprsEntry, std::vector<CAPRSFrame *>& frames);
private:
std::string m_gpsdAddress;

@ -18,7 +18,6 @@
*/
#include <cassert>
#include <boost/algorithm/string.hpp>
#include <cmath>
#include <cassert>
#include <algorithm>
@ -34,24 +33,12 @@
#include "APRSFormater.h"
#include "APRSUtils.h"
CAPRSHandler::CAPRSHandler(const std::string& hostname, unsigned int port, const std::string& gateway, const std::string& password, const std::string& address) :
m_thread(NULL),
m_gateway(),
m_address(),
m_port(0U),
CAPRSHandler::CAPRSHandler(IAPRSHandlerBackend* thread) :
m_backend(thread),
m_array(),
m_idFrameProvider(nullptr)
{
assert(!hostname.empty());
assert(port > 0U);
assert(!gateway.empty());
assert(!password.empty());
m_thread = new CAPRSHandlerThread(gateway, password, address, hostname, port);
m_gateway = gateway;
m_gateway = m_gateway.substr(0, LONG_CALLSIGN_LENGTH - 1U);
boost::trim(m_gateway);
assert(thread != nullptr);
}
CAPRSHandler::~CAPRSHandler()
@ -61,6 +48,7 @@ CAPRSHandler::~CAPRSHandler()
}
m_array.clear();
delete m_backend;
}
void CAPRSHandler::setPort(const std::string& callsign, const std::string& band, double frequency, double offset, double range, double latitude, double longitude, double agl)
@ -74,7 +62,7 @@ void CAPRSHandler::setPort(const std::string& callsign, const std::string& band,
bool CAPRSHandler::open()
{
return m_thread->start();
return m_backend->start();
}
void CAPRSHandler::writeHeader(const std::string& callsign, const CHeaderData& header)
@ -89,7 +77,7 @@ void CAPRSHandler::writeHeader(const std::string& callsign, const CHeaderData& h
CAPRSCollector* collector = entry->getCollector();
collector->writeHeader(header.getMyCall1());
collector->writeHeader(header);
}
void CAPRSHandler::writeData(const std::string& callsign, const CAMBEData& data)
@ -117,22 +105,22 @@ void CAPRSHandler::writeData(const std::string& callsign, const CAMBEData& data)
if (!complete)
return;
if (!m_thread->isConnected()) {
if (!m_backend->isConnected()) {
collector->reset();
return;
}
collector->getData([=](const std::string& text)
collector->getData([=](const std::string& rawFrame, const std::string& dstarCall)
{
CAPRSFrame frame;
if(!CAPRSParser::parseFrame(text, frame)) {
CLog::logWarning("Failed to parse DPRS Frame : %s", text.c_str());
if(!CAPRSParser::parseFrame(rawFrame, frame)) {
CLog::logWarning("Failed to parse DPRS Frame : %s", rawFrame.c_str());
return;
}
// If we already have a q-construct, don't send it on
if(std::any_of(frame.getPath().begin(), frame.getPath().end(), [] (std::string s) { return !s.empty() && s[0] == 'q'; })) {
CLog::logWarning("DPRS Frame already has q construct, not forwarding to APRS-IS: %s", text.c_str());
CLog::logWarning("DPRS Frame already has q construct, not forwarding to APRS-IS: %s", rawFrame.c_str());
return;
}
@ -142,7 +130,9 @@ void CAPRSHandler::writeData(const std::string& callsign, const CAMBEData& data)
std::string output ;
CAPRSFormater::frameToString(output, frame);
m_thread->write(frame);
CLog::logInfo("DPRS\t%s\t%s\t%s", dstarCall.c_str(), frame.getSource().c_str(), rawFrame.c_str());
m_backend->write(frame);
});
}
@ -159,7 +149,7 @@ void CAPRSHandler::writeStatus(const std::string& callsign, const std::string st
void CAPRSHandler::clock(unsigned int ms)
{
m_thread->clock(ms);
m_backend->clock(ms);
if(m_idFrameProvider != nullptr) {
m_idFrameProvider->clock(ms);
@ -181,7 +171,7 @@ void CAPRSHandler::sendStatusFrame(CAPRSEntry * entry)
{
assert(entry != nullptr);
if(!m_thread->isConnected())
if(!m_backend->isConnected())
return;
@ -199,19 +189,19 @@ void CAPRSHandler::sendStatusFrame(CAPRSEntry * entry)
body,
APFT_STATUS);
m_thread->write(frame);
m_backend->write(frame);
}
void CAPRSHandler::sendIdFrames()
{
if(m_thread->isConnected())
if(m_backend->isConnected())
{
for(auto entry : m_array) {
std::vector<CAPRSFrame *> frames;
if(m_idFrameProvider->buildAPRSFrames(m_gateway, entry.second, frames)) {
if(m_idFrameProvider->buildAPRSFrames(entry.second, frames)) {
for(auto frame : frames) {
m_thread->write(*frame);
m_backend->write(*frame);
delete frame;
}
}
@ -221,12 +211,12 @@ void CAPRSHandler::sendIdFrames()
bool CAPRSHandler::isConnected() const
{
return m_thread->isConnected();
return m_backend->isConnected();
}
void CAPRSHandler::close()
{
m_thread->stop();
m_backend->stop();
if(m_idFrameProvider != nullptr) {
m_idFrameProvider->close();
@ -237,5 +227,5 @@ void CAPRSHandler::close()
void CAPRSHandler::addReadAPRSCallback(IReadAPRSFrameCallback* cb)
{
m_thread->addReadAPRSCallback(cb);
m_backend->addReadAPRSCallback(cb);
}

@ -26,7 +26,6 @@
#include "APRSEntry.h"
#include "APRSHandlerThread.h"
#include "UDPReaderWriter.h"
#include "APRSCollector.h"
#include "DStarDefines.h"
@ -34,10 +33,11 @@
#include "AMBEData.h"
#include "Timer.h"
#include "APRSIdFrameProvider.h"
#include "IAPRSHandlerBackend.h"
class CAPRSHandler {
public:
CAPRSHandler(const std::string& hostname, unsigned int port, const std::string& gateway, const std::string& password, const std::string& address);
CAPRSHandler(IAPRSHandlerBackend * thread);
~CAPRSHandler();
bool open();
@ -61,10 +61,7 @@ public:
void addReadAPRSCallback(IReadAPRSFrameCallback* cb);
private:
CAPRSHandlerThread* m_thread;
std::string m_gateway;
in_addr m_address;
unsigned int m_port;
IAPRSHandlerBackend* m_backend;
std::unordered_map<std::string,CAPRSEntry *> m_array;
CAPRSIdFrameProvider * m_idFrameProvider;

@ -21,7 +21,7 @@
#include <iostream>
#include <boost/algorithm/string.hpp>
#include "APRSHandlerThread.h"
#include "APRSISHandlerThread.h"
#include "DStarDefines.h"
#include "Utils.h"
#include "Defs.h"
@ -36,7 +36,7 @@ const unsigned int APRS_TIMEOUT = 10U;
const unsigned int APRS_READ_TIMEOUT = 1U;
const unsigned int APRS_KEEP_ALIVE_TIMEOUT = 60U;
CAPRSHandlerThread::CAPRSHandlerThread(const std::string& callsign, const std::string& password, const std::string& address, const std::string& hostname, unsigned int port) :
CAPRSISHandlerThread::CAPRSISHandlerThread(const std::string& callsign, const std::string& password, const std::string& address, const std::string& hostname, unsigned int port) :
CThread("APRS"),
m_username(callsign),
m_password(password),
@ -64,7 +64,7 @@ m_clientName(FULL_PRODUCT_NAME)
m_ssid = m_ssid.substr(LONG_CALLSIGN_LENGTH - 1U, 1);
}
CAPRSHandlerThread::CAPRSHandlerThread(const std::string& callsign, const std::string& password, const std::string& address, const std::string& hostname, unsigned int port, const std::string& filter) :
CAPRSISHandlerThread::CAPRSISHandlerThread(const std::string& callsign, const std::string& password, const std::string& address, const std::string& hostname, unsigned int port, const std::string& filter) :
CThread("APRS"),
m_username(callsign),
m_password(password),
@ -92,7 +92,7 @@ m_clientName(FULL_PRODUCT_NAME)
m_ssid = m_ssid.substr(LONG_CALLSIGN_LENGTH - 1U, 1);
}
CAPRSHandlerThread::~CAPRSHandlerThread()
CAPRSISHandlerThread::~CAPRSISHandlerThread()
{
std::vector<IReadAPRSFrameCallback *> callBacksCopy;
callBacksCopy.assign(m_APRSReadCallbacks.begin(), m_APRSReadCallbacks.end());
@ -105,7 +105,7 @@ CAPRSHandlerThread::~CAPRSHandlerThread()
m_password.clear();
}
bool CAPRSHandlerThread::start()
bool CAPRSISHandlerThread::start()
{
Create();
Run();
@ -113,7 +113,7 @@ bool CAPRSHandlerThread::start()
return true;
}
void* CAPRSHandlerThread::Entry()
void* CAPRSISHandlerThread::Entry()
{
CLog::logInfo("Starting the APRS Writer thread");
@ -151,7 +151,7 @@ void* CAPRSHandlerThread::Entry()
if(!m_queue.empty()){
auto frameStr = m_queue.getData();
CLog::logInfo("APRS ==> %s", frameStr.c_str());
CLog::logInfo("APRS Frame sent to IS ==> %s", frameStr.c_str());
bool ret = m_socket.writeLine(frameStr);
if (!ret) {
@ -176,7 +176,7 @@ void* CAPRSHandlerThread::Entry()
}
else if(line.length() > 0 && line[0] != '#') {
m_keepAliveTimer.start();
CLog::logDebug("APRS <== %s", line.c_str());
CLog::logDebug("APRS Frame received from IS <== %s", line.c_str());
CAPRSFrame readFrame;
if(CAPRSParser::parseFrame(line, readFrame)) {
for(auto cb : m_APRSReadCallbacks) {
@ -214,13 +214,13 @@ void* CAPRSHandlerThread::Entry()
return NULL;
}
void CAPRSHandlerThread::addReadAPRSCallback(IReadAPRSFrameCallback * cb)
void CAPRSISHandlerThread::addReadAPRSCallback(IReadAPRSFrameCallback * cb)
{
assert(cb != nullptr);
m_APRSReadCallbacks.push_back(cb);
}
void CAPRSHandlerThread::write(CAPRSFrame& frame)
void CAPRSISHandlerThread::write(CAPRSFrame& frame)
{
if (!m_connected)
return;
@ -235,25 +235,25 @@ void CAPRSHandlerThread::write(CAPRSFrame& frame)
}
}
bool CAPRSHandlerThread::isConnected() const
bool CAPRSISHandlerThread::isConnected() const
{
return m_connected;
}
void CAPRSHandlerThread::stop()
void CAPRSISHandlerThread::stop()
{
m_exit = true;
Wait();
}
void CAPRSHandlerThread::clock(unsigned int ms)
void CAPRSISHandlerThread::clock(unsigned int ms)
{
m_reconnectTimer.clock(ms);
m_keepAliveTimer.clock(ms);
}
bool CAPRSHandlerThread::connect()
bool CAPRSISHandlerThread::connect()
{
m_socket.close();
bool ret = m_socket.open();
@ -304,7 +304,7 @@ bool CAPRSHandlerThread::connect()
return true;
}
void CAPRSHandlerThread::startReconnectionTimer()
void CAPRSISHandlerThread::startReconnectionTimer()
{
// Clamp at a ten minutes reconnect time
m_tries++;

@ -25,15 +25,15 @@
#include "RingBuffer.h"
#include "Timer.h"
#include "Thread.h"
#include "ReadAPRSFrameCallback.h"
#include "IAPRSHandlerBackend.h"
#include "APRSFrame.h"
class CAPRSHandlerThread : public CThread {
class CAPRSISHandlerThread : public CThread, IAPRSHandlerBackend {
public:
CAPRSHandlerThread(const std::string& callsign, const std::string& password, const std::string& address, const std::string& hostname, unsigned int port);
CAPRSHandlerThread(const std::string& callsign, const std::string& password, const std::string& address, const std::string& hostname, unsigned int port, const std::string& filter);
virtual ~CAPRSHandlerThread();
CAPRSISHandlerThread(const std::string& callsign, const std::string& password, const std::string& address, const std::string& hostname, unsigned int port);
CAPRSISHandlerThread(const std::string& callsign, const std::string& password, const std::string& address, const std::string& hostname, unsigned int port, const std::string& filter);
virtual ~CAPRSISHandlerThread();
bool start();

@ -17,13 +17,21 @@
*/
#include <cassert>
#include <boost/algorithm/string.hpp>
#include "APRSIdFrameProvider.h"
CAPRSIdFrameProvider::CAPRSIdFrameProvider(unsigned int timeout) :
CAPRSIdFrameProvider::CAPRSIdFrameProvider(const std::string& gateway, unsigned int timeout) :
m_gateway(),
m_timer(1000U)
{
assert(!gateway.empty());
m_timer.start(timeout);
m_gateway = gateway;
m_gateway = m_gateway.substr(0, LONG_CALLSIGN_LENGTH - 1U);
boost::trim(m_gateway);
}
CAPRSIdFrameProvider::~CAPRSIdFrameProvider()
@ -31,11 +39,11 @@ CAPRSIdFrameProvider::~CAPRSIdFrameProvider()
}
bool CAPRSIdFrameProvider::buildAPRSFrames(const std::string& gateway, const CAPRSEntry * entry, std::vector<CAPRSFrame *> & frames)
bool CAPRSIdFrameProvider::buildAPRSFrames(const CAPRSEntry * entry, std::vector<CAPRSFrame *> & frames)
{
assert(entry != nullptr);
return buildAPRSFramesInt(gateway, entry, frames);
return buildAPRSFramesInt(entry, frames);
}
bool CAPRSIdFrameProvider::wantsToSend()

@ -27,23 +27,25 @@
class CAPRSIdFrameProvider
{
public:
CAPRSIdFrameProvider(unsigned int timeOut);
CAPRSIdFrameProvider(const std::string& gateway, unsigned int timeOut);
virtual ~CAPRSIdFrameProvider();
bool buildAPRSFrames(const std::string& gateway, const CAPRSEntry * aprsEntry, std::vector<CAPRSFrame *>& frames);
bool buildAPRSFrames(const CAPRSEntry * aprsEntry, std::vector<CAPRSFrame *>& frames);
void clock(unsigned int ms) { m_timer.clock(ms); }
bool wantsToSend();
virtual void start() { };
virtual void close() { };
protected:
virtual bool buildAPRSFramesInt(const std::string& gateway, const CAPRSEntry * aprsEntry, std::vector<CAPRSFrame *>& frames) = 0;
virtual bool buildAPRSFramesInt(const CAPRSEntry * aprsEntry, std::vector<CAPRSFrame *>& frames) = 0;
void setTimeout(unsigned int timeout)
{
m_timer.start(timeout);
}
protected:
std::string m_gateway;
private:
CTimer m_timer;
};

@ -0,0 +1,55 @@
/*
* Copyright (C) 2021, 2022 by Geoffrey Merck F4FXL / KC3FRA
*
* 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 "DummyAPRSHandlerThread.h"
CDummyAPRSHandlerBackend::CDummyAPRSHandlerBackend()
{
}
CDummyAPRSHandlerBackend::~CDummyAPRSHandlerBackend()
{
}
bool CDummyAPRSHandlerBackend::start()
{
return true;
}
bool CDummyAPRSHandlerBackend::isConnected() const
{
return true;
}
void CDummyAPRSHandlerBackend::write(CAPRSFrame &)
{
}
void CDummyAPRSHandlerBackend::clock(unsigned int)
{
}
void CDummyAPRSHandlerBackend::stop()
{
}
void CDummyAPRSHandlerBackend::addReadAPRSCallback(IReadAPRSFrameCallback *)
{
}

@ -0,0 +1,35 @@
/*
* Copyright (C) 2021, 2022 by Geoffrey Merck F4FXL / KC3FRA
*
* 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.
*/
#pragma once
#include "IAPRSHandlerBackend.h"
class CDummyAPRSHandlerBackend : public IAPRSHandlerBackend
{
public:
CDummyAPRSHandlerBackend();
~CDummyAPRSHandlerBackend();
bool start();
bool isConnected() const;
void write(CAPRSFrame& frame);
void clock(unsigned int ms);
void stop();
void addReadAPRSCallback(IReadAPRSFrameCallback* cb);
};

@ -64,10 +64,11 @@ bool CHeardData::setIcomRepeaterData(const unsigned char *data, unsigned int len
assert(data != NULL);
assert(length >= 26U);
std::string sdata((const char *)data);
std::string suser((const char *)data + 10U);
std::string srptr((const char *)data + 18U);
m_user = sdata.substr(10, LONG_CALLSIGN_LENGTH);
m_repeater = sdata.substr(18, LONG_CALLSIGN_LENGTH);
m_user = suser.substr(0, LONG_CALLSIGN_LENGTH);
m_repeater = srptr.substr(0, LONG_CALLSIGN_LENGTH);
m_address = address;
m_port = port;

@ -0,0 +1,35 @@
/*
* Copyright (C) 2021, 2022 by Geoffrey Merck F4FXL / KC3FRA
*
* 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.
*/
#pragma once
#include "APRSFrame.h"
#include "ReadAPRSFrameCallback.h"
class IAPRSHandlerBackend
{
public:
virtual ~IAPRSHandlerBackend() { } ;
virtual bool start() = 0;
virtual bool isConnected() const = 0;
virtual void write(CAPRSFrame& frame) = 0;
virtual void clock(unsigned int ms) = 0;
virtual void stop() = 0;
virtual void addReadAPRSCallback(IReadAPRSFrameCallback* cb) = 0;
};

@ -58,7 +58,7 @@ unsigned char CNMEASentenceCollector::calcXOR(const std::string& nmea)
unsigned char res = 0U;
if(!nmea.empty()) {
unsigned int i = nmea[0] == '$' ? 1U : 0U; //skip $ it it is there
unsigned int i = nmea[0] == '$' ? 1U : 0U; //skip $ if it is there
while(i < nmea.length())
{
if(nmea[i] != '*') {
@ -98,15 +98,22 @@ unsigned int CNMEASentenceCollector::getDataInt(unsigned char * data, unsigned i
bool CNMEASentenceCollector::getDataInt(std::string& data)
{
if(getMyCall().empty() || getSentence().empty())
if(getMyCall1().empty() || getSentence().empty())
return false;
data.clear();
auto nmea = getSentence();
fixUpNMEATimeStamp(nmea);
std::string fromCall = getMyCall();
std::string fromCall = getMyCall1();
CAPRSUtils::dstarCallsignToAPRS(fromCall);
// 20230425 Fix for https://github.com/F4FXL/DStarGateway/issues/33
size_t hyphenIndex = fromCall.find('-');
if(hyphenIndex != std::string::npos) {
fromCall = fromCall.substr(0, hyphenIndex);
}
std::string aprsFrame(fromCall);
aprsFrame.append("-5>GPS30,DSTAR*:")
.append(nmea);

@ -59,7 +59,8 @@ bool CRepeaterHandler::m_dtmfEnabled = true;
CHeaderLogger* CRepeaterHandler::m_headerLogger = NULL;
CAPRSHandler* CRepeaterHandler::m_aprsWriter = NULL;
CAPRSHandler* CRepeaterHandler::m_outgoingAprsHandler = NULL; //handles APRS/DPRS frames coming from radio to network
CAPRSHandler* CRepeaterHandler::m_incomingAprsHandler = NULL; //handles APRS/DPRS frames coming from network to radio
CCallsignList* CRepeaterHandler::m_restrictList = NULL;
@ -352,9 +353,10 @@ void CRepeaterHandler::setHeaderLogger(CHeaderLogger* logger)
m_headerLogger = logger;
}
void CRepeaterHandler::setAPRSWriter(CAPRSHandler* writer)
void CRepeaterHandler::setAPRSHandlers(CAPRSHandler* outgoingAprsHandler, CAPRSHandler* incomingAprsHandler)
{
m_aprsWriter = writer;
m_outgoingAprsHandler = outgoingAprsHandler;
m_incomingAprsHandler = incomingAprsHandler;
}
void CRepeaterHandler::setLocalAddress(const std::string& address)
@ -613,8 +615,8 @@ void CRepeaterHandler::processRepeater(CHeaderData& header)
m_text.clear();
// Reset the APRS Writer if it's enabled
if (m_aprsWriter != NULL)
m_aprsWriter->writeHeader(m_rptCallsign, header);
if (m_outgoingAprsHandler != NULL)
m_outgoingAprsHandler->writeHeader(m_rptCallsign, header);
// Write to Header.log if it's enabled
if (m_headerLogger != NULL)
@ -823,8 +825,8 @@ void CRepeaterHandler::processRepeater(CAMBEData& data)
if (m_drats != NULL)
m_drats->writeData(data);
if (m_aprsWriter != NULL)
m_aprsWriter->writeData(m_rptCallsign, data);
if (m_outgoingAprsHandler != NULL)
m_outgoingAprsHandler->writeData(m_rptCallsign, data);
if (m_text.empty() && !data.isEnd()) {
m_textCollector.writeData(data);
@ -1173,6 +1175,9 @@ bool CRepeaterHandler::process(CHeaderData& header, DIRECTION, AUDIO_SOURCE sour
if (source == AS_DUP)
return true;
if(m_incomingAprsHandler != nullptr)
m_incomingAprsHandler->writeHeader(m_rptCallsign, header);
sendToIncoming(header);
#ifdef USE_CCS
@ -1212,6 +1217,9 @@ bool CRepeaterHandler::process(CAMBEData& data, DIRECTION, AUDIO_SOURCE source)
m_repeaterHandler->writeAMBE(data);
if(m_incomingAprsHandler != nullptr)
m_incomingAprsHandler->writeData(m_rptCallsign, data);
sendToIncoming(data);
#ifdef USE_CCS
@ -2413,8 +2421,8 @@ void CRepeaterHandler::startupInt()
m_irc->rptrQTH(callsign, m_latitude, m_longitude, m_description1, m_description2, m_url);
}
if(m_aprsWriter != nullptr) {
m_aprsWriter->addReadAPRSCallback(this);
if(m_outgoingAprsHandler != nullptr) {
m_outgoingAprsHandler->addReadAPRSCallback(this);
}
#ifdef USE_CCS
@ -2564,8 +2572,8 @@ void CRepeaterHandler::writeLinkingTo(const std::string &callsign)
m_infoAudio->setStatus(m_linkStatus, m_linkRepeater, text);
triggerInfo();
if(m_aprsWriter != nullptr)
m_aprsWriter->writeStatus(m_rptCallsign, text);
if(m_outgoingAprsHandler != nullptr)
m_outgoingAprsHandler->writeStatus(m_rptCallsign, text);
#ifdef USE_CCS
m_ccsHandler->setReflector();
@ -2619,8 +2627,8 @@ void CRepeaterHandler::writeLinkedTo(const std::string &callsign)
m_infoAudio->setStatus(m_linkStatus, m_linkRepeater, text);
triggerInfo();
if(m_aprsWriter != nullptr)
m_aprsWriter->writeStatus(m_rptCallsign, text);
if(m_outgoingAprsHandler != nullptr)
m_outgoingAprsHandler->writeStatus(m_rptCallsign, text);
#ifdef USE_CCS
m_ccsHandler->setReflector(callsign);
@ -2674,8 +2682,8 @@ void CRepeaterHandler::writeNotLinked()
m_infoAudio->setStatus(m_linkStatus, m_linkRepeater, text);
triggerInfo();
if(m_aprsWriter != nullptr)
m_aprsWriter->writeStatus(m_rptCallsign, text);
if(m_outgoingAprsHandler != nullptr)
m_outgoingAprsHandler->writeStatus(m_rptCallsign, text);
#ifdef USE_CCS
m_ccsHandler->setReflector();
@ -2745,8 +2753,8 @@ void CRepeaterHandler::writeIsBusy(const std::string& callsign)
m_infoAudio->setTempStatus(m_linkStatus, m_linkRepeater, tempText);
triggerInfo();
if(m_aprsWriter != nullptr)
m_aprsWriter->writeStatus(m_rptCallsign, text);
if(m_outgoingAprsHandler != nullptr)
m_outgoingAprsHandler->writeStatus(m_rptCallsign, text);
#ifdef USE_CCS
m_ccsHandler->setReflector();

@ -74,7 +74,7 @@ public:
static void setDPlusEnabled(bool enabled);
static void setDCSEnabled(bool enabled);
static void setHeaderLogger(CHeaderLogger* logger);
static void setAPRSWriter(CAPRSHandler* writer);
static void setAPRSHandlers(CAPRSHandler* outgoingAprsHandler, CAPRSHandler* incomingAprsHandler);
static void setInfoEnabled(bool enabled);
static void setEchoEnabled(bool enabled);
static void setDTMFEnabled(bool enabled);
@ -169,7 +169,8 @@ private:
static CHeaderLogger* m_headerLogger;
static CAPRSHandler* m_aprsWriter;
static CAPRSHandler* m_outgoingAprsHandler;
static CAPRSHandler* m_incomingAprsHandler;
static CCallsignList* m_whiteList;
static CCallsignList* m_blackList;

@ -27,7 +27,7 @@ const unsigned int SLOW_DATA_BLOCK_LENGTH = 6U;
CSlowDataCollector::CSlowDataCollector(unsigned char slowDataType) :
m_slowDataType(slowDataType),
m_myCall(),
m_myCall1(),
m_state(SS_FIRST)
{
m_buffer = new unsigned char[SLOW_DATA_BLOCK_LENGTH];
@ -39,14 +39,24 @@ CSlowDataCollector::~CSlowDataCollector()
delete[] m_buffer;
}
std::string CSlowDataCollector::getMyCall() const
std::string CSlowDataCollector::getMyCall1() const
{
return m_myCall;
return m_myCall1;
}
void CSlowDataCollector::setMyCall(const std::string& myCall)
void CSlowDataCollector::setMyCall1(const std::string& myCall)
{
m_myCall = myCall;
m_myCall1 = myCall;
}
std::string CSlowDataCollector::getMyCall2() const
{
return m_myCall2;
}
void CSlowDataCollector::setMyCall2(const std::string& myCall)
{
m_myCall2 = myCall;
}
bool CSlowDataCollector::writeData(const unsigned char* data)

@ -29,8 +29,10 @@ class ISlowDataCollector
public:
virtual ~ISlowDataCollector() { } ;
virtual std::string getMyCall() const = 0;
virtual void setMyCall(const std::string& mycall) = 0;
virtual std::string getMyCall1() const = 0;
virtual void setMyCall1(const std::string& mycall) = 0;
virtual std::string getMyCall2() const = 0;
virtual void setMyCall2(const std::string& mycall) = 0;
virtual bool writeData(const unsigned char* data) = 0;
virtual void sync() = 0;
virtual unsigned int getData(unsigned char* data, unsigned int length) = 0;
@ -46,8 +48,10 @@ public:
CSlowDataCollector(unsigned char slowDataType);
virtual ~CSlowDataCollector();
std::string getMyCall() const;
void setMyCall(const std::string& mycall);
std::string getMyCall1() const;
void setMyCall1(const std::string& mycall);
std::string getMyCall2() const;
void setMyCall2(const std::string& mycall);
bool writeData(const unsigned char* data);
void sync();
unsigned int getData(unsigned char* data, unsigned int length);
@ -64,7 +68,8 @@ protected:
private:
unsigned char m_slowDataType;
std::string m_myCall;
std::string m_myCall1;
std::string m_myCall2;
SLOWDATA_STATE m_state;
unsigned char * m_buffer;
};

@ -33,16 +33,27 @@ CSlowDataCollectorThrottle::~CSlowDataCollectorThrottle()
delete m_collector;
}
std::string CSlowDataCollectorThrottle::getMyCall() const
std::string CSlowDataCollectorThrottle::getMyCall1() const
{
return m_collector->getMyCall();
return m_collector->getMyCall1();
}
void CSlowDataCollectorThrottle::setMyCall(const std::string& mycall)
void CSlowDataCollectorThrottle::setMyCall1(const std::string& mycall)
{
m_isFirst = true;
m_collector->setMyCall(mycall);
m_collector->setMyCall1(mycall);
}
std::string CSlowDataCollectorThrottle::getMyCall2() const
{
return m_collector->getMyCall2();
}
void CSlowDataCollectorThrottle::setMyCall2(const std::string& mycall)
{
m_isFirst = true;
m_collector->setMyCall2(mycall);
}
bool CSlowDataCollectorThrottle::writeData(const unsigned char* data)
{
m_isComplete = false;

@ -28,8 +28,10 @@ class CSlowDataCollectorThrottle : public ISlowDataCollector
public:
CSlowDataCollectorThrottle(ISlowDataCollector* collector, unsigned int timeout);
~CSlowDataCollectorThrottle();
std::string getMyCall() const;
void setMyCall(const std::string& mycall);
std::string getMyCall1() const;
void setMyCall1(const std::string& mycall);
std::string getMyCall2() const;
void setMyCall2(const std::string& mycall);
bool writeData(const unsigned char* data);
void sync();
unsigned int getData(unsigned char* data, unsigned int length);

@ -1,6 +1,6 @@
/*
* Copyright (C) 2010,2011 by Jonathan Naylor G4KLX
* Copyright (c) 2021-2022 by Geoffrey Merck F4FXL / KC3FRA
* Copyright (c) 2021,2022 by Geoffrey Merck F4FXL / KC3FRA
*
* 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
@ -48,6 +48,8 @@
#include "APRSGPSDIdFrameProvider.h"
#include "APRSFixedIdFrameProvider.h"
#include "Daemon.h"
#include "APRSISHandlerThread.h"
#include "DummyAPRSHandlerThread.h"
CDStarGatewayApp * CDStarGatewayApp::g_app = nullptr;
const std::string BANNER_1 = CStringUtils::string_format("%s Copyright (C) %s\n", FULL_PRODUCT_NAME.c_str(), VENDOR_NAME.c_str());
@ -192,23 +194,28 @@ bool CDStarGatewayApp::createThread()
// Setup APRS
TAPRS aprsConfig;
m_config->getAPRS(aprsConfig);
CAPRSHandler * aprsWriter = NULL;
CAPRSHandler * outgoingAprsWriter = nullptr;
CAPRSHandler * incomingAprsWriter = nullptr;
if(aprsConfig.enabled && !aprsConfig.password.empty()) {
aprsWriter = new CAPRSHandler(aprsConfig.hostname, aprsConfig.port, gatewayConfig.callsign, aprsConfig.password, gatewayConfig.address);
if(aprsWriter->open()) {
CAPRSISHandlerThread* aprsisthread = new CAPRSISHandlerThread(gatewayConfig.callsign, aprsConfig.password, gatewayConfig.address, aprsConfig.hostname, aprsConfig.port);
outgoingAprsWriter = new CAPRSHandler((IAPRSHandlerBackend *)aprsisthread);
incomingAprsWriter = new CAPRSHandler((IAPRSHandlerBackend *)new CDummyAPRSHandlerBackend());
if(outgoingAprsWriter->open()) {
#ifdef USE_GPSD
CAPRSIdFrameProvider * idFrameProvider = aprsConfig.m_positionSource == POSSRC_GPSD ? (CAPRSIdFrameProvider *)new CAPRSGPSDIdFrameProvider(gpsdConfig.m_address, gpsdConfig.m_port)
: new CAPRSFixedIdFrameProvider();
CAPRSIdFrameProvider * idFrameProvider = aprsConfig.m_positionSource == POSSRC_GPSD ? (CAPRSIdFrameProvider *)new CAPRSGPSDIdFrameProvider(gatewayConfig.callsign, gpsdConfig.m_address, gpsdConfig.m_port)
: new CAPRSFixedIdFrameProvider(gatewayConfig.callsign);
#else
CAPRSIdFrameProvider * idFrameProvider = new CAPRSFixedIdFrameProvider();
CAPRSIdFrameProvider * idFrameProvider = new CAPRSFixedIdFrameProvider(gatewayConfig.callsign);
#endif
idFrameProvider->start();
aprsWriter->setIdFrameProvider(idFrameProvider);
m_thread->setAPRSWriter(aprsWriter);
outgoingAprsWriter->setIdFrameProvider(idFrameProvider);
m_thread->setAPRSWriters(outgoingAprsWriter, incomingAprsWriter);
}
else {
delete aprsWriter;
aprsWriter = NULL;
delete outgoingAprsWriter;
outgoingAprsWriter = NULL;
}
}
@ -278,7 +285,10 @@ bool CDStarGatewayApp::createThread()
rptrConfig.band2,
rptrConfig.band3);
aprsWriter->setPort(rptrConfig.callsign, rptrConfig.band, rptrConfig.frequency, rptrConfig.offset, rptrConfig.range, rptrConfig.latitude, rptrConfig.longitude, rptrConfig.agl);
if(outgoingAprsWriter != nullptr)
outgoingAprsWriter->setPort(rptrConfig.callsign, rptrConfig.band, rptrConfig.frequency, rptrConfig.offset, rptrConfig.range, rptrConfig.latitude, rptrConfig.longitude, rptrConfig.agl);
if(incomingAprsWriter != nullptr)
incomingAprsWriter->setPort(rptrConfig.callsign, rptrConfig.band, rptrConfig.frequency, rptrConfig.offset, rptrConfig.range, rptrConfig.latitude, rptrConfig.longitude, rptrConfig.agl);
if(!ddEnabled) ddEnabled = rptrConfig.band.length() > 1U;
}

@ -69,15 +69,16 @@ m_stopped(true),
m_gatewayType(GT_REPEATER),
m_gatewayCallsign(),
m_gatewayAddress(),
m_icomRepeaterHandler(NULL),
m_hbRepeaterHandler(NULL),
m_dummyRepeaterHandler(NULL),
m_dextraPool(NULL),
m_dplusPool(NULL),
m_dcsPool(NULL),
m_g2HandlerPool(NULL),
m_aprsWriter(NULL),
m_irc(NULL),
m_icomRepeaterHandler(nullptr),
m_hbRepeaterHandler(nullptr),
m_dummyRepeaterHandler(nullptr),
m_dextraPool(nullptr),
m_dplusPool(nullptr),
m_dcsPool(nullptr),
m_g2HandlerPool(nullptr),
m_outgoingAprsHandler(nullptr),
m_incomingAprsHandler(nullptr),
m_irc(nullptr),
m_cache(),
m_language(TL_ENGLISH_UK),
m_dextraEnabled(true),
@ -110,9 +111,9 @@ m_status4(),
m_status5(),
m_latitude(0.0),
m_longitude(0.0),
m_whiteList(NULL),
m_blackList(NULL),
m_restrictList(NULL)
m_whiteList(nullptr),
m_blackList(nullptr),
m_restrictList(nullptr)
{
CHeaderData::initialise();
CG2Handler::initialise(MAX_ROUTES);
@ -250,7 +251,7 @@ void* CDStarGatewayThread::Entry()
CRepeaterHandler::setDPlusEnabled(m_dplusEnabled);
CRepeaterHandler::setDCSEnabled(m_dcsEnabled);
CRepeaterHandler::setHeaderLogger(headerLogger);
CRepeaterHandler::setAPRSWriter(m_aprsWriter);
CRepeaterHandler::setAPRSHandlers(m_outgoingAprsHandler, m_incomingAprsHandler);
CRepeaterHandler::setInfoEnabled(m_infoEnabled);
CRepeaterHandler::setEchoEnabled(m_echoEnabled);
CRepeaterHandler::setDTMFEnabled(m_dtmfEnabled);
@ -377,8 +378,8 @@ void* CDStarGatewayThread::Entry()
m_statusFileTimer.start();
}
if (m_aprsWriter != NULL)
m_aprsWriter->clock(ms);
if (m_outgoingAprsHandler != NULL)
m_outgoingAprsHandler->clock(ms);
if (m_logEnabled) {
m_statusTimer1.clock(ms);
@ -469,9 +470,9 @@ void* CDStarGatewayThread::Entry()
delete m_remote;
}
if(m_aprsWriter != nullptr) {
m_aprsWriter->close();
delete m_aprsWriter;
if(m_outgoingAprsHandler != nullptr) {
m_outgoingAprsHandler->close();
delete m_outgoingAprsHandler;
}
if (headerLogger != NULL) {
@ -636,9 +637,10 @@ void CDStarGatewayThread::setLog(bool enabled)
m_logEnabled = enabled;
}
void CDStarGatewayThread::setAPRSWriter(CAPRSHandler* writer)
void CDStarGatewayThread::setAPRSWriters(CAPRSHandler* outgoingWriter, CAPRSHandler* incomingWriter)
{
m_aprsWriter = writer;
m_outgoingAprsHandler = outgoingWriter;
m_incomingAprsHandler = incomingWriter;
}
void CDStarGatewayThread::setInfoEnabled(bool enabled)
@ -1244,8 +1246,8 @@ void CDStarGatewayThread::writeStatus()
CDStarGatewayStatusData* CDStarGatewayThread::getStatus() const
{
bool aprsStatus = false;
if (m_aprsWriter != NULL)
aprsStatus = m_aprsWriter->isConnected();
if (m_outgoingAprsHandler != NULL)
aprsStatus = m_outgoingAprsHandler->isConnected();
CDStarGatewayStatusData* status = new CDStarGatewayStatusData(m_lastStatus, aprsStatus);

@ -66,7 +66,7 @@ public:
virtual void setCCS(bool enabled, const std::string& host);
#endif
virtual void setLog(bool enabled);
virtual void setAPRSWriter(CAPRSHandler* writer);
virtual void setAPRSWriters(CAPRSHandler* outgoingAprsWriter, CAPRSHandler* incomingAPRSHandler);
virtual void setInfoEnabled(bool enabled);
virtual void setEchoEnabled(bool enabled);
virtual void setDTMFEnabled(bool enabled);
@ -100,7 +100,8 @@ private:
CDPlusProtocolHandlerPool* m_dplusPool;
CDCSProtocolHandlerPool* m_dcsPool;
CG2ProtocolHandlerPool* m_g2HandlerPool;
CAPRSHandler* m_aprsWriter;
CAPRSHandler* m_outgoingAprsHandler;
CAPRSHandler* m_incomingAprsHandler;
CIRCDDB* m_irc;
CCacheManager m_cache;
TEXT_LANG m_language;

@ -1,3 +1,4 @@
[![F4FXL](https://circleci.com/gh/F4FXL/DStarGateway.svg?style=svg)](https://app.circleci.com/pipelines/github/F4FXL/DStarGateway?filter=all)
- [1. Introduction](#1-introduction)
- [2. Current State](#2-current-state)
- [2.1. Code sanity](#21-code-sanity)
@ -9,7 +10,7 @@
- [3. Building and installing](#3-building-and-installing)
- [3.1. Initial setup](#31-initial-setup)
- [3.2. Get latest stable version (recommended)](#32-get-latest-stable-version-recommended)
- [3.3. Get latest development version version](#33-get-latest-development-version-version)
- [3.3. Get latest development version](#33-get-latest-development-version)
- [3.4. Prerequisites and dependencies](#34-prerequisites-and-dependencies)
- [3.5. Building](#35-building)
- [3.5.0.1. Build With GPSD Support](#3501-build-with-gpsd-support)
@ -21,12 +22,13 @@
- [4.1. Work Flow](#41-work-flow)
- [4.2. Continuous Integration](#42-continuous-integration)
- [5. Version History](#5-version-history)
- [5.1. Version 0.6](#51-version-06)
- [5.2. Version 0.5](#52-version-05)
- [5.3. Version 0.4](#53-version-04)
- [5.4. Version 0.3](#54-version-03)
- [5.5. Version 0.2](#55-version-02)
- [5.6. Version 0.1](#56-version-01)
- [5.1. Version 0.7](#51-version-07)
- [5.2. Version 0.6](#52-version-06)
- [5.3. Version 0.5](#53-version-05)
- [5.4. Version 0.4](#54-version-04)
- [5.5. Version 0.3](#55-version-03)
- [5.6. Version 0.2](#56-version-02)
- [5.7. Version 0.1](#57-version-01)
- [6. Future](#6-future)
@ -59,7 +61,7 @@ All the features found in ircddbGateway are supposed to be working. Except the o
### 2.4.2. Additional Features compared to ircddbGateway:
- DPlus, DExtra and G2 NAT Traversal using ircddb network as rendez-vous server. I.e. it is not required to open firewall ports for Callsign Routing or Gateway calls. however it is still recommended to do so. But NAT Traversal will bring more flexibility when operating on CGNAT (Mobile) Networks.
- Forward RSMS1A app messages from/to APRS-IS Network, yes you can send/receive messages to and from aprs. Yes, you can send messages to APRS stations and Vice Versa. Additionnally part of the message is sent as Text Dat in the slow data. This allows you to read the message dirdclty on your radio screen.
- Forward RSMS1A app messages from/to APRS-IS Network, yes you can send/receive messages to and from aprs. Yes, you can send messages to APRS stations and Vice Versa. Additionnally, part of the message is sent as Text Dat in the slow data. This allows you to read the message directly on your radio screen.
- Repeater Link status is sent to APRS-IS as a status frame
# 3. Building and installing
@ -77,7 +79,7 @@ git fetch --tags
latestTag=$(git describe --tags `git rev-list --tags --max-count=1`)
git checkout $latestTag
```
## 3.3. Get latest development version version
## 3.3. Get latest development version
```
git checkout develop
```
@ -142,15 +144,21 @@ I have added some basic CI using CircleCI [![F4FXL](https://circleci.com/gh/F4FX
The testing framwework used is Google Test.
# 5. Version History
## 5.1. Version 0.6
- [**Improvement**] Add DRats Support ([#22](https://github.com/F4FXL/DStarGateway/issues/22))
## 5.1. Version 0.7
- [**Bugfix**] Unknow repeater entries in log when using Icom Hardware ([#35](https://github.com/F4FXL/DStarGateway/issues/35))
- [**Bugfix**] Malformed callsign in some cases when using DV-G (NMEA) ([#33](https://github.com/F4FXL/DStarGateway/issues/33))
- [**Bugfix**] Crash on startup with Icom Hardware. Thanks to Josh AB9FT for reporting the issue.([#31](https://github.com/F4FXL/DStarGateway/issues/31))
- [**Improvement**] Add/Fix DPRS Object support([#28](https://github.com/F4FXL/DStarGateway/issues/28))
- [**Improvement**] Log incoming DPRS frames so they can be used in e.g. dashboards([#29](https://github.com/F4FXL/DStarGateway/issues/29))
## 5.2. Version 0.6
- [**Improvement**] Add DRats Support ([#24](https://github.com/F4FXL/DStarGateway/issues/24))
- [**Improvement**] Add call sign lists ([#22](https://github.com/F4FXL/DStarGateway/issues/22))
- [**Improvement**] Add a way to override Slow Data in VoiceTransmit ([#23](https://github.com/F4FXL/DStarGateway/issues/23))
- [**Improvement**] Add time server
- [**Improvement**] Gracefully exit on SIGINT and SIGTERM ([#21](https://github.com/F4FXL/DStarGateway/issues/21)). DStarGateway can also be run as a "forking" daemon. This might be required for distros still using sysv. Systemd can live without it.
- [**Improvement**] Add text transmit utility dgwtexttransmit ([#18](https://github.com/F4FXL/DStarGateway/issues/18))
- [**Improvement**] Add voice transmit utility dgwvoicetransmit ([#18](https://github.com/F4FXL/DStarGateway/issues/18))
## 5.2. Version 0.5
## 5.3. Version 0.5
- [**Improvement**] Add remote control utility dgwremotecontrol ([#17](https://github.com/F4FXL/DStarGateway/issues/17))
- [**Bugfix**] Two simultaneous incoming G2 streams would fail to be transmitted on dual band repeaters ([#16](https://github.com/F4FXL/DStarGateway/issues/16))
- [**Improvement**] Add NAT Traversal for G2 and DExtra, using IRCDDB as a Rendez Vous server ([#5](https://github.com/F4FXL/DStarGateway/issues/5))
@ -158,17 +166,17 @@ The testing framwework used is Google Test.
- [**Bugfix**] Failed to download XLX Hosts when URL contains a = sign ([#14](https://github.com/F4FXL/DStarGateway/issues/14))
- [**Bugfix**] Remote control connection failed ([#13](https://github.com/F4FXL/DStarGateway/issues/13))
- [**Bugfix**] Trying to connect to ghost ircDDB when no ircDDB is configured
## 5.3. Version 0.4
## 5.4. Version 0.4
- [**Improvement**] Add APRS status link feature ([#8](https://github.com/F4FXL/DStarGateway/issues/8))
- [**Bugfix**] Posotions received over radio were not sent to APRS-IS when GPDS connection failed. ([#7](https://github.com/F4FXL/DStarGateway/issues/7))
- [**Improvement**] Bring back GPSD support ([#6](https://github.com/F4FXL/DStarGateway/issues/6))
- [**Improvement**] Log enhancements ([#4](https://github.com/F4FXL/DStarGateway/issues/4))
## 5.4. Version 0.3
## 5.5. Version 0.3
- [**Improvement**] Get ride of libcongig++ dependency. When upgrading from earlier version you need to manualy delete the config file before reinstalling.
## 5.5. Version 0.2
## 5.6. Version 0.2
- [**Bugfix**] ircDDBFreeze when repeater not found ([#1](https://github.com/F4FXL/DStarGateway/issues/1))
- Code sanitization
## 5.6. Version 0.1
## 5.7. Version 0.1
First working version
# 6. Future
I started this during my 2021 seasons holiday. It took me almost 8 days to get to a workable version. Here are a couple of stuff I'd like to do :

@ -173,6 +173,50 @@ namespace APRSParserTests
EXPECT_EQ(aprsFrame.getPath().size(), 0);
}
TEST_F(APRSParser_parseAPRSFrame, ObjectAlive)
{
CAPRSFrame aprsFrame;
bool retVal = CAPRSParser::parseFrame("F8DSN-15>API510,DSTAR*:;F1ZBV *091510h4802.40N/00647.12ErPHG7430/A=003182R Vosges 145,6625@-0,6MHz", aprsFrame);
EXPECT_TRUE(retVal);
EXPECT_STRCASEEQ(aprsFrame.getBody().c_str(), ";F1ZBV *091510h4802.40N/00647.12ErPHG7430/A=003182R Vosges 145,6625@-0,6MHz");
EXPECT_STRCASEEQ(aprsFrame.getDestination().c_str(), "API510");
EXPECT_STRCASEEQ(aprsFrame.getSource().c_str(), "F8DSN-15");
EXPECT_EQ(aprsFrame.getType(), APFT_OBJECT);
EXPECT_EQ(aprsFrame.getPath().size(), 1);
EXPECT_STRCASEEQ(aprsFrame.getPath().at(0).c_str(), "DSTAR*");
}
TEST_F(APRSParser_parseAPRSFrame, ObjectKilled)
{
CAPRSFrame aprsFrame;
bool retVal = CAPRSParser::parseFrame("F8DSN-15>API510,DSTAR*:;F1ZBV _091510h4802.40N/00647.12ErPHG7430/A=003182R Vosges 145,6625@-0,6MHz", aprsFrame);
EXPECT_TRUE(retVal);
EXPECT_STRCASEEQ(aprsFrame.getBody().c_str(), ";F1ZBV _091510h4802.40N/00647.12ErPHG7430/A=003182R Vosges 145,6625@-0,6MHz");
EXPECT_STRCASEEQ(aprsFrame.getDestination().c_str(), "API510");
EXPECT_STRCASEEQ(aprsFrame.getSource().c_str(), "F8DSN-15");
EXPECT_EQ(aprsFrame.getType(), APFT_OBJECT);
EXPECT_EQ(aprsFrame.getPath().size(), 1);
EXPECT_STRCASEEQ(aprsFrame.getPath().at(0).c_str(), "DSTAR*");
}
TEST_F(APRSParser_parseAPRSFrame, ObjectInvalid)
{
CAPRSFrame aprsFrame;
bool retVal = CAPRSParser::parseFrame("F8DSN-15>API510,DSTAR*:;F1ZBV ~091510h4802.40N/00647.12ErPHG7430/A=003182R Vosges 145,6625@-0,6MHz", aprsFrame);
EXPECT_FALSE(retVal);
}
TEST_F(APRSParser_parseAPRSFrame, ObjectTooShort)
{
CAPRSFrame aprsFrame;
bool retVal = CAPRSParser::parseFrame("F8DSN-15>API510,DSTAR*:;F1ZBV", aprsFrame);
EXPECT_FALSE(retVal);
}
TEST_F(APRSParser_parseAPRSFrame, messageToSelf)
{
CAPRSFrame aprsFrame;

@ -20,7 +20,7 @@
#include "APRSUtils.h"
namespace APRStoDPRSTests
namespace APRSUtilsTests
{
class APRSUtils_calcGPSAIcomCRC : public ::testing::Test {
};

@ -0,0 +1,51 @@
/*
* Copyright (c) 2021-2023 by Geoffrey Merck F4FXL / KC3FRA
*
* 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 <gtest/gtest.h>
#include "APRSUtils.h"
namespace APRSUtilsTests
{
class APRSUtils_dstarCallsignToAPRS : public ::testing::Test {
};
TEST_F(APRSUtils_dstarCallsignToAPRS, noBlanks)
{
std::string call("N0CALL");
CAPRSUtils::dstarCallsignToAPRS(call);
EXPECT_STRCASEEQ(call.c_str(), "N0CALL") << "Call shall not have changed";
}
TEST_F(APRSUtils_dstarCallsignToAPRS, twoBlanks)
{
std::string call("F4ABC B");
CAPRSUtils::dstarCallsignToAPRS(call);
EXPECT_STRCASEEQ(call.c_str(), "F4ABC-B") << "-H shall have been removed";
}
TEST_F(APRSUtils_dstarCallsignToAPRS, threeBlanks)
{
std::string call("F4AB B");
CAPRSUtils::dstarCallsignToAPRS(call);
EXPECT_STRCASEEQ(call.c_str(), "F4AB-B") << "-H shall have been removed";
}
}

@ -0,0 +1,45 @@
/*
* Copyright (C) 2021-2023 by Geoffrey Merck F4FXL / KC3FRA
*
* 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 <gtest/gtest.h>
#include "HeardData.h"
namespace HeardDataTests
{
class HeardData_setIcomRepeaterData: public ::testing::Test {
};
TEST_F(HeardData_setIcomRepeaterData, setCorrectValues)
{
CHeardData hdata;
in_addr addr;
addr.s_addr=123;
std::string data("0123456789abcdefghijklmnopqrstuvwxyz");
hdata.setIcomRepeaterData((const unsigned char*)data.c_str(), data.length(), addr, 456U);
EXPECT_STREQ(hdata.getUser().c_str(), "abcdefgh") << "User not correctly set";
EXPECT_STREQ(hdata.getRepeater().c_str(), "ijklmnop") << "Repeater not correctly set";
EXPECT_EQ(hdata.getAddress().s_addr, 123) << "Addr not correctly set";
EXPECT_EQ(hdata.getPort(), 456) << "Port not correctly set";
}
}

@ -0,0 +1,87 @@
/*
* Copyright (C) 2021-2023 by Geoffrey Merck F4FXL / KC3FRA
*
* 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 <gtest/gtest.h>
#include "NMEASentenceCollector.h"
namespace NMEASentenceCollectorTests
{
class NMEASentenceCollectorTests_getData: public ::testing::Test
{
protected:
CNMEASentenceCollector * m_collector;
void SetUp() override
{
m_collector = new CNMEASentenceCollector("$GPRMC");
std::string nmea("$GPRMC,092751.000,A,5321.6802,N,00630.3371,W,0.06,31.66,280511,,,A*45\x0A");
unsigned char data[3];
unsigned int len = nmea.length() + (nmea.length() % 3);
bool first = true;
for (unsigned int i = 0; i < len;) {
if(first) {
data[0] = SLOW_DATA_TYPE_GPS ^ SCRAMBLER_BYTE1;
first = false;
}
else {
data[0] = (i < nmea.length() ? nmea[i] : 'f') ^ SCRAMBLER_BYTE1;
i++;
first = true;
}
data[1] = (i < nmea.length() ? nmea[i] : 'f') ^ SCRAMBLER_BYTE2;
i++;
data[2] = (i < nmea.length() ? nmea[i] : 'f') ^ SCRAMBLER_BYTE3;
i++;
m_collector->writeData(data);
}
}
void TearDown() override
{
delete m_collector;
}
};
TEST_F(NMEASentenceCollectorTests_getData, noSSIDinCallsign)
{
std::string data;
m_collector->setMyCall1("N0CALL");
m_collector->setMyCall2("5100");
m_collector->getData(data);
EXPECT_STREQ(data.c_str(), "N0CALL-5>GPS30,DSTAR*:$GPRMC,092751.000,A,5321.6802,N,00630.3371,W,0.06,31.66,280511,,,A*45");
}
TEST_F(NMEASentenceCollectorTests_getData, SSIDinCallsign)
{
std::string data;
m_collector->setMyCall1("N0CALL H");
m_collector->setMyCall2("5100");
m_collector->getData(data);
EXPECT_STREQ(data.c_str(), "N0CALL-5>GPS30,DSTAR*:$GPRMC,092751.000,A,5321.6802,N,00630.3371,W,0.06,31.66,280511,,,A*45");
}
}

@ -26,7 +26,7 @@
const std::string PRODUCT_NAME("DStarGateway");
const std::string VENDOR_NAME("Geoffrey Merck F4FXL / KC3FRA and Contributors");
const std::string VERSION("0.6");
const std::string VERSION("0.7");
const std::string LONG_VERSION = VERSION + "-" + gitversion;
const std::string FULL_PRODUCT_NAME = PRODUCT_NAME + " v" + VERSION + "-" + gitversion;
const std::string SHORT_PRODUCT_NAME = "DStarGW v" + VERSION + "-" + gitversion;

@ -6,6 +6,7 @@ Wants=network-online.target
[Service]
User=dstar
Type=simple
ExecStartPre=/bin/bash -c 'until host google.com; do sleep 1; done'
ExecStart=/usr/local/bin/dstargateway %CFG_DIR%/dstargateway.cfg
Restart=on-failure
RestartSec=5

Loading…
Cancel
Save

Powered by TurnKey Linux.