diff --git a/YSFGateway/APRSWriter.cpp b/YSFGateway/APRSWriter.cpp index 03db91c..ba1551b 100644 --- a/YSFGateway/APRSWriter.cpp +++ b/YSFGateway/APRSWriter.cpp @@ -36,7 +36,10 @@ m_latitude(0.0F), m_longitude(0.0F), m_height(0), m_desc(), -m_suffix(suffix) +m_suffix(suffix), +m_mobileGPSAddress(), +m_mobileGPSPort(0U), +m_socket(NULL) { assert(!callsign.empty()); assert(!password.empty()); @@ -65,9 +68,33 @@ void CAPRSWriter::setInfo(unsigned int txFrequency, unsigned int rxFrequency, fl m_desc = desc; } +void CAPRSWriter::setMobileGPS(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); + } + m_idTimer.start(); + return m_thread->start(); } @@ -135,18 +162,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*)"YSFGateway", 10U, m_mobileGPSAddress, m_mobileGPSPort); +} + +void CAPRSWriter::sendIdFrameFixed() { if (!m_thread->isConnected()) return; @@ -211,3 +259,92 @@ void CAPRSWriter::sendIdFrames() 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* p1 = ::strtok((char*)buffer, ","); // Latitude + char* p2 = ::strtok(NULL, ","); // Longitude + char* p3 = ::strtok(NULL, ","); // Altitude (m) + char* p4 = ::strtok(NULL, ","); // Speed (kms/h) + char* p5 = ::strtok(NULL, "\n"); // Bearing + + if (p1 == NULL || p2 == NULL || p3 == NULL || p4 == NULL || p5 == NULL) + return; + + float rawLatitude = ::atof(p1); + float rawLongitude = ::atof(p2); + float rawAltitude = ::atof(p3); + float rawSpeed = ::atof(p4); + float rawBearing = ::atof(p5); + + 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&%03.0f/%03.0f/A=%06.0f%s %s", + m_callsign.c_str(), server.c_str(), + lat, (rawLatitude < 0.0F) ? 'S' : 'N', + lon, (rawLongitude < 0.0F) ? 'W' : 'E', + rawBearing, rawSpeed * 0.539957F, + float(rawAltitude) * 3.28F, band, desc); + + m_thread->write(output); + + m_idTimer.start(); +} diff --git a/YSFGateway/APRSWriter.h b/YSFGateway/APRSWriter.h index 22e1111..1839c64 100644 --- a/YSFGateway/APRSWriter.h +++ b/YSFGateway/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& rptSuffix, const std::string& password, const std::string& address, unsigned int port, const std::string& suffix); @@ -33,6 +47,8 @@ public: void setInfo(unsigned int txFrequency, unsigned int rxFrequency, float latitude, float longitude, int height, const std::string& desc); + void setMobileGPS(const std::string& address, unsigned int port); + void write(const unsigned char* source, const char* type, unsigned char radio, float latitude, float longitude); void clock(unsigned int ms); @@ -51,8 +67,13 @@ private: int m_height; std::string m_desc; std::string m_suffix; + in_addr m_mobileGPSAddress; + unsigned int m_mobileGPSPort; + CUDPSocket* m_socket; - void sendIdFrames(); + bool pollGPS(); + void sendIdFrameFixed(); + void sendIdFrameMobile(); }; #endif diff --git a/YSFGateway/Conf.cpp b/YSFGateway/Conf.cpp index 3cccc84..7566783 100644 --- a/YSFGateway/Conf.cpp +++ b/YSFGateway/Conf.cpp @@ -34,7 +34,8 @@ enum SECTION { SECTION_APRS_FI, SECTION_NETWORK, SECTION_YSF_NETWORK, - SECTION_FCS_NETWORK + SECTION_FCS_NETWORK, + SECTION_MOBILE_GPS }; CConf::CConf(const std::string& file) : @@ -83,7 +84,10 @@ m_ysfNetworkYSF2P25Address("127.0.0.1"), m_ysfNetworkYSF2P25Port(0U), m_fcsNetworkEnabled(false), m_fcsNetworkFile(), -m_fcsNetworkPort(0U) +m_fcsNetworkPort(0U), +m_mobileGPSEnabled(false), +m_mobileGPSAddress(), +m_mobileGPSPort(0U) { } @@ -121,13 +125,15 @@ bool CConf::read() section = SECTION_YSF_NETWORK; else if (::strncmp(buffer, "[FCS Network]", 13U) == 0) section = SECTION_FCS_NETWORK; + else if (::strncmp(buffer, "[Mobile GPS]", 12U) == 0) + section = SECTION_MOBILE_GPS; else - section = SECTION_NONE; + section = SECTION_NONE; - continue; + continue; } - char* key = ::strtok(buffer, " \t=\r\n"); + char* key = ::strtok(buffer, " \t=\r\n"); if (key == NULL) continue; @@ -235,6 +241,13 @@ bool CConf::read() m_fcsNetworkFile = value; else if (::strcmp(key, "Port") == 0) m_fcsNetworkPort = (unsigned int)::atoi(value); + } 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); } } @@ -453,6 +466,7 @@ unsigned int CConf::getYSFNetworkYSF2P25Port() const return m_ysfNetworkYSF2P25Port; } + bool CConf::getFCSNetworkEnabled() const { return m_fcsNetworkEnabled; @@ -467,3 +481,18 @@ unsigned int CConf::getFCSNetworkPort() const { return m_fcsNetworkPort; } + +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/YSFGateway/Conf.h b/YSFGateway/Conf.h index 0cef458..8a1a6f5 100644 --- a/YSFGateway/Conf.h +++ b/YSFGateway/Conf.h @@ -88,6 +88,11 @@ public: std::string getFCSNetworkFile() const; unsigned int getFCSNetworkPort() 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; @@ -141,6 +146,10 @@ private: bool m_fcsNetworkEnabled; std::string m_fcsNetworkFile; unsigned int m_fcsNetworkPort; + + bool m_mobileGPSEnabled; + std::string m_mobileGPSAddress; + unsigned int m_mobileGPSPort; }; #endif diff --git a/YSFGateway/GPS.cpp b/YSFGateway/GPS.cpp index 0932e25..2100413 100644 --- a/YSFGateway/GPS.cpp +++ b/YSFGateway/GPS.cpp @@ -31,15 +31,12 @@ const unsigned char NULL_GPS[] = {0x47U, 0x63U}; const unsigned char SHRT_GPS[] = {0x22U, 0x62U}; const unsigned char LONG_GPS[] = {0x47U, 0x64U}; -CGPS::CGPS(const std::string& callsign, const std::string& rptSuffix, const std::string& password, const std::string& address, unsigned int port, const std::string suffix) : -m_writer(callsign, rptSuffix, password, address, port, suffix), +CGPS::CGPS(CAPRSWriter* writer) : +m_writer(writer), m_buffer(NULL), m_sent(false) { - assert(!callsign.empty()); - assert(!password.empty()); - assert(!address.empty()); - assert(port > 0U); + assert(writer != NULL); m_buffer = new unsigned char[300U]; } @@ -49,16 +46,6 @@ CGPS::~CGPS() delete[] m_buffer; } -void CGPS::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); -} - -bool CGPS::open() -{ - return m_writer.open(); -} - void CGPS::data(const unsigned char* source, const unsigned char* data, unsigned char fi, unsigned char dt, unsigned char fn, unsigned char ft) { if (m_sent) @@ -150,6 +137,8 @@ void CGPS::reset() void CGPS::transmitGPS(const unsigned char* source) { + assert(m_writer != NULL); + // We don't know who its from! if (::memcmp(source, " ", YSF_CALLSIGN_LENGTH) == 0) return; @@ -275,17 +264,7 @@ void CGPS::transmitGPS(const unsigned char* source) LogMessage("GPS Position from %10.10s of radio=%s lat=%f long=%f", source, radio, latitude, longitude); - m_writer.write(source, radio, m_buffer[4U], latitude, longitude); + m_writer->write(source, radio, m_buffer[4U], latitude, longitude); m_sent = true; } - -void CGPS::clock(unsigned int ms) -{ - m_writer.clock(ms); -} - -void CGPS::close() -{ - m_writer.close(); -} diff --git a/YSFGateway/GPS.h b/YSFGateway/GPS.h index 3a163f4..cbdf838 100644 --- a/YSFGateway/GPS.h +++ b/YSFGateway/GPS.h @@ -25,23 +25,15 @@ class CGPS { public: - CGPS(const std::string& callsign, const std::string& rptSuffix, const std::string& password, const std::string& address, unsigned int port, const std::string suffix); + CGPS(CAPRSWriter* writer); ~CGPS(); - void setInfo(unsigned int txFrequency, unsigned int rxFrequency, float latitude, float longitude, int height, const std::string& desc); - - bool open(); - void data(const unsigned char* source, const unsigned char* data, unsigned char fi, unsigned char dt, unsigned char fn, unsigned char ft); - void clock(unsigned int ms); - void reset(); - void close(); - private: - CAPRSWriter m_writer; + CAPRSWriter* m_writer; unsigned char* m_buffer; bool m_sent; diff --git a/YSFGateway/YSFGateway.cpp b/YSFGateway/YSFGateway.cpp index 57c6cae..6b00450 100644 --- a/YSFGateway/YSFGateway.cpp +++ b/YSFGateway/YSFGateway.cpp @@ -78,6 +78,7 @@ CYSFGateway::CYSFGateway(const std::string& configFile) : m_callsign(), m_suffix(), m_conf(configFile), +m_writer(NULL), m_gps(NULL), m_reflectors(NULL), m_wiresX(NULL), @@ -328,8 +329,8 @@ int CYSFGateway::run() m_ysfNetwork->clock(ms); if (m_fcsNetwork != NULL) m_fcsNetwork->clock(ms); - if (m_gps != NULL) - m_gps->clock(ms); + if (m_writer != NULL) + m_writer->clock(ms); m_wiresX->clock(ms); m_inactivityTimer.clock(ms); @@ -401,7 +402,8 @@ int CYSFGateway::run() rptNetwork.close(); if (m_gps != NULL) { - m_gps->close(); + m_writer->close(); + delete m_writer; delete m_gps; } @@ -433,7 +435,7 @@ void CYSFGateway::createGPS() std::string suffix = m_conf.getAPRSSuffix(); std::string desc = m_conf.getAPRSDescription(); - m_gps = new CGPS(m_callsign, m_suffix, password, hostname, port, suffix); + m_writer = new CAPRSWriter(m_callsign, m_suffix, password, hostname, port, suffix); unsigned int txFrequency = m_conf.getTxFrequency(); unsigned int rxFrequency = m_conf.getRxFrequency(); @@ -441,13 +443,24 @@ void CYSFGateway::createGPS() float longitude = m_conf.getLongitude(); int height = m_conf.getHeight(); - m_gps->setInfo(txFrequency, rxFrequency, latitude, longitude, height, desc); + m_writer->setInfo(txFrequency, rxFrequency, latitude, longitude, height, desc); - bool ret = m_gps->open(); + bool enabled = m_conf.getMobileGPSEnabled(); + if (enabled) { + std::string address = m_conf.getMobileGPSAddress(); + unsigned int port = m_conf.getMobileGPSPort(); + + m_writer->setMobileGPS(address, port); + } + + bool ret = m_writer->open(); if (!ret) { - delete m_gps; - m_gps = NULL; + delete m_writer; + m_writer = NULL; + return; } + + m_gps = new CGPS(m_writer); } void CYSFGateway::createWiresX(CYSFNetwork* rptNetwork) diff --git a/YSFGateway/YSFGateway.h b/YSFGateway/YSFGateway.h index 755142b..e25b3e6 100644 --- a/YSFGateway/YSFGateway.h +++ b/YSFGateway/YSFGateway.h @@ -22,6 +22,7 @@ #include "YSFNetwork.h" #include "YSFReflectors.h" #include "FCSNetwork.h" +#include "APRSWriter.h" #include "WiresX.h" #include "Timer.h" #include "Conf.h" @@ -48,6 +49,7 @@ private: std::string m_callsign; std::string m_suffix; CConf m_conf; + CAPRSWriter* m_writer; CGPS* m_gps; CYSFReflectors* m_reflectors; CWiresX* m_wiresX; diff --git a/YSFGateway/YSFGateway.ini b/YSFGateway/YSFGateway.ini index acb6a67..0cb1b20 100644 --- a/YSFGateway/YSFGateway.ini +++ b/YSFGateway/YSFGateway.ini @@ -60,3 +60,8 @@ YSF2P25Port=42015 Enable=1 Rooms=./FCSRooms.txt Port=42001 + +[Mobile GPS] +Enable=0 +Address=127.0.0.1 +Port=7834