diff --git a/Conf.cpp b/Conf.cpp index 719e406..5dbba42 100644 --- a/Conf.cpp +++ b/Conf.cpp @@ -57,7 +57,7 @@ enum SECTION { SECTION_OLED, SECTION_LCDPROC, SECTION_LOCK_FILE, - SECTION_MOBILE_GPS, + SECTION_GPSD, SECTION_REMOTE_CONTROL }; @@ -236,6 +236,7 @@ m_p25LocalPort(0U), m_p25NetworkModeHang(3U), m_p25NetworkDebug(false), m_nxdnNetworkEnabled(false), +m_nxdnNetworkProtocol("Icom"), m_nxdnGatewayAddress(), m_nxdnGatewayPort(0U), m_nxdnLocalAddress(), @@ -282,9 +283,9 @@ m_lcdprocUTC(false), m_lcdprocDimOnIdle(false), m_lockFileEnabled(false), m_lockFileName(), -m_mobileGPSEnabled(false), -m_mobileGPSAddress(), -m_mobileGPSPort(0U), +m_gpsdEnabled(false), +m_gpsdAddress(), +m_gpsdPort(), m_remoteControlEnabled(false), m_remoteControlAddress("127.0.0.1"), m_remoteControlPort(0U) @@ -367,8 +368,8 @@ bool CConf::read() section = SECTION_LCDPROC; else if (::strncmp(buffer, "[Lock File]", 11U) == 0) section = SECTION_LOCK_FILE; - else if (::strncmp(buffer, "[Mobile GPS]", 12U) == 0) - section = SECTION_MOBILE_GPS; + else if (::strncmp(buffer, "[GPSD]", 6U) == 0) + section = SECTION_GPSD; else if (::strncmp(buffer, "[Remote Control]", 16U) == 0) section = SECTION_REMOTE_CONTROL; else @@ -390,6 +391,17 @@ bool CConf::read() if (len > 1U && *value == '"' && value[len - 1U] == '"') { value[len - 1U] = '\0'; value++; + } else { + char *p; + + // if value is not quoted, remove after # (to make comment) + if ((p = strchr(value, '#')) != NULL) + *p = '\0'; + + // remove trailing tab/space + for (p = value + strlen(value) - 1; + p >= value && (*p == '\t' || *p == ' '); p--) + *p = '\0'; } if (section == SECTION_GENERAL) { @@ -843,6 +855,8 @@ bool CConf::read() } else if (section == SECTION_NXDN_NETWORK) { if (::strcmp(key, "Enable") == 0) m_nxdnNetworkEnabled = ::atoi(value) == 1; + else if (::strcmp(key, "Protocol") == 0) + m_nxdnNetworkProtocol = value; else if (::strcmp(key, "LocalAddress") == 0) m_nxdnLocalAddress = value; else if (::strcmp(key, "LocalPort") == 0) @@ -914,7 +928,7 @@ bool CConf::read() else if (::strcmp(key, "IdleBrightness") == 0) m_nextionIdleBrightness = (unsigned int)::atoi(value); else if (::strcmp(key, "ScreenLayout") == 0) - m_nextionScreenLayout = (unsigned int)::atoi(value); + m_nextionScreenLayout = (unsigned int)::strtoul(value, NULL, 0); else if (::strcmp(key, "DisplayTempInFahrenheit") == 0) m_nextionTempInFahrenheit = ::atoi(value) == 1; } else if (section == SECTION_OLED) { @@ -948,13 +962,13 @@ bool CConf::read() m_lockFileEnabled = ::atoi(value) == 1; else if (::strcmp(key, "File") == 0) m_lockFileName = value; - } else if (section == SECTION_MOBILE_GPS) { + } else if (section == SECTION_GPSD) { if (::strcmp(key, "Enable") == 0) - m_mobileGPSEnabled = ::atoi(value) == 1; + m_gpsdEnabled = ::atoi(value) == 1; else if (::strcmp(key, "Address") == 0) - m_mobileGPSAddress = value; + m_gpsdAddress = value; else if (::strcmp(key, "Port") == 0) - m_mobileGPSPort = (unsigned int)::atoi(value); + m_gpsdPort = value; } else if (section == SECTION_REMOTE_CONTROL) { if (::strcmp(key, "Enable") == 0) m_remoteControlEnabled = ::atoi(value) == 1; @@ -1835,6 +1849,11 @@ bool CConf::getNXDNNetworkEnabled() const return m_nxdnNetworkEnabled; } +std::string CConf::getNXDNNetworkProtocol() const +{ + return m_nxdnNetworkProtocol; +} + std::string CConf::getNXDNGatewayAddress() const { return m_nxdnGatewayAddress; @@ -2066,19 +2085,19 @@ std::string CConf::getLockFileName() const return m_lockFileName; } -bool CConf::getMobileGPSEnabled() const +bool CConf::getGPSDEnabled() const { - return m_mobileGPSEnabled; + return m_gpsdEnabled; } -std::string CConf::getMobileGPSAddress() const +std::string CConf::getGPSDAddress() const { - return m_mobileGPSAddress; + return m_gpsdAddress; } -unsigned int CConf::getMobileGPSPort() const +std::string CConf::getGPSDPort() const { - return m_mobileGPSPort; + return m_gpsdPort; } bool CConf::getRemoteControlEnabled() const diff --git a/Conf.h b/Conf.h index f1745bc..1165367 100644 --- a/Conf.h +++ b/Conf.h @@ -244,6 +244,7 @@ public: // The NXDN Network section bool getNXDNNetworkEnabled() const; + std::string getNXDNNetworkProtocol() const; std::string getNXDNGatewayAddress() const; unsigned int getNXDNGatewayPort() const; std::string getNXDNLocalAddress() const; @@ -305,10 +306,10 @@ public: bool getLockFileEnabled() const; std::string getLockFileName() const; - // The Mobile GPS section - bool getMobileGPSEnabled() const; - std::string getMobileGPSAddress() const; - unsigned int getMobileGPSPort() const; + // The GPSD section + bool getGPSDEnabled() const; + std::string getGPSDAddress() const; + std::string getGPSDPort() const; // The Remote Control section bool getRemoteControlEnabled() const; @@ -510,6 +511,7 @@ private: bool m_p25NetworkDebug; bool m_nxdnNetworkEnabled; + std::string m_nxdnNetworkProtocol; std::string m_nxdnGatewayAddress; unsigned int m_nxdnGatewayPort; std::string m_nxdnLocalAddress; @@ -564,9 +566,9 @@ private: bool m_lockFileEnabled; std::string m_lockFileName; - bool m_mobileGPSEnabled; - std::string m_mobileGPSAddress; - unsigned int m_mobileGPSPort; + bool m_gpsdEnabled; + std::string m_gpsdAddress; + std::string m_gpsdPort; bool m_remoteControlEnabled; std::string m_remoteControlAddress; diff --git a/DMRNetwork.cpp b/DMRNetwork.cpp index 91ae0a4..959bb65 100644 --- a/DMRNetwork.cpp +++ b/DMRNetwork.cpp @@ -67,7 +67,8 @@ m_height(0), m_location(), m_description(), m_url(), -m_beacon(false) +m_beacon(false), +m_random() { assert(!address.empty()); assert(port > 0U); @@ -86,11 +87,13 @@ m_beacon(false) m_id[2U] = id >> 8; m_id[3U] = id >> 0; - CStopWatch stopWatch; - ::srand(stopWatch.start()); + std::random_device rd; + std::mt19937 mt(rd()); + m_random = mt; - m_streamId[0U] = ::rand() + 1U; - m_streamId[1U] = ::rand() + 1U; + std::uniform_int_distribution dist(0x00000001, 0xfffffffe); + m_streamId[0U] = dist(m_random); + m_streamId[1U] = dist(m_random); } CDMRNetwork::~CDMRNetwork() @@ -247,6 +250,7 @@ bool CDMRNetwork::write(const CDMRData& data) unsigned int slotIndex = slotNo - 1U; + std::uniform_int_distribution dist(0x00000001, 0xfffffffe); unsigned char dataType = data.getDataType(); if (dataType == DT_VOICE_SYNC) { buffer[15U] |= 0x10U; @@ -254,10 +258,10 @@ bool CDMRNetwork::write(const CDMRData& data) buffer[15U] |= data.getN(); } else { if (dataType == DT_VOICE_LC_HEADER) - m_streamId[slotIndex] = ::rand() + 1U; + m_streamId[slotIndex] = dist(m_random); if (dataType == DT_CSBK || dataType == DT_DATA_HEADER) - m_streamId[slotIndex] = ::rand() + 1U; + m_streamId[slotIndex] = dist(m_random); buffer[15U] |= (0x20U | dataType); } diff --git a/DMRNetwork.h b/DMRNetwork.h index 96f1074..ee860d6 100644 --- a/DMRNetwork.h +++ b/DMRNetwork.h @@ -27,6 +27,7 @@ #include #include +#include class CDMRNetwork { @@ -107,6 +108,7 @@ private: std::string m_url; bool m_beacon; + std::mt19937 m_random; bool writeLogin(); bool writeAuthorisation(); diff --git a/DStarNetwork.cpp b/DStarNetwork.cpp index 072b7cf..551a1c5 100644 --- a/DStarNetwork.cpp +++ b/DStarNetwork.cpp @@ -44,14 +44,16 @@ m_inId(0U), m_buffer(1000U, "D-Star Network"), m_pollTimer(1000U, 60U), m_linkStatus(LS_NONE), -m_linkReflector(NULL) +m_linkReflector(NULL), +m_random() { CUDPSocket::lookup(gatewayAddress, gatewayPort, m_address, m_addrlen); m_linkReflector = new unsigned char[DSTAR_LONG_CALLSIGN_LENGTH]; - CStopWatch stopWatch; - ::srand(stopWatch.start()); + std::random_device rd; + std::mt19937 mt(rd()); + m_random = mt; } CDStarNetwork::~CDStarNetwork() @@ -85,7 +87,8 @@ bool CDStarNetwork::writeHeader(const unsigned char* header, unsigned int length buffer[4] = busy ? 0x22U : 0x20U; // Create a random id for this transmission - m_outId = (::rand() % 65535U) + 1U; + std::uniform_int_distribution dist(0x0001, 0xfffe); + m_outId = dist(m_random); buffer[5] = m_outId / 256U; // Unique session id buffer[6] = m_outId % 256U; diff --git a/DStarNetwork.h b/DStarNetwork.h index 6f96880..fc1fd68 100644 --- a/DStarNetwork.h +++ b/DStarNetwork.h @@ -26,6 +26,7 @@ #include #include +#include class CDStarNetwork { public: @@ -64,6 +65,7 @@ private: CTimer m_pollTimer; LINK_STATUS m_linkStatus; unsigned char* m_linkReflector; + std::mt19937 m_random; bool writePoll(const char* text); }; diff --git a/Display.cpp b/Display.cpp index 0b47b64..d0e6fd0 100644 --- a/Display.cpp +++ b/Display.cpp @@ -566,7 +566,7 @@ CDisplay* CDisplay::createDisplay(const CConf& conf, CUMP* ump, CModem* modem) } } else { SERIAL_SPEED baudrate = SERIAL_9600; - if (screenLayout==4U) + if (screenLayout&0x0cU) baudrate = SERIAL_115200; LogInfo(" Display baudrate: %u ",baudrate); diff --git a/GPSD.cpp b/GPSD.cpp new file mode 100644 index 0000000..c06321a --- /dev/null +++ b/GPSD.cpp @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2018,2020 by Jonathan Naylor G4KLX + * + * 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 "GPSD.h" + +#if defined(USE_GPSD) + +#include +#include +#include +#include + +CGPSD::CGPSD(const std::string& address, const std::string& port, CDMRNetwork* network) : +m_gpsdAddress(address), +m_gpsdPort(port), +m_network(network), +m_gpsdData(), +m_idTimer(1000U, 60U) +{ + assert(!address.empty()); + assert(!port.empty()); + assert(network != NULL); +} + +CGPSD::~CGPSD() +{ +} + +bool CGPSD::open() +{ + int ret = ::gps_open(m_gpsdAddress.c_str(), m_gpsdPort.c_str(), &m_gpsdData); + if (ret != 0) { + LogError("Error when opening access to gpsd - %d - %s", errno, ::gps_errstr(errno)); + return false; + } + + ::gps_stream(&m_gpsdData, WATCH_ENABLE | WATCH_JSON, NULL); + + LogMessage("Connected to GPSD"); + + m_idTimer.start(); + + return true; +} + +void CGPSD::clock(unsigned int ms) +{ + m_idTimer.clock(ms); + + if (m_idTimer.hasExpired()) { + sendReport(); + m_idTimer.start(); + } +} + +void CGPSD::close() +{ + ::gps_stream(&m_gpsdData, WATCH_DISABLE, NULL); + ::gps_close(&m_gpsdData); +} + +void CGPSD::sendReport() +{ + 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; +#endif + + if (m_gpsdData.status != STATUS_FIX) + return; + + bool latlonSet = (m_gpsdData.set & LATLON_SET) == LATLON_SET; + if (!latlonSet) + return; + + float latitude = float(m_gpsdData.fix.latitude); + float longitude = float(m_gpsdData.fix.longitude); + + m_network->writeHomePosition(latitude, longitude); +} + +#endif diff --git a/MobileGPS.h b/GPSD.h similarity index 59% rename from MobileGPS.h rename to GPSD.h index 8384c65..cef93b5 100644 --- a/MobileGPS.h +++ b/GPSD.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 by Jonathan Naylor G4KLX + * Copyright (C) 2018,2020 by Jonathan Naylor G4KLX * * 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 @@ -16,32 +16,22 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#ifndef MobileGPS_H -#define MobileGPS_H +#ifndef GPSD_H +#define GPSD_H + +#if defined(USE_GPSD) #include "DMRNetwork.h" -#include "UDPSocket.h" #include "Timer.h" #include -#if !defined(_WIN32) && !defined(_WIN64) -#include -#include -#include -#include -#include -#include -#include -#include -#else -#include -#endif +#include -class CMobileGPS { +class CGPSD { public: - CMobileGPS(const std::string& address, unsigned int port, CDMRNetwork* network); - ~CMobileGPS(); + CGPSD(const std::string& address, const std::string& port, CDMRNetwork* network); + ~CGPSD(); bool open(); @@ -50,14 +40,15 @@ public: void close(); private: - CTimer m_idTimer; - sockaddr_storage m_address; - unsigned int m_addrlen; - CUDPSocket m_socket; - CDMRNetwork* m_network; + std::string m_gpsdAddress; + std::string m_gpsdPort; + CDMRNetwork* m_network; + struct gps_data_t m_gpsdData; + CTimer m_idTimer; - bool pollGPS(); void sendReport(); }; #endif + +#endif diff --git a/MMDVM.ini b/MMDVM.ini index e205e69..fae9030 100644 --- a/MMDVM.ini +++ b/MMDVM.ini @@ -215,6 +215,7 @@ Debug=0 [NXDN Network] Enable=1 +Protocol=Icom LocalAddress=127.0.0.1 LocalPort=14021 GatewayAddress=127.0.0.1 @@ -287,10 +288,10 @@ UTC=0 Enable=0 File=/tmp/MMDVM_Active.lck -[Mobile GPS] +[GPSD] Enable=0 Address=127.0.0.1 -Port=7834 +Port=2947 [Remote Control] Enable=0 diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index ba93b6c..a12477d 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -17,6 +17,8 @@ */ #include "MMDVMHost.h" +#include "NXDNKenwoodNetwork.h" +#include "NXDNIcomNetwork.h" #include "RSSIInterpolator.h" #include "SerialController.h" #include "Version.h" @@ -159,7 +161,9 @@ m_id(0U), m_cwCallsign(), m_lockFileEnabled(false), m_lockFileName(), -m_mobileGPS(NULL), +#if defined(USE_GPSD) +m_gpsd(NULL), +#endif m_remoteControl(NULL), m_fixedMode(false) { @@ -1003,8 +1007,10 @@ int CMMDVMHost::run() if (m_pocsagNetwork != NULL) m_pocsagNetwork->clock(ms); - if (m_mobileGPS != NULL) - m_mobileGPS->clock(ms); +#if defined(USE_GPSD) + if (m_gpsd != NULL) + m_gpsd->clock(ms); +#endif m_cwIdTimer.clock(ms); if (m_cwIdTimer.isRunning() && m_cwIdTimer.hasExpired()) { @@ -1081,10 +1087,12 @@ int CMMDVMHost::run() m_display->close(); delete m_display; - if (m_mobileGPS != NULL) { - m_mobileGPS->close(); - delete m_mobileGPS; +#if defined(USE_GPSD) + if (m_gpsd != NULL) { + m_gpsd->close(); + delete m_gpsd; } +#endif if (m_ump != NULL) { m_ump->close(); @@ -1391,23 +1399,25 @@ bool CMMDVMHost::createDMRNetwork() return false; } - bool mobileGPSEnabled = m_conf.getMobileGPSEnabled(); - if (mobileGPSEnabled) { - std::string mobileGPSAddress = m_conf.getMobileGPSAddress(); - unsigned int mobileGPSPort = m_conf.getMobileGPSPort(); +#if defined(USE_GPSD) + bool gpsdEnabled = m_conf.getGPSDEnabled(); + if (gpsdEnabled) { + std::string gpsdAddress = m_conf.getGPSDAddress(); + std::string gpsdPort = m_conf.getGPSDPort(); - LogInfo("Mobile GPS Parameters"); - LogInfo(" Address: %s", mobileGPSAddress.c_str()); - LogInfo(" Port: %u", mobileGPSPort); + LogInfo("GPSD Parameters"); + LogInfo(" Address: %s", gpsdAddress.c_str()); + LogInfo(" Port: %s", gpsdPort.c_str()); - m_mobileGPS = new CMobileGPS(address, port, m_dmrNetwork); + m_gpsd = new CGPSD(gpsdAddress, gpsdPort, m_dmrNetwork); - ret = m_mobileGPS->open(); + ret = m_gpsd->open(); if (!ret) { - delete m_mobileGPS; - m_mobileGPS = NULL; + delete m_gpsd; + m_gpsd = NULL; } } +#endif m_dmrNetwork->enable(true); @@ -1474,6 +1484,7 @@ bool CMMDVMHost::createP25Network() bool CMMDVMHost::createNXDNNetwork() { + std::string protocol = m_conf.getNXDNNetworkProtocol(); std::string gatewayAddress = m_conf.getNXDNGatewayAddress(); unsigned int gatewayPort = m_conf.getNXDNGatewayPort(); std::string localAddress = m_conf.getNXDNLocalAddress(); @@ -1482,13 +1493,17 @@ bool CMMDVMHost::createNXDNNetwork() bool debug = m_conf.getNXDNNetworkDebug(); LogInfo("NXDN Network Parameters"); + LogInfo(" Protocol: %s", protocol.c_str()); LogInfo(" Gateway Address: %s", gatewayAddress.c_str()); LogInfo(" Gateway Port: %u", gatewayPort); LogInfo(" Local Address: %s", localAddress.c_str()); LogInfo(" Local Port: %u", localPort); LogInfo(" Mode Hang: %us", m_nxdnNetModeHang); - m_nxdnNetwork = new CNXDNNetwork(localAddress, localPort, gatewayAddress, gatewayPort, debug); + if (protocol == "Kenwood") + m_nxdnNetwork = new CNXDNKenwoodNetwork(localAddress, localPort, gatewayAddress, gatewayPort, debug); + else + m_nxdnNetwork = new CNXDNIcomNetwork(localAddress, localPort, gatewayAddress, gatewayPort, debug); bool ret = m_nxdnNetwork->open(); if (!ret) { @@ -1999,22 +2014,32 @@ void CMMDVMHost::remoteControl() case RCD_ENABLE_DSTAR: if (m_dstar != NULL && m_dstarEnabled==false) processEnableCommand(m_dstarEnabled, true); + if (m_dstarNetwork != NULL) + m_dstarNetwork->enable(true); break; case RCD_ENABLE_DMR: if (m_dmr != NULL && m_dmrEnabled==false) processEnableCommand(m_dmrEnabled, true); + if (m_dmrNetwork != NULL) + m_dmrNetwork->enable(true); break; case RCD_ENABLE_YSF: if (m_ysf != NULL && m_ysfEnabled==false) processEnableCommand(m_ysfEnabled, true); + if (m_ysfNetwork != NULL) + m_ysfNetwork->enable(true); break; case RCD_ENABLE_P25: if (m_p25 != NULL && m_p25Enabled==false) processEnableCommand(m_p25Enabled, true); + if (m_p25Network != NULL) + m_p25Network->enable(true); break; case RCD_ENABLE_NXDN: if (m_nxdn != NULL && m_nxdnEnabled==false) processEnableCommand(m_nxdnEnabled, true); + if (m_nxdnNetwork != NULL) + m_nxdnNetwork->enable(true); break; case RCD_ENABLE_FM: if (m_fmEnabled==false) @@ -2023,22 +2048,32 @@ void CMMDVMHost::remoteControl() case RCD_DISABLE_DSTAR: if (m_dstar != NULL && m_dstarEnabled==true) processEnableCommand(m_dstarEnabled, false); + if (m_dstarNetwork != NULL) + m_dstarNetwork->enable(false); break; case RCD_DISABLE_DMR: if (m_dmr != NULL && m_dmrEnabled==true) processEnableCommand(m_dmrEnabled, false); + if (m_dmrNetwork != NULL) + m_dmrNetwork->enable(false); break; case RCD_DISABLE_YSF: if (m_ysf != NULL && m_ysfEnabled==true) processEnableCommand(m_ysfEnabled, false); + if (m_ysfNetwork != NULL) + m_ysfNetwork->enable(false); break; case RCD_DISABLE_P25: if (m_p25 != NULL && m_p25Enabled==true) processEnableCommand(m_p25Enabled, false); + if (m_p25Network != NULL) + m_p25Network->enable(false); break; case RCD_DISABLE_NXDN: if (m_nxdn != NULL && m_nxdnEnabled==true) processEnableCommand(m_nxdnEnabled, false); + if (m_nxdnNetwork != NULL) + m_nxdnNetwork->enable(false); break; case RCD_DISABLE_FM: if (m_fmEnabled == true) diff --git a/MMDVMHost.h b/MMDVMHost.h index 17d6786..3d77653 100644 --- a/MMDVMHost.h +++ b/MMDVMHost.h @@ -34,11 +34,11 @@ #include "P25Network.h" #include "DMRNetwork.h" #include "DMRLookup.h" -#include "MobileGPS.h" #include "Display.h" #include "Timer.h" #include "Modem.h" #include "Conf.h" +#include "GPSD.h" #include "UMP.h" #include @@ -66,7 +66,7 @@ private: CDMRNetwork* m_dmrNetwork; CYSFNetwork* m_ysfNetwork; CP25Network* m_p25Network; - CNXDNNetwork* m_nxdnNetwork; + INXDNNetwork* m_nxdnNetwork; CPOCSAGNetwork* m_pocsagNetwork; CDisplay* m_display; CUMP* m_ump; @@ -102,7 +102,9 @@ private: std::string m_cwCallsign; bool m_lockFileEnabled; std::string m_lockFileName; - CMobileGPS* m_mobileGPS; +#if defined(USE_GPSD) + CGPSD* m_gpsd; +#endif CRemoteControl* m_remoteControl; bool m_fixedMode; diff --git a/MMDVMHost.vcxproj b/MMDVMHost.vcxproj index 812c7a4..b17f851 100644 --- a/MMDVMHost.vcxproj +++ b/MMDVMHost.vcxproj @@ -183,13 +183,13 @@ + - @@ -203,6 +203,8 @@ + + @@ -279,12 +281,12 @@ + - @@ -297,6 +299,8 @@ + + diff --git a/MMDVMHost.vcxproj.filters b/MMDVMHost.vcxproj.filters index fb8a362..7168194 100644 --- a/MMDVMHost.vcxproj.filters +++ b/MMDVMHost.vcxproj.filters @@ -278,9 +278,6 @@ Header Files - - Header Files - Header Files @@ -299,6 +296,15 @@ Header Files + + Header Files + + + Header Files + + + Header Files + @@ -541,9 +547,6 @@ Source Files - - Source Files - Source Files @@ -562,5 +565,14 @@ Source Files + + Source Files + + + Source Files + + + Source Files + \ No newline at end of file diff --git a/Makefile b/Makefile index efdaba6..1ad3c8a 100644 --- a/Makefile +++ b/Makefile @@ -2,18 +2,26 @@ CC = cc CXX = c++ + +# Use the following CFLAGS and LIBS if you don't want to use gpsd. CFLAGS = -g -O3 -Wall -std=c++0x -pthread LIBS = -lpthread + +# Use the following CFLAGS and LIBS if you do want to use gpsd. +#CFLAGS = -g -O3 -Wall -DUSE_GPSD -std=c++0x -pthread +#LIBS = -lpthread -lgps + LDFLAGS = -g OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o \ DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \ - DStarSlowData.o Golay2087.o Golay24128.o Hamming.o I2CController.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o ModemSerialPort.o Mutex.o \ - NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNLayer3.o NXDNLICH.o \ - NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o \ - POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o \ - TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o + DStarSlowData.o Golay2087.o Golay24128.o GPSD.o Hamming.o I2CController.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o \ + NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o \ + NXDNKenwoodNetwork.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o \ + P25Network.o P25NID.o P25Trellis.o P25Utils.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o \ + SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o \ + YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost RemoteCommand @@ -26,6 +34,10 @@ RemoteCommand: Log.o RemoteCommand.o UDPSocket.o %.o: %.cpp $(CXX) $(CFLAGS) -c -o $@ $< +install: + install -m 755 MMDVMHost /usr/local/bin/ + install -m 755 RemoteCommand /usr/local/bin/ + clean: $(RM) MMDVMHost RemoteCommand *.o *.d *.bak *~ GitVersion.h diff --git a/Makefile.Pi b/Makefile.Pi index 640c07f..53e457e 100644 --- a/Makefile.Pi +++ b/Makefile.Pi @@ -2,18 +2,25 @@ CC = gcc CXX = g++ +# Use the following CFLAGS and LIBS if you don't want to use gpsd. CFLAGS = -g -O3 -Wall -std=c++0x -pthread -DRASPBERRY_PI -I/usr/local/include LIBS = -lwiringPi -lwiringPiDev -lpthread + +# Use the following CFLAGS and LIBS if you do want to use gpsd. +#CFLAGS = -g -O3 -Wall -DUSE_GPSD -std=c++0x -pthread -DRASPBERRY_PI -I/usr/local/include +#LIBS = -lwiringPi -lwiringPiDev -lpthread -lgps + LDFLAGS = -g -L/usr/local/lib OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o \ DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \ - DStarSlowData.o Golay2087.o Golay24128.o Hamming.o I2CController.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o ModemSerialPort.o Mutex.o \ - NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o \ - NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o POCSAGControl.o \ - POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o \ - UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o + DStarSlowData.o Golay2087.o Golay24128.o GPSD.o Hamming.o I2CController.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o \ + NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o \ + NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o \ + P25Trellis.o P25Utils.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ + SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \ + YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost RemoteCommand @@ -26,6 +33,10 @@ RemoteCommand: Log.o RemoteCommand.o UDPSocket.o %.o: %.cpp $(CXX) $(CFLAGS) -c -o $@ $< +install: + install -m 755 MMDVMHost /usr/local/bin/ + install -m 755 RemoteCommand /usr/local/bin/ + clean: $(RM) MMDVMHost RemoteCommand *.o *.d *.bak *~ GitVersion.h diff --git a/Makefile.Pi.Adafruit b/Makefile.Pi.Adafruit index 24c2907..0a8fa85 100644 --- a/Makefile.Pi.Adafruit +++ b/Makefile.Pi.Adafruit @@ -3,18 +3,25 @@ CC = gcc CXX = g++ +# Use the following CFLAGS and LIBS if you don't want to use gpsd. CFLAGS = -g -O3 -Wall -std=c++0x -pthread -DHD44780 -DADAFRUIT_DISPLAY -I/usr/local/include LIBS = -lwiringPi -lwiringPiDev -lpthread + +# Use the following CFLAGS and LIBS if you do want to use gpsd. +#CFLAGS = -g -O3 -Wall -DUSE_GPSD -std=c++0x -pthread -DHD44780 -DADAFRUIT_DISPLAY -I/usr/local/include +#LIBS = -lwiringPi -lwiringPiDev -lpthread -lgps + LDFLAGS = -g -L/usr/local/lib OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o \ DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \ - DStarSlowData.o Golay2087.o Golay24128.o Hamming.o HD44780.o I2CController.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o ModemSerialPort.o Mutex.o \ - NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o \ - NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o POCSAGControl.o \ - POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o \ - Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o + DStarSlowData.o Golay2087.o Golay24128.o GPSD.o Hamming.o HD44780.o I2CController.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o \ + NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o \ + NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o \ + P25Trellis.o P25Utils.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ + SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \ + YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost RemoteCommand @@ -27,6 +34,10 @@ RemoteCommand: Log.o RemoteCommand.o UDPSocket.o %.o: %.cpp $(CXX) $(CFLAGS) -c -o $@ $< +install: + install -m 755 MMDVMHost /usr/local/bin/ + install -m 755 RemoteCommand /usr/local/bin/ + clean: $(RM) MMDVMHost RemoteCommand *.o *.d *.bak *~ GitVersion.h diff --git a/Makefile.Pi.HD44780 b/Makefile.Pi.HD44780 index c2faad2..5417946 100644 --- a/Makefile.Pi.HD44780 +++ b/Makefile.Pi.HD44780 @@ -2,18 +2,26 @@ CC = gcc CXX = g++ + +# Use the following CFLAGS and LIBS if you don't want to use gpsd. CFLAGS = -g -O3 -Wall -std=c++0x -pthread -DHD44780 -I/usr/local/include LIBS = -lwiringPi -lwiringPiDev -lpthread + +# Use the following CFLAGS and LIBS if you do want to use gpsd. +#CFLAGS = -g -O3 -Wall -DUSE_GPSD -std=c++0x -pthread -DHD44780 -I/usr/local/include +#LIBS = -lwiringPi -lwiringPiDev -lpthread -lgps + LDFLAGS = -g -L/usr/local/lib OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o \ DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \ - DStarSlowData.o Golay2087.o Golay24128.o Hamming.o HD44780.o I2CController.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o ModemSerialPort.o Mutex.o \ - NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o \ - NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o POCSAGControl.o \ - POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o \ - Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o + DStarSlowData.o Golay2087.o Golay24128.o GPSD.o Hamming.o HD44780.o I2CController.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o \ + NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o \ + NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o \ + P25Trellis.o P25Utils.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ + SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \ + YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost RemoteCommand @@ -26,6 +34,10 @@ RemoteCommand: Log.o RemoteCommand.o UDPSocket.o %.o: %.cpp $(CXX) $(CFLAGS) -c -o $@ $< +install: + install -m 755 MMDVMHost /usr/local/bin/ + install -m 755 RemoteCommand /usr/local/bin/ + clean: $(RM) MMDVMHost RemoteCommand *.o *.d *.bak *~ GitVersion.h diff --git a/Makefile.Pi.OLED b/Makefile.Pi.OLED index d2db40c..9949cf2 100644 --- a/Makefile.Pi.OLED +++ b/Makefile.Pi.OLED @@ -2,18 +2,26 @@ CC = gcc CXX = g++ + +# Use the following CFLAGS and LIBS if you don't want to use gpsd. CFLAGS = -g -O3 -Wall -std=c++0x -pthread -DOLED -I/usr/local/include LIBS = -lArduiPi_OLED -lwiringPi -lpthread + +# Use the following CFLAGS and LIBS if you do want to use gpsd. +#CFLAGS = -g -O3 -Wall -DUSE_GPSD -std=c++0x -pthread -DOLED -I/usr/local/include +#LIBS = -lArduiPi_OLED -lwiringPi -lpthread -lgps + LDFLAGS = -g -L/usr/local/lib OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o \ DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \ - DStarSlowData.o Golay2087.o Golay24128.o Hamming.o I2CController.o OLED.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o ModemSerialPort.o Mutex.o \ - NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o \ - NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o POCSAGControl.o \ - POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o \ - Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o + DStarSlowData.o Golay2087.o Golay24128.o GPSD.o Hamming.o I2CController.o OLED.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o \ + NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o \ + NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o \ + P25Trellis.o P25Utils.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ + SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \ + YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost RemoteCommand @@ -26,6 +34,10 @@ RemoteCommand: Log.o RemoteCommand.o UDPSocket.o %.o: %.cpp $(CXX) $(CFLAGS) -c -o $@ $< +install: + install -m 755 MMDVMHost /usr/local/bin/ + install -m 755 RemoteCommand /usr/local/bin/ + clean: $(RM) MMDVMHost RemoteCommand *.o *.d *.bak *~ GitVersion.h diff --git a/Makefile.Pi.PCF8574 b/Makefile.Pi.PCF8574 index 4c5d3a3..aa84cc8 100644 --- a/Makefile.Pi.PCF8574 +++ b/Makefile.Pi.PCF8574 @@ -3,18 +3,26 @@ CC = gcc CXX = g++ + +# Use the following CFLAGS and LIBS if you don't want to use gpsd. CFLAGS = -g -O3 -Wall -std=c++0x -pthread -DHD44780 -DPCF8574_DISPLAY -I/usr/local/include LIBS = -lwiringPi -lwiringPiDev -lpthread + +# Use the following CFLAGS and LIBS if you do want to use gpsd. +#CFLAGS = -g -O3 -Wall -DUSE_GPSD -std=c++0x -pthread -DHD44780 -DPCF8574_DISPLAY -I/usr/local/include +#LIBS = -lwiringPi -lwiringPiDev -lpthread -lgps + LDFLAGS = -g -L/usr/local/lib OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o \ DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \ - DStarSlowData.o Golay2087.o Golay24128.o Hamming.o HD44780.o I2CController.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o ModemSerialPort.o Mutex.o \ - NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o \ - NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o POCSAGControl.o \ - POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o \ - Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o + DStarSlowData.o Golay2087.o Golay24128.o GPSD.o Hamming.o HD44780.o I2CController.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o \ + NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o \ + NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o \ + P25Trellis.o P25Utils.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ + SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \ + YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost RemoteCommand @@ -27,6 +35,10 @@ RemoteCommand: Log.o RemoteCommand.o UDPSocket.o %.o: %.cpp $(CXX) $(CFLAGS) -c -o $@ $< +install: + install -m 755 MMDVMHost /usr/local/bin/ + install -m 755 RemoteCommand /usr/local/bin/ + clean: $(RM) MMDVMHost RemoteCommand *.o *.d *.bak *~ GitVersion.h diff --git a/Makefile.Solaris b/Makefile.Solaris deleted file mode 100644 index c50d41e..0000000 --- a/Makefile.Solaris +++ /dev/null @@ -1,38 +0,0 @@ -# This makefile is for Solaris using gcc - -CC = gcc -CXX = g++ -CFLAGS = -g -O3 -Wall -std=c++0x -pthread -LIBS = -lpthread -lsocket -LDFLAGS = -g - -OBJECTS = \ - AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o \ - DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \ - DStarSlowData.o Golay2087.o Golay24128.o Hamming.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o \ - NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o \ - NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o POCSAGControl.o POCSAGNetwork.o \ - QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o \ - UMP.o UserDB.o UserDBebtry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o - -all: MMDVMHost RemoteCommand - -MMDVMHost: GitVersion.h $(OBJECTS) - $(CXX) $(OBJECTS) $(CFLAGS) $(LIBS) -o MMDVMHost - -RemoteCommand: Log.o RemoteCommand.o UDPSocket.o - $(CXX) Log.o RemoteCommand.o UDPSocket.o $(CFLAGS) $(LIBS) -o RemoteCommand - -%.o: %.cpp - $(CXX) $(CFLAGS) -c -o $@ $< - -clean: - $(RM) MMDVMHost RemoteCommand *.o *.d *.bak *~ GitVersion.h - -# Export the current git version if the index file exists, else 000... -GitVersion.h: -ifneq ("$(wildcard .git/index)","") - echo "const char *gitversion = \"$(shell git rev-parse HEAD)\";" > $@ -else - echo "const char *gitversion = \"0000000000000000000000000000000000000000\";" > $@ -endif diff --git a/MobileGPS.cpp b/MobileGPS.cpp deleted file mode 100644 index 0cb2c3b..0000000 --- a/MobileGPS.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (C) 2018 by Jonathan Naylor G4KLX - * - * 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 "MobileGPS.h" - -#include -#include -#include -#include - -CMobileGPS::CMobileGPS(const std::string& address, unsigned int port, CDMRNetwork* network) : -m_idTimer(1000U, 60U), -m_address(), -m_addrlen(), -m_socket(), -m_network(network) -{ - assert(!address.empty()); - assert(port > 0U); - assert(network != NULL); - - CUDPSocket::lookup(address, port, m_address, m_addrlen); -} - -CMobileGPS::~CMobileGPS() -{ -} - -bool CMobileGPS::open() -{ - bool ret = m_socket.open(m_address.ss_family); - if (!ret) - return false; - - m_idTimer.start(); - - return true; -} - -void CMobileGPS::clock(unsigned int ms) -{ - m_idTimer.clock(ms); - - if (m_idTimer.hasExpired()) { - pollGPS(); - m_idTimer.start(); - } - - sendReport(); -} - -void CMobileGPS::close() -{ - m_socket.close(); -} - -bool CMobileGPS::pollGPS() -{ - return m_socket.write((unsigned char*)"MMDVMHost", 9U, m_address, m_addrlen); -} - -void CMobileGPS::sendReport() -{ - // Grab GPS data if it's available - unsigned char buffer[200U]; - sockaddr_storage address; - unsigned int addrlen; - int ret = m_socket.read(buffer, 200U, address, addrlen); - if (ret <= 0) - return; - - buffer[ret] = '\0'; - - // Parse the GPS data - char* pLatitude = ::strtok((char*)buffer, ",\n"); // Latitude - char* pLongitude = ::strtok(NULL, ",\n"); // Longitude - - if (pLatitude == NULL || pLongitude == NULL) - return; - - float latitude = float(::atof(pLatitude)); - float longitude = float(::atof(pLongitude)); - - m_network->writeHomePosition(latitude, longitude); -} - diff --git a/NXDNControl.cpp b/NXDNControl.cpp index 1f3fa4c..1e200c4 100644 --- a/NXDNControl.cpp +++ b/NXDNControl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2019 Jonathan Naylor, G4KLX + * Copyright (C) 2015-2020 Jonathan Naylor, G4KLX * * 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 @@ -39,7 +39,7 @@ const unsigned char BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04 #define WRITE_BIT1(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i)&7]) #define READ_BIT1(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7]) -CNXDNControl::CNXDNControl(unsigned int ran, unsigned int id, bool selfOnly, CNXDNNetwork* network, CDisplay* display, unsigned int timeout, bool duplex, bool remoteGateway, CNXDNLookup* lookup, CRSSIInterpolator* rssiMapper) : +CNXDNControl::CNXDNControl(unsigned int ran, unsigned int id, bool selfOnly, INXDNNetwork* network, CDisplay* display, unsigned int timeout, bool duplex, bool remoteGateway, CNXDNLookup* lookup, CRSSIInterpolator* rssiMapper) : m_ran(ran), m_id(id), m_selfOnly(selfOnly), diff --git a/NXDNControl.h b/NXDNControl.h index 5c441e2..af2fba1 100644 --- a/NXDNControl.h +++ b/NXDNControl.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2019 by Jonathan Naylor G4KLX + * Copyright (C) 2015-2020 by Jonathan Naylor G4KLX * * 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 @@ -36,7 +36,7 @@ class CNXDNControl { public: - CNXDNControl(unsigned int ran, unsigned int id, bool selfOnly, CNXDNNetwork* network, CDisplay* display, unsigned int timeout, bool duplex, bool remoteGateway, CNXDNLookup* lookup, CRSSIInterpolator* rssiMapper); + CNXDNControl(unsigned int ran, unsigned int id, bool selfOnly, INXDNNetwork* network, CDisplay* display, unsigned int timeout, bool duplex, bool remoteGateway, CNXDNLookup* lookup, CRSSIInterpolator* rssiMapper); ~CNXDNControl(); bool writeModem(unsigned char* data, unsigned int len); @@ -53,7 +53,7 @@ private: unsigned int m_ran; unsigned int m_id; bool m_selfOnly; - CNXDNNetwork* m_network; + INXDNNetwork* m_network; CDisplay* m_display; bool m_duplex; bool m_remoteGateway; diff --git a/NXDNIcomNetwork.cpp b/NXDNIcomNetwork.cpp new file mode 100644 index 0000000..3b340cc --- /dev/null +++ b/NXDNIcomNetwork.cpp @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2009-2014,2016,2018-2020 by Jonathan Naylor G4KLX + * + * 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 "NXDNIcomNetwork.h" +#include "NXDNDefines.h" +#include "Defines.h" +#include "Utils.h" +#include "Log.h" + +#include +#include +#include + +const unsigned int BUFFER_LENGTH = 200U; + +CNXDNIcomNetwork::CNXDNIcomNetwork(const std::string& localAddress, unsigned int localPort, const std::string& gatewayAddress, unsigned int gatewayPort, bool debug) : +m_socket(localAddress, localPort), +m_address(), +m_addrlen(), +m_debug(debug), +m_enabled(false), +m_buffer(1000U, "NXDN Network") +{ + assert(gatewayPort > 0U); + assert(!gatewayAddress.empty()); + + CUDPSocket::lookup(gatewayAddress, gatewayPort, m_address, m_addrlen); +} + +CNXDNIcomNetwork::~CNXDNIcomNetwork() +{ +} + +bool CNXDNIcomNetwork::open() +{ + LogMessage("Opening NXDN network connection"); + + if (CUDPSocket::isnone(m_address)) + return false; + + return m_socket.open(); +} + +bool CNXDNIcomNetwork::write(const unsigned char* data, NXDN_NETWORK_MESSAGE_TYPE type) +{ + assert(data != NULL); + + unsigned char buffer[110U]; + ::memset(buffer, 0x00U, 110U); + + buffer[0U] = 'I'; + buffer[1U] = 'C'; + buffer[2U] = 'O'; + buffer[3U] = 'M'; + buffer[4U] = 0x01U; + buffer[5U] = 0x01U; + buffer[6U] = 0x08U; + buffer[7U] = 0xE0U; + + switch (type) { + case NNMT_VOICE_HEADER: + case NNMT_VOICE_TRAILER: + buffer[37U] = 0x23U; + buffer[38U] = 0x1CU; + buffer[39U] = 0x21U; + break; + case NNMT_VOICE_BODY: + buffer[37U] = 0x23U; + buffer[38U] = 0x10U; + buffer[39U] = 0x21U; + break; + case NNMT_DATA_HEADER: + case NNMT_DATA_BODY: + case NNMT_DATA_TRAILER: + buffer[37U] = 0x23U; + buffer[38U] = 0x02U; + buffer[39U] = 0x18U; + break; + default: + return false; + } + + ::memcpy(buffer + 40U, data, 33U); + + if (m_debug) + CUtils::dump(1U, "NXDN Network Data Sent", buffer, 102U); + + return m_socket.write(buffer, 102U, m_address, m_addrlen); +} + +void CNXDNIcomNetwork::clock(unsigned int ms) +{ + unsigned char buffer[BUFFER_LENGTH]; + + sockaddr_storage address; + unsigned int addrlen; + int length = m_socket.read(buffer, BUFFER_LENGTH, address, addrlen); + if (length <= 0 || !CUDPSocket::match(m_address, address)) + return; + + // Invalid packet type? + if (::memcmp(buffer, "ICOM", 4U) != 0) + return; + + if (length != 102) + return; + + if (!m_enabled) + return; + + if (m_debug) + CUtils::dump(1U, "NXDN Network Data Received", buffer, length); + + m_buffer.addData(buffer + 40U, 33U); +} + +bool CNXDNIcomNetwork::read(unsigned char* data) +{ + assert(data != NULL); + + if (m_buffer.isEmpty()) + return false; + + m_buffer.getData(data, 33U); + + return true; +} + +void CNXDNIcomNetwork::reset() +{ +} + +void CNXDNIcomNetwork::close() +{ + m_socket.close(); + + LogMessage("Closing NXDN network connection"); +} + +void CNXDNIcomNetwork::enable(bool enabled) +{ + if (enabled && !m_enabled) + reset(); + else if (!enabled && m_enabled) + m_buffer.clear(); + + m_enabled = enabled; +} diff --git a/NXDNIcomNetwork.h b/NXDNIcomNetwork.h new file mode 100644 index 0000000..18bdd97 --- /dev/null +++ b/NXDNIcomNetwork.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2009-2014,2016,2018,2020 by Jonathan Naylor G4KLX + * + * 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. + */ + +#ifndef NXDNIcomNetwork_H +#define NXDNIcomNetwork_H + +#include "NXDNNetwork.h" +#include "NXDNDefines.h" +#include "RingBuffer.h" +#include "UDPSocket.h" +#include "Timer.h" + +#include +#include + +class CNXDNIcomNetwork : public INXDNNetwork { +public: + CNXDNIcomNetwork(const std::string& localAddress, unsigned int localPort, const std::string& gatewayAddress, unsigned int gatewayPort, bool debug); + virtual ~CNXDNIcomNetwork(); + + virtual bool open(); + + virtual void enable(bool enabled); + + virtual bool write(const unsigned char* data, NXDN_NETWORK_MESSAGE_TYPE type); + + virtual bool read(unsigned char* data); + + virtual void reset(); + + virtual void close(); + + virtual void clock(unsigned int ms); + +private: + CUDPSocket m_socket; + sockaddr_storage m_address; + unsigned int m_addrlen; + bool m_debug; + bool m_enabled; + CRingBuffer m_buffer; +}; + +#endif diff --git a/NXDNKenwoodNetwork.cpp b/NXDNKenwoodNetwork.cpp new file mode 100644 index 0000000..f84af6e --- /dev/null +++ b/NXDNKenwoodNetwork.cpp @@ -0,0 +1,1167 @@ +/* + * Copyright (C) 2009-2014,2016,2018,2020 by Jonathan Naylor G4KLX + * + * 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 "NXDNKenwoodNetwork.h" +#include "NXDNCRC.h" +#include "Utils.h" +#include "Log.h" + +#include +#include +#include +#include + +const unsigned char BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U }; + +#define WRITE_BIT(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i)&7]) +#define READ_BIT(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7]) + +const unsigned int BUFFER_LENGTH = 200U; + +CNXDNKenwoodNetwork::CNXDNKenwoodNetwork(const std::string& localAddress, unsigned int localPort, const std::string& gwyAddress, unsigned int gwyPort, bool debug) : +m_rtpSocket(localAddress, localPort + 0U), +m_rtcpSocket(localAddress, localPort + 1U), +m_rtcpaddress(), +m_rtpaddress(), +m_addrlen(), +m_enabled(false), +m_headerSeen(false), +m_seen1(false), +m_seen2(false), +m_seen3(false), +m_seen4(false), +m_sacch(NULL), +m_sessionId(1U), +m_seqNo(0U), +m_ssrc(0U), +m_debug(debug), +m_startSecs(0U), +m_startUSecs(0U), +m_rtcpTimer(1000U, 0U, 200U), +m_hangTimer(1000U, 5U), +m_hangType(0U), +m_hangSrc(0U), +m_hangDst(0U), +m_random() +{ + assert(localPort > 0U); + assert(!gwyAddress.empty()); + assert(gwyPort > 0U); + + m_sacch = new unsigned char[10U]; + + CUDPSocket::lookup(gwyAddress, gwyPort + 1, m_rtcpaddress, m_addrlen); + CUDPSocket::lookup(gwyAddress, gwyPort, m_rtpaddress, m_addrlen); + + std::random_device rd; + std::mt19937 mt(rd()); + m_random = mt; +} + +CNXDNKenwoodNetwork::~CNXDNKenwoodNetwork() +{ + delete[] m_sacch; +} + +bool CNXDNKenwoodNetwork::open() +{ + LogMessage("Opening Kenwood connection"); + + if (CUDPSocket::isnone(m_rtpaddress) || + CUDPSocket::isnone(m_rtcpaddress)) + return false; + + if (!m_rtcpSocket.open()) + return false; + + if (!m_rtpSocket.open()) { + m_rtcpSocket.close(); + return false; + } + + std::uniform_int_distribution dist(0x00000001, 0xfffffffe); + m_ssrc = dist(m_random); + + return true; +} + +bool CNXDNKenwoodNetwork::write(const unsigned char* data, NXDN_NETWORK_MESSAGE_TYPE type) +{ + assert(data != NULL); + + switch (type) { + case NNMT_VOICE_HEADER: // Voice header or trailer + case NNMT_VOICE_TRAILER: + return processIcomVoiceHeader(data); + case NNMT_VOICE_BODY: // Voice data + return processIcomVoiceData(data); + case NNMT_DATA_HEADER: // Data header or trailer + case NNMT_DATA_TRAILER: + return processIcomDataHeader(data); + case NNMT_DATA_BODY: // Data data + return processIcomDataData(data); + default: + return false; + } +} + +bool CNXDNKenwoodNetwork::processIcomVoiceHeader(const unsigned char* inData) +{ + assert(inData != NULL); + + unsigned char outData[30U]; + ::memset(outData, 0x00U, 30U); + + // SACCH + outData[0U] = inData[2U]; + outData[1U] = inData[1U]; + outData[2U] = inData[4U] & 0xC0U; + outData[3U] = inData[3U]; + + // FACCH 1+2 + outData[4U] = outData[14U] = inData[6U]; + outData[5U] = outData[15U] = inData[5U]; + outData[6U] = outData[16U] = inData[8U]; + outData[7U] = outData[17U] = inData[7U]; + outData[8U] = outData[18U] = inData[10U]; + outData[9U] = outData[19U] = inData[9U]; + outData[10U] = outData[20U] = inData[12U]; + outData[11U] = outData[21U] = inData[11U]; + + unsigned short src = (inData[8U] << 8) + (inData[9U] << 0); + unsigned short dst = (inData[10U] << 8) + (inData[11U] << 0); + unsigned char type = (inData[7U] >> 5) & 0x07U; + + switch (inData[5U] & 0x3FU) { + case 0x01U: + m_hangTimer.stop(); + m_rtcpTimer.start(); + writeRTCPStart(); + return writeRTPVoiceHeader(outData); + case 0x08U: { + m_hangTimer.start(); + bool ret = writeRTPVoiceTrailer(outData); + writeRTCPHang(type, src, dst); + return ret; + } + default: + return false; + } +} + +bool CNXDNKenwoodNetwork::processIcomVoiceData(const unsigned char* inData) +{ + assert(inData != NULL); + + unsigned char outData[40U], temp[10U]; + ::memset(outData, 0x00U, 40U); + + // SACCH + outData[0U] = inData[2U]; + outData[1U] = inData[1U]; + outData[2U] = inData[4U] & 0xC0U; + outData[3U] = inData[3U]; + + // Audio 1 + ::memset(temp, 0x00U, 10U); + for (unsigned int i = 0U; i < 49U; i++) { + unsigned int offset = (5U * 8U) + i; + bool b = READ_BIT(inData, offset); + WRITE_BIT(temp, i, b); + } + outData[4U] = temp[1U]; + outData[5U] = temp[0U]; + outData[6U] = temp[3U]; + outData[7U] = temp[2U]; + outData[8U] = temp[5U]; + outData[9U] = temp[4U]; + outData[10U] = temp[7U]; + outData[11U] = temp[6U]; + + // Audio 2 + ::memset(temp, 0x00U, 10U); + for (unsigned int i = 0U; i < 49U; i++) { + unsigned int offset = (5U * 8U) + 49U + i; + bool b = READ_BIT(inData, offset); + WRITE_BIT(temp, i, b); + } + outData[12U] = temp[1U]; + outData[13U] = temp[0U]; + outData[14U] = temp[3U]; + outData[15U] = temp[2U]; + outData[16U] = temp[5U]; + outData[17U] = temp[4U]; + outData[18U] = temp[7U]; + outData[19U] = temp[6U]; + + // Audio 3 + ::memset(temp, 0x00U, 10U); + for (unsigned int i = 0U; i < 49U; i++) { + unsigned int offset = (19U * 8U) + i; + bool b = READ_BIT(inData, offset); + WRITE_BIT(temp, i, b); + } + outData[20U] = temp[1U]; + outData[21U] = temp[0U]; + outData[22U] = temp[3U]; + outData[23U] = temp[2U]; + outData[24U] = temp[5U]; + outData[25U] = temp[4U]; + outData[26U] = temp[7U]; + outData[27U] = temp[6U]; + + // Audio 4 + ::memset(temp, 0x00U, 10U); + for (unsigned int i = 0U; i < 49U; i++) { + unsigned int offset = (19U * 8U) + 49U + i; + bool b = READ_BIT(inData, offset); + WRITE_BIT(temp, i, b); + } + outData[28U] = temp[1U]; + outData[29U] = temp[0U]; + outData[30U] = temp[3U]; + outData[31U] = temp[2U]; + outData[32U] = temp[5U]; + outData[33U] = temp[4U]; + outData[34U] = temp[7U]; + outData[35U] = temp[6U]; + + return writeRTPVoiceData(outData); +} + +bool CNXDNKenwoodNetwork::processIcomDataHeader(const unsigned char* inData) +{ + assert(inData != NULL); + + unsigned char outData[30U]; + ::memset(outData, 0x00U, 30U); + + // SACCH + outData[0U] = inData[2U]; + outData[1U] = inData[1U]; + outData[2U] = inData[4U] & 0xC0U; + outData[3U] = inData[3U]; + + // FACCH 1+2 + outData[4U] = outData[14U] = inData[6U]; + outData[5U] = outData[15U] = inData[5U]; + outData[6U] = outData[16U] = inData[8U]; + outData[7U] = outData[17U] = inData[7U]; + outData[8U] = outData[18U] = inData[10U]; + outData[9U] = outData[19U] = inData[9U]; + outData[10U] = outData[20U] = inData[12U]; + outData[11U] = outData[21U] = inData[11U]; + + unsigned short src = (inData[8U] << 8) + (inData[9U] << 0); + unsigned short dst = (inData[10U] << 8) + (inData[11U] << 0); + unsigned char type = (inData[7U] >> 5) & 0x07U; + + switch (inData[5U] & 0x3FU) { + case 0x09U: + m_hangTimer.stop(); + m_rtcpTimer.start(); + writeRTCPStart(); + return writeRTPDataHeader(outData); + case 0x08U: { + m_hangTimer.start(); + bool ret = writeRTPDataTrailer(outData); + writeRTCPHang(type, src, dst); + return ret; + } + default: + return false; + } +} + +bool CNXDNKenwoodNetwork::processIcomDataData(const unsigned char* inData) +{ + assert(inData != NULL); + + unsigned char outData[40U]; + ::memset(outData, 0x00U, 40U); + + outData[0U] = inData[2U]; + outData[1U] = inData[1U]; + outData[2U] = inData[4U]; + outData[3U] = inData[3U]; + outData[4U] = inData[6U]; + outData[5U] = inData[5U]; + outData[6U] = inData[8U]; + outData[7U] = inData[7U]; + outData[8U] = inData[10U]; + outData[9U] = inData[9U]; + outData[10U] = inData[12U]; + outData[11U] = inData[11U]; + outData[12U] = inData[14U]; + outData[13U] = inData[13U]; + outData[14U] = inData[16U]; + outData[15U] = inData[15U]; + outData[16U] = inData[18U]; + outData[17U] = inData[17U]; + outData[18U] = inData[20U]; + outData[19U] = inData[19U]; + outData[20U] = inData[22U]; + outData[21U] = inData[21U]; + + return writeRTPDataData(outData); +} + +bool CNXDNKenwoodNetwork::writeRTPVoiceHeader(const unsigned char* data) +{ + assert(data != NULL); + + unsigned char buffer[50U]; + ::memset(buffer, 0x00U, 50U); + + buffer[0U] = 0x80U; + buffer[1U] = 0x66U; + + m_seqNo++; + buffer[2U] = (m_seqNo >> 8) & 0xFFU; + buffer[3U] = (m_seqNo >> 0) & 0xFFU; + + unsigned long timeStamp = getTimeStamp(); + buffer[4U] = (timeStamp >> 24) & 0xFFU; + buffer[5U] = (timeStamp >> 16) & 0xFFU; + buffer[6U] = (timeStamp >> 8) & 0xFFU; + buffer[7U] = (timeStamp >> 0) & 0xFFU; + + buffer[8U] = (m_ssrc >> 24) & 0xFFU; + buffer[9U] = (m_ssrc >> 16) & 0xFFU; + buffer[10U] = (m_ssrc >> 8) & 0xFFU; + buffer[11U] = (m_ssrc >> 0) & 0xFFU; + + m_sessionId++; + buffer[12U] = m_sessionId; + + buffer[13U] = 0x00U; + buffer[14U] = 0x00U; + buffer[15U] = 0x00U; + buffer[16U] = 0x03U; + buffer[17U] = 0x03U; + buffer[18U] = 0x04U; + buffer[19U] = 0x04U; + buffer[20U] = 0x0AU; + buffer[21U] = 0x05U; + buffer[22U] = 0x0AU; + + ::memcpy(buffer + 23U, data, 24U); + + if (m_debug) + CUtils::dump(1U, "Kenwood Network RTP Data Sent", buffer, 47U); + + return m_rtpSocket.write(buffer, 47U, m_rtpaddress, m_addrlen); +} + +bool CNXDNKenwoodNetwork::writeRTPVoiceTrailer(const unsigned char* data) +{ + assert(data != NULL); + + unsigned char buffer[50U]; + ::memset(buffer, 0x00U, 50U); + + buffer[0U] = 0x80U; + buffer[1U] = 0x66U; + + m_seqNo++; + buffer[2U] = (m_seqNo >> 8) & 0xFFU; + buffer[3U] = (m_seqNo >> 0) & 0xFFU; + + unsigned long timeStamp = getTimeStamp(); + buffer[4U] = (timeStamp >> 24) & 0xFFU; + buffer[5U] = (timeStamp >> 16) & 0xFFU; + buffer[6U] = (timeStamp >> 8) & 0xFFU; + buffer[7U] = (timeStamp >> 0) & 0xFFU; + + buffer[8U] = (m_ssrc >> 24) & 0xFFU; + buffer[9U] = (m_ssrc >> 16) & 0xFFU; + buffer[10U] = (m_ssrc >> 8) & 0xFFU; + buffer[11U] = (m_ssrc >> 0) & 0xFFU; + + buffer[12U] = m_sessionId; + + buffer[13U] = 0x00U; + buffer[14U] = 0x00U; + buffer[15U] = 0x00U; + buffer[16U] = 0x03U; + buffer[17U] = 0x03U; + buffer[18U] = 0x04U; + buffer[19U] = 0x04U; + buffer[20U] = 0x0AU; + buffer[21U] = 0x05U; + buffer[22U] = 0x0AU; + + ::memcpy(buffer + 23U, data, 24U); + + if (m_debug) + CUtils::dump(1U, "Kenwood Network RTP Data Sent", buffer, 47U); + + return m_rtpSocket.write(buffer, 47U, m_rtpaddress, m_addrlen); +} + +bool CNXDNKenwoodNetwork::writeRTPVoiceData(const unsigned char* data) +{ + assert(data != NULL); + + unsigned char buffer[60U]; + ::memset(buffer, 0x00U, 60U); + + buffer[0U] = 0x80U; + buffer[1U] = 0x66U; + + m_seqNo++; + buffer[2U] = (m_seqNo >> 8) & 0xFFU; + buffer[3U] = (m_seqNo >> 0) & 0xFFU; + + unsigned long timeStamp = getTimeStamp(); + buffer[4U] = (timeStamp >> 24) & 0xFFU; + buffer[5U] = (timeStamp >> 16) & 0xFFU; + buffer[6U] = (timeStamp >> 8) & 0xFFU; + buffer[7U] = (timeStamp >> 0) & 0xFFU; + + buffer[8U] = (m_ssrc >> 24) & 0xFFU; + buffer[9U] = (m_ssrc >> 16) & 0xFFU; + buffer[10U] = (m_ssrc >> 8) & 0xFFU; + buffer[11U] = (m_ssrc >> 0) & 0xFFU; + + buffer[12U] = m_sessionId; + + buffer[13U] = 0x00U; + buffer[14U] = 0x00U; + buffer[15U] = 0x00U; + buffer[16U] = 0x03U; + buffer[17U] = 0x02U; + buffer[18U] = 0x04U; + buffer[19U] = 0x07U; + buffer[20U] = 0x10U; + buffer[21U] = 0x08U; + buffer[22U] = 0x10U; + + ::memcpy(buffer + 23U, data, 36U); + + if (m_debug) + CUtils::dump(1U, "Kenwood Network RTP Data Sent", buffer, 59U); + + return m_rtpSocket.write(buffer, 59U, m_rtpaddress, m_addrlen); +} + +bool CNXDNKenwoodNetwork::writeRTPDataHeader(const unsigned char* data) +{ + assert(data != NULL); + + unsigned char buffer[50U]; + ::memset(buffer, 0x00U, 50U); + + buffer[0U] = 0x80U; + buffer[1U] = 0x66U; + + m_seqNo++; + buffer[2U] = (m_seqNo >> 8) & 0xFFU; + buffer[3U] = (m_seqNo >> 0) & 0xFFU; + + unsigned long timeStamp = getTimeStamp(); + buffer[4U] = (timeStamp >> 24) & 0xFFU; + buffer[5U] = (timeStamp >> 16) & 0xFFU; + buffer[6U] = (timeStamp >> 8) & 0xFFU; + buffer[7U] = (timeStamp >> 0) & 0xFFU; + + buffer[8U] = (m_ssrc >> 24) & 0xFFU; + buffer[9U] = (m_ssrc >> 16) & 0xFFU; + buffer[10U] = (m_ssrc >> 8) & 0xFFU; + buffer[11U] = (m_ssrc >> 0) & 0xFFU; + + m_sessionId++; + buffer[12U] = m_sessionId; + + buffer[13U] = 0x00U; + buffer[14U] = 0x00U; + buffer[15U] = 0x00U; + buffer[16U] = 0x01U; + buffer[17U] = 0x01U; + + ::memcpy(buffer + 18U, data, 24U); + + if (m_debug) + CUtils::dump(1U, "Kenwood Network RTP Data Sent", buffer, 42U); + + return m_rtpSocket.write(buffer, 42U, m_rtpaddress, m_addrlen); +} + +bool CNXDNKenwoodNetwork::writeRTPDataTrailer(const unsigned char* data) +{ + assert(data != NULL); + + unsigned char buffer[50U]; + ::memset(buffer, 0x00U, 50U); + + buffer[0U] = 0x80U; + buffer[1U] = 0x66U; + + m_seqNo++; + buffer[2U] = (m_seqNo >> 8) & 0xFFU; + buffer[3U] = (m_seqNo >> 0) & 0xFFU; + + unsigned long timeStamp = getTimeStamp(); + buffer[4U] = (timeStamp >> 24) & 0xFFU; + buffer[5U] = (timeStamp >> 16) & 0xFFU; + buffer[6U] = (timeStamp >> 8) & 0xFFU; + buffer[7U] = (timeStamp >> 0) & 0xFFU; + + buffer[8U] = (m_ssrc >> 24) & 0xFFU; + buffer[9U] = (m_ssrc >> 16) & 0xFFU; + buffer[10U] = (m_ssrc >> 8) & 0xFFU; + buffer[11U] = (m_ssrc >> 0) & 0xFFU; + + m_sessionId++; + buffer[12U] = m_sessionId; + + buffer[13U] = 0x00U; + buffer[14U] = 0x00U; + buffer[15U] = 0x00U; + buffer[16U] = 0x01U; + buffer[17U] = 0x06U; + + ::memcpy(buffer + 18U, data, 24U); + + if (m_debug) + CUtils::dump(1U, "Kenwood Network RTP Data Sent", buffer, 42U); + + return m_rtpSocket.write(buffer, 42U, m_rtpaddress, m_addrlen); +} + +bool CNXDNKenwoodNetwork::writeRTPDataData(const unsigned char* data) +{ + assert(data != NULL); + + unsigned char buffer[50U]; + ::memset(buffer, 0x00U, 50U); + + buffer[0U] = 0x80U; + buffer[1U] = 0x66U; + + m_seqNo++; + buffer[2U] = (m_seqNo >> 8) & 0xFFU; + buffer[3U] = (m_seqNo >> 0) & 0xFFU; + + unsigned long timeStamp = getTimeStamp(); + buffer[4U] = (timeStamp >> 24) & 0xFFU; + buffer[5U] = (timeStamp >> 16) & 0xFFU; + buffer[6U] = (timeStamp >> 8) & 0xFFU; + buffer[7U] = (timeStamp >> 0) & 0xFFU; + + buffer[8U] = (m_ssrc >> 24) & 0xFFU; + buffer[9U] = (m_ssrc >> 16) & 0xFFU; + buffer[10U] = (m_ssrc >> 8) & 0xFFU; + buffer[11U] = (m_ssrc >> 0) & 0xFFU; + + m_sessionId++; + buffer[12U] = m_sessionId; + + buffer[13U] = 0x00U; + buffer[14U] = 0x00U; + buffer[15U] = 0x00U; + buffer[16U] = 0x01U; + buffer[17U] = 0x01U; + + ::memcpy(buffer + 18U, data, 24U); + + if (m_debug) + CUtils::dump(1U, "Kenwood Network RTP Data Sent", buffer, 42U); + + return m_rtpSocket.write(buffer, 42U, m_rtpaddress, m_addrlen); +} + +bool CNXDNKenwoodNetwork::writeRTCPStart() +{ +#if defined(_WIN32) || defined(_WIN64) + time_t now; + ::time(&now); + + m_startSecs = uint32_t(now); + + SYSTEMTIME st; + ::GetSystemTime(&st); + + m_startUSecs = st.wMilliseconds * 1000U; +#else + struct timeval tod; + ::gettimeofday(&tod, NULL); + + m_startSecs = tod.tv_sec; + m_startUSecs = tod.tv_usec; +#endif + + unsigned char buffer[30U]; + ::memset(buffer, 0x00U, 30U); + + buffer[0U] = 0x8AU; + buffer[1U] = 0xCCU; + buffer[2U] = 0x00U; + buffer[3U] = 0x06U; + + buffer[4U] = (m_ssrc >> 24) & 0xFFU; + buffer[5U] = (m_ssrc >> 16) & 0xFFU; + buffer[6U] = (m_ssrc >> 8) & 0xFFU; + buffer[7U] = (m_ssrc >> 0) & 0xFFU; + + buffer[8U] = 'K'; + buffer[9U] = 'W'; + buffer[10U] = 'N'; + buffer[11U] = 'E'; + + buffer[12U] = (m_startSecs >> 24) & 0xFFU; + buffer[13U] = (m_startSecs >> 16) & 0xFFU; + buffer[14U] = (m_startSecs >> 8) & 0xFFU; + buffer[15U] = (m_startSecs >> 0) & 0xFFU; + + buffer[16U] = (m_startUSecs >> 24) & 0xFFU; + buffer[17U] = (m_startUSecs >> 16) & 0xFFU; + buffer[18U] = (m_startUSecs >> 8) & 0xFFU; + buffer[19U] = (m_startUSecs >> 0) & 0xFFU; + + buffer[22U] = 0x02U; + + buffer[24U] = 0x01U; + + buffer[27U] = 0x0AU; + + if (m_debug) + CUtils::dump(1U, "Kenwood Network RTCP Data Sent", buffer, 28U); + + return m_rtcpSocket.write(buffer, 28U, m_rtcpaddress, m_addrlen); +} + +bool CNXDNKenwoodNetwork::writeRTCPPing() +{ + unsigned char buffer[30U]; + ::memset(buffer, 0x00U, 30U); + + buffer[0U] = 0x8AU; + buffer[1U] = 0xCCU; + buffer[2U] = 0x00U; + buffer[3U] = 0x06U; + + buffer[4U] = (m_ssrc >> 24) & 0xFFU; + buffer[5U] = (m_ssrc >> 16) & 0xFFU; + buffer[6U] = (m_ssrc >> 8) & 0xFFU; + buffer[7U] = (m_ssrc >> 0) & 0xFFU; + + buffer[8U] = 'K'; + buffer[9U] = 'W'; + buffer[10U] = 'N'; + buffer[11U] = 'E'; + + buffer[12U] = (m_startSecs >> 24) & 0xFFU; + buffer[13U] = (m_startSecs >> 16) & 0xFFU; + buffer[14U] = (m_startSecs >> 8) & 0xFFU; + buffer[15U] = (m_startSecs >> 0) & 0xFFU; + + buffer[16U] = (m_startUSecs >> 24) & 0xFFU; + buffer[17U] = (m_startUSecs >> 16) & 0xFFU; + buffer[18U] = (m_startUSecs >> 8) & 0xFFU; + buffer[19U] = (m_startUSecs >> 0) & 0xFFU; + + buffer[22U] = 0x02U; + + buffer[24U] = 0x01U; + + buffer[27U] = 0x7BU; + + if (m_debug) + CUtils::dump(1U, "Kenwood Network RTCP Data Sent", buffer, 28U); + + return m_rtcpSocket.write(buffer, 28U, m_rtcpaddress, m_addrlen); +} + +bool CNXDNKenwoodNetwork::writeRTCPHang(unsigned char type, unsigned short src, unsigned short dst) +{ + m_hangType = type; + m_hangSrc = src; + m_hangDst = dst; + + return writeRTCPHang(); +} + +bool CNXDNKenwoodNetwork::writeRTCPHang() +{ + unsigned char buffer[30U]; + ::memset(buffer, 0x00U, 30U); + + buffer[0U] = 0x8BU; + buffer[1U] = 0xCCU; + buffer[2U] = 0x00U; + buffer[3U] = 0x04U; + + buffer[4U] = (m_ssrc >> 24) & 0xFFU; + buffer[5U] = (m_ssrc >> 16) & 0xFFU; + buffer[6U] = (m_ssrc >> 8) & 0xFFU; + buffer[7U] = (m_ssrc >> 0) & 0xFFU; + + buffer[8U] = 'K'; + buffer[9U] = 'W'; + buffer[10U] = 'N'; + buffer[11U] = 'E'; + + buffer[12U] = (m_hangSrc >> 8) & 0xFFU; + buffer[13U] = (m_hangSrc >> 0) & 0xFFU; + + buffer[14U] = (m_hangDst >> 8) & 0xFFU; + buffer[15U] = (m_hangDst >> 0) & 0xFFU; + + buffer[16U] = m_hangType; + + if (m_debug) + CUtils::dump(1U, "Kenwood Network RTCP Data Sent", buffer, 20U); + + return m_rtcpSocket.write(buffer, 20U, m_rtcpaddress, m_addrlen); +} + +bool CNXDNKenwoodNetwork::read(unsigned char* data) +{ + assert(data != NULL); + + unsigned char dummy[BUFFER_LENGTH]; + readRTCP(dummy); + + unsigned int len = readRTP(data); + switch (len) { + case 0U: // Nothing received + return false; + case 35U: // Voice header or trailer + return processKenwoodVoiceHeader(data); + case 47U: // Voice data + if (m_headerSeen) + return processKenwoodVoiceData(data); + else + return processKenwoodVoiceLateEntry(data); + case 31U: // Data + return processKenwoodData(data); + default: + CUtils::dump(5U, "Unknown data received from the Kenwood network", data, len); + return false; + } +} + +unsigned int CNXDNKenwoodNetwork::readRTP(unsigned char* data) +{ + assert(data != NULL); + + unsigned char buffer[BUFFER_LENGTH]; + + sockaddr_storage address; + unsigned int addrlen; + int length = m_rtpSocket.read(buffer, BUFFER_LENGTH, address, addrlen); + if (length <= 0 || !CUDPSocket::match_addr(m_rtpaddress, address)) + return 0U; + + if (!m_enabled) + return 0U; + + if (m_debug) + CUtils::dump(1U, "Kenwood Network RTP Data Received", buffer, length); + + ::memcpy(data, buffer + 12U, length - 12U); + + return length - 12U; +} + +unsigned int CNXDNKenwoodNetwork::readRTCP(unsigned char* data) +{ + assert(data != NULL); + + unsigned char buffer[BUFFER_LENGTH]; + + sockaddr_storage address; + unsigned int addrlen; + int length = m_rtcpSocket.read(buffer, BUFFER_LENGTH, address, addrlen); + if (length <= 0 || !CUDPSocket::match_addr(m_rtcpaddress, address)) + return 0U; + + if (!m_enabled) + return 0U; + + if (m_debug) + CUtils::dump(1U, "Kenwood Network RTCP Data Received", buffer, length); + + if (::memcmp(buffer + 8U, "KWNE", 4U) != 0) { + LogError("Missing RTCP KWNE signature"); + return 0U; + } + + ::memcpy(data, buffer + 12U, length - 12U); + + return length - 12U; +} + +void CNXDNKenwoodNetwork::reset() +{ + m_rtcpTimer.stop(); + m_hangTimer.stop(); + + m_headerSeen = false; + m_seen1 = false; + m_seen2 = false; + m_seen3 = false; + m_seen4 = false; +} + +void CNXDNKenwoodNetwork::close() +{ + m_rtcpSocket.close(); + m_rtpSocket.close(); + + LogMessage("Closing Kenwood connection"); +} + +void CNXDNKenwoodNetwork::clock(unsigned int ms) +{ + m_rtcpTimer.clock(ms); + if (m_rtcpTimer.isRunning() && m_rtcpTimer.hasExpired()) { + if (m_hangTimer.isRunning()) + writeRTCPHang(); + else + writeRTCPPing(); + m_rtcpTimer.start(); + } + + m_hangTimer.clock(ms); + if (m_hangTimer.isRunning() && m_hangTimer.hasExpired()) { + m_rtcpTimer.stop(); + m_hangTimer.stop(); + } +} + +bool CNXDNKenwoodNetwork::processKenwoodVoiceHeader(unsigned char* inData) +{ + assert(inData != NULL); + + unsigned char outData[50U], temp[20U]; + ::memset(outData, 0x00U, 50U); + + // LICH + outData[0U] = 0x83U; + + // SACCH + ::memset(temp, 0x00U, 20U); + temp[0U] = inData[12U]; + temp[1U] = inData[11U]; + temp[2U] = inData[14U]; + temp[3U] = inData[13U]; + CNXDNCRC::encodeCRC6(temp, 26U); + ::memcpy(outData + 1U, temp, 4U); + + // FACCH 1+2 + ::memset(temp, 0x00U, 20U); + temp[0U] = inData[16U]; + temp[1U] = inData[15U]; + temp[2U] = inData[18U]; + temp[3U] = inData[17U]; + temp[4U] = inData[20U]; + temp[5U] = inData[19U]; + temp[6U] = inData[22U]; + temp[7U] = inData[21U]; + temp[8U] = inData[24U]; + temp[9U] = inData[23U]; + CNXDNCRC::encodeCRC12(temp, 80U); + ::memcpy(outData + 5U, temp, 12U); + ::memcpy(outData + 19U, temp, 12U); + + switch (outData[5U] & 0x3FU) { + case 0x01U: + ::memcpy(inData, outData, 33U); + m_headerSeen = true; + m_seen1 = false; + m_seen2 = false; + m_seen3 = false; + m_seen4 = false; + return true; + case 0x08U: + ::memcpy(inData, outData, 33U); + m_headerSeen = false; + m_seen1 = false; + m_seen2 = false; + m_seen3 = false; + m_seen4 = false; + return true; + default: + return false; + } +} + +bool CNXDNKenwoodNetwork::processKenwoodVoiceData(unsigned char* inData) +{ + assert(inData != NULL); + + unsigned char outData[50U], temp[20U]; + ::memset(outData, 0x00U, 50U); + + // LICH + outData[0U] = 0xAEU; + + // SACCH + ::memset(temp, 0x00U, 20U); + temp[0U] = inData[12U]; + temp[1U] = inData[11U]; + temp[2U] = inData[14U]; + temp[3U] = inData[13U]; + CNXDNCRC::encodeCRC6(temp, 26U); + ::memcpy(outData + 1U, temp, 4U); + + // AMBE 1+2 + unsigned int n = 5U * 8U; + + temp[0U] = inData[16U]; + temp[1U] = inData[15U]; + temp[2U] = inData[18U]; + temp[3U] = inData[17U]; + temp[4U] = inData[20U]; + temp[5U] = inData[19U]; + temp[6U] = inData[22U]; + temp[7U] = inData[21U]; + + for (unsigned int i = 0U; i < 49U; i++, n++) { + bool b = READ_BIT(temp, i); + WRITE_BIT(outData, n, b); + } + + temp[0U] = inData[24U]; + temp[1U] = inData[23U]; + temp[2U] = inData[26U]; + temp[3U] = inData[25U]; + temp[4U] = inData[28U]; + temp[5U] = inData[27U]; + temp[6U] = inData[30U]; + temp[7U] = inData[29U]; + + for (unsigned int i = 0U; i < 49U; i++, n++) { + bool b = READ_BIT(temp, i); + WRITE_BIT(outData, n, b); + } + + // AMBE 3+4 + n = 19U * 8U; + + temp[0U] = inData[32U]; + temp[1U] = inData[31U]; + temp[2U] = inData[34U]; + temp[3U] = inData[33U]; + temp[4U] = inData[36U]; + temp[5U] = inData[35U]; + temp[6U] = inData[38U]; + temp[7U] = inData[37U]; + + for (unsigned int i = 0U; i < 49U; i++, n++) { + bool b = READ_BIT(temp, i); + WRITE_BIT(outData, n, b); + } + + temp[0U] = inData[40U]; + temp[1U] = inData[39U]; + temp[2U] = inData[42U]; + temp[3U] = inData[41U]; + temp[4U] = inData[44U]; + temp[5U] = inData[43U]; + temp[6U] = inData[46U]; + temp[7U] = inData[45U]; + + for (unsigned int i = 0U; i < 49U; i++, n++) { + bool b = READ_BIT(temp, i); + WRITE_BIT(outData, n, b); + } + + ::memcpy(inData, outData, 33U); + + return true; +} + +bool CNXDNKenwoodNetwork::processKenwoodData(unsigned char* inData) +{ + if (inData[7U] != 0x09U && inData[7U] != 0x0BU && inData[7U] != 0x08U) + return false; + + unsigned char outData[50U]; + + if (inData[7U] == 0x09U || inData[7U] == 0x08U) { + outData[0U] = 0x90U; + outData[1U] = inData[8U]; + outData[2U] = inData[7U]; + outData[3U] = inData[10U]; + outData[4U] = inData[9U]; + outData[5U] = inData[12U]; + outData[6U] = inData[11U]; + outData[7U] = inData[14U]; + outData[8U] = inData[13U]; + outData[9U] = inData[16U]; + outData[10U] = inData[15U]; + outData[11U] = inData[18U]; + outData[12U] = inData[17U]; + outData[13U] = inData[20U]; + outData[14U] = inData[19U]; + outData[15U] = inData[22U]; + outData[16U] = inData[21U]; + outData[17U] = inData[24U]; + outData[18U] = inData[23U]; + outData[19U] = inData[26U]; + ::memcpy(inData, outData, 20U); + return true; + } else { + outData[0U] = 0x90U; + outData[1U] = inData[8U]; + outData[2U] = inData[7U]; + outData[3U] = inData[10U]; + outData[4U] = inData[9U]; + outData[5U] = inData[12U]; + outData[6U] = inData[11U]; + outData[7U] = inData[14U]; + outData[8U] = inData[13U]; + outData[9U] = inData[16U]; + outData[10U] = inData[15U]; + outData[11U] = inData[18U]; + outData[12U] = inData[17U]; + outData[13U] = inData[20U]; + outData[14U] = inData[19U]; + outData[15U] = inData[22U]; + outData[16U] = inData[21U]; + outData[17U] = inData[24U]; + outData[18U] = inData[23U]; + outData[19U] = inData[26U]; + outData[20U] = inData[25U]; + outData[21U] = inData[28U]; + outData[22U] = inData[27U]; + outData[23U] = inData[29U]; + ::memcpy(inData, outData, 24U); + return true; + } +} + +unsigned long CNXDNKenwoodNetwork::getTimeStamp() const +{ + unsigned long timeStamp = 0UL; + +#if defined(_WIN32) || defined(_WIN64) + SYSTEMTIME st; + ::GetSystemTime(&st); + + unsigned int hh = st.wHour; + unsigned int mm = st.wMinute; + unsigned int ss = st.wSecond; + unsigned int ms = st.wMilliseconds; + + timeStamp += hh * 3600U * 1000U * 80U; + timeStamp += mm * 60U * 1000U * 80U; + timeStamp += ss * 1000U * 80U; + timeStamp += ms * 80U; +#else + struct timeval tod; + ::gettimeofday(&tod, NULL); + + unsigned int ss = tod.tv_sec; + unsigned int ms = tod.tv_usec / 1000U; + + timeStamp += ss * 1000U * 80U; + timeStamp += ms * 80U; +#endif + + return timeStamp; +} + +bool CNXDNKenwoodNetwork::processKenwoodVoiceLateEntry(unsigned char* inData) +{ + assert(inData != NULL); + + unsigned char sacch[4U]; + sacch[0U] = inData[12U]; + sacch[1U] = inData[11U]; + sacch[2U] = inData[14U]; + sacch[3U] = inData[13U]; + + switch (sacch[0U] & 0xC0U) { + case 0xC0U: + if (!m_seen1) { + unsigned int offset = 0U; + for (unsigned int i = 8U; i < 26U; i++, offset++) { + bool b = READ_BIT(sacch, i) != 0U; + WRITE_BIT(m_sacch, offset, b); + } + m_seen1 = true; + } + break; + case 0x80U: + if (!m_seen2) { + unsigned int offset = 18U; + for (unsigned int i = 8U; i < 26U; i++, offset++) { + bool b = READ_BIT(sacch, i) != 0U; + WRITE_BIT(m_sacch, offset, b); + } + m_seen2 = true; + } + break; + case 0x40U: + if (!m_seen3) { + unsigned int offset = 36U; + for (unsigned int i = 8U; i < 26U; i++, offset++) { + bool b = READ_BIT(sacch, i) != 0U; + WRITE_BIT(m_sacch, offset, b); + } + m_seen3 = true; + } + break; + case 0x00U: + if (!m_seen4) { + unsigned int offset = 54U; + for (unsigned int i = 8U; i < 26U; i++, offset++) { + bool b = READ_BIT(sacch, i) != 0U; + WRITE_BIT(m_sacch, offset, b); + } + m_seen4 = true; + } + break; + } + + if (!m_seen1 || !m_seen2 || !m_seen3 || !m_seen4) + return false; + + // Create a dummy header + // Header SACCH + inData[11U] = 0x10U; + inData[12U] = 0x01U; + inData[13U] = 0x00U; + inData[14U] = 0x00U; + + // Header FACCH + inData[15U] = m_sacch[1U]; + inData[16U] = m_sacch[0U]; + inData[17U] = m_sacch[3U]; + inData[18U] = m_sacch[2U]; + inData[19U] = m_sacch[5U]; + inData[20U] = m_sacch[4U]; + inData[21U] = m_sacch[7U]; + inData[22U] = m_sacch[6U]; + inData[23U] = 0x00U; + inData[24U] = m_sacch[8U]; + + return processKenwoodVoiceHeader(inData); +} + +void CNXDNKenwoodNetwork::enable(bool enabled) +{ + if (enabled && !m_enabled) + reset(); + + m_enabled = enabled; +} diff --git a/NXDNKenwoodNetwork.h b/NXDNKenwoodNetwork.h new file mode 100644 index 0000000..3466569 --- /dev/null +++ b/NXDNKenwoodNetwork.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2009-2014,2016,2018,2020 by Jonathan Naylor G4KLX + * + * 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. + */ + +#ifndef NXDNKenwoodNetwork_H +#define NXDNKenwoodNetwork_H + +#include "NXDNNetwork.h" +#include "UDPSocket.h" +#include "Timer.h" + +#include +#include +#include + +class CNXDNKenwoodNetwork : public INXDNNetwork { +public: + CNXDNKenwoodNetwork(const std::string& localAddress, unsigned int localPort, const std::string& gwyAddress, unsigned int gwyPort, bool debug); + virtual ~CNXDNKenwoodNetwork(); + + virtual bool open(); + + virtual void enable(bool enabled); + + virtual bool write(const unsigned char* data, NXDN_NETWORK_MESSAGE_TYPE type); + + virtual bool read(unsigned char* data); + + virtual void reset(); + + virtual void close(); + + virtual void clock(unsigned int ms); + +private: + CUDPSocket m_rtpSocket; + CUDPSocket m_rtcpSocket; + sockaddr_storage m_rtcpaddress; + sockaddr_storage m_rtpaddress; + unsigned int m_addrlen; + bool m_enabled; + bool m_headerSeen; + bool m_seen1; + bool m_seen2; + bool m_seen3; + bool m_seen4; + unsigned char* m_sacch; + uint8_t m_sessionId; + uint16_t m_seqNo; + unsigned int m_ssrc; + bool m_debug; + uint32_t m_startSecs; + uint32_t m_startUSecs; + CTimer m_rtcpTimer; + CTimer m_hangTimer; + unsigned char m_hangType; + unsigned short m_hangSrc; + unsigned short m_hangDst; + std::mt19937 m_random; + + bool processIcomVoiceHeader(const unsigned char* data); + bool processIcomVoiceData(const unsigned char* data); + bool processIcomDataHeader(const unsigned char* data); + bool processIcomDataData(const unsigned char* data); + bool processIcomDataTrailer(const unsigned char* data); + bool processKenwoodVoiceHeader(unsigned char* data); + bool processKenwoodVoiceData(unsigned char* data); + bool processKenwoodVoiceLateEntry(unsigned char* data); + bool processKenwoodData(unsigned char* data); + bool writeRTPVoiceHeader(const unsigned char* data); + bool writeRTPVoiceData(const unsigned char* data); + bool writeRTPVoiceTrailer(const unsigned char* data); + bool writeRTPDataHeader(const unsigned char* data); + bool writeRTPDataData(const unsigned char* data); + bool writeRTPDataTrailer(const unsigned char* data); + bool writeRTCPStart(); + bool writeRTCPPing(); + bool writeRTCPHang(unsigned char type, unsigned short src, unsigned short dst); + bool writeRTCPHang(); + unsigned int readRTP(unsigned char* data); + unsigned int readRTCP(unsigned char* data); + unsigned long getTimeStamp() const; +}; + +#endif diff --git a/NXDNNetwork.cpp b/NXDNNetwork.cpp index dcf215e..0f55011 100644 --- a/NXDNNetwork.cpp +++ b/NXDNNetwork.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2014,2016,2018,2019 by Jonathan Naylor G4KLX + * Copyright (C) 2020 by Jonathan Naylor G4KLX * * 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 @@ -16,148 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "NXDNDefines.h" #include "NXDNNetwork.h" -#include "Defines.h" -#include "Utils.h" -#include "Log.h" -#include -#include -#include - -const unsigned int BUFFER_LENGTH = 200U; - -CNXDNNetwork::CNXDNNetwork(const std::string& localAddress, unsigned int localPort, const std::string& gatewayAddress, unsigned int gatewayPort, bool debug) : -m_socket(localAddress, localPort), -m_address(), -m_addrlen(), -m_debug(debug), -m_enabled(false), -m_buffer(1000U, "NXDN Network") -{ - assert(gatewayPort > 0U); - assert(!gatewayAddress.empty()); - - CUDPSocket::lookup(gatewayAddress, gatewayPort, m_address, m_addrlen); -} - -CNXDNNetwork::~CNXDNNetwork() +INXDNNetwork::~INXDNNetwork() { } - -bool CNXDNNetwork::open() -{ - LogMessage("Opening NXDN network connection"); - - if (CUDPSocket::isnone(m_address)) - return false; - - return m_socket.open(); -} - -bool CNXDNNetwork::write(const unsigned char* data, NXDN_NETWORK_MESSAGE_TYPE type) -{ - assert(data != NULL); - - unsigned char buffer[110U]; - ::memset(buffer, 0x00U, 110U); - - buffer[0U] = 'I'; - buffer[1U] = 'C'; - buffer[2U] = 'O'; - buffer[3U] = 'M'; - buffer[4U] = 0x01U; - buffer[5U] = 0x01U; - buffer[6U] = 0x08U; - buffer[7U] = 0xE0U; - - switch (type) { - case NNMT_VOICE_HEADER: - case NNMT_VOICE_TRAILER: - buffer[37U] = 0x23U; - buffer[38U] = 0x1CU; - buffer[39U] = 0x21U; - break; - case NNMT_VOICE_BODY: - buffer[37U] = 0x23U; - buffer[38U] = 0x10U; - buffer[39U] = 0x21U; - break; - case NNMT_DATA_HEADER: - case NNMT_DATA_BODY: - case NNMT_DATA_TRAILER: - buffer[37U] = 0x23U; - buffer[38U] = 0x02U; - buffer[39U] = 0x18U; - break; - default: - return false; - } - - ::memcpy(buffer + 40U, data, 33U); - - if (m_debug) - CUtils::dump(1U, "NXDN Network Data Sent", buffer, 102U); - - return m_socket.write(buffer, 102U, m_address, m_addrlen); -} - -void CNXDNNetwork::clock(unsigned int ms) -{ - unsigned char buffer[BUFFER_LENGTH]; - - sockaddr_storage address; - unsigned int addrlen; - int length = m_socket.read(buffer, BUFFER_LENGTH, address, addrlen); - if (length <= 0 || !CUDPSocket::match(m_address, address)) - return; - - // Invalid packet type? - if (::memcmp(buffer, "ICOM", 4U) != 0) - return; - - if (length != 102) - return; - - if (!m_enabled) - return; - - if (m_debug) - CUtils::dump(1U, "NXDN Network Data Received", buffer, length); - - m_buffer.addData(buffer + 40U, 33U); -} - -bool CNXDNNetwork::read(unsigned char* data) -{ - assert(data != NULL); - - if (m_buffer.isEmpty()) - return false; - - m_buffer.getData(data, 33U); - - return true; -} - -void CNXDNNetwork::reset() -{ -} - -void CNXDNNetwork::close() -{ - m_socket.close(); - - LogMessage("Closing NXDN network connection"); -} - -void CNXDNNetwork::enable(bool enabled) -{ - if (enabled && !m_enabled) - reset(); - else if (!enabled && m_enabled) - m_buffer.clear(); - - m_enabled = enabled; -} diff --git a/NXDNNetwork.h b/NXDNNetwork.h index ec428d9..564196b 100644 --- a/NXDNNetwork.h +++ b/NXDNNetwork.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2014,2016,2018 by Jonathan Naylor G4KLX + * Copyright (C) 2020 by Jonathan Naylor G4KLX * * 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 @@ -20,12 +20,8 @@ #define NXDNNetwork_H #include "NXDNDefines.h" -#include "RingBuffer.h" -#include "UDPSocket.h" -#include "Timer.h" #include -#include enum NXDN_NETWORK_MESSAGE_TYPE { NNMT_VOICE_HEADER, @@ -36,32 +32,25 @@ enum NXDN_NETWORK_MESSAGE_TYPE { NNMT_DATA_TRAILER }; -class CNXDNNetwork { +class INXDNNetwork { public: - CNXDNNetwork(const std::string& localAddress, unsigned int localPort, const std::string& gatewayAddress, unsigned int gatewayPort, bool debug); - ~CNXDNNetwork(); + virtual ~INXDNNetwork() = 0; - bool open(); + virtual bool open() = 0; - void enable(bool enabled); + virtual void enable(bool enabled) = 0; - bool write(const unsigned char* data, NXDN_NETWORK_MESSAGE_TYPE type); + virtual bool write(const unsigned char* data, NXDN_NETWORK_MESSAGE_TYPE type) = 0; - bool read(unsigned char* data); + virtual bool read(unsigned char* data) = 0; - void reset(); + virtual void reset() = 0; - void close(); + virtual void close() = 0; - void clock(unsigned int ms); + virtual void clock(unsigned int ms) = 0; private: - CUDPSocket m_socket; - sockaddr_storage m_address; - unsigned int m_addrlen; - bool m_debug; - bool m_enabled; - CRingBuffer m_buffer; }; #endif diff --git a/Nextion.cpp b/Nextion.cpp index f15d6cf..adb8e76 100644 --- a/Nextion.cpp +++ b/Nextion.cpp @@ -38,6 +38,16 @@ const unsigned int P25_BER_COUNT = 7U; // 7 * 180ms = 1260ms const unsigned int NXDN_RSSI_COUNT = 28U; // 28 * 40ms = 1120ms const unsigned int NXDN_BER_COUNT = 28U; // 28 * 40ms = 1120ms +#define LAYOUT_COMPAT_MASK (7 << 0) // compatibility for old setting +#define LAYOUT_TA_ENABLE (1 << 4) // enable Talker Alias (TA) display +#define LAYOUT_TA_COLOUR (1 << 5) // TA display with font colour change +#define LAYOUT_TA_FONTSIZE (1 << 6) // TA display with font size change +#define LAYOUT_DIY (1 << 7) // use ON7LDS-DIY layout + +// bit[3:2] is used in Display.cpp to set connection speed for LCD panel. +// 00:low, others:high-speed. bit[2] is overlapped with LAYOUT_COMPAT_MASK. +#define LAYOUT_HIGHSPEED (3 << 2) + CNextion::CNextion(const std::string& callsign, unsigned int dmrid, ISerialPort* serial, unsigned int brightness, bool displayClock, bool utc, unsigned int idleBrightness, unsigned int screenLayout, unsigned int txFrequency, unsigned int rxFrequency, bool displayTempInF, const std::string& location) : CDisplay(), m_callsign(callsign), @@ -49,7 +59,7 @@ m_mode(MODE_IDLE), m_displayClock(displayClock), m_utc(utc), m_idleBrightness(idleBrightness), -m_screenLayout(screenLayout), +m_screenLayout(0), m_clockDisplayTimer(1000U, 0U, 400U), m_rssiAccum1(0U), m_rssiAccum2(0U), @@ -68,6 +78,23 @@ m_location(location) { assert(serial != NULL); assert(brightness >= 0U && brightness <= 100U); + + static const unsigned int feature_set[] = { + 0, // 0: G4KLX + 0, // 1: (reserved, low speed) + // 2: ON7LDS + LAYOUT_TA_ENABLE | LAYOUT_TA_COLOUR | LAYOUT_TA_FONTSIZE, + LAYOUT_TA_ENABLE | LAYOUT_DIY, // 3: ON7LDS-DIY + LAYOUT_TA_ENABLE | LAYOUT_DIY, // 4: ON7LDS-DIY (high speed) + 0, // 5: (reserved, high speed) + 0, // 6: (reserved, high speed) + 0, // 7: (reserved, high speed) + }; + + if (screenLayout & ~LAYOUT_COMPAT_MASK) + m_screenLayout = screenLayout & ~LAYOUT_COMPAT_MASK; + else + m_screenLayout = feature_set[screenLayout]; } CNextion::~CNextion() @@ -118,7 +145,7 @@ void CNextion::setIdleInt() ::sprintf(command, "t0.txt=\"%s/%u\"", m_callsign.c_str(), m_dmrid); sendCommand(command); - if (m_screenLayout > 2U) { + if (m_screenLayout & LAYOUT_DIY) { ::sprintf(command, "t4.txt=\"%s\"", m_callsign.c_str()); sendCommand(command); ::sprintf(command, "t5.txt=\"%u\"", m_dmrid); @@ -350,17 +377,21 @@ void CNextion::writeDMRInt(unsigned int slotNo, const std::string& src, bool gro if (slotNo == 1U) { - if (m_screenLayout == 2U) { - sendCommand("t2.pco=0"); - sendCommand("t2.font=4"); + if (m_screenLayout & LAYOUT_TA_ENABLE) { + if (m_screenLayout & LAYOUT_TA_COLOUR) + sendCommand("t2.pco=0"); + if (m_screenLayout & LAYOUT_TA_FONTSIZE) + sendCommand("t2.font=4"); } sendCommand("t2.txt=\"2 Listening\""); sendCommandAction(69U); } else { - if (m_screenLayout == 2U) { - sendCommand("t0.pco=0"); - sendCommand("t0.font=4"); + if (m_screenLayout & LAYOUT_TA_ENABLE) { + if (m_screenLayout & LAYOUT_TA_COLOUR) + sendCommand("t0.pco=0"); + if (m_screenLayout & LAYOUT_TA_FONTSIZE) + sendCommand("t0.font=4"); } sendCommand("t0.txt=\"1 Listening\""); @@ -377,9 +408,11 @@ void CNextion::writeDMRInt(unsigned int slotNo, const std::string& src, bool gro if (slotNo == 1U) { ::sprintf(text, "t0.txt=\"1 %s %s\"", type, src.c_str()); - if (m_screenLayout == 2U) { - sendCommand("t0.pco=0"); - sendCommand("t0.font=4"); + if (m_screenLayout & LAYOUT_TA_ENABLE) { + if (m_screenLayout & LAYOUT_TA_COLOUR) + sendCommand("t0.pco=0"); + if (m_screenLayout & LAYOUT_TA_FONTSIZE) + sendCommand("t0.font=4"); } sendCommand(text); @@ -391,9 +424,11 @@ void CNextion::writeDMRInt(unsigned int slotNo, const std::string& src, bool gro } else { ::sprintf(text, "t2.txt=\"2 %s %s\"", type, src.c_str()); - if (m_screenLayout == 2U) { - sendCommand("t2.pco=0"); - sendCommand("t2.font=4"); + if (m_screenLayout & LAYOUT_TA_ENABLE) { + if (m_screenLayout & LAYOUT_TA_COLOUR) + sendCommand("t2.pco=0"); + if (m_screenLayout & LAYOUT_TA_FONTSIZE) + sendCommand("t2.font=4"); } sendCommand(text); @@ -448,15 +483,17 @@ void CNextion::writeDMRRSSIInt(unsigned int slotNo, unsigned char rssi) void CNextion::writeDMRTAInt(unsigned int slotNo, unsigned char* talkerAlias, const char* type) { - if (m_screenLayout < 2U) + if (!(m_screenLayout & LAYOUT_TA_ENABLE)) return; if (type[0] == ' ') { if (slotNo == 1U) { - if (m_screenLayout == 2U) sendCommand("t0.pco=33808"); + if (m_screenLayout & LAYOUT_TA_COLOUR) + sendCommand("t0.pco=33808"); sendCommandAction(64U); } else { - if (m_screenLayout == 2U) sendCommand("t2.pco=33808"); + if (m_screenLayout & LAYOUT_TA_COLOUR) + sendCommand("t2.pco=33808"); sendCommandAction(72U); } @@ -467,33 +504,36 @@ void CNextion::writeDMRTAInt(unsigned int slotNo, unsigned char* talkerAlias, co char text[50U]; ::sprintf(text, "t0.txt=\"1 %s %s\"", type, talkerAlias); - if (m_screenLayout == 2U) { + if (m_screenLayout & LAYOUT_TA_FONTSIZE) { if (::strlen((char*)talkerAlias) > (16U-4U)) sendCommand("t0.font=3"); if (::strlen((char*)talkerAlias) > (20U-4U)) sendCommand("t0.font=2"); if (::strlen((char*)talkerAlias) > (24U-4U)) sendCommand("t0.font=1"); - - sendCommand("t0.pco=1024"); } + if (m_screenLayout & LAYOUT_TA_COLOUR) + sendCommand("t0.pco=1024"); + sendCommand(text); sendCommandAction(63U); } else { char text[50U]; ::sprintf(text, "t2.txt=\"2 %s %s\"", type, talkerAlias); - if (m_screenLayout == 2U) { + if (m_screenLayout & LAYOUT_TA_FONTSIZE) { if (::strlen((char*)talkerAlias) > (16U-4U)) sendCommand("t2.font=3"); if (::strlen((char*)talkerAlias) > (20U-4U)) sendCommand("t2.font=2"); if (::strlen((char*)talkerAlias) > (24U-4U)) sendCommand("t2.font=1"); - - sendCommand("t2.pco=1024"); } + + if (m_screenLayout & LAYOUT_TA_COLOUR) + sendCommand("t2.pco=1024"); + sendCommand(text); sendCommandAction(71U); } @@ -535,9 +575,11 @@ void CNextion::clearDMRInt(unsigned int slotNo) sendCommand("t0.txt=\"1 Listening\""); sendCommandAction(61U); - if (m_screenLayout == 2U) { - sendCommand("t0.pco=0"); - sendCommand("t0.font=4"); + if (m_screenLayout & LAYOUT_TA_ENABLE) { + if (m_screenLayout & LAYOUT_TA_COLOUR) + sendCommand("t0.pco=0"); + if (m_screenLayout & LAYOUT_TA_FONTSIZE) + sendCommand("t0.font=4"); } sendCommand("t1.txt=\"\""); @@ -547,9 +589,11 @@ void CNextion::clearDMRInt(unsigned int slotNo) sendCommand("t2.txt=\"2 Listening\""); sendCommandAction(69U); - if (m_screenLayout == 2U) { - sendCommand("t2.pco=0"); - sendCommand("t2.font=4"); + if (m_screenLayout & LAYOUT_TA_ENABLE) { + if (m_screenLayout & LAYOUT_TA_COLOUR) + sendCommand("t2.pco=0"); + if (m_screenLayout & LAYOUT_TA_FONTSIZE) + sendCommand("t2.font=4"); } sendCommand("t3.txt=\"\""); @@ -862,7 +906,7 @@ void CNextion::close() void CNextion::sendCommandAction(unsigned int status) { - if (m_screenLayout<3U) + if (!(m_screenLayout & LAYOUT_DIY)) return; char text[30U]; @@ -881,4 +925,4 @@ void CNextion::sendCommand(const char* command) // we must add a bit of a delay to allow the display to process the commands, else some are getting mangled. // 10 ms is just a guess, but seems to be sufficient. CThread::sleep(10U); - } +} diff --git a/OLED.cpp b/OLED.cpp index 6f9b4ec..02afc2d 100644 --- a/OLED.cpp +++ b/OLED.cpp @@ -240,7 +240,8 @@ void COLED::setIdleInt() // m_display.print("Idle"); // m_display.setTextSize(1); - m_display.startscrolldiagright(0x00,0x0f); //the MMDVM logo scrolls the whole screen + if (m_displayScroll && m_displayLogoScreensaver) + m_display.startscrolldiagright(0x00,0x0f); //the MMDVM logo scrolls the whole screen m_display.display(); unsigned char info[100U]; @@ -568,7 +569,8 @@ void COLED::writeCWInt() m_display.setTextSize(1); m_display.display(); - m_display.startscrollright(0x02,0x0f); + if (m_displayScroll) + m_display.startscrollright(0x02,0x0f); } void COLED::clearCWInt() @@ -581,14 +583,16 @@ void COLED::clearCWInt() m_display.setTextSize(1); m_display.display(); - m_display.startscrollleft(0x02,0x0f); + if (m_displayScroll) + m_display.startscrollleft(0x02,0x0f); } void COLED::close() { m_display.clearDisplay(); m_display.fillRect(0, 0, m_display.width(), 16, BLACK); - m_display.startscrollright(0x00,0x01); + if (m_displayScroll) + m_display.startscrollright(0x00,0x01); m_display.setCursor(0,00); m_display.setTextSize(2); m_display.print("-CLOSE-"); diff --git a/UDPSocket.cpp b/UDPSocket.cpp index beec3ce..0bbe27b 100644 --- a/UDPSocket.cpp +++ b/UDPSocket.cpp @@ -118,6 +118,27 @@ bool CUDPSocket::match(const sockaddr_storage &addr1, const sockaddr_storage &ad } } +bool CUDPSocket::match_addr(const sockaddr_storage &addr1, const sockaddr_storage &addr2) +{ + if (addr1.ss_family != addr2.ss_family) + return false; + + switch (addr1.ss_family) { + case AF_INET: + struct sockaddr_in *in_1, *in_2; + in_1 = (struct sockaddr_in *)&addr1; + in_2 = (struct sockaddr_in *)&addr2; + return (in_1->sin_addr.s_addr == in_2->sin_addr.s_addr); + case AF_INET6: + struct sockaddr_in6 *in6_1, *in6_2; + in6_1 = (struct sockaddr_in6 *)&addr1; + in6_2 = (struct sockaddr_in6 *)&addr2; + return IN6_ARE_ADDR_EQUAL(&in6_1->sin6_addr, &in6_2->sin6_addr); + default: + return false; + } +} + bool CUDPSocket::isnone(const sockaddr_storage &addr) { struct sockaddr_in *in = (struct sockaddr_in *)&addr; diff --git a/UDPSocket.h b/UDPSocket.h index 46b2370..ad5b2a1 100644 --- a/UDPSocket.h +++ b/UDPSocket.h @@ -52,6 +52,7 @@ public: static int lookup(const std::string& hostName, unsigned int port, sockaddr_storage &address, unsigned int &address_length); static int lookup(const std::string& hostName, unsigned int port, sockaddr_storage &address, unsigned int &address_length, struct addrinfo &hints); static bool match(const sockaddr_storage &addr1, const sockaddr_storage &addr2); + static bool match_addr(const sockaddr_storage &addr1, const sockaddr_storage &addr2); static bool isnone(const sockaddr_storage &addr); private: diff --git a/Version.h b/Version.h index 101ca94..bb444d2 100644 --- a/Version.h +++ b/Version.h @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20200608"; +const char* VERSION = "20200630"; #endif