Add MobileGPS support.

This commit is contained in:
Jonathan Naylor 2018-11-06 11:27:36 +00:00
parent 08844423e3
commit 70099695df
9 changed files with 264 additions and 65 deletions

View File

@ -26,7 +26,7 @@
CAPRSWriter::CAPRSWriter(const std::string& callsign, const std::string& suffix, const std::string& password, const std::string& address, unsigned int port) :
m_thread(NULL),
m_enabled(false),
m_idTimer(1000U, 20U * 60U), // 20 minutes
m_idTimer(1000U),
m_callsign(callsign),
m_txFrequency(0U),
m_rxFrequency(0U),
@ -52,19 +52,49 @@ CAPRSWriter::~CAPRSWriter()
{
}
void CAPRSWriter::setInfo(unsigned int txFrequency, unsigned int rxFrequency, float latitude, float longitude, int height, const std::string& desc)
void CAPRSWriter::setInfo(unsigned int txFrequency, unsigned int rxFrequency, const std::string& desc)
{
m_txFrequency = txFrequency;
m_rxFrequency = rxFrequency;
m_latitude = latitude;
m_longitude = longitude;
m_height = height;
m_desc = desc;
}
void CAPRSWriter::setStaticLocation(float latitude, float longitude, int height)
{
m_latitude = latitude;
m_longitude = longitude;
m_height = height;
}
void CAPRSWriter::setMobileLocation(const std::string& address, unsigned int port)
{
assert(!address.empty());
assert(port > 0U);
m_mobileGPSAddress = CUDPSocket::lookup(address);
m_mobileGPSPort = port;
m_socket = new CUDPSocket;
}
bool CAPRSWriter::open()
{
if (m_socket != NULL) {
bool ret = m_socket->open();
if (!ret) {
delete m_socket;
m_socket = NULL;
return false;
}
// Poll the GPS every minute
m_idTimer.setTimeout(60U);
} else {
m_idTimer.setTimeout(20U * 60U);
}
m_idTimer.start();
return m_thread->start();
}
@ -79,18 +109,39 @@ void CAPRSWriter::clock(unsigned int ms)
{
m_idTimer.clock(ms);
if (m_idTimer.hasExpired()) {
sendIdFrames();
m_idTimer.start();
if (m_socket != NULL) {
if (m_idTimer.hasExpired()) {
pollGPS();
m_idTimer.start();
}
sendIdFrameMobile();
} else {
if (m_idTimer.hasExpired()) {
sendIdFrameFixed();
m_idTimer.start();
}
}
}
void CAPRSWriter::close()
{
if (m_socket != NULL) {
m_socket->close();
delete m_socket;
}
m_thread->stop();
}
void CAPRSWriter::sendIdFrames()
bool CAPRSWriter::pollGPS()
{
assert(m_socket != NULL);
return m_socket->write((unsigned char*)"NXDNGateway", 11U, m_mobileGPSAddress, m_mobileGPSPort);
}
void CAPRSWriter::sendIdFrameFixed()
{
if (!m_thread->isConnected())
return;
@ -152,6 +203,97 @@ void CAPRSWriter::sendIdFrames()
float(m_height) * 3.28F, band, desc);
m_thread->write(output);
m_idTimer.start();
}
void CAPRSWriter::sendIdFrameMobile()
{
// Grab GPS data if it's available
unsigned char buffer[200U];
in_addr address;
unsigned int port;
int ret = m_socket->read(buffer, 200U, address, port);
if (ret <= 0)
return;
if (!m_thread->isConnected())
return;
buffer[ret] = '\0';
// Parse the GPS data
char* pLatitude = ::strtok((char*)buffer, ",\n"); // Latitude
char* pLongitude = ::strtok(NULL, ",\n"); // Longitude
char* pAltitude = ::strtok(NULL, ",\n"); // Altitude (m)
char* pVelocity = ::strtok(NULL, ",\n"); // Velocity (kms/h)
char* pBearing = ::strtok(NULL, "\n"); // Bearing
if (pLatitude == NULL || pLongitude == NULL || pAltitude == NULL)
return;
float rawLatitude = ::atof(pLatitude);
float rawLongitude = ::atof(pLongitude);
float rawAltitude = ::atof(pAltitude);
char desc[200U];
if (m_txFrequency != 0U) {
float offset = float(int(m_rxFrequency) - int(m_txFrequency)) / 1000000.0F;
::sprintf(desc, "MMDVM Voice %.5LfMHz %c%.4lfMHz%s%s",
(long double)(m_txFrequency) / 1000000.0F,
offset < 0.0F ? '-' : '+',
::fabs(offset), m_desc.empty() ? "" : ", ", m_desc.c_str());
} else {
::sprintf(desc, "MMDVM Voice%s%s", m_desc.empty() ? "" : ", ", m_desc.c_str());
}
const char* band = "4m";
if (m_txFrequency >= 1200000000U)
band = "1.2";
else if (m_txFrequency >= 420000000U)
band = "440";
else if (m_txFrequency >= 144000000U)
band = "2m";
else if (m_txFrequency >= 50000000U)
band = "6m";
else if (m_txFrequency >= 28000000U)
band = "10m";
double tempLat = ::fabs(rawLatitude);
double tempLong = ::fabs(rawLongitude);
double latitude = ::floor(tempLat);
double longitude = ::floor(tempLong);
latitude = (tempLat - latitude) * 60.0 + latitude * 100.0;
longitude = (tempLong - longitude) * 60.0 + longitude * 100.0;
char lat[20U];
::sprintf(lat, "%07.2lf", latitude);
char lon[20U];
::sprintf(lon, "%08.2lf", longitude);
std::string server = m_callsign;
size_t pos = server.find_first_of('-');
if (pos == std::string::npos)
server.append("-S");
else
server.append("S");
char output[500U];
::sprintf(output, "%s>APDG03,TCPIP*,qAC,%s:!%s%cD%s%c&",
m_callsign.c_str(), server.c_str(),
lat, (rawLatitude < 0.0F) ? 'S' : 'N',
lon, (rawLongitude < 0.0F) ? 'W' : 'E');
if (pBearing != NULL && pVelocity != NULL) {
float rawBearing = ::atof(pBearing);
float rawVelocity = ::atof(pVelocity);
::sprintf(output + ::strlen(output), "%03.0f/%03.0f", rawBearing, rawVelocity * 0.539957F);
}
::sprintf(output + ::strlen(output), "/A=%06.0f%s %s", float(rawAltitude) * 3.28F, band, desc);
m_thread->write(output);
}

View File

@ -20,10 +20,24 @@
#define APRSWriter_H
#include "APRSWriterThread.h"
#include "UDPSocket.h"
#include "Timer.h"
#include <string>
#if !defined(_WIN32) && !defined(_WIN64)
#include <netdb.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#else
#include <winsock.h>
#endif
class CAPRSWriter {
public:
CAPRSWriter(const std::string& callsign, const std::string& suffix, const std::string& password, const std::string& address, unsigned int port);
@ -31,7 +45,11 @@ public:
bool open();
void setInfo(unsigned int txFrequency, unsigned int rxFrequency, float latitude, float longitude, int height, const std::string& desc);
void setInfo(unsigned int txFrequency, unsigned int rxFrequency, const std::string& desc);
void setStaticLocation(float latitude, float longitude, int height);
void setMobileLocation(const std::string& address, unsigned int port);
void write(const char* data);
@ -50,8 +68,13 @@ private:
float m_longitude;
int m_height;
std::string m_desc;
in_addr m_mobileGPSAddress;
unsigned int m_mobileGPSPort;
CUDPSocket* m_socket;
void sendIdFrames();
bool pollGPS();
void sendIdFrameFixed();
void sendIdFrameMobile();
};
#endif

View File

@ -34,7 +34,8 @@ enum SECTION {
SECTION_VOICE,
SECTION_LOG,
SECTION_APRS_FI,
SECTION_NETWORK
SECTION_NETWORK,
SECTION_MOBILE_GPS
};
CConf::CConf(const std::string& file) :
@ -77,7 +78,10 @@ m_networkNXDN2DMRAddress("127.0.0.1"),
m_networkNXDN2DMRPort(0U),
m_networkStartup(9999U),
m_networkInactivityTimeout(0U),
m_networkDebug(false)
m_networkDebug(false),
m_mobileGPSEnabled(false),
m_mobileGPSAddress(),
m_mobileGPSPort(0U)
{
}
@ -115,6 +119,8 @@ bool CConf::read()
section = SECTION_APRS_FI;
else if (::strncmp(buffer, "[Network]", 9U) == 0)
section = SECTION_NETWORK;
else if (::strncmp(buffer, "[Mobile GPS]", 12U) == 0)
section = SECTION_MOBILE_GPS;
else
section = SECTION_NONE;
@ -217,6 +223,13 @@ bool CConf::read()
m_networkInactivityTimeout = (unsigned int)::atoi(value);
else if (::strcmp(key, "Debug") == 0)
m_networkDebug = ::atoi(value) == 1;
} else if (section == SECTION_MOBILE_GPS) {
if (::strcmp(key, "Enable") == 0)
m_mobileGPSEnabled = ::atoi(value) == 1;
else if (::strcmp(key, "Address") == 0)
m_mobileGPSAddress = value;
else if (::strcmp(key, "Port") == 0)
m_mobileGPSPort = (unsigned int)::atoi(value);
}
}
@ -419,3 +432,19 @@ bool CConf::getNetworkDebug() const
{
return m_networkDebug;
}
bool CConf::getMobileGPSEnabled() const
{
return m_mobileGPSEnabled;
}
std::string CConf::getMobileGPSAddress() const
{
return m_mobileGPSAddress;
}
unsigned int CConf::getMobileGPSPort() const
{
return m_mobileGPSPort;
}

View File

@ -83,6 +83,11 @@ public:
unsigned int getNetworkInactivityTimeout() const;
bool getNetworkDebug() const;
// The Mobile GPS section
bool getMobileGPSEnabled() const;
std::string getMobileGPSAddress() const;
unsigned int getMobileGPSPort() const;
private:
std::string m_file;
std::string m_callsign;
@ -130,6 +135,10 @@ private:
unsigned short m_networkStartup;
unsigned int m_networkInactivityTimeout;
bool m_networkDebug;
bool m_mobileGPSEnabled;
std::string m_mobileGPSAddress;
unsigned int m_mobileGPSPort;
};
#endif

View File

@ -29,18 +29,16 @@ const unsigned char NXDN_DATA_TYPE_GPS = 0x06U;
const unsigned int NXDN_DATA_LENGTH = 20U;
const unsigned int NXDN_DATA_MAX_LENGTH = 16U * NXDN_DATA_LENGTH;
CGPSHandler::CGPSHandler(const std::string& callsign, const std::string& rptSuffix, const std::string& password, const std::string& address, unsigned int port, const std::string& suffix) :
CGPSHandler::CGPSHandler(const std::string& callsign, const std::string& suffix, CAPRSWriter* writer) :
m_callsign(callsign),
m_writer(callsign, rptSuffix, password, address, port),
m_writer(writer),
m_data(NULL),
m_length(0U),
m_source(),
m_suffix(suffix)
{
assert(!callsign.empty());
assert(!password.empty());
assert(!address.empty());
assert(port > 0U);
assert(writer != NULL);
m_data = new unsigned char[NXDN_DATA_MAX_LENGTH];
@ -52,16 +50,6 @@ CGPSHandler::~CGPSHandler()
delete[] m_data;
}
bool CGPSHandler::open()
{
return m_writer.open();
}
void CGPSHandler::setInfo(unsigned int txFrequency, unsigned int rxFrequency, float latitude, float longitude, int height, const std::string& desc)
{
m_writer.setInfo(txFrequency, rxFrequency, latitude, longitude, height, desc);
}
void CGPSHandler::processHeader(const std::string& source)
{
reset();
@ -86,16 +74,6 @@ void CGPSHandler::processEnd()
reset();
}
void CGPSHandler::clock(unsigned int ms)
{
m_writer.clock(ms);
}
void CGPSHandler::close()
{
m_writer.close();
}
void CGPSHandler::reset()
{
::memset(m_data, 0x00U, NXDN_DATA_MAX_LENGTH);
@ -163,7 +141,7 @@ void CGPSHandler::processNMEA()
source.c_str(), m_callsign.c_str(), latitude, pRMC[4U], longitude, pRMC[6U]);
}
m_writer.write(output);
m_writer->write(output);
}
bool CGPSHandler::checkXOR() const

View File

@ -25,26 +25,18 @@
class CGPSHandler {
public:
CGPSHandler(const std::string& callsign, const std::string& rptSuffix, const std::string& password, const std::string& address, unsigned int port, const std::string& suffix);
CGPSHandler(const std::string& callsign, const std::string& suffix, CAPRSWriter* writer);
~CGPSHandler();
bool open();
void setInfo(unsigned int txFrequency, unsigned int rxFrequency, float latitude, float longitude, int height, const std::string& desc);
void processHeader(const std::string& source);
void processData(const unsigned char* data);
void processEnd();
void clock(unsigned int ms);
void close();
private:
std::string m_callsign;
CAPRSWriter m_writer;
CAPRSWriter* m_writer;
unsigned char* m_data;
unsigned int m_length;
std::string m_source;

View File

@ -87,7 +87,9 @@ int main(int argc, char** argv)
}
CNXDNGateway::CNXDNGateway(const std::string& file) :
m_conf(file)
m_conf(file),
m_writer(NULL),
m_gps(NULL)
{
}
@ -458,8 +460,8 @@ startupId = 9999U;
lostTimer.stop();
}
if (m_gps != NULL)
m_gps->clock(ms);
if (m_writer != NULL)
m_writer->clock(ms);
if (ms < 5U)
CThread::sleep(5U);
@ -474,7 +476,8 @@ startupId = 9999U;
lookup->stop();
if (m_gps != NULL) {
m_gps->close();
m_writer->close();
delete m_writer;
delete m_gps;
}
@ -491,22 +494,37 @@ void CNXDNGateway::createGPS()
std::string hostname = m_conf.getAPRSServer();
unsigned int port = m_conf.getAPRSPort();
std::string password = m_conf.getAPRSPassword();
std::string desc = m_conf.getAPRSDescription();
std::string suffix = m_conf.getAPRSSuffix();
m_gps = new CGPSHandler(callsign, rptSuffix, password, hostname, port, suffix);
m_writer = new CAPRSWriter(callsign, rptSuffix, password, hostname, port);
unsigned int txFrequency = m_conf.getTxFrequency();
unsigned int rxFrequency = m_conf.getRxFrequency();
float latitude = m_conf.getLatitude();
float longitude = m_conf.getLongitude();
int height = m_conf.getHeight();
std::string desc = m_conf.getAPRSDescription();
m_gps->setInfo(txFrequency, rxFrequency, latitude, longitude, height, desc);
m_writer->setInfo(txFrequency, rxFrequency, desc);
bool ret = m_gps->open();
if (!ret) {
delete m_gps;
m_gps = NULL;
bool enabled = m_conf.getMobileGPSEnabled();
if (enabled) {
std::string address = m_conf.getMobileGPSAddress();
unsigned int port = m_conf.getMobileGPSPort();
m_writer->setMobileLocation(address, port);
} else {
float latitude = m_conf.getLatitude();
float longitude = m_conf.getLongitude();
int height = m_conf.getHeight();
m_writer->setStaticLocation(latitude, longitude, height);
}
bool ret = m_writer->open();
if (!ret) {
delete m_writer;
m_writer = NULL;
return;
}
m_gps = new CGPSHandler(callsign, suffix, m_writer);
}

View File

@ -19,6 +19,7 @@
#if !defined(NXDNGateway_H)
#define NXDNGateway_H
#include "APRSWriter.h"
#include "GPSHandler.h"
#include "Timer.h"
#include "Conf.h"
@ -49,6 +50,7 @@ public:
private:
CConf m_conf;
CAPRSWriter* m_writer;
CGPSHandler* m_gps;
void createGPS();

View File

@ -51,3 +51,9 @@ NXDN2DMRPort=42022
Startup=10200
InactivityTimeout=10
Debug=0
[Mobile GPS]
Enable=0
Address=127.0.0.1
Port=7834