diff --git a/NXDNGateway/APRSWriter.cpp b/NXDNGateway/APRSWriter.cpp index 52fab1c..bfd62c1 100644 --- a/NXDNGateway/APRSWriter.cpp +++ b/NXDNGateway/APRSWriter.cpp @@ -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); +} + diff --git a/NXDNGateway/APRSWriter.h b/NXDNGateway/APRSWriter.h index baa9141..0ea1ad6 100644 --- a/NXDNGateway/APRSWriter.h +++ b/NXDNGateway/APRSWriter.h @@ -20,10 +20,24 @@ #define APRSWriter_H #include "APRSWriterThread.h" +#include "UDPSocket.h" #include "Timer.h" #include +#if !defined(_WIN32) && !defined(_WIN64) +#include +#include +#include +#include +#include +#include +#include +#include +#else +#include +#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 diff --git a/NXDNGateway/Conf.cpp b/NXDNGateway/Conf.cpp index 8b4dda2..92cba3c 100644 --- a/NXDNGateway/Conf.cpp +++ b/NXDNGateway/Conf.cpp @@ -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; +} + diff --git a/NXDNGateway/Conf.h b/NXDNGateway/Conf.h index 64f29d6..29dce87 100644 --- a/NXDNGateway/Conf.h +++ b/NXDNGateway/Conf.h @@ -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 diff --git a/NXDNGateway/GPSHandler.cpp b/NXDNGateway/GPSHandler.cpp index 95dfd02..696f5ff 100644 --- a/NXDNGateway/GPSHandler.cpp +++ b/NXDNGateway/GPSHandler.cpp @@ -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 diff --git a/NXDNGateway/GPSHandler.h b/NXDNGateway/GPSHandler.h index 23c816a..44cdb34 100644 --- a/NXDNGateway/GPSHandler.h +++ b/NXDNGateway/GPSHandler.h @@ -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; diff --git a/NXDNGateway/NXDNGateway.cpp b/NXDNGateway/NXDNGateway.cpp index 14a4f25..b86fb9e 100644 --- a/NXDNGateway/NXDNGateway.cpp +++ b/NXDNGateway/NXDNGateway.cpp @@ -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); } + diff --git a/NXDNGateway/NXDNGateway.h b/NXDNGateway/NXDNGateway.h index e01b74a..e1eb7ac 100644 --- a/NXDNGateway/NXDNGateway.h +++ b/NXDNGateway/NXDNGateway.h @@ -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(); diff --git a/NXDNGateway/NXDNGateway.ini b/NXDNGateway/NXDNGateway.ini index a77efca..884d8bd 100644 --- a/NXDNGateway/NXDNGateway.ini +++ b/NXDNGateway/NXDNGateway.ini @@ -51,3 +51,9 @@ NXDN2DMRPort=42022 Startup=10200 InactivityTimeout=10 Debug=0 + +[Mobile GPS] +Enable=0 +Address=127.0.0.1 +Port=7834 +