Merge branch 'feature/GPSD' into develop

closes#6
pull/11/head
Geoffrey Merck 4 years ago
commit 6f17973615

@ -0,0 +1,119 @@
/*
* Copyright (C) 2010,2011,2012,2018 by Jonathan Naylor G4KLX
* Copyright (C) 2021 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 <boost/algorithm/string.hpp>
#include "APRSEntry.h"
CAPRSEntry::CAPRSEntry(const std::string& callsign, const std::string& band, double frequency, double offset, double range, double latitude, double longitude, double agl) :
m_callsign(callsign),
m_band(band),
m_frequency(frequency),
m_offset(offset),
m_range(range),
m_latitude(latitude),
m_longitude(longitude),
m_agl(agl),
m_timer(1000U, 10U),
m_first(true),
m_collector(NULL)
{
boost::trim(m_callsign);
m_collector = new CAPRSCollector;
}
CAPRSEntry::~CAPRSEntry()
{
delete m_collector;
}
std::string CAPRSEntry::getCallsign() const
{
return m_callsign;
}
std::string CAPRSEntry::getBand() const
{
return m_band;
}
double CAPRSEntry::getFrequency() const
{
return m_frequency;
}
double CAPRSEntry::getOffset() const
{
return m_offset;
}
double CAPRSEntry::getRange() const
{
return m_range;
}
double CAPRSEntry::getLatitude() const
{
return m_latitude;
}
double CAPRSEntry::getLongitude() const
{
return m_longitude;
}
double CAPRSEntry::getAGL() const
{
return m_agl;
}
CAPRSCollector* CAPRSEntry::getCollector() const
{
return m_collector;
}
void CAPRSEntry::reset()
{
m_first = true;
m_timer.stop();
m_collector->reset();
}
void CAPRSEntry::clock(unsigned int ms)
{
m_timer.clock(ms);
}
bool CAPRSEntry::isOK()
{
if (m_first) {
m_first = false;
m_timer.start();
return true;
}
if (m_timer.hasExpired()) {
m_timer.start();
return true;
} else {
m_timer.start();
return false;
}
}

@ -0,0 +1,59 @@
/*
* Copyright (C) 2010,2011,2012,2018 by Jonathan Naylor G4KLX
* Copyright (C) 2021 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 <string>
#include "APRSCollector.h"
#include "Timer.h"
class CAPRSEntry {
public:
CAPRSEntry(const std::string& callsign, const std::string& band, double frequency, double offset, double range, double latitude, double longitude, double agl);
~CAPRSEntry();
std::string getCallsign() const;
std::string getBand() const;
double getFrequency() const;
double getOffset() const;
double getRange() const;
double getLatitude() const;
double getLongitude() const;
double getAGL() const;
CAPRSCollector* getCollector() const;
// Transmission timer
void reset();
void clock(unsigned int ms);
bool isOK();
private:
std::string m_callsign;
std::string m_band;
double m_frequency;
double m_offset;
double m_range;
double m_latitude;
double m_longitude;
double m_agl;
CTimer m_timer;
bool m_first;
CAPRSCollector* m_collector;
};

@ -20,6 +20,7 @@
#include <cassert> #include <cassert>
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#include <cmath> #include <cmath>
#include <cassert>
#include "StringUtils.h" #include "StringUtils.h"
#include "Log.h" #include "Log.h"
@ -28,111 +29,19 @@
#include "Defs.h" #include "Defs.h"
#include "Log.h" #include "Log.h"
CAPRSEntry::CAPRSEntry(const std::string& callsign, const std::string& band, double frequency, double offset, double range, double latitude, double longitude, double agl) :
m_callsign(callsign),
m_band(band),
m_frequency(frequency),
m_offset(offset),
m_range(range),
m_latitude(latitude),
m_longitude(longitude),
m_agl(agl),
m_timer(1000U, 10U),
m_first(true),
m_collector(NULL)
{
boost::trim(m_callsign);
m_collector = new CAPRSCollector;
}
CAPRSEntry::~CAPRSEntry()
{
delete m_collector;
}
std::string CAPRSEntry::getCallsign() const
{
return m_callsign;
}
std::string CAPRSEntry::getBand() const
{
return m_band;
}
double CAPRSEntry::getFrequency() const
{
return m_frequency;
}
double CAPRSEntry::getOffset() const
{
return m_offset;
}
double CAPRSEntry::getRange() const
{
return m_range;
}
double CAPRSEntry::getLatitude() const
{
return m_latitude;
}
double CAPRSEntry::getLongitude() const
{
return m_longitude;
}
double CAPRSEntry::getAGL() const
{
return m_agl;
}
CAPRSCollector* CAPRSEntry::getCollector() const
{
return m_collector;
}
void CAPRSEntry::reset()
{
m_first = true;
m_timer.stop();
m_collector->reset();
}
void CAPRSEntry::clock(unsigned int ms)
{
m_timer.clock(ms);
}
bool CAPRSEntry::isOK()
{
if (m_first) {
m_first = false;
m_timer.start();
return true;
}
if (m_timer.hasExpired()) {
m_timer.start();
return true;
} else {
m_timer.start();
return false;
}
}
CAPRSWriter::CAPRSWriter(const std::string& hostname, unsigned int port, const std::string& gateway, const std::string& password, const std::string& address) : CAPRSWriter::CAPRSWriter(const std::string& hostname, unsigned int port, const std::string& gateway, const std::string& password, const std::string& address) :
m_thread(NULL), m_thread(NULL),
m_idTimer(1000U), m_idTimer(1000U),
m_gateway(), m_gateway(),
m_address(), m_address(),
m_port(0U), m_port(0U),
m_socket(NULL),
m_array() m_array()
#ifdef USE_GPSD
, m_gpsdEnabled(false),
m_gpsdAddress(),
m_gpsdPort(),
m_gpsdData()
#endif
{ {
assert(!hostname.empty()); assert(!hostname.empty());
assert(port > 0U); assert(port > 0U);
@ -164,37 +73,42 @@ void CAPRSWriter::setPortFixed(const std::string& callsign, const std::string& b
m_array[temp] = new CAPRSEntry(callsign, band, frequency, offset, range, latitude, longitude, agl); m_array[temp] = new CAPRSEntry(callsign, band, frequency, offset, range, latitude, longitude, agl);
} }
void CAPRSWriter::setPortMobile(const std::string& callsign, const std::string& band, double frequency, double offset, double range, const std::string& address, unsigned int port) #ifdef USE_GPSD
void CAPRSWriter::setPortGPSD(const std::string& callsign, const std::string& band, double frequency, double offset, double range, const std::string& address, const std::string& port)
{ {
assert(!address.empty());
assert(!port.empty());
std::string temp = callsign; std::string temp = callsign;
temp.resize(LONG_CALLSIGN_LENGTH - 1U, ' '); temp.resize(LONG_CALLSIGN_LENGTH - 1U, ' ');
temp += band; temp.append(band);
m_array[temp] = new CAPRSEntry(callsign, band, frequency, offset, range, 0.0, 0.0, 0.0); m_array[temp] = new CAPRSEntry(callsign, band, frequency, offset, range, 0.0, 0.0, 0.0);
if (m_socket == NULL) { m_gpsdEnabled = true;
m_address = CUDPReaderWriter::lookup(address); m_gpsdAddress = address;
m_port = port; m_gpsdPort = port;
m_socket = new CUDPReaderWriter();
}
} }
#endif
bool CAPRSWriter::open() bool CAPRSWriter::open()
{ {
if (m_socket != NULL) { m_idTimer.setTimeout(20U * 60U);
bool ret = m_socket->open(); #ifdef USE_GPSD
if (!ret) { if (m_gpsdEnabled) {
delete m_socket; int ret = ::gps_open(m_gpsdAddress.c_str(), m_gpsdPort.c_str(), &m_gpsdData);
m_socket = NULL; if (ret != 0) {
CLog::logError("Error when opening access to gpsd - %d - %s", errno, ::gps_errstr(errno));
return false; return false;
} }
// Poll the GPS every minute ::gps_stream(&m_gpsdData, WATCH_ENABLE | WATCH_JSON, NULL);
CLog::logError("Connected to GPSD");
m_idTimer.setTimeout(60U); m_idTimer.setTimeout(60U);
} else {
m_idTimer.setTimeout(20U * 60U);
} }
#endif
m_idTimer.start(); m_idTimer.start();
@ -293,19 +207,22 @@ void CAPRSWriter::clock(unsigned int ms)
m_thread->clock(ms); m_thread->clock(ms);
if (m_socket != NULL) { #ifdef USE_GPSD
if (m_gpsdEnabled) {
if (m_idTimer.hasExpired()) { if (m_idTimer.hasExpired()) {
pollGPS(); sendIdFramesMobile();
m_idTimer.start(); m_idTimer.start();
} }
sendIdFramesMobile();
} else { } else {
#endif
if (m_idTimer.hasExpired()) { if (m_idTimer.hasExpired()) {
sendIdFramesFixed(); sendIdFramesFixed();
m_idTimer.start(); m_idTimer.start();
} }
#ifdef USE_GPSD
} }
#endif
for (auto it = m_array.begin(); it != m_array.end(); ++it) { for (auto it = m_array.begin(); it != m_array.end(); ++it) {
if(it->second != NULL) if(it->second != NULL)
@ -320,21 +237,16 @@ bool CAPRSWriter::isConnected() const
void CAPRSWriter::close() void CAPRSWriter::close()
{ {
if (m_socket != NULL) { #ifdef USE_GPSD
m_socket->close(); if (m_gpsdEnabled) {
delete m_socket; ::gps_stream(&m_gpsdData, WATCH_DISABLE, NULL);
::gps_close(&m_gpsdData);
} }
#endif
m_thread->stop(); m_thread->stop();
} }
bool CAPRSWriter::pollGPS()
{
assert(m_socket != NULL);
return m_socket->write((unsigned char*)"ircDDBGateway", 13U, m_address, m_port);
}
void CAPRSWriter::sendIdFramesFixed() void CAPRSWriter::sendIdFramesFixed()
{ {
if (!m_thread->isConnected()) if (!m_thread->isConnected())
@ -447,34 +359,51 @@ void CAPRSWriter::sendIdFramesFixed()
} }
} }
#ifdef USE_GPSD
void CAPRSWriter::sendIdFramesMobile() void CAPRSWriter::sendIdFramesMobile()
{ {
// Grab GPS data if it's available if (!m_thread->isConnected())
unsigned char buffer[200U];
in_addr address;
unsigned int port;
int ret = m_socket->read(buffer, 200U, address, port);
if (ret <= 0)
return; return;
if (!m_thread->isConnected()) if (!m_gpsdEnabled)
return;
if (!::gps_waiting(&m_gpsdData, 0))
return;
#if GPSD_API_MAJOR_VERSION >= 7
if (::gps_read(&m_gpsdData, NULL, 0) <= 0)
return;
#else
if (::gps_read(&m_gpsdData) <= 0)
return; return;
#endif
buffer[ret] = '\0'; #if GPSD_API_MAJOR_VERSION >= 11 // F4FXL 2021-12-31 not sure if 11 is porper version, best guess as i could not find any change log
if(m_gpsdData.fix.mode < MODE_3D)
return;
#else
if (m_gpsdData.status != STATUS_FIX)
return;
#endif
// Parse the GPS data bool latlonSet = (m_gpsdData.set & LATLON_SET) == LATLON_SET;
char* pLatitude = ::strtok((char*)buffer, ",\n"); // Latitude bool altitudeSet = (m_gpsdData.set & ALTITUDE_SET) == ALTITUDE_SET;
char* pLongitude = ::strtok(NULL, ",\n"); // Longitude bool velocitySet = (m_gpsdData.set & SPEED_SET) == SPEED_SET;
char* pAltitude = ::strtok(NULL, ",\n"); // Altitude (m) bool bearingSet = (m_gpsdData.set & TRACK_SET) == TRACK_SET;
char* pVelocity = ::strtok(NULL, ",\n"); // Velocity (kms/h)
char* pBearing = ::strtok(NULL, "\n"); // Bearing
if (pLatitude == NULL || pLongitude == NULL || pAltitude == NULL) if (!latlonSet)
return; return;
double rawLatitude = ::atof(pLatitude); float rawLatitude = float(m_gpsdData.fix.latitude);
double rawLongitude = ::atof(pLongitude); float rawLongitude = float(m_gpsdData.fix.longitude);
double rawAltitude = ::atof(pAltitude); #if GPSD_API_MAJOR_VERSION >= 9
float rawAltitude = float(m_gpsdData.fix.altMSL);
#else
float rawAltitude = float(m_gpsdData.fix.altitude);
#endif
float rawVelocity = float(m_gpsdData.fix.speed);
float rawBearing = float(m_gpsdData.fix.track);
time_t now; time_t now;
::time(&now); ::time(&now);
@ -557,15 +486,11 @@ void CAPRSWriter::sendIdFramesMobile()
rawAltitude * 3.28); rawAltitude * 3.28);
std::string output2; std::string output2;
if (pBearing != NULL && pVelocity != NULL) { if (bearingSet && velocitySet)
double rawBearing = ::atof(pBearing);
double rawVelocity = ::atof(pVelocity);
output2 = CStringUtils::string_format("%03.0lf/%03.0lf", rawBearing, rawVelocity * 0.539957F); output2 = CStringUtils::string_format("%03.0lf/%03.0lf", rawBearing, rawVelocity * 0.539957F);
}
std::string output3; std::string output3;
output3 = CStringUtils::string_format("RNG%04.0lf %s %s", entry->getRange() * 0.6214, band.c_str(), desc.c_str()); output3 = CStringUtils::string_format("RNG%04.0lf %s %s\r\n", entry->getRange() * 0.6214, band.c_str(), desc.c_str());
char ascii[300U]; char ascii[300U];
::memset(ascii, 0x00, 300U); ::memset(ascii, 0x00, 300U);
@ -577,14 +502,22 @@ void CAPRSWriter::sendIdFramesMobile()
for (unsigned int i = 0U; i < output3.length(); i++, n++) for (unsigned int i = 0U; i < output3.length(); i++, n++)
ascii[n] = output3[i]; ascii[n] = output3[i];
CLog::logDebug("APRS ==> %s%s%s", output1.c_str(), output2.c_str(), output3.c_str());
m_thread->write(ascii); m_thread->write(ascii);
if (entry->getBand().length() == 1U) { if (entry->getBand().length() == 1U) {
output1 = CStringUtils::string_format("%s-%s>APD5T2,TCPIP*,qAC,%s-%sS:!%s%cD%s%c&/A=%06.0lf", if (altitudeSet)
entry->getCallsign().c_str(), entry->getBand().c_str(), entry->getCallsign().c_str(), entry->getBand().c_str(), output1 = CStringUtils::string_format("%s-%s>APD5T2,TCPIP*,qAC,%s-%sS:!%s%cD%s%c&/A=%06.0lf",
lat.c_str(), (rawLatitude < 0.0) ? 'S' : 'N', entry->getCallsign().c_str(), entry->getBand().c_str(), entry->getCallsign().c_str(), entry->getBand().c_str(),
lon.c_str(), (rawLongitude < 0.0) ? 'W' : 'E', lat.c_str(), (rawLatitude < 0.0) ? 'S' : 'N',
rawAltitude * 3.28); lon.c_str(), (rawLongitude < 0.0) ? 'W' : 'E',
rawAltitude * 3.28);
else
output1 = CStringUtils::string_format("%s-%s>APD5T2,TCPIP*,qAC,%s-%sS:!%s%cD%s%c&",
entry->getCallsign().c_str(), entry->getBand().c_str(), entry->getCallsign().c_str(), entry->getBand().c_str(),
lat.c_str(), (rawLatitude < 0.0) ? 'S' : 'N',
lon.c_str(), (rawLongitude < 0.0) ? 'W' : 'E');
::memset(ascii, 0x00, 300U); ::memset(ascii, 0x00, 300U);
unsigned int n = 0U; unsigned int n = 0U;
@ -595,8 +528,10 @@ void CAPRSWriter::sendIdFramesMobile()
for (unsigned int i = 0U; i < output3.length(); i++, n++) for (unsigned int i = 0U; i < output3.length(); i++, n++)
ascii[n] = output3[i]; ascii[n] = output3[i];
CLog::logDebug("APRS ==> %s%s%s", output1.c_str(), output2.c_str(), output3.c_str());
m_thread->write(ascii); m_thread->write(ascii);
} }
} }
} }
#endif

@ -22,7 +22,11 @@
#include <unordered_map> #include <unordered_map>
#include <string> #include <string>
#ifdef USE_GPSD
#include <gps.h>
#endif
#include "APRSEntry.h"
#include "APRSWriterThread.h" #include "APRSWriterThread.h"
#include "UDPReaderWriter.h" #include "UDPReaderWriter.h"
#include "APRSCollector.h" #include "APRSCollector.h"
@ -32,40 +36,6 @@
#include "Timer.h" #include "Timer.h"
#include "Defs.h" #include "Defs.h"
class CAPRSEntry {
public:
CAPRSEntry(const std::string& callsign, const std::string& band, double frequency, double offset, double range, double latitude, double longitude, double agl);
~CAPRSEntry();
std::string getCallsign() const;
std::string getBand() const;
double getFrequency() const;
double getOffset() const;
double getRange() const;
double getLatitude() const;
double getLongitude() const;
double getAGL() const;
CAPRSCollector* getCollector() const;
// Transmission timer
void reset();
void clock(unsigned int ms);
bool isOK();
private:
std::string m_callsign;
std::string m_band;
double m_frequency;
double m_offset;
double m_range;
double m_latitude;
double m_longitude;
double m_agl;
CTimer m_timer;
bool m_first;
CAPRSCollector* m_collector;
};
class CAPRSWriter { class CAPRSWriter {
public: public:
CAPRSWriter(const std::string& hostname, unsigned int port, const std::string& gateway, const std::string& password, const std::string& address); CAPRSWriter(const std::string& hostname, unsigned int port, const std::string& gateway, const std::string& password, const std::string& address);
@ -74,9 +44,9 @@ public:
bool open(); bool open();
void setPortFixed(const std::string& callsign, const std::string& band, double frequency, double offset, double range, double latitude, double longitude, double agl); void setPortFixed(const std::string& callsign, const std::string& band, double frequency, double offset, double range, double latitude, double longitude, double agl);
#ifdef USE_GPSD
void setPortMobile(const std::string& callsign, const std::string& band, double frequency, double offset, double range, const std::string& address, unsigned int port); void setPortGPSD(const std::string& callsign, const std::string& band, double frequency, double offset, double range, const std::string& address, const std::string& port);
#endif
void writeHeader(const std::string& callsign, const CHeaderData& header); void writeHeader(const std::string& callsign, const CHeaderData& header);
void writeData(const std::string& callsign, const CAMBEData& data); void writeData(const std::string& callsign, const CAMBEData& data);
@ -93,9 +63,15 @@ private:
std::string m_gateway; std::string m_gateway;
in_addr m_address; in_addr m_address;
unsigned int m_port; unsigned int m_port;
CUDPReaderWriter* m_socket;
std::unordered_map<std::string,CAPRSEntry *> m_array; std::unordered_map<std::string,CAPRSEntry *> m_array;
#ifdef USE_GPSD
bool m_gpsdEnabled;
std::string m_gpsdAddress;
std::string m_gpsdPort;
struct gps_data_t m_gpsdData;
#endif
bool pollGPS(); bool pollGPS();
void sendIdFramesFixed(); void sendIdFramesFixed();
void sendIdFramesMobile(); void sendIdFramesMobile();

@ -26,6 +26,7 @@
#include "Utils.h" #include "Utils.h"
#include "Defs.h" #include "Defs.h"
#include "Log.h" #include "Log.h"
#include "Version.h"
// #define DUMP_TX // #define DUMP_TX
@ -44,7 +45,7 @@ m_reconnectTimer(1000U),
m_tries(0U), m_tries(0U),
m_APRSReadCallback(NULL), m_APRSReadCallback(NULL),
m_filter(""), m_filter(""),
m_clientName("DStarGateway") m_clientName(FULL_PRODUCT_NAME)
{ {
assert(!callsign.empty()); assert(!callsign.empty());
assert(!password.empty()); assert(!password.empty());
@ -154,7 +155,7 @@ void* CAPRSWriterThread::Entry()
if (length < 0) { if (length < 0) {
m_connected = false; m_connected = false;
m_socket.close(); m_socket.close();
CLog::logInfo("Error when reading from the APRS server"); CLog::logError("Error when reading from the APRS server");
startReconnectionTimer(); startReconnectionTimer();
} }
@ -249,7 +250,7 @@ bool CAPRSWriterThread::connect()
std::stringstream connectString; std::stringstream connectString;
connectString << "User " << m_username << "-" << m_ssid connectString << "User " << m_username << "-" << m_ssid
<< " pass " << m_password << " pass " << m_password
<< " vers " << (m_clientName.length() ? m_clientName : "DStarGateway") << " vers " << (!m_clientName.empty() ? m_clientName : FULL_PRODUCT_NAME)
<< filter; << filter;
//CLog::logInfo("Connect String : ") + connectString); //CLog::logInfo("Connect String : ") + connectString);
ret = m_socket.writeLine(connectString.str()); ret = m_socket.writeLine(connectString.str());

@ -49,7 +49,7 @@ int main(int argc, char *argv[])
} }
if ('-' == argv[1][0]) { if ('-' == argv[1][0]) {
printf("\nDStarGateway Version %s (GitID #%.7s) Copyright (C) %s\n", VERSION.c_str(), gitversion, VENDOR_NAME.c_str()); printf("\n%s Copyright (C) %s\n", FULL_PRODUCT_NAME.c_str(), VENDOR_NAME.c_str());
printf("DStarGateway comes with ABSOLUTELY NO WARRANTY; see the LICENSE for details.\n"); printf("DStarGateway comes with ABSOLUTELY NO WARRANTY; see the LICENSE for details.\n");
printf("This is free software, and you are welcome to distribute it\nunder certain conditions that are discussed in the LICENSE file.\n\n"); printf("This is free software, and you are welcome to distribute it\nunder certain conditions that are discussed in the LICENSE file.\n\n");
return 0; return 0;
@ -91,7 +91,7 @@ void CDStarGatewayApp::run()
bool CDStarGatewayApp::createThread() bool CDStarGatewayApp::createThread()
{ {
printf("\nDStarGateway Version %s (GitID #%.7s) Copyright (C) %s\n", VERSION.c_str(), gitversion, VENDOR_NAME.c_str()); printf("\n%s Copyright (C) %s\n", FULL_PRODUCT_NAME.c_str(), VENDOR_NAME.c_str());
printf("DStarGateway comes with ABSOLUTELY NO WARRANTY; see the LICENSE for details.\n"); printf("DStarGateway comes with ABSOLUTELY NO WARRANTY; see the LICENSE for details.\n");
printf("This is free software, and you are welcome to distribute it\nunder certain conditions that are discussed in the LICENSE file.\n\n"); printf("This is free software, and you are welcome to distribute it\nunder certain conditions that are discussed in the LICENSE file.\n\n");
@ -125,15 +125,14 @@ bool CDStarGatewayApp::createThread()
CAPRSWriter * aprsWriter = NULL; CAPRSWriter * aprsWriter = NULL;
if(aprsConfig.enabled && !aprsConfig.password.empty()) { if(aprsConfig.enabled && !aprsConfig.password.empty()) {
aprsWriter = new CAPRSWriter(aprsConfig.hostname, aprsConfig.port, gatewayConfig.callsign, aprsConfig.password, gatewayConfig.address); aprsWriter = new CAPRSWriter(aprsConfig.hostname, aprsConfig.port, gatewayConfig.callsign, aprsConfig.password, gatewayConfig.address);
if(aprsWriter->open()) {
m_thread->setAPRSWriter(aprsWriter);
}
else {
delete aprsWriter;
aprsWriter = NULL;
}
} }
#ifdef USE_GPSD
// Setup GPSD
TGPSD gpsdConfig;
config.getGPSD(gpsdConfig);
#endif
// Setup the repeaters // Setup the repeaters
if(config.getRepeaterCount() == 0U) { if(config.getRepeaterCount() == 0U) {
CLog::logInfo("No repeater configured\n"); CLog::logInfo("No repeater configured\n");
@ -165,13 +164,34 @@ bool CDStarGatewayApp::createThread()
rptrConfig.band1, rptrConfig.band1,
rptrConfig.band2, rptrConfig.band2,
rptrConfig.band3); rptrConfig.band3);
#ifdef USE_GPSD
if(aprsWriter != NULL) aprsWriter->setPortFixed(rptrConfig.callsign, rptrConfig.band, rptrConfig.frequency, rptrConfig.offset, rptrConfig.range, rptrConfig.latitude, rptrConfig.longitude, rptrConfig.agl); if(aprsWriter != NULL) {
if(aprsConfig.m_positionSource == POSSRC_GPSD)
aprsWriter->setPortGPSD(rptrConfig.callsign, rptrConfig.band, rptrConfig.frequency, rptrConfig.offset, rptrConfig.range, gpsdConfig.m_address, gpsdConfig.m_port);
else
aprsWriter->setPortFixed(rptrConfig.callsign, rptrConfig.band, rptrConfig.frequency, rptrConfig.offset, rptrConfig.range, rptrConfig.latitude, rptrConfig.longitude, rptrConfig.agl);
}
#else
aprsWriter->setPortFixed(rptrConfig.callsign, rptrConfig.band, rptrConfig.frequency, rptrConfig.offset, rptrConfig.range, rptrConfig.latitude, rptrConfig.longitude, rptrConfig.agl);
#endif
if(!ddEnabled) ddEnabled = rptrConfig.band.length() > 1U; if(!ddEnabled) ddEnabled = rptrConfig.band.length() > 1U;
} }
m_thread->setDDModeEnabled(ddEnabled); m_thread->setDDModeEnabled(ddEnabled);
CLog::logInfo("DD Mode enabled: %d", int(ddEnabled)); CLog::logInfo("DD Mode enabled: %d", int(ddEnabled));
// open APRS after setting the repeaters because of GPSD
if(aprsWriter != nullptr) {
if(aprsWriter->open()) {
m_thread->setAPRSWriter(aprsWriter);
}
else {
delete aprsWriter;
aprsWriter = NULL;
}
}
// Setup ircddb // Setup ircddb
std::vector<CIRCDDB *> clients; std::vector<CIRCDDB *> clients;
for(unsigned int i=0; i < config.getIrcDDBCount(); i++) { for(unsigned int i=0; i < config.getIrcDDBCount(); i++) {

@ -52,6 +52,9 @@ bool CDStarGatewayConfig::load()
ret = loadDPlus(cfg) && ret; ret = loadDPlus(cfg) && ret;
ret = loadRemote(cfg) && ret; ret = loadRemote(cfg) && ret;
ret = loadXLX(cfg) && ret; ret = loadXLX(cfg) && ret;
#ifdef USE_GPSD
ret = loadGPSD(cfg) && ret;
#endif
} }
if(ret) { if(ret) {
@ -118,6 +121,16 @@ bool CDStarGatewayConfig::loadAPRS(const CConfig & cfg)
ret = cfg.getValue("aprs", "port", m_aprs.port, 1U, 65535U, 14580U) && ret; ret = cfg.getValue("aprs", "port", m_aprs.port, 1U, 65535U, 14580U) && ret;
ret = cfg.getValue("aprs", "hostname", m_aprs.hostname, 0, 1024, "rotate.aprs2.net") && ret; ret = cfg.getValue("aprs", "hostname", m_aprs.hostname, 0, 1024, "rotate.aprs2.net") && ret;
ret = cfg.getValue("aprs", "password", m_aprs.password, 0U, 30U, "") && ret; ret = cfg.getValue("aprs", "password", m_aprs.password, 0U, 30U, "") && ret;
#ifdef USE_GPSD
std::string positionSource;
ret = cfg.getValue("aprs", "positionSource", positionSource, "fixed", {"fixed", "gpsd"}) && ret;
if(ret) {
if(positionSource == "fixed") m_aprs.m_positionSource = POSSRC_FIXED;
else if(positionSource == "gpsd") m_aprs.m_positionSource = POSSRC_GPSD;
}
#else
m_aprs.m_positionSource = POSSRC_FIXED;
#endif
m_aprs.enabled = m_aprs.enabled && !m_aprs.password.empty(); m_aprs.enabled = m_aprs.enabled && !m_aprs.password.empty();
@ -319,6 +332,16 @@ bool CDStarGatewayConfig::loadGateway(const CConfig & cfg)
return ret; return ret;
} }
#ifdef USE_GPSD
bool CDStarGatewayConfig::loadGPSD(const CConfig & cfg)
{
bool ret = cfg.getValue("gpsd", "address", m_gpsd.m_address, 0U, 15U, "127.0.0.1");
ret = cfg.getValue("gpsd", "port", m_gpsd.m_port, 0U, 5U, "2947") && ret;
return ret;
}
#endif
bool CDStarGatewayConfig::open(CConfig & cfg) bool CDStarGatewayConfig::open(CConfig & cfg)
{ {
try { try {
@ -408,3 +431,10 @@ void CDStarGatewayConfig::getXLX(TXLX & xlx) const
{ {
xlx = m_xlx; xlx = m_xlx;
} }
#ifdef USE_GPSD
void CDStarGatewayConfig::getGPSD(TGPSD & gpsd) const
{
gpsd = m_gpsd;
}
#endif

@ -91,6 +91,7 @@ typedef struct {
std::string hostname; std::string hostname;
unsigned int port; unsigned int port;
std::string password; std::string password;
POSITION_SOURCE m_positionSource;
} TAPRS; } TAPRS;
typedef struct { typedef struct {
@ -120,6 +121,12 @@ typedef struct {
std::string password; std::string password;
} TRemote; } TRemote;
#ifdef USE_GPSD
typedef struct {
std::string m_address;
std::string m_port;
} TGPSD;
#endif
class CDStarGatewayConfig { class CDStarGatewayConfig {
public: public:
@ -140,6 +147,9 @@ public:
void getDCS(TDCS & dcs) const; void getDCS(TDCS & dcs) const;
void getRemote(TRemote & remote) const; void getRemote(TRemote & remote) const;
void getXLX(TXLX & xlx) const; void getXLX(TXLX & xlx) const;
#ifdef USE_GPSD
void getGPSD(TGPSD & gpsd) const;
#endif
private: private:
bool open(CConfig & cfg); bool open(CConfig & cfg);
@ -154,6 +164,9 @@ private:
bool loadDCS(const CConfig & cfg); bool loadDCS(const CConfig & cfg);
bool loadRemote(const CConfig & cfg); bool loadRemote(const CConfig & cfg);
bool loadXLX(const CConfig & cfg); bool loadXLX(const CConfig & cfg);
#ifdef USE_GPSD
bool loadGPSD(const CConfig & cfg);
#endif
std::string m_fileName; std::string m_fileName;
TGateway m_gateway; TGateway m_gateway;
@ -165,6 +178,9 @@ private:
TRemote m_remote; TRemote m_remote;
TXLX m_xlx; TXLX m_xlx;
TLog m_log; TLog m_log;
#ifdef USE_GPSD
TGPSD m_gpsd;
#endif
std::vector<TRepeater *> m_repeaters; std::vector<TRepeater *> m_repeaters;
std::vector<TircDDB *> m_ircDDB; std::vector<TircDDB *> m_ircDDB;
}; };

@ -137,5 +137,10 @@ enum GATEWAY_TYPE {
GT_SMARTGROUP GT_SMARTGROUP
}; };
enum POSITION_SOURCE {
POSSRC_FIXED,
POSSRC_GPSD
};
const unsigned int TIME_PER_TIC_MS = 5U; const unsigned int TIME_PER_TIC_MS = 5U;

@ -26,6 +26,13 @@ CPPFLAGS=-g -ggdb -W -Wall -std=c++17
# or, you can choose this for a much smaller executable without debugging help # or, you can choose this for a much smaller executable without debugging help
#CPPFLAGS=-W -Wall -std=c++17 #CPPFLAGS=-W -Wall -std=c++17
LDFLAGS:=-lcurl -pthread
ifeq ($(USE_GPSD), 1)
CPPFLAGS+= -DUSE_GPSD
LDFLAGS+= -lgps
endif
SRCS = $(wildcard *.cpp) SRCS = $(wildcard *.cpp)
OBJS = $(SRCS:.cpp=.o) OBJS = $(SRCS:.cpp=.o)
DEPS = $(SRCS:.cpp=.d) DEPS = $(SRCS:.cpp=.d)
@ -34,16 +41,20 @@ DEPS = $(SRCS:.cpp=.d)
all: dstargateway all: dstargateway
dstargateway : GitVersion.h $(OBJS) dstargateway : GitVersion.h $(OBJS)
g++ $(CPPFLAGS) -o dstargateway $(OBJS) -lcurl -pthread g++ $(CPPFLAGS) -o dstargateway $(OBJS) $(LDFLAGS)
%.o : %.cpp %.o : %.cpp
g++ $(CPPFLAGS) -MMD -MD -c $< -o $@ g++ $(CPPFLAGS) -MMD -MD -c $< -o $@
GitVersion.h : FORCE GitVersion.h : FORCE
ifneq ("$(wildcard .git/index)","") ifneq ("$(wildcard .git/index)","")
@echo "#pragma once\nconst char *gitversion = \"$(shell git rev-parse HEAD)\";" > /tmp/$@ @echo "#pragma once" > /tmp/$@
@echo "#include <string>" >> /tmp/$@
@echo "const std::string gitversion(\"$(shell git rev-parse --short HEAD)\");" >> /tmp/$@
else else
@echo "#pragma once\nconst char *gitversion = \"0000000000000000000000000000000000000000\";" > /tmp/$@ @echo "#pragma once" > /tmp/$@
@echo "#include <string>" >> /tmp/$@
@echo "const std::string gitversion(\"0000000\");" >> /tmp/$@
endif endif
@cmp -s /tmp/$@ $@; \ @cmp -s /tmp/$@ $@; \
RETVAL=$$?; \ RETVAL=$$?; \

@ -5,10 +5,11 @@
- [2.3. Features](#23-features) - [2.3. Features](#23-features)
- [3. Building and installing](#3-building-and-installing) - [3. Building and installing](#3-building-and-installing)
- [3.1. Initial setup](#31-initial-setup) - [3.1. Initial setup](#31-initial-setup)
- [3.2. Get latest stable version](#32-get-latest-stable-version) - [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 version](#33-get-latest-development-version-version)
- [3.4. Prerequisites and dependencies](#34-prerequisites-and-dependencies) - [3.4. Prerequisites and dependencies](#34-prerequisites-and-dependencies)
- [3.5. Building](#35-building) - [3.5. Building](#35-building)
- [Build With GPSD Support](#build-with-gpsd-support)
- [3.6. Installing](#36-installing) - [3.6. Installing](#36-installing)
- [3.7. Configuring](#37-configuring) - [3.7. Configuring](#37-configuring)
- [4. Contributing](#4-contributing) - [4. Contributing](#4-contributing)
@ -41,8 +42,7 @@ Features that where left out :
- CCS: is still being used? I always considered this as trojan horse to push some DMR Agenda into DStar an more or les a burdain to use. Call sign routing is by far more flexible and superior. - CCS: is still being used? I always considered this as trojan horse to push some DMR Agenda into DStar an more or les a burdain to use. Call sign routing is by far more flexible and superior.
- Starnet: You might consider running [Smart Group Server XL](https://github.com/F4FXL/smart-group-server-xl) from a dedicated computer instead. - Starnet: You might consider running [Smart Group Server XL](https://github.com/F4FXL/smart-group-server-xl) from a dedicated computer instead.
- Announcement: same can be achieved using transmitd. - Announcement: same can be achieved using transmitd.
- APRSGateway capability: I would prefer to have some sort of TCP "APRS-IS proxy" program sitting between the program and the APRS server, thus keeping the ability to directly connect to APRS-IS or not. - APRSGateway capability: I would prefer to have some sort of TCP "APRS-IS proxy" program sitting between the program and the APRS server, thus keeping the ability to directly connect to APRS-IS or not, depending on the system owner wish. I run mostly DStar Only repeaters, having an additional program to maintain is unnecessary burden.
- Mobile APRS: Code has been ported, yet I am targeting repeaters so low priority.
- DRats : No opinion on this one, I am not using it. - DRats : No opinion on this one, I am not using it.
- CallSign Server : this is a legacy from the dead project xreflector.net, I will most probably drop it. - CallSign Server : this is a legacy from the dead project xreflector.net, I will most probably drop it.
@ -53,7 +53,7 @@ Clone the repository (only required initally)
git clone https://github.com/F4FXL/DStarGateway.git git clone https://github.com/F4FXL/DStarGateway.git
cd DStarGateway cd DStarGateway
``` ```
## 3.2. Get latest stable version ## 3.2. Get latest stable version (recommended)
From inside the cloned repository run following commands to get the latest stable version From inside the cloned repository run following commands to get the latest stable version
``` ```
git pull -p git pull -p
@ -71,10 +71,19 @@ Before first time building you need to install dependencies and prerequisites
``` ```
apt install build-essential libcurl4-openssl-dev libboost-dev apt install build-essential libcurl4-openssl-dev libboost-dev
``` ```
If you are going to build with gpsd support, also install libgps-dev
```
apt install libgps-dev
```
## 3.5. Building ## 3.5. Building
Regular building
``` ```
make make
``` ```
#### Build With GPSD Support
```
make USE_GPS=1
```
## 3.6. Installing ## 3.6. Installing
The program is meant to run as a systemd service. All bits an pieces are provided. The program is meant to run as a systemd service. All bits an pieces are provided.
``` ```
@ -99,11 +108,12 @@ I Use [Git flow](https://danielkummer.github.io/git-flow-cheatsheet/) as my work
# 5. Version History # 5. Version History
## 5.1. Version 0.4 ## 5.1. Version 0.4
- [improvement] Log enhancements ([#4])(https://github.com/F4FXL/DStarGateway/issues/4) - [Improvement] Bring back GPSD support (https://github.com/F4FXL/DStarGateway/issues/6)
- [Improvement] Log enhancements ([#4])(https://github.com/F4FXL/DStarGateway/issues/4)
## 5.2. Version 0.3 ## 5.2. Version 0.3
- [Improvement] Get ride of libcongif++ dependency. When upgrading from earlier version you need to manualy delete the config file before reinstalling. - [Improvement] Get ride of libcongif++ dependency. When upgrading from earlier version you need to manualy delete the config file before reinstalling.
## 5.3. Version 0.2 ## 5.3. Version 0.2
- [bugfix] ircDDBFreeze when repeater not found ([#1](https://github.com/F4FXL/DStarGateway/issues/1)) - [Bugfix] ircDDBFreeze when repeater not found ([#1](https://github.com/F4FXL/DStarGateway/issues/1))
- Code sanitization - Code sanitization
## 5.4. Version 0.1 ## 5.4. Version 0.1
First working version First working version

@ -22,5 +22,10 @@
#include <string> #include <string>
const std::string VENDOR_NAME("Geoffrey Merck F4FXL / KC3FRA"); #include "GitVersion.h"
const std::string PRODUCT_NAME("DStarGateway");
const std::string VENDOR_NAME("Geoffrey Merck F4FXL / KC3FRA and Contributors");
const std::string VERSION("0.4"); const std::string VERSION("0.4");
const std::string FULL_PRODUCT_NAME = PRODUCT_NAME + " v" + VERSION + "-" + gitversion;
const std::string SHORT_PRODUCT_NAME = "DStarGW v" + VERSION + "-" + gitversion;

@ -45,13 +45,13 @@ m_out(0U)
m_data = new CAMBEData*[NUM_FRAMES]; m_data = new CAMBEData*[NUM_FRAMES];
char vstr[32]; auto vstr = SHORT_PRODUCT_NAME;
snprintf(vstr, 32, "DStar GW - %s", VERSION.substr(0, 8).c_str()); vstr.resize(NUM_FRAMES, ' ');
CLog::logInfo("Version text set to \"%s\"\n", vstr); CLog::logInfo("Version text set to \"%s\"\n", vstr);
CSlowDataEncoder encoder; CSlowDataEncoder encoder;
encoder.setTextData(std::string(vstr)); encoder.setTextData(vstr);
// Seq No and end // Seq No and end
for (unsigned int i = 0U; i < NUM_FRAMES; i++) { for (unsigned int i = 0U; i < NUM_FRAMES; i++) {

@ -139,6 +139,11 @@ enabled=true
hostname=rotate.aprs2.net # Defaults to rotate.aprs2.net hostname=rotate.aprs2.net # Defaults to rotate.aprs2.net
port=14580 # Defaults to 14580, there is no reason to change this port=14580 # Defaults to 14580, there is no reason to change this
password=12345 password=12345
positionSource= # Sets how the position is determined fixed or gpsd. this is ignored if DStargateway was built without GPSD support
[GPSD]
address= # GPSD address, defaults to 127.0.0.1
port= # GPSD port, defaults to 2947
[Log] [Log]
path=/var/log/dstargateway/ path=/var/log/dstargateway/

Loading…
Cancel
Save

Powered by TurnKey Linux.