diff --git a/CASTInfo.cpp b/CASTInfo.cpp index b1bed7f..cce34d8 100644 --- a/CASTInfo.cpp +++ b/CASTInfo.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016,2018 by Jonathan Naylor G4KLX + * Copyright (C) 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 @@ -76,6 +76,10 @@ void CCASTInfo::setQuitInt() { } +void CCASTInfo::setFMInt() +{ +} + void CCASTInfo::writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector) { if (m_modem != NULL) diff --git a/CASTInfo.h b/CASTInfo.h index 326ecad..9254995 100644 --- a/CASTInfo.h +++ b/CASTInfo.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016,2018 by Jonathan Naylor G4KLX + * Copyright (C) 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 @@ -40,6 +40,7 @@ protected: virtual void setErrorInt(const char* text); virtual void setLockoutInt(); virtual void setQuitInt(); + virtual void setFMInt(); virtual void writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector); virtual void clearDStarInt(); diff --git a/Conf.cpp b/Conf.cpp index 9325a1b..719e406 100644 --- a/Conf.cpp +++ b/Conf.cpp @@ -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 @@ -44,6 +44,7 @@ enum SECTION { SECTION_P25, SECTION_NXDN, SECTION_POCSAG, + SECTION_FM, SECTION_DSTAR_NETWORK, SECTION_DMR_NETWORK, SECTION_FUSION_NETWORK, @@ -109,6 +110,7 @@ m_modemYSFTXLevel(50.0F), m_modemP25TXLevel(50.0F), m_modemNXDNTXLevel(50.0F), m_modemPOCSAGTXLevel(50.0F), +m_modemFMTXLevel(50.0F), m_modemRSSIMappingFile(), m_modemTrace(false), m_modemDebug(false), @@ -161,15 +163,48 @@ m_p25NAC(0x293U), m_p25SelfOnly(false), m_p25OverrideUID(false), m_p25RemoteGateway(false), +m_p25TXHang(5U), m_p25ModeHang(10U), m_nxdnEnabled(false), m_nxdnId(0U), m_nxdnRAN(1U), m_nxdnSelfOnly(false), m_nxdnRemoteGateway(false), +m_nxdnTXHang(5U), m_nxdnModeHang(10U), m_pocsagEnabled(false), m_pocsagFrequency(0U), +m_fmEnabled(false), +m_fmCallsign(), +m_fmCallsignSpeed(20U), +m_fmCallsignFrequency(1000U), +m_fmCallsignTime(10U), +m_fmCallsignHoldoff(1U), +m_fmCallsignHighLevel(35.0F), +m_fmCallsignLowLevel(15.0F), +m_fmCallsignAtStart(true), +m_fmCallsignAtEnd(true), +m_fmCallsignAtLatch(true), +m_fmRFAck("K"), +m_fmExtAck("N"), +m_fmAckSpeed(20U), +m_fmAckFrequency(1750U), +m_fmAckMinTime(5U), +m_fmAckDelay(1000U), +m_fmAckLevel(80.0F), +m_fmTimeout(180U), +m_fmTimeoutLevel(80.0F), +m_fmCTCSSFrequency(88.6F), +m_fmCTCSSHighThreshold(30U), +m_fmCTCSSLowThreshold(20U), +m_fmCTCSSLevel(2.0F), +m_fmKerchunkTime(0U), +m_fmHangTime(7U), +m_fmUseCOS(true), +m_fmCOSInvert(false), +m_fmRFAudioBoost(1U), +m_fmMaxDevLevel(90.0F), +m_fmExtAudioBoost(1U), m_dstarNetworkEnabled(false), m_dstarGatewayAddress(), m_dstarGatewayPort(0U), @@ -244,12 +279,14 @@ m_lcdprocPort(0U), m_lcdprocLocalPort(0U), m_lcdprocDisplayClock(false), m_lcdprocUTC(false), +m_lcdprocDimOnIdle(false), m_lockFileEnabled(false), m_lockFileName(), m_mobileGPSEnabled(false), m_mobileGPSAddress(), m_mobileGPSPort(0U), m_remoteControlEnabled(false), +m_remoteControlAddress("127.0.0.1"), m_remoteControlPort(0U) { } @@ -304,6 +341,8 @@ bool CConf::read() section = SECTION_NXDN; else if (::strncmp(buffer, "[POCSAG]", 8U) == 0) section = SECTION_POCSAG; + else if (::strncmp(buffer, "[FM]", 4U) == 0) + section = SECTION_FM; else if (::strncmp(buffer, "[D-Star Network]", 16U) == 0) section = SECTION_DSTAR_NETWORK; else if (::strncmp(buffer, "[DMR Network]", 13U) == 0) @@ -358,11 +397,11 @@ bool CConf::read() // Convert the callsign to upper case for (unsigned int i = 0U; value[i] != 0; i++) value[i] = ::toupper(value[i]); - m_cwIdCallsign = m_callsign = value; + m_fmCallsign = m_cwIdCallsign = m_callsign = value; } else if (::strcmp(key, "Id") == 0) m_id = m_p25Id = m_dmrId = (unsigned int)::atoi(value); else if (::strcmp(key, "Timeout") == 0) - m_timeout = (unsigned int)::atoi(value); + m_fmTimeout = m_timeout = (unsigned int)::atoi(value); else if (::strcmp(key, "Duplex") == 0) m_duplex = ::atoi(value) == 1; else if (::strcmp(key, "ModeHang") == 0) @@ -455,7 +494,7 @@ bool CConf::read() else if (::strcmp(key, "RXLevel") == 0) m_modemRXLevel = float(::atof(value)); else if (::strcmp(key, "TXLevel") == 0) - m_modemCWIdTXLevel = m_modemDStarTXLevel = m_modemDMRTXLevel = m_modemYSFTXLevel = m_modemP25TXLevel = m_modemNXDNTXLevel = float(::atof(value)); + m_modemFMTXLevel = m_modemCWIdTXLevel = m_modemDStarTXLevel = m_modemDMRTXLevel = m_modemYSFTXLevel = m_modemP25TXLevel = m_modemNXDNTXLevel = float(::atof(value)); else if (::strcmp(key, "CWIdTXLevel") == 0) m_modemCWIdTXLevel = float(::atof(value)); else if (::strcmp(key, "D-StarTXLevel") == 0) @@ -470,6 +509,8 @@ bool CConf::read() m_modemNXDNTXLevel = float(::atof(value)); else if (::strcmp(key, "POCSAGTXLevel") == 0) m_modemPOCSAGTXLevel = float(::atof(value)); + else if (::strcmp(key, "FMTXLevel") == 0) + m_modemFMTXLevel = float(::atof(value)); else if (::strcmp(key, "RSSIMappingFile") == 0) m_modemRSSIMappingFile = value; else if (::strcmp(key, "Trace") == 0) @@ -636,6 +677,8 @@ bool CConf::read() m_p25SelfOnly = ::atoi(value) == 1; else if (::strcmp(key, "RemoteGateway") == 0) m_p25RemoteGateway = ::atoi(value) == 1; + else if (::strcmp(key, "TXHang") == 0) + m_p25TXHang = (unsigned int)::atoi(value); else if (::strcmp(key, "ModeHang") == 0) m_p25ModeHang = (unsigned int)::atoi(value); } else if (section == SECTION_NXDN) { @@ -649,13 +692,90 @@ bool CConf::read() m_nxdnSelfOnly = ::atoi(value) == 1; else if (::strcmp(key, "RemoteGateway") == 0) m_nxdnRemoteGateway = ::atoi(value) == 1; + else if (::strcmp(key, "TXHang") == 0) + m_nxdnTXHang = (unsigned int)::atoi(value); else if (::strcmp(key, "ModeHang") == 0) m_nxdnModeHang = (unsigned int)::atoi(value); } else if (section == SECTION_POCSAG) { + if (::strcmp(key, "Enable") == 0) + m_pocsagEnabled = ::atoi(value) == 1; + else if (::strcmp(key, "Frequency") == 0) + m_pocsagFrequency = (unsigned int)::atoi(value); + } + else if (section == SECTION_FM) { if (::strcmp(key, "Enable") == 0) - m_pocsagEnabled = ::atoi(value) == 1; - else if (::strcmp(key, "Frequency") == 0) - m_pocsagFrequency = (unsigned int)::atoi(value); + m_fmEnabled = ::atoi(value) == 1; + else if (::strcmp(key, "Callsign") == 0) { + // Convert the callsign to upper case + for (unsigned int i = 0U; value[i] != 0; i++) + value[i] = ::toupper(value[i]); + m_fmCallsign = value; + } else if (::strcmp(key, "CallsignSpeed") == 0) + m_fmCallsignSpeed = (unsigned int)::atoi(value); + else if (::strcmp(key, "CallsignFrequency") == 0) + m_fmCallsignFrequency = (unsigned int)::atoi(value); + else if (::strcmp(key, "CallsignTime") == 0) + m_fmCallsignTime = (unsigned int)::atoi(value); + else if (::strcmp(key, "CallsignHoldoff") == 0) + m_fmCallsignHoldoff = (unsigned int)::atoi(value); + else if (::strcmp(key, "CallsignHighLevel") == 0) + m_fmCallsignHighLevel = float(::atof(value)); + else if (::strcmp(key, "CallsignLowLevel") == 0) + m_fmCallsignLowLevel = float(::atof(value)); + else if (::strcmp(key, "CallsignAtStart") == 0) + m_fmCallsignAtStart = ::atoi(value) == 1; + else if (::strcmp(key, "CallsignAtEnd") == 0) + m_fmCallsignAtEnd = ::atoi(value) == 1; + else if (::strcmp(key, "CallsignAtLatch") == 0) + m_fmCallsignAtLatch = ::atoi(value) == 1; + else if (::strcmp(key, "RFAck") == 0) { + // Convert the ack to upper case + for (unsigned int i = 0U; value[i] != 0; i++) + value[i] = ::toupper(value[i]); + m_fmRFAck = value; + } else if (::strcmp(key, "ExtAck") == 0) { + // Convert the ack to upper case + for (unsigned int i = 0U; value[i] != 0; i++) + value[i] = ::toupper(value[i]); + m_fmExtAck = value; + } else if (::strcmp(key, "AckSpeed") == 0) + m_fmAckSpeed = (unsigned int)::atoi(value); + else if (::strcmp(key, "AckFrequency") == 0) + m_fmAckFrequency = (unsigned int)::atoi(value); + else if (::strcmp(key, "AckMinTime") == 0) + m_fmAckMinTime = (unsigned int)::atoi(value); + else if (::strcmp(key, "AckDelay") == 0) + m_fmAckDelay = (unsigned int)::atoi(value); + else if (::strcmp(key, "AckLevel") == 0) + m_fmAckLevel = float(::atof(value)); + else if (::strcmp(key, "Timeout") == 0) + m_fmTimeout = (unsigned int)::atoi(value); + else if (::strcmp(key, "TimeoutLevel") == 0) + m_fmTimeoutLevel = float(::atof(value)); + else if (::strcmp(key, "CTCSSFrequency") == 0) + m_fmCTCSSFrequency = float(::atof(value)); + else if (::strcmp(key, "CTCSSThreshold") == 0) + m_fmCTCSSHighThreshold = m_fmCTCSSLowThreshold = (unsigned int)::atoi(value); + else if (::strcmp(key, "CTCSSHighThreshold") == 0) + m_fmCTCSSHighThreshold = (unsigned int)::atoi(value); + else if (::strcmp(key, "CTCSSLowThreshold") == 0) + m_fmCTCSSLowThreshold = (unsigned int)::atoi(value); + else if (::strcmp(key, "CTCSSLevel") == 0) + m_fmCTCSSLevel = float(::atof(value)); + else if (::strcmp(key, "KerchunkTime") == 0) + m_fmKerchunkTime = (unsigned int)::atoi(value); + else if (::strcmp(key, "HangTime") == 0) + m_fmHangTime = (unsigned int)::atoi(value); + else if (::strcmp(key, "UseCOS") == 0) + m_fmUseCOS = ::atoi(value) == 1; + else if (::strcmp(key, "COSInvert") == 0) + m_fmCOSInvert = ::atoi(value) == 1; + else if (::strcmp(key, "RFAudioBoost") == 0) + m_fmRFAudioBoost = (unsigned int)::atoi(value); + else if (::strcmp(key, "MaxDevLevel") == 0) + m_fmMaxDevLevel = float(::atof(value)); + else if (::strcmp(key, "ExtAudioBoost") == 0) + m_fmExtAudioBoost = (unsigned int)::atoi(value); } else if (section == SECTION_DSTAR_NETWORK) { if (::strcmp(key, "Enable") == 0) m_dstarNetworkEnabled = ::atoi(value) == 1; @@ -838,6 +958,8 @@ bool CConf::read() } else if (section == SECTION_REMOTE_CONTROL) { if (::strcmp(key, "Enable") == 0) m_remoteControlEnabled = ::atoi(value) == 1; + else if (::strcmp(key, "Address") == 0) + m_remoteControlAddress = value; else if (::strcmp(key, "Port") == 0) m_remoteControlPort = (unsigned int)::atoi(value); } @@ -1083,6 +1205,11 @@ float CConf::getModemPOCSAGTXLevel() const return m_modemPOCSAGTXLevel; } +float CConf::getModemFMTXLevel() const +{ + return m_modemFMTXLevel; +} + std::string CConf::getModemRSSIMappingFile () const { return m_modemRSSIMappingFile; @@ -1343,6 +1470,11 @@ bool CConf::getP25RemoteGateway() const return m_p25RemoteGateway; } +unsigned int CConf::getP25TXHang() const +{ + return m_p25TXHang; +} + unsigned int CConf::getP25ModeHang() const { return m_p25ModeHang; @@ -1373,6 +1505,11 @@ bool CConf::getNXDNRemoteGateway() const return m_nxdnRemoteGateway; } +unsigned int CConf::getNXDNTXHang() const +{ + return m_nxdnTXHang; +} + unsigned int CConf::getNXDNModeHang() const { return m_nxdnModeHang; @@ -1388,6 +1525,161 @@ unsigned int CConf::getPOCSAGFrequency() const return m_pocsagFrequency; } +bool CConf::getFMEnabled() const +{ + return m_fmEnabled; +} + +std::string CConf::getFMCallsign() const +{ + return m_fmCallsign; +} + +unsigned int CConf::getFMCallsignSpeed() const +{ + return m_fmCallsignSpeed; +} + +unsigned int CConf::getFMCallsignFrequency() const +{ + return m_fmCallsignFrequency; +} + +unsigned int CConf::getFMCallsignTime() const +{ + return m_fmCallsignTime; +} + +unsigned int CConf::getFMCallsignHoldoff() const +{ + return m_fmCallsignHoldoff; +} + +float CConf::getFMCallsignHighLevel() const +{ + return m_fmCallsignHighLevel; +} + +float CConf::getFMCallsignLowLevel() const +{ + return m_fmCallsignLowLevel; +} + +bool CConf::getFMCallsignAtStart() const +{ + return m_fmCallsignAtStart; +} + +bool CConf::getFMCallsignAtEnd() const +{ + return m_fmCallsignAtEnd; +} + +bool CConf::getFMCallsignAtLatch() const +{ + return m_fmCallsignAtLatch; +} + +std::string CConf::getFMRFAck() const +{ + return m_fmRFAck; +} + +std::string CConf::getFMExtAck() const +{ + return m_fmExtAck; +} + +unsigned int CConf::getFMAckSpeed() const +{ + return m_fmAckSpeed; +} + +unsigned int CConf::getFMAckFrequency() const +{ + return m_fmAckFrequency; +} + +unsigned int CConf::getFMAckMinTime() const +{ + return m_fmAckMinTime; +} + +unsigned int CConf::getFMAckDelay() const +{ + return m_fmAckDelay; +} + +float CConf::getFMAckLevel() const +{ + return m_fmAckLevel; +} + +unsigned int CConf::getFMTimeout() const +{ + return m_fmTimeout; +} + +float CConf::getFMTimeoutLevel() const +{ + return m_fmTimeoutLevel; +} + +float CConf::getFMCTCSSFrequency() const +{ + return m_fmCTCSSFrequency; +} + +unsigned int CConf::getFMCTCSSHighThreshold() const +{ + return m_fmCTCSSHighThreshold; +} + +unsigned int CConf::getFMCTCSSLowThreshold() const +{ + return m_fmCTCSSLowThreshold; +} + +float CConf::getFMCTCSSLevel() const +{ + return m_fmCTCSSLevel; +} + +unsigned int CConf::getFMKerchunkTime() const +{ + return m_fmKerchunkTime; +} + +unsigned int CConf::getFMHangTime() const +{ + return m_fmHangTime; +} + +bool CConf::getFMUseCOS() const +{ + return m_fmUseCOS; +} + +bool CConf::getFMCOSInvert() const +{ + return m_fmCOSInvert; +} + +unsigned int CConf::getFMRFAudioBoost() const +{ + return m_fmRFAudioBoost; +} + +float CConf::getFMMaxDevLevel() const +{ + return m_fmMaxDevLevel; +} + +unsigned int CConf::getFMExtAudioBoost() const +{ + return m_fmExtAudioBoost; +} + bool CConf::getDStarNetworkEnabled() const { return m_dstarNetworkEnabled; @@ -1794,6 +2086,11 @@ bool CConf::getRemoteControlEnabled() const return m_remoteControlEnabled; } +std::string CConf::getRemoteControlAddress() const +{ + return m_remoteControlAddress; +} + unsigned int CConf::getRemoteControlPort() const { return m_remoteControlPort; diff --git a/Conf.h b/Conf.h index c76b202..f1745bc 100644 --- a/Conf.h +++ b/Conf.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 @@ -90,6 +90,7 @@ public: float getModemP25TXLevel() const; float getModemNXDNTXLevel() const; float getModemPOCSAGTXLevel() const; + float getModemFMTXLevel() const; std::string getModemRSSIMappingFile() const; bool getModemTrace() const; bool getModemDebug() const; @@ -154,6 +155,7 @@ public: bool getP25SelfOnly() const; bool getP25OverrideUID() const; bool getP25RemoteGateway() const; + unsigned int getP25TXHang() const; unsigned int getP25ModeHang() const; // The NXDN section @@ -162,12 +164,46 @@ public: unsigned int getNXDNRAN() const; bool getNXDNSelfOnly() const; bool getNXDNRemoteGateway() const; + unsigned int getNXDNTXHang() const; unsigned int getNXDNModeHang() const; // The POCSAG section bool getPOCSAGEnabled() const; unsigned int getPOCSAGFrequency() const; + // The FM Section + bool getFMEnabled() const; + std::string getFMCallsign() const; + unsigned int getFMCallsignSpeed() const; + unsigned int getFMCallsignFrequency() const; + unsigned int getFMCallsignTime() const; + unsigned int getFMCallsignHoldoff() const; + float getFMCallsignHighLevel() const; + float getFMCallsignLowLevel() const; + bool getFMCallsignAtStart() const; + bool getFMCallsignAtEnd() const; + bool getFMCallsignAtLatch() const; + std::string getFMRFAck() const; + std::string getFMExtAck() const; + unsigned int getFMAckSpeed() const; + unsigned int getFMAckFrequency() const; + unsigned int getFMAckMinTime() const; + unsigned int getFMAckDelay() const; + float getFMAckLevel() const; + unsigned int getFMTimeout() const; + float getFMTimeoutLevel() const; + float getFMCTCSSFrequency() const; + unsigned int getFMCTCSSHighThreshold() const; + unsigned int getFMCTCSSLowThreshold() const; + float getFMCTCSSLevel() const; + unsigned int getFMKerchunkTime() const; + unsigned int getFMHangTime() const; + bool getFMUseCOS() const; + bool getFMCOSInvert() const; + unsigned int getFMRFAudioBoost() const; + float getFMMaxDevLevel() const; + unsigned int getFMExtAudioBoost() const; + // The D-Star Network section bool getDStarNetworkEnabled() const; std::string getDStarGatewayAddress() const; @@ -276,6 +312,7 @@ public: // The Remote Control section bool getRemoteControlEnabled() const; + std::string getRemoteControlAddress() const; unsigned int getRemoteControlPort() const; private: @@ -333,6 +370,7 @@ private: float m_modemP25TXLevel; float m_modemNXDNTXLevel; float m_modemPOCSAGTXLevel; + float m_modemFMTXLevel; std::string m_modemRSSIMappingFile; bool m_modemTrace; bool m_modemDebug; @@ -391,6 +429,7 @@ private: bool m_p25SelfOnly; bool m_p25OverrideUID; bool m_p25RemoteGateway; + unsigned int m_p25TXHang; unsigned int m_p25ModeHang; bool m_nxdnEnabled; @@ -398,11 +437,44 @@ private: unsigned int m_nxdnRAN; bool m_nxdnSelfOnly; bool m_nxdnRemoteGateway; + unsigned int m_nxdnTXHang; unsigned int m_nxdnModeHang; bool m_pocsagEnabled; unsigned int m_pocsagFrequency; + bool m_fmEnabled; + std::string m_fmCallsign; + unsigned int m_fmCallsignSpeed; + unsigned int m_fmCallsignFrequency; + unsigned int m_fmCallsignTime; + unsigned int m_fmCallsignHoldoff; + float m_fmCallsignHighLevel; + float m_fmCallsignLowLevel; + bool m_fmCallsignAtStart; + bool m_fmCallsignAtEnd; + bool m_fmCallsignAtLatch; + std::string m_fmRFAck; + std::string m_fmExtAck; + unsigned int m_fmAckSpeed; + unsigned int m_fmAckFrequency; + unsigned int m_fmAckMinTime; + unsigned int m_fmAckDelay; + float m_fmAckLevel; + unsigned int m_fmTimeout; + float m_fmTimeoutLevel; + float m_fmCTCSSFrequency; + unsigned int m_fmCTCSSHighThreshold; + unsigned int m_fmCTCSSLowThreshold; + float m_fmCTCSSLevel; + unsigned int m_fmKerchunkTime; + unsigned int m_fmHangTime; + bool m_fmUseCOS; + bool m_fmCOSInvert; + unsigned int m_fmRFAudioBoost; + float m_fmMaxDevLevel; + unsigned int m_fmExtAudioBoost; + bool m_dstarNetworkEnabled; std::string m_dstarGatewayAddress; unsigned int m_dstarGatewayPort; @@ -497,6 +569,7 @@ private: unsigned int m_mobileGPSPort; bool m_remoteControlEnabled; + std::string m_remoteControlAddress; unsigned int m_remoteControlPort; }; diff --git a/DMRNetwork.cpp b/DMRNetwork.cpp index b2aedb5..91ae0a4 100644 --- a/DMRNetwork.cpp +++ b/DMRNetwork.cpp @@ -36,6 +36,7 @@ const unsigned int HOMEBREW_DATA_PACKET_LENGTH = 55U; CDMRNetwork::CDMRNetwork(const std::string& address, unsigned int port, unsigned int local, unsigned int id, const std::string& password, bool duplex, const char* version, bool debug, bool slot1, bool slot2, HW_TYPE hwType) : m_addressStr(address), m_address(), +m_addrlen(), m_port(port), m_id(NULL), m_password(password), @@ -73,7 +74,7 @@ m_beacon(false) assert(id > 1000U); assert(!password.empty()); - m_address = CUDPSocket::lookup(address); + CUDPSocket::lookup(m_addressStr, m_port, m_address, m_addrlen); m_buffer = new unsigned char[BUFFER_LENGTH]; m_salt = new unsigned char[sizeof(uint32_t)]; @@ -124,8 +125,8 @@ bool CDMRNetwork::open() { LogMessage("DMR, Opening DMR Network"); - if (m_address.s_addr == INADDR_NONE) - m_address = CUDPSocket::lookup(m_addressStr); + if (CUDPSocket::isnone(m_address)) + CUDPSocket::lookup(m_addressStr, m_port, m_address, m_addrlen); m_status = WAITING_CONNECT; m_timeoutTimer.stop(); @@ -361,7 +362,7 @@ void CDMRNetwork::clock(unsigned int ms) if (m_status == WAITING_CONNECT) { m_retryTimer.clock(ms); if (m_retryTimer.isRunning() && m_retryTimer.hasExpired()) { - bool ret = m_socket.open(); + bool ret = m_socket.open(m_address.ss_family); if (ret) { ret = writeLogin(); if (!ret) @@ -377,9 +378,9 @@ void CDMRNetwork::clock(unsigned int ms) return; } - in_addr address; - unsigned int port; - int length = m_socket.read(m_buffer, BUFFER_LENGTH, address, port); + sockaddr_storage address; + unsigned int addrlen; + int length = m_socket.read(m_buffer, BUFFER_LENGTH, address, addrlen); if (length < 0) { LogError("DMR, Socket has failed, retrying connection to the master"); close(); @@ -390,7 +391,7 @@ void CDMRNetwork::clock(unsigned int ms) // if (m_debug && length > 0) // CUtils::dump(1U, "Network Received", m_buffer, length); - if (length > 0 && m_address.s_addr == address.s_addr && m_port == port) { + if (length > 0 && CUDPSocket::match(m_address, address)) { if (::memcmp(m_buffer, "DMRD", 4U) == 0) { if (m_enabled) { if (m_debug) @@ -663,7 +664,7 @@ bool CDMRNetwork::write(const unsigned char* data, unsigned int length) // if (m_debug) // CUtils::dump(1U, "Network Transmitted", data, length); - bool ret = m_socket.write(data, length, m_address, m_port); + bool ret = m_socket.write(data, length, m_address, m_addrlen); if (!ret) { LogError("DMR, Socket has failed when writing data to the master, retrying connection"); m_socket.close(); diff --git a/DMRNetwork.h b/DMRNetwork.h index 9d1c52e..96f1074 100644 --- a/DMRNetwork.h +++ b/DMRNetwork.h @@ -60,7 +60,8 @@ public: private: std::string m_addressStr; - in_addr m_address; + sockaddr_storage m_address; + unsigned int m_addrlen; unsigned int m_port; uint8_t* m_id; std::string m_password; diff --git a/DStarNetwork.cpp b/DStarNetwork.cpp index de0af69..072b7cf 100644 --- a/DStarNetwork.cpp +++ b/DStarNetwork.cpp @@ -33,7 +33,7 @@ const unsigned int BUFFER_LENGTH = 100U; CDStarNetwork::CDStarNetwork(const std::string& gatewayAddress, unsigned int gatewayPort, unsigned int localPort, bool duplex, const char* version, bool debug) : m_socket(localPort), m_address(), -m_port(gatewayPort), +m_addrlen(), m_duplex(duplex), m_version(version), m_debug(debug), @@ -46,7 +46,7 @@ m_pollTimer(1000U, 60U), m_linkStatus(LS_NONE), m_linkReflector(NULL) { - m_address = CUDPSocket::lookup(gatewayAddress); + CUDPSocket::lookup(gatewayAddress, gatewayPort, m_address, m_addrlen); m_linkReflector = new unsigned char[DSTAR_LONG_CALLSIGN_LENGTH]; @@ -63,12 +63,12 @@ bool CDStarNetwork::open() { LogMessage("Opening D-Star network connection"); - if (m_address.s_addr == INADDR_NONE) + if (CUDPSocket::isnone(m_address)) return false; m_pollTimer.start(); - return m_socket.open(); + return m_socket.open(m_address.ss_family); } bool CDStarNetwork::writeHeader(const unsigned char* header, unsigned int length, bool busy) @@ -100,7 +100,7 @@ bool CDStarNetwork::writeHeader(const unsigned char* header, unsigned int length CUtils::dump(1U, "D-Star Network Header Sent", buffer, 49U); for (unsigned int i = 0U; i < 2U; i++) { - bool ret = m_socket.write(buffer, 49U, m_address, m_port); + bool ret = m_socket.write(buffer, 49U, m_address, m_addrlen); if (!ret) return false; } @@ -143,7 +143,7 @@ bool CDStarNetwork::writeData(const unsigned char* data, unsigned int length, un if (m_debug) CUtils::dump(1U, "D-Star Network Data Sent", buffer, length + 9U); - return m_socket.write(buffer, length + 9U, m_address, m_port); + return m_socket.write(buffer, length + 9U, m_address, m_addrlen); } bool CDStarNetwork::writePoll(const char* text) @@ -167,7 +167,7 @@ bool CDStarNetwork::writePoll(const char* text) // if (m_debug) // CUtils::dump(1U, "D-Star Network Poll Sent", buffer, 6U + length); - return m_socket.write(buffer, 6U + length, m_address, m_port); + return m_socket.write(buffer, 6U + length, m_address, m_addrlen); } void CDStarNetwork::clock(unsigned int ms) @@ -192,18 +192,12 @@ void CDStarNetwork::clock(unsigned int ms) unsigned char buffer[BUFFER_LENGTH]; - in_addr address; - unsigned int port; - int length = m_socket.read(buffer, BUFFER_LENGTH, address, port); - if (length <= 0) + 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; - // Check if the data is for us - if (m_address.s_addr != address.s_addr || m_port != port) { - LogMessage("D-Star packet received from an invalid source, %08X != %08X and/or %u != %u", m_address.s_addr, address.s_addr, m_port, port); - return; - } - // Invalid packet type? if (::memcmp(buffer, "DSRP", 4U) != 0) return; diff --git a/DStarNetwork.h b/DStarNetwork.h index aeebbbf..6f96880 100644 --- a/DStarNetwork.h +++ b/DStarNetwork.h @@ -51,8 +51,8 @@ public: private: CUDPSocket m_socket; - in_addr m_address; - unsigned int m_port; + sockaddr_storage m_address; + unsigned int m_addrlen; bool m_duplex; const char* m_version; bool m_debug; diff --git a/Defines.h b/Defines.h index 5c7fe76..18c103e 100644 --- a/Defines.h +++ b/Defines.h @@ -26,6 +26,9 @@ const unsigned char MODE_YSF = 3U; const unsigned char MODE_P25 = 4U; const unsigned char MODE_NXDN = 5U; const unsigned char MODE_POCSAG = 6U; + +const unsigned char MODE_FM = 10U; + const unsigned char MODE_CW = 98U; const unsigned char MODE_LOCKOUT = 99U; const unsigned char MODE_ERROR = 100U; diff --git a/Display.cpp b/Display.cpp index 5a74747..0b47b64 100644 --- a/Display.cpp +++ b/Display.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016,2017,2018 by Jonathan Naylor G4KLX + * Copyright (C) 2016,2017,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 @@ -101,6 +101,17 @@ void CDisplay::setQuit() setQuitInt(); } +void CDisplay::setFM() +{ + m_timer1.stop(); + m_timer2.stop(); + + m_mode1 = MODE_FM; + m_mode2 = MODE_FM; + + setFMInt(); +} + void CDisplay::writeDStar(const char* my1, const char* my2, const char* your, const char* type, const char* reflector) { assert(my1 != NULL); @@ -190,6 +201,7 @@ void CDisplay::writeDMRBER(unsigned int slotNo, float ber) { writeDMRBERInt(slotNo, ber); } + void CDisplay::clearDMR(unsigned int slotNo) { if (slotNo == 1U) { diff --git a/Display.h b/Display.h index 74fa25b..17caa41 100644 --- a/Display.h +++ b/Display.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016,2017,2018 by Jonathan Naylor G4KLX + * Copyright (C) 2016,2017,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 @@ -42,6 +42,7 @@ public: void setLockout(); void setError(const char* text); void setQuit(); + void setFM(); void writeDStar(const char* my1, const char* my2, const char* your, const char* type, const char* reflector); void writeDStarRSSI(unsigned char rssi); @@ -87,6 +88,7 @@ protected: virtual void setLockoutInt() = 0; virtual void setErrorInt(const char* text) = 0; virtual void setQuitInt() = 0; + virtual void setFMInt() = 0; virtual void writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector) = 0; virtual void writeDStarRSSIInt(unsigned char rssi); diff --git a/HD44780.cpp b/HD44780.cpp index 970f174..32f15fb 100644 --- a/HD44780.cpp +++ b/HD44780.cpp @@ -399,6 +399,37 @@ void CHD44780::setQuitInt() m_dmr = false; } +void CHD44780::setFMInt() +{ + m_clockDisplayTimer.stop(); + ::lcdClear(m_fd); + +#ifdef ADAFRUIT_DISPLAY + adafruitLCDColour(AC_WHITE); +#endif + + if (m_pwm) { + if (m_pwmPin != 1U) + ::softPwmWrite(m_pwmPin, m_pwmDim); + else + ::pwmWrite(m_pwmPin, (m_pwmDim / 100) * 1024); + } + + // Print callsign and ID at on top row for all screen sizes + ::lcdPosition(m_fd, 0, 0); + ::lcdPrintf(m_fd, "%-6s", m_callsign.c_str()); + ::lcdPosition(m_fd, m_cols - 7, 0); + ::lcdPrintf(m_fd, "%7u", m_dmrid); + + // Print MMDVM and Idle on bottom row for all screen sizes + ::lcdPosition(m_fd, 0, m_rows - 1); + ::lcdPuts(m_fd, "MMDVM"); + ::lcdPosition(m_fd, m_cols - 4, m_rows - 1); + ::lcdPuts(m_fd, "FM"); // Gets overwritten by clock on 2 line screen + + m_dmr = false; +} + void CHD44780::writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector) { assert(my1 != NULL); diff --git a/HD44780.h b/HD44780.h index 6160482..18c036e 100644 --- a/HD44780.h +++ b/HD44780.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016,2017,2018 by Jonathan Naylor G4KLX & Tony Corbett G0WFV + * Copyright (C) 2016,2017,2018,2020 by Jonathan Naylor G4KLX & Tony Corbett G0WFV * * 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 @@ -101,6 +101,7 @@ protected: virtual void setErrorInt(const char* text); virtual void setLockoutInt(); virtual void setQuitInt(); + virtual void setFMInt(); virtual void writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector); virtual void writeDStarRSSIInt(unsigned char rssi); diff --git a/LCDproc.cpp b/LCDproc.cpp index 8ef2721..2da21d7 100644 --- a/LCDproc.cpp +++ b/LCDproc.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2016,2017,2018 by Tony Corbett G0WFV - * 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 @@ -121,44 +121,53 @@ CLCDproc::~CLCDproc() bool CLCDproc::open() { - const char *server; - unsigned int port, localPort; - struct sockaddr_in serverAddress, clientAddress; - struct hostent *h; + int err; + unsigned int addrlen; + std::string port, localPort; + struct sockaddr_storage serverAddress, clientAddress; + struct addrinfo hints, *res; - server = m_address.c_str(); - port = m_port; - localPort = m_localPort; + port = std::to_string(m_port); + localPort = std::to_string(m_localPort); + memset(&hints, 0, sizeof(hints)); + /* Lookup the hostname address */ + hints.ai_flags = AI_NUMERICSERV; + hints.ai_socktype = SOCK_STREAM; + err = getaddrinfo(m_address.c_str(), port.c_str(), &hints, &res); + if (err) { + LogError("LCDproc, cannot lookup server"); + return false; + } + memcpy(&serverAddress, res->ai_addr, addrlen = res->ai_addrlen); + freeaddrinfo(res); + + /* Lookup the client address (random port - need to specify manual port from ini file) */ + hints.ai_flags = AI_NUMERICSERV | AI_PASSIVE; + hints.ai_family = serverAddress.ss_family; + err = getaddrinfo(NULL, localPort.c_str(), &hints, &res); + if (err) { + LogError("LCDproc, cannot lookup client"); + return false; + } + memcpy(&clientAddress, res->ai_addr, res->ai_addrlen); + freeaddrinfo(res); /* Create TCP socket */ - m_socketfd = socket(AF_INET, SOCK_STREAM, 0); + m_socketfd = socket(clientAddress.ss_family, SOCK_STREAM, 0); if (m_socketfd == -1) { LogError("LCDproc, failed to create socket"); return false; } - /* Sets client address (random port - need to specify manual port from ini file?) */ - clientAddress.sin_family = AF_INET; - clientAddress.sin_addr.s_addr = htonl(INADDR_ANY); - //clientAddress.sin_port = htons(0); - clientAddress.sin_port = htons(localPort); - /* Bind the address to the socket */ - if (bind(m_socketfd, (struct sockaddr *)&clientAddress, sizeof(clientAddress)) == -1) { + if (bind(m_socketfd, (struct sockaddr *)&clientAddress, addrlen) == -1) { LogError("LCDproc, error whilst binding address"); return false; } - /* Lookup the hostname address */ - h = gethostbyname(server); - - /* Sets server address */ - serverAddress.sin_family = h->h_addrtype; - memcpy((char*)&serverAddress.sin_addr.s_addr, h->h_addr_list[0], h->h_length); - serverAddress.sin_port = htons(port); - - if (connect(m_socketfd, (struct sockaddr * )&serverAddress, sizeof(serverAddress))==-1) { + /* Connect to server */ + if (connect(m_socketfd, (struct sockaddr *)&serverAddress, addrlen) == -1) { LogError("LCDproc, cannot connect to server"); return false; } @@ -241,6 +250,23 @@ void CLCDproc::setQuitInt() m_dmr = false; } +void CLCDproc::setFMInt() +{ + m_clockDisplayTimer.stop(); // Stop the clock display + + if (m_screensDefined) { + socketPrintf(m_socketfd, "screen_set DStar -priority hidden"); + socketPrintf(m_socketfd, "screen_set DMR -priority hidden"); + socketPrintf(m_socketfd, "screen_set YSF -priority hidden"); + socketPrintf(m_socketfd, "screen_set P25 -priority hidden"); + socketPrintf(m_socketfd, "screen_set NXDN -priority hidden"); + socketPrintf(m_socketfd, "widget_set Status Status %u %u FM", m_cols - 6, m_rows); + socketPrintf(m_socketfd, "output 0"); // Clear all LEDs + } + + m_dmr = false; +} + void CLCDproc::writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector) { assert(my1 != NULL); @@ -294,7 +320,7 @@ void CLCDproc::clearDStarInt() { m_clockDisplayTimer.stop(); // Stop the clock display - socketPrintf(m_socketfd, "widget_set DStar Line2 1 2 15 2 h 3 Listening"); + socketPrintf(m_socketfd, "widget_set DStar Line2 1 2 15 2 h 3 \"Listening\""); socketPrintf(m_socketfd, "widget_set DStar Line3 1 3 15 3 h 3 \"\""); socketPrintf(m_socketfd, "widget_set DStar Line4 1 4 15 4 h 3 \"\""); socketPrintf(m_socketfd, "output 8"); // Set LED4 color green @@ -387,7 +413,7 @@ void CLCDproc::clearDMRInt(unsigned int slotNo) socketPrintf(m_socketfd, "widget_set DMR Slot2RSSI %u %u %*.s", (m_cols / 2) + 1, 4, m_cols / 2, " "); } } else { - socketPrintf(m_socketfd, "widget_set DMR Slot1 1 2 15 2 h 3 Listening"); + socketPrintf(m_socketfd, "widget_set DMR Slot1 1 2 15 2 h 3 \"Listening\""); socketPrintf(m_socketfd, "widget_set DMR Slot2 1 3 15 3 h 3 \"\""); socketPrintf(m_socketfd, "widget_set DMR Slot2RSSI %u %u %*.s", (m_cols / 2) + 1, 4, m_cols / 2, " "); } @@ -435,7 +461,7 @@ void CLCDproc::clearFusionInt() { m_clockDisplayTimer.stop(); // Stop the clock display - socketPrintf(m_socketfd, "widget_set YSF Line2 1 2 15 2 h 3 Listening"); + socketPrintf(m_socketfd, "widget_set YSF Line2 1 2 15 2 h 3 \"Listening\""); socketPrintf(m_socketfd, "widget_set YSF Line3 1 3 15 3 h 3 \"\""); socketPrintf(m_socketfd, "widget_set YSF Line4 1 4 15 4 h 3 \"\""); socketPrintf(m_socketfd, "output 4"); // Set LED3 color green @@ -480,7 +506,7 @@ void CLCDproc::clearP25Int() { m_clockDisplayTimer.stop(); // Stop the clock display - socketPrintf(m_socketfd, "widget_set P25 Line2 1 2 15 2 h 3 Listening"); + socketPrintf(m_socketfd, "widget_set P25 Line2 1 2 15 2 h 3 \"Listening\""); socketPrintf(m_socketfd, "widget_set P25 Line3 1 3 15 3 h 3 \"\""); socketPrintf(m_socketfd, "widget_set P25 Line4 1 4 15 4 h 3 \"\""); socketPrintf(m_socketfd, "output 2"); // Set LED2 color green @@ -525,7 +551,7 @@ void CLCDproc::clearNXDNInt() { m_clockDisplayTimer.stop(); // Stop the clock display - socketPrintf(m_socketfd, "widget_set NXDN Line2 1 2 15 2 h 3 Listening"); + socketPrintf(m_socketfd, "widget_set NXDN Line2 1 2 15 2 h 3 \"Listening\""); socketPrintf(m_socketfd, "widget_set NXDN Line3 1 3 15 3 h 3 \"\""); socketPrintf(m_socketfd, "widget_set NXDN Line4 1 4 15 4 h 3 \"\""); socketPrintf(m_socketfd, "output 16"); // Set LED5 color green @@ -752,7 +778,7 @@ void CLCDproc::defineScreens() socketPrintf(m_socketfd, "widget_add DStar Line4 scroller"); /* Do we need to pre-populate the values?? - socketPrintf(m_socketfd, "widget_set DStar Line2 1 2 15 2 h 3 Listening"); + socketPrintf(m_socketfd, "widget_set DStar Line2 1 2 15 2 h 3 \"Listening\""); socketPrintf(m_socketfd, "widget_set DStar Line3 1 3 15 3 h 3 \"\""); socketPrintf(m_socketfd, "widget_set DStar Line4 1 4 15 4 h 3 \"\""); */ @@ -773,8 +799,8 @@ void CLCDproc::defineScreens() /* Do we need to pre-populate the values?? socketPrintf(m_socketfd, "widget_set DMR Slot1_ 1 %u 1", m_rows / 2); socketPrintf(m_socketfd, "widget_set DMR Slot2_ 1 %u 2", m_rows / 2 + 1); - socketPrintf(m_socketfd, "widget_set DMR Slot1 3 1 15 1 h 3 Listening"); - socketPrintf(m_socketfd, "widget_set DMR Slot2 3 2 15 2 h 3 Listening"); + socketPrintf(m_socketfd, "widget_set DMR Slot1 3 1 15 1 h 3 \"Listening\""); + socketPrintf(m_socketfd, "widget_set DMR Slot2 3 2 15 2 h 3 \"Listening\""); */ // The YSF Screen @@ -788,7 +814,7 @@ void CLCDproc::defineScreens() socketPrintf(m_socketfd, "widget_add YSF Line4 scroller"); /* Do we need to pre-populate the values?? - socketPrintf(m_socketfd, "widget_set YSF Line2 2 1 15 1 h 3 Listening"); + socketPrintf(m_socketfd, "widget_set YSF Line2 2 1 15 1 h 3 \"Listening\""); socketPrintf(m_socketfd, "widget_set YSF Line3 3 1 15 1 h 3 \" \""); socketPrintf(m_socketfd, "widget_set YSF Line4 4 2 15 2 h 3 \" \""); */ @@ -804,7 +830,7 @@ void CLCDproc::defineScreens() socketPrintf(m_socketfd, "widget_add P25 Line4 scroller"); /* Do we need to pre-populate the values?? - socketPrintf(m_socketfd, "widget_set P25 Line3 2 1 15 1 h 3 Listening"); + socketPrintf(m_socketfd, "widget_set P25 Line3 2 1 15 1 h 3 \"Listening\""); socketPrintf(m_socketfd, "widget_set P25 Line3 3 1 15 1 h 3 \" \""); socketPrintf(m_socketfd, "widget_set P25 Line4 4 2 15 2 h 3 \" \""); */ @@ -820,7 +846,7 @@ void CLCDproc::defineScreens() socketPrintf(m_socketfd, "widget_add NXDN Line4 scroller"); /* Do we need to pre-populate the values?? - socketPrintf(m_socketfd, "widget_set NXDN Line3 2 1 15 1 h 3 Listening"); + socketPrintf(m_socketfd, "widget_set NXDN Line3 2 1 15 1 h 3 \"Listening\""); socketPrintf(m_socketfd, "widget_set NXDN Line3 3 1 15 1 h 3 \" \""); socketPrintf(m_socketfd, "widget_set NXDN Line4 4 2 15 2 h 3 \" \""); */ diff --git a/LCDproc.h b/LCDproc.h index 2554d36..0352251 100644 --- a/LCDproc.h +++ b/LCDproc.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2016,2017 by Tony Corbett G0WFV - * 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 @@ -40,8 +40,8 @@ protected: virtual void setErrorInt(const char* text); virtual void setLockoutInt(); virtual void setQuitInt(); + virtual void setFMInt(); - virtual void writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector); virtual void writeDStarRSSIInt(unsigned char rssi); virtual void clearDStarInt(); diff --git a/Log.cpp b/Log.cpp index fc37ebf..f600b90 100644 --- a/Log.cpp +++ b/Log.cpp @@ -22,6 +22,7 @@ #include #else #include +#include #endif #include @@ -36,6 +37,7 @@ static std::string m_filePath; static std::string m_fileRoot; static FILE* m_fpLog = NULL; +static bool m_daemon = false; static unsigned int m_displayLevel = 2U; @@ -45,6 +47,8 @@ static char LEVELS[] = " DMIWEF"; static bool LogOpen() { + bool status = false; + if (m_fileLevel == 0U) return true; @@ -68,18 +72,28 @@ static bool LogOpen() ::sprintf(filename, "%s/%s-%04d-%02d-%02d.log", m_filePath.c_str(), m_fileRoot.c_str(), tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday); #endif - m_fpLog = ::fopen(filename, "a+t"); + if ((m_fpLog = ::fopen(filename, "a+t")) != NULL) + { + status = true; + +#if !defined(_WIN32) && !defined(_WIN64) + if (m_daemon) + dup2(fileno(m_fpLog), fileno(stderr)); +#endif + } + m_tm = *tm; - return m_fpLog != NULL; + return status; } -bool LogInitialise(const std::string& filePath, const std::string& fileRoot, unsigned int fileLevel, unsigned int displayLevel) +bool LogInitialise(bool daemon, const std::string& filePath, const std::string& fileRoot, unsigned int fileLevel, unsigned int displayLevel) { m_filePath = filePath; m_fileRoot = fileRoot; m_fileLevel = fileLevel; m_displayLevel = displayLevel; + m_daemon = daemon; return ::LogOpen(); } diff --git a/Log.h b/Log.h index d671ef9..0d00653 100644 --- a/Log.h +++ b/Log.h @@ -30,7 +30,7 @@ extern void Log(unsigned int level, const char* fmt, ...); -extern bool LogInitialise(const std::string& filePath, const std::string& fileRoot, unsigned int fileLevel, unsigned int displayLevel); +extern bool LogInitialise(bool daemon, const std::string& filePath, const std::string& fileRoot, unsigned int fileLevel, unsigned int displayLevel); extern void LogFinalise(); #endif diff --git a/MMDVM.ini b/MMDVM.ini index d6a8d84..e205e69 100644 --- a/MMDVM.ini +++ b/MMDVM.ini @@ -43,7 +43,7 @@ Time=24 [Modem] # Port=/dev/ttyACM0 # Port=/dev/ttyAMA0 -Port=\\.\COM3 +Port=\\.\COM4 Protocol=uart # Address=0x22 TXInvert=1 @@ -65,6 +65,7 @@ RFLevel=100 # P25TXLevel=50 # NXDNTXLevel=50 # POCSAGTXLevel=50 +# FMTXLevel=50 RSSIMappingFile=RSSI.dat Trace=0 Debug=0 @@ -125,6 +126,7 @@ NAC=293 SelfOnly=0 OverrideUIDCheck=0 RemoteGateway=0 +TXHang=5 # ModeHang=10 [NXDN] @@ -132,12 +134,47 @@ Enable=1 RAN=1 SelfOnly=0 RemoteGateway=0 +TXHang=5 # ModeHang=10 [POCSAG] Enable=1 Frequency=439987500 +[FM] +Enable=1 +# Callsign=G4KLX +CallsignSpeed=20 +CallsignFrequency=1000 +CallsignTime=10 +CallsignHoldoff=0 +CallsignHighLevel=50 +CallsignLowLevel=20 +CallsignAtStart=1 +CallsignAtEnd=1 +CallsignAtLatch=0 +RFAck=K +ExtAck=N +AckSpeed=20 +AckFrequency=1750 +AckMinTime=4 +AckDelay=1000 +AckLevel=50 +# Timeout=180 +TimeoutLevel=80 +CTCSSFrequency=88.4 +CTCSSThreshold=30 +# CTCSSHighThreshold=30 +# CTCSSLowThreshold=20 +CTCSSLevel=20 +KerchunkTime=0 +HangTime=7 +UseCOS=1 +COSInvert=0 +RFAudioBoost=1 +MaxDevLevel=90 +ExtAudioBoost=1 + [D-Star Network] Enable=1 GatewayAddress=127.0.0.1 @@ -257,4 +294,5 @@ Port=7834 [Remote Control] Enable=0 +Address=127.0.0.1 Port=7642 diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index 53f6d1f..ba93b6c 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -150,6 +150,7 @@ m_ysfEnabled(false), m_p25Enabled(false), m_nxdnEnabled(false), m_pocsagEnabled(false), +m_fmEnabled(false), m_cwIdTime(0U), m_dmrLookup(NULL), m_nxdnLookup(NULL), @@ -236,7 +237,11 @@ int CMMDVMHost::run() #endif #endif - ret = ::LogInitialise(m_conf.getLogFilePath(), m_conf.getLogFileRoot(), m_conf.getLogFileLevel(), m_conf.getLogDisplayLevel()); +#if !defined(_WIN32) && !defined(_WIN64) + ret = ::LogInitialise(m_daemon, m_conf.getLogFilePath(), m_conf.getLogFileRoot(), m_conf.getLogFileLevel(), m_conf.getLogDisplayLevel()); +#else + ret = ::LogInitialise(false, m_conf.getLogFilePath(), m_conf.getLogFileRoot(), m_conf.getLogFileLevel(), m_conf.getLogDisplayLevel()); +#endif if (!ret) { ::fprintf(stderr, "MMDVMHost: unable to open the log file\n"); return 1; @@ -246,7 +251,6 @@ int CMMDVMHost::run() if (m_daemon) { ::close(STDIN_FILENO); ::close(STDOUT_FILENO); - ::close(STDERR_FILENO); } #endif @@ -316,8 +320,8 @@ int CMMDVMHost::run() return 1; } - in_addr transparentAddress; - unsigned int transparentPort = 0U; + sockaddr_storage transparentAddress; + unsigned int transparentAddrLen; CUDPSocket* transparentSocket = NULL; unsigned int sendFrameType = 0U; @@ -333,11 +337,10 @@ int CMMDVMHost::run() LogInfo(" Local Port: %u", localPort); LogInfo(" Send Frame Type: %u", sendFrameType); - transparentAddress = CUDPSocket::lookup(remoteAddress); - transparentPort = remotePort; + CUDPSocket::lookup(remoteAddress, remotePort, transparentAddress, transparentAddrLen); transparentSocket = new CUDPSocket(localPort); - ret = transparentSocket->open(); + ret = transparentSocket->open(transparentAddress.ss_family); if (!ret) { LogWarning("Could not open the Transparent data socket, disabling"); delete transparentSocket; @@ -546,12 +549,13 @@ int CMMDVMHost::run() } if (m_p25Enabled) { - unsigned int id = m_conf.getP25Id(); - unsigned int nac = m_conf.getP25NAC(); - bool uidOverride = m_conf.getP25OverrideUID(); - bool selfOnly = m_conf.getP25SelfOnly(); - bool remoteGateway = m_conf.getP25RemoteGateway(); - m_p25RFModeHang = m_conf.getP25ModeHang(); + unsigned int id = m_conf.getP25Id(); + unsigned int nac = m_conf.getP25NAC(); + unsigned int txHang = m_conf.getP25TXHang(); + bool uidOverride = m_conf.getP25OverrideUID(); + bool selfOnly = m_conf.getP25SelfOnly(); + bool remoteGateway = m_conf.getP25RemoteGateway(); + m_p25RFModeHang = m_conf.getP25ModeHang(); LogInfo("P25 RF Parameters"); LogInfo(" Id: %u", id); @@ -559,6 +563,7 @@ int CMMDVMHost::run() LogInfo(" UID Override: %s", uidOverride ? "yes" : "no"); LogInfo(" Self Only: %s", selfOnly ? "yes" : "no"); LogInfo(" Remote Gateway: %s", remoteGateway ? "yes" : "no"); + LogInfo(" TX Hang: %us", txHang); LogInfo(" Mode Hang: %us", m_p25RFModeHang); m_p25 = new CP25Control(nac, id, selfOnly, uidOverride, m_p25Network, m_display, m_timeout, m_duplex, m_dmrLookup, remoteGateway, rssi); @@ -576,17 +581,19 @@ int CMMDVMHost::run() m_nxdnLookup = new CNXDNLookup(lookupFile, reloadTime); m_nxdnLookup->read(); - unsigned int id = m_conf.getNXDNId(); - unsigned int ran = m_conf.getNXDNRAN(); - bool selfOnly = m_conf.getNXDNSelfOnly(); - bool remoteGateway = m_conf.getNXDNRemoteGateway(); - m_nxdnRFModeHang = m_conf.getNXDNModeHang(); + unsigned int id = m_conf.getNXDNId(); + unsigned int ran = m_conf.getNXDNRAN(); + bool selfOnly = m_conf.getNXDNSelfOnly(); + bool remoteGateway = m_conf.getNXDNRemoteGateway(); + unsigned int txHang = m_conf.getNXDNTXHang(); + m_nxdnRFModeHang = m_conf.getNXDNModeHang(); LogInfo("NXDN RF Parameters"); LogInfo(" Id: %u", id); LogInfo(" RAN: %u", ran); LogInfo(" Self Only: %s", selfOnly ? "yes" : "no"); LogInfo(" Remote Gateway: %s", remoteGateway ? "yes" : "no"); + LogInfo(" TX Hang: %us", txHang); LogInfo(" Mode Hang: %us", m_nxdnRFModeHang); m_nxdn = new CNXDNControl(ran, id, selfOnly, m_nxdnNetwork, m_display, m_timeout, m_duplex, remoteGateway, m_nxdnLookup, rssi); @@ -602,17 +609,20 @@ int CMMDVMHost::run() m_pocsag = new CPOCSAGControl(m_pocsagNetwork, m_display); - pocsagTimer.start(); + if (m_pocsagNetwork != NULL) + pocsagTimer.start(); } bool remoteControlEnabled = m_conf.getRemoteControlEnabled(); if (remoteControlEnabled) { + std::string address = m_conf.getRemoteControlAddress(); unsigned int port = m_conf.getRemoteControlPort(); LogInfo("Remote Control Parameters"); + LogInfo(" Address: %s", address.c_str()); LogInfo(" Port: %u", port); - m_remoteControl = new CRemoteControl(port); + m_remoteControl = new CRemoteControl(address, port); ret = m_remoteControl->open(); if (!ret) { @@ -642,6 +652,12 @@ int CMMDVMHost::run() else if (!error && m_mode == MODE_ERROR) setMode(MODE_IDLE); + unsigned char mode = m_modem->getMode(); + if (mode == MODE_FM && m_mode != MODE_FM) + setMode(mode); + else if (mode != MODE_FM && m_mode == MODE_FM) + setMode(mode); + if (m_ump != NULL) { bool tx = m_modem->hasTX(); m_ump->setTX(tx); @@ -793,7 +809,7 @@ int CMMDVMHost::run() len = m_modem->readTransparentData(data); if (transparentSocket != NULL && len > 0U) - transparentSocket->write(data, len, transparentAddress, transparentPort); + transparentSocket->write(data, len, transparentAddress, transparentAddrLen); if (!m_fixedMode) { if (m_modeTimer.isRunning() && m_modeTimer.hasExpired()) @@ -942,9 +958,9 @@ int CMMDVMHost::run() } if (transparentSocket != NULL) { - in_addr address; - unsigned int port = 0U; - len = transparentSocket->read(data, 200U, address, port); + sockaddr_storage address; + unsigned int addrlen; + len = transparentSocket->read(data, 200U, address, addrlen); if (len > 0U) m_modem->writeTransparentData(data, len); } @@ -1149,11 +1165,14 @@ bool CMMDVMHost::createModem() float p25TXLevel = m_conf.getModemP25TXLevel(); float nxdnTXLevel = m_conf.getModemNXDNTXLevel(); float pocsagTXLevel = m_conf.getModemPOCSAGTXLevel(); + float fmTXLevel = m_conf.getModemFMTXLevel(); bool trace = m_conf.getModemTrace(); bool debug = m_conf.getModemDebug(); unsigned int colorCode = m_conf.getDMRColorCode(); bool lowDeviation = m_conf.getFusionLowDeviation(); - unsigned int txHang = m_conf.getFusionTXHang(); + unsigned int ysfTXHang = m_conf.getFusionTXHang(); + unsigned int p25TXHang = m_conf.getP25TXHang(); + unsigned int nxdnTXHang = m_conf.getNXDNTXHang(); unsigned int rxFrequency = m_conf.getRXFrequency(); unsigned int txFrequency = m_conf.getTXFrequency(); unsigned int pocsagFrequency = m_conf.getPOCSAGFrequency(); @@ -1186,16 +1205,87 @@ bool CMMDVMHost::createModem() LogInfo(" P25 TX Level: %.1f%%", p25TXLevel); LogInfo(" NXDN TX Level: %.1f%%", nxdnTXLevel); LogInfo(" POCSAG TX Level: %.1f%%", pocsagTXLevel); - LogInfo(" RX Frequency: %uHz (%uHz)", rxFrequency, rxFrequency + rxOffset); + LogInfo(" FM TX Level: %.1f%%", fmTXLevel); LogInfo(" TX Frequency: %uHz (%uHz)", txFrequency, txFrequency + txOffset); m_modem = CModem::createModem(port, m_duplex, rxInvert, txInvert, pttInvert, txDelay, dmrDelay, trace, debug); m_modem->setSerialParams(protocol,address); - m_modem->setModeParams(m_dstarEnabled, m_dmrEnabled, m_ysfEnabled, m_p25Enabled, m_nxdnEnabled, m_pocsagEnabled); - m_modem->setLevels(rxLevel, cwIdTXLevel, dstarTXLevel, dmrTXLevel, ysfTXLevel, p25TXLevel, nxdnTXLevel, pocsagTXLevel); + m_modem->setModeParams(m_dstarEnabled, m_dmrEnabled, m_ysfEnabled, m_p25Enabled, m_nxdnEnabled, m_pocsagEnabled, m_fmEnabled); + m_modem->setLevels(rxLevel, cwIdTXLevel, dstarTXLevel, dmrTXLevel, ysfTXLevel, p25TXLevel, nxdnTXLevel, pocsagTXLevel, fmTXLevel); m_modem->setRFParams(rxFrequency, rxOffset, txFrequency, txOffset, txDCOffset, rxDCOffset, rfLevel, pocsagFrequency); m_modem->setDMRParams(colorCode); - m_modem->setYSFParams(lowDeviation, txHang); + m_modem->setYSFParams(lowDeviation, ysfTXHang); + m_modem->setP25Params(p25TXHang); + m_modem->setNXDNParams(nxdnTXHang); + + if (m_fmEnabled) { + std::string callsign = m_conf.getFMCallsign(); + unsigned int callsignSpeed = m_conf.getFMCallsignSpeed(); + unsigned int callsignFrequency = m_conf.getFMCallsignFrequency(); + unsigned int callsignTime = m_conf.getFMCallsignTime(); + unsigned int callsignHoldoff = m_conf.getFMCallsignHoldoff(); + float callsignHighLevel = m_conf.getFMCallsignHighLevel(); + float callsignLowLevel = m_conf.getFMCallsignLowLevel(); + bool callsignAtStart = m_conf.getFMCallsignAtStart(); + bool callsignAtEnd = m_conf.getFMCallsignAtEnd(); + bool callsignAtLatch = m_conf.getFMCallsignAtLatch(); + std::string rfAck = m_conf.getFMRFAck(); + std::string extAck = m_conf.getFMExtAck(); + unsigned int ackSpeed = m_conf.getFMAckSpeed(); + unsigned int ackFrequency = m_conf.getFMAckFrequency(); + unsigned int ackMinTime = m_conf.getFMAckMinTime(); + unsigned int ackDelay = m_conf.getFMAckDelay(); + float ackLevel = m_conf.getFMAckLevel(); + unsigned int timeout = m_conf.getFMTimeout(); + float timeoutLevel = m_conf.getFMTimeoutLevel(); + float ctcssFrequency = m_conf.getFMCTCSSFrequency(); + unsigned int ctcssHighThreshold = m_conf.getFMCTCSSHighThreshold(); + unsigned int ctcssLowThreshold = m_conf.getFMCTCSSLowThreshold(); + float ctcssLevel = m_conf.getFMCTCSSLevel(); + unsigned int kerchunkTime = m_conf.getFMKerchunkTime(); + unsigned int hangTime = m_conf.getFMHangTime(); + bool useCOS = m_conf.getFMUseCOS(); + bool cosInvert = m_conf.getFMCOSInvert(); + unsigned int rfAudioBoost = m_conf.getFMRFAudioBoost(); + float maxDevLevel = m_conf.getFMMaxDevLevel(); + unsigned int extAudioBoost = m_conf.getFMExtAudioBoost(); + + LogInfo("FM Parameters"); + LogInfo(" Callsign: %s", callsign.c_str()); + LogInfo(" Callsign Speed: %uWPM", callsignSpeed); + LogInfo(" Callsign Frequency: %uHz", callsignFrequency); + LogInfo(" Callsign Time: %umins", callsignTime); + LogInfo(" Callsign Holdoff: 1/%u", callsignHoldoff); + LogInfo(" Callsign High Level: %.1f%%", callsignHighLevel); + LogInfo(" Callsign Low Level: %.1f%%", callsignLowLevel); + LogInfo(" Callsign At Start: %s", callsignAtStart ? "yes" : "no"); + LogInfo(" Callsign At End: %s", callsignAtEnd ? "yes" : "no"); + LogInfo(" Callsign At Latch: %s", callsignAtLatch ? "yes" : "no"); + LogInfo(" RF Ack: %s", rfAck.c_str()); + // LogInfo(" Ext. Ack: %s", extAck.c_str()); + LogInfo(" Ack Speed: %uWPM", ackSpeed); + LogInfo(" Ack Frequency: %uHz", ackFrequency); + LogInfo(" Ack Min Time: %us", ackMinTime); + LogInfo(" Ack Delay: %ums", ackDelay); + LogInfo(" Ack Level: %.1f%%", ackLevel); + LogInfo(" Timeout: %us", timeout); + LogInfo(" Timeout Level: %.1f%%", timeoutLevel); + LogInfo(" CTCSS Frequency: %.1fHz", ctcssFrequency); + LogInfo(" CTCSS High Threshold: %u", ctcssHighThreshold); + LogInfo(" CTCSS Low Threshold: %u", ctcssLowThreshold); + LogInfo(" CTCSS Level: %.1f%%", ctcssLevel); + LogInfo(" Kerchunk Time: %us", kerchunkTime); + LogInfo(" Hang Time: %us", hangTime); + LogInfo(" Use COS: %s", useCOS ? "yes" : "no"); + LogInfo(" COS Invert: %s", cosInvert ? "yes" : "no"); + LogInfo(" RF Audio Boost: x%u", rfAudioBoost); + LogInfo(" Max. Deviation Level: %.1f%%", maxDevLevel); + // LogInfo(" Ext. Audio Boost: x%u", extAudioBoost); + + m_modem->setFMCallsignParams(callsign, callsignSpeed, callsignFrequency, callsignTime, callsignHoldoff, callsignHighLevel, callsignLowLevel, callsignAtStart, callsignAtEnd, callsignAtLatch); + m_modem->setFMAckParams(rfAck, ackSpeed, ackFrequency, ackMinTime, ackDelay, ackLevel); + m_modem->setFMMiscParams(timeout, timeoutLevel, ctcssFrequency, ctcssHighThreshold, ctcssLowThreshold, ctcssLevel, kerchunkTime, hangTime, useCOS, cosInvert, rfAudioBoost, maxDevLevel); + } bool ret = m_modem->open(); if (!ret) { @@ -1450,6 +1540,7 @@ void CMMDVMHost::readParams() m_p25Enabled = m_conf.getP25Enabled(); m_nxdnEnabled = m_conf.getNXDNEnabled(); m_pocsagEnabled = m_conf.getPOCSAGEnabled(); + m_fmEnabled = m_conf.getFMEnabled(); m_duplex = m_conf.getDuplex(); m_callsign = m_conf.getCallsign(); m_id = m_conf.getId(); @@ -1466,6 +1557,7 @@ void CMMDVMHost::readParams() LogInfo(" P25: %s", m_p25Enabled ? "enabled" : "disabled"); LogInfo(" NXDN: %s", m_nxdnEnabled ? "enabled" : "disabled"); LogInfo(" POCSAG: %s", m_pocsagEnabled ? "enabled" : "disabled"); + LogInfo(" FM: %s", m_fmEnabled ? "enabled" : "disabled"); } void CMMDVMHost::setMode(unsigned char mode) @@ -1682,8 +1774,45 @@ void CMMDVMHost::setMode(unsigned char mode) createLockFile("POCSAG"); break; + case MODE_FM: + if (m_dstarNetwork != NULL) + m_dstarNetwork->enable(false); + if (m_dmrNetwork != NULL) + m_dmrNetwork->enable(false); + if (m_ysfNetwork != NULL) + m_ysfNetwork->enable(false); + if (m_p25Network != NULL) + m_p25Network->enable(false); + if (m_nxdnNetwork != NULL) + m_nxdnNetwork->enable(false); + if (m_pocsagNetwork != NULL) + m_pocsagNetwork->enable(false); + if (m_dstar != NULL) + m_dstar->enable(false); + if (m_dmr != NULL) + m_dmr->enable(false); + if (m_ysf != NULL) + m_ysf->enable(false); + if (m_p25 != NULL) + m_p25->enable(false); + if (m_nxdn != NULL) + m_nxdn->enable(false); + if (m_pocsag != NULL) + m_pocsag->enable(false); + if (m_mode == MODE_DMR && m_duplex && m_modem->hasTX()) { + m_modem->writeDMRStart(false); + m_dmrTXTimer.stop(); + } + if (m_ump != NULL) + m_ump->setMode(MODE_FM); + m_display->setFM(); + m_mode = MODE_FM; + m_modeTimer.stop(); + m_cwIdTimer.stop(); + createLockFile("FM"); + break; + case MODE_LOCKOUT: - LogMessage("Mode set to Lockout"); if (m_dstarNetwork != NULL) m_dstarNetwork->enable(false); if (m_dmrNetwork != NULL) @@ -1863,6 +1992,58 @@ void CMMDVMHost::remoteControl() if (m_nxdn != NULL) processModeCommand(MODE_NXDN, m_nxdnRFModeHang); break; + case RCD_MODE_FM: + if (m_fmEnabled != false) + processModeCommand(MODE_FM, 0); + break; + case RCD_ENABLE_DSTAR: + if (m_dstar != NULL && m_dstarEnabled==false) + processEnableCommand(m_dstarEnabled, true); + break; + case RCD_ENABLE_DMR: + if (m_dmr != NULL && m_dmrEnabled==false) + processEnableCommand(m_dmrEnabled, true); + break; + case RCD_ENABLE_YSF: + if (m_ysf != NULL && m_ysfEnabled==false) + processEnableCommand(m_ysfEnabled, true); + break; + case RCD_ENABLE_P25: + if (m_p25 != NULL && m_p25Enabled==false) + processEnableCommand(m_p25Enabled, true); + break; + case RCD_ENABLE_NXDN: + if (m_nxdn != NULL && m_nxdnEnabled==false) + processEnableCommand(m_nxdnEnabled, true); + break; + case RCD_ENABLE_FM: + if (m_fmEnabled==false) + processEnableCommand(m_fmEnabled, true); + break; + case RCD_DISABLE_DSTAR: + if (m_dstar != NULL && m_dstarEnabled==true) + processEnableCommand(m_dstarEnabled, false); + break; + case RCD_DISABLE_DMR: + if (m_dmr != NULL && m_dmrEnabled==true) + processEnableCommand(m_dmrEnabled, false); + break; + case RCD_DISABLE_YSF: + if (m_ysf != NULL && m_ysfEnabled==true) + processEnableCommand(m_ysfEnabled, false); + break; + case RCD_DISABLE_P25: + if (m_p25 != NULL && m_p25Enabled==true) + processEnableCommand(m_p25Enabled, false); + break; + case RCD_DISABLE_NXDN: + if (m_nxdn != NULL && m_nxdnEnabled==true) + processEnableCommand(m_nxdnEnabled, false); + break; + case RCD_DISABLE_FM: + if (m_fmEnabled == true) + processEnableCommand(m_fmEnabled, false); + break; case RCD_PAGE: if (m_pocsag != NULL) { unsigned int ric = m_remoteControl->getArgUInt(0U); @@ -1874,6 +2055,18 @@ void CMMDVMHost::remoteControl() } m_pocsag->sendPage(ric, text); } + case RCD_CW: + setMode(MODE_IDLE); // Force the modem to go idle so that we can send the CW text. + if (!m_modem->hasTX()){ + std::string cwtext; + for (unsigned int i = 0U; i < m_remoteControl->getArgCount(); i++) { + if (i > 0U) + cwtext += " "; + cwtext += m_remoteControl->getArgString(i); + } + m_display->writeCW(); + m_modem->sendCWId(cwtext); + } default: break; } @@ -1896,3 +2089,12 @@ void CMMDVMHost::processModeCommand(unsigned char mode, unsigned int timeout) setMode(mode); } + +void CMMDVMHost::processEnableCommand(bool& mode, bool enabled) +{ + LogDebug("Setting mode current=%s new=%s",mode ? "true" : "false",enabled ? "true" : "false"); + mode=enabled; + m_modem->setModeParams(m_dstarEnabled, m_dmrEnabled, m_ysfEnabled, m_p25Enabled, m_nxdnEnabled, m_pocsagEnabled, m_fmEnabled); + if (!m_modem->writeConfig()) + LogError("Cannot write Config to MMDVM"); +} diff --git a/MMDVMHost.h b/MMDVMHost.h index 177989a..17d6786 100644 --- a/MMDVMHost.h +++ b/MMDVMHost.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 @@ -93,6 +93,7 @@ private: bool m_p25Enabled; bool m_nxdnEnabled; bool m_pocsagEnabled; + bool m_fmEnabled; unsigned int m_cwIdTime; CDMRLookup* m_dmrLookup; CNXDNLookup* m_nxdnLookup; @@ -116,6 +117,7 @@ private: void remoteControl(); void processModeCommand(unsigned char mode, unsigned int timeout); + void processEnableCommand(bool& mode, bool enabled); void setMode(unsigned char mode); diff --git a/MMDVMHost.vcxproj b/MMDVMHost.vcxproj index 7b2121c..812c7a4 100644 --- a/MMDVMHost.vcxproj +++ b/MMDVMHost.vcxproj @@ -238,6 +238,8 @@ + + @@ -327,6 +329,8 @@ + + diff --git a/MMDVMHost.vcxproj.filters b/MMDVMHost.vcxproj.filters index 3b299d3..fb8a362 100644 --- a/MMDVMHost.vcxproj.filters +++ b/MMDVMHost.vcxproj.filters @@ -293,6 +293,12 @@ Header Files + + Header Files + + + Header Files + @@ -550,5 +556,11 @@ Source Files + + Source Files + + + Source Files + \ No newline at end of file diff --git a/MobileGPS.cpp b/MobileGPS.cpp index 27721bd..0cb2c3b 100644 --- a/MobileGPS.cpp +++ b/MobileGPS.cpp @@ -26,7 +26,7 @@ CMobileGPS::CMobileGPS(const std::string& address, unsigned int port, CDMRNetwork* network) : m_idTimer(1000U, 60U), m_address(), -m_port(port), +m_addrlen(), m_socket(), m_network(network) { @@ -34,7 +34,7 @@ m_network(network) assert(port > 0U); assert(network != NULL); - m_address = CUDPSocket::lookup(address); + CUDPSocket::lookup(address, port, m_address, m_addrlen); } CMobileGPS::~CMobileGPS() @@ -43,7 +43,7 @@ CMobileGPS::~CMobileGPS() bool CMobileGPS::open() { - bool ret = m_socket.open(); + bool ret = m_socket.open(m_address.ss_family); if (!ret) return false; @@ -71,16 +71,16 @@ void CMobileGPS::close() bool CMobileGPS::pollGPS() { - return m_socket.write((unsigned char*)"MMDVMHost", 9U, m_address, m_port); + 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]; - in_addr address; - unsigned int port; - int ret = m_socket.read(buffer, 200U, address, port); + sockaddr_storage address; + unsigned int addrlen; + int ret = m_socket.read(buffer, 200U, address, addrlen); if (ret <= 0) return; diff --git a/MobileGPS.h b/MobileGPS.h index 8d69572..8384c65 100644 --- a/MobileGPS.h +++ b/MobileGPS.h @@ -51,8 +51,8 @@ public: private: CTimer m_idTimer; - in_addr m_address; - unsigned int m_port; + sockaddr_storage m_address; + unsigned int m_addrlen; CUDPSocket m_socket; CDMRNetwork* m_network; diff --git a/Modem.cpp b/Modem.cpp index 176a11d..93319be 100644 --- a/Modem.cpp +++ b/Modem.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 by Jonathan Naylor G4KLX + * Copyright (C) 2011-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 @@ -76,6 +76,10 @@ const unsigned char MMDVM_NXDN_LOST = 0x41U; const unsigned char MMDVM_POCSAG_DATA = 0x50U; +const unsigned char MMDVM_FM_PARAMS1 = 0x60U; +const unsigned char MMDVM_FM_PARAMS2 = 0x61U; +const unsigned char MMDVM_FM_PARAMS3 = 0x62U; + const unsigned char MMDVM_ACK = 0x70U; const unsigned char MMDVM_NAK = 0x7FU; @@ -100,6 +104,8 @@ m_port(port), m_dmrColorCode(0U), m_ysfLoDev(false), m_ysfTXHang(4U), +m_p25TXHang(5U), +m_nxdnTXHang(5U), m_duplex(duplex), m_rxInvert(rxInvert), m_txInvert(txInvert), @@ -114,6 +120,7 @@ m_ysfTXLevel(0U), m_p25TXLevel(0U), m_nxdnTXLevel(0U), m_pocsagTXLevel(0U), +m_fmTXLevel(0U), m_trace(trace), m_debug(debug), m_rxFrequency(0U), @@ -125,6 +132,7 @@ m_ysfEnabled(false), m_p25Enabled(false), m_nxdnEnabled(false), m_pocsagEnabled(false), +m_fmEnabled(false), m_rxDCOffset(0), m_txDCOffset(0), m_serial(NULL), @@ -161,11 +169,40 @@ m_tx(false), m_cd(false), m_lockout(false), m_error(false), -m_hwType(HWT_UNKNOWN) +m_mode(MODE_IDLE), +m_hwType(HWT_UNKNOWN), +m_fmCallsign(), +m_fmCallsignSpeed(20U), +m_fmCallsignFrequency(1000U), +m_fmCallsignTime(600U), +m_fmCallsignHoldoff(0U), +m_fmCallsignHighLevel(35.0F), +m_fmCallsignLowLevel(15.0F), +m_fmCallsignAtStart(true), +m_fmCallsignAtEnd(true), +m_fmCallsignAtLatch(true), +m_fmRfAck("K"), +m_fmAckSpeed(20U), +m_fmAckFrequency(1750U), +m_fmAckMinTime(4U), +m_fmAckDelay(1000U), +m_fmAckLevel(80.0F), +m_fmTimeout(120U), +m_fmTimeoutLevel(80.0F), +m_fmCtcssFrequency(88.4F), +m_fmCtcssHighThreshold(30U), +m_fmCtcssLowThreshold(20U), +m_fmCtcssLevel(10.0F), +m_fmKerchunkTime(0U), +m_fmHangTime(5U), +m_fmUseCOS(true), +m_fmCOSInvert(false), +m_fmRFAudioBoost(1U), +m_fmMaxDevLevel(90.0F) { - assert(!port.empty()); - m_buffer = new unsigned char[BUFFER_LENGTH]; + + assert(!port.empty()); } CModem::~CModem() @@ -193,7 +230,7 @@ void CModem::setRFParams(unsigned int rxFrequency, int rxOffset, unsigned int tx m_pocsagFrequency = pocsagFrequency + txOffset; } -void CModem::setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, bool p25Enabled, bool nxdnEnabled, bool pocsagEnabled) +void CModem::setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, bool p25Enabled, bool nxdnEnabled, bool pocsagEnabled, bool fmEnabled) { m_dstarEnabled = dstarEnabled; m_dmrEnabled = dmrEnabled; @@ -201,9 +238,10 @@ void CModem::setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, m_p25Enabled = p25Enabled; m_nxdnEnabled = nxdnEnabled; m_pocsagEnabled = pocsagEnabled; + m_fmEnabled = fmEnabled; } -void CModem::setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel, float nxdnTXLevel, float pocsagTXLevel) +void CModem::setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel, float nxdnTXLevel, float pocsagTXLevel, float fmTXLevel) { m_rxLevel = rxLevel; m_cwIdTXLevel = cwIdTXLevel; @@ -213,6 +251,7 @@ void CModem::setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, flo m_p25TXLevel = p25TXLevel; m_nxdnTXLevel = nxdnTXLevel; m_pocsagTXLevel = pocsagTXLevel; + m_fmTXLevel = fmTXLevel; } void CModem::setDMRParams(unsigned int colorCode) @@ -228,6 +267,16 @@ void CModem::setYSFParams(bool loDev, unsigned int txHang) m_ysfTXHang = txHang; } +void CModem::setP25Params(unsigned int txHang) +{ + m_p25TXHang = txHang; +} + +void CModem::setNXDNParams(unsigned int txHang) +{ + m_nxdnTXHang = txHang; +} + void CModem::setTransparentDataParams(unsigned int sendFrameType) { m_sendTransparentDataFrameType = sendFrameType; @@ -269,6 +318,32 @@ bool CModem::open() return false; } + if (m_fmEnabled && m_duplex) { + ret = setFMCallsignParams(); + if (!ret) { + m_serial->close(); + delete m_serial; + m_serial = NULL; + return false; + } + + ret = setFMAckParams(); + if (!ret) { + m_serial->close(); + delete m_serial; + m_serial = NULL; + return false; + } + + ret = setFMMiscParams(); + if (!ret) { + m_serial->close(); + delete m_serial; + m_serial = NULL; + return false; + } + } + m_statusTimer.start(); m_error = false; @@ -518,6 +593,8 @@ void CModem::clock(unsigned int ms) m_nxdnSpace = 0U; m_pocsagSpace = 0U; + m_mode = m_buffer[4U]; + m_tx = (m_buffer[5U] & 0x01U) == 0x01U; bool adcOverflow = (m_buffer[5U] & 0x02U) == 0x02U; @@ -1429,6 +1506,11 @@ bool CModem::readStatus() return m_serial->write(buffer, 3U) == 3; } +bool CModem::writeConfig() +{ + return setConfig(); +} + bool CModem::setConfig() { assert(m_serial != NULL); @@ -1437,7 +1519,7 @@ bool CModem::setConfig() buffer[0U] = MMDVM_FRAME_START; - buffer[1U] = 21U; + buffer[1U] = 24U; buffer[2U] = MMDVM_SET_CONFIG; @@ -1468,6 +1550,8 @@ bool CModem::setConfig() buffer[4U] |= 0x10U; if (m_pocsagEnabled) buffer[4U] |= 0x20U; + if (m_fmEnabled && m_duplex) + buffer[4U] |= 0x40U; buffer[5U] = m_txDelay / 10U; // In 10ms units @@ -1497,10 +1581,16 @@ bool CModem::setConfig() buffer[20U] = (unsigned char)(m_pocsagTXLevel * 2.55F + 0.5F); - // CUtils::dump(1U, "Written", buffer, 21U); + buffer[21U] = (unsigned char)(m_fmTXLevel * 2.55F + 0.5F); - int ret = m_serial->write(buffer, 21U); - if (ret != 21) + buffer[22U] = (unsigned char)m_p25TXHang; + + buffer[23U] = (unsigned char)m_nxdnTXHang; + + // CUtils::dump(1U, "Written", buffer, 24U); + + int ret = m_serial->write(buffer, 24U); + if (ret != 24) return false; unsigned int count = 0U; @@ -1706,6 +1796,11 @@ HW_TYPE CModem::getHWType() const return m_hwType; } +unsigned char CModem::getMode() const +{ + return m_mode; +} + bool CModem::setMode(unsigned char mode) { assert(m_serial != NULL); @@ -1811,6 +1906,227 @@ bool CModem::writeDMRShortLC(const unsigned char* lc) return m_serial->write(buffer, 12U) == 12; } +void CModem::setFMCallsignParams(const std::string& callsign, unsigned int callsignSpeed, unsigned int callsignFrequency, unsigned int callsignTime, unsigned int callsignHoldoff, float callsignHighLevel, float callsignLowLevel, bool callsignAtStart, bool callsignAtEnd, bool callsignAtLatch) +{ + m_fmCallsign = callsign; + m_fmCallsignSpeed = callsignSpeed; + m_fmCallsignFrequency = callsignFrequency; + m_fmCallsignTime = callsignTime; + m_fmCallsignHoldoff = callsignHoldoff; + m_fmCallsignHighLevel = callsignHighLevel; + m_fmCallsignLowLevel = callsignLowLevel; + m_fmCallsignAtStart = callsignAtStart; + m_fmCallsignAtEnd = callsignAtEnd; + m_fmCallsignAtLatch = callsignAtLatch; +} + +void CModem::setFMAckParams(const std::string& rfAck, unsigned int ackSpeed, unsigned int ackFrequency, unsigned int ackMinTime, unsigned int ackDelay, float ackLevel) +{ + m_fmRfAck = rfAck; + m_fmAckSpeed = ackSpeed; + m_fmAckFrequency = ackFrequency; + m_fmAckMinTime = ackMinTime; + m_fmAckDelay = ackDelay; + m_fmAckLevel = ackLevel; +} + +void CModem::setFMMiscParams(unsigned int timeout, float timeoutLevel, float ctcssFrequency, unsigned int ctcssHighThreshold, unsigned int ctcssLowThreshold, float ctcssLevel, unsigned int kerchunkTime, unsigned int hangTime, bool useCOS, bool cosInvert, unsigned int rfAudioBoost, float maxDevLevel) +{ + m_fmTimeout = timeout; + m_fmTimeoutLevel = timeoutLevel; + + m_fmCtcssFrequency = ctcssFrequency; + m_fmCtcssHighThreshold = ctcssHighThreshold; + m_fmCtcssLowThreshold = ctcssLowThreshold; + m_fmCtcssLevel = ctcssLevel; + + m_fmKerchunkTime = kerchunkTime; + m_fmHangTime = hangTime; + + m_fmUseCOS = useCOS; + m_fmCOSInvert = cosInvert; + + m_fmRFAudioBoost = rfAudioBoost; + m_fmMaxDevLevel = maxDevLevel; +} + +bool CModem::setFMCallsignParams() +{ + assert(m_serial != NULL); + + unsigned char buffer[80U]; + unsigned char len = 10U + m_fmCallsign.size(); + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = len; + buffer[2U] = MMDVM_FM_PARAMS1; + + buffer[3U] = m_fmCallsignSpeed; + buffer[4U] = m_fmCallsignFrequency / 10U; + buffer[5U] = m_fmCallsignTime; + buffer[6U] = m_fmCallsignHoldoff; + + buffer[7U] = (unsigned char)(m_fmCallsignHighLevel * 2.55F + 0.5F); + buffer[8U] = (unsigned char)(m_fmCallsignLowLevel * 2.55F + 0.5F); + + buffer[9U] = 0x00U; + if (m_fmCallsignAtStart) + buffer[9U] |= 0x01U; + if (m_fmCallsignAtEnd) + buffer[9U] |= 0x02U; + if (m_fmCallsignAtLatch) + buffer[9U] |= 0x04U; + + for (unsigned int i = 0U; i < m_fmCallsign.size(); i++) + buffer[10U + i] = m_fmCallsign.at(i); + + // CUtils::dump(1U, "Written", buffer, len); + + int ret = m_serial->write(buffer, len); + if (ret != len) + return false; + + unsigned int count = 0U; + RESP_TYPE_MMDVM resp; + do { + CThread::sleep(10U); + + resp = getResponse(); + if (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK) { + count++; + if (count >= MAX_RESPONSES) { + LogError("The MMDVM is not responding to the SET_FM_PARAMS1 command"); + return false; + } + } + } while (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK); + + // CUtils::dump(1U, "Response", m_buffer, m_length); + + if (resp == RTM_OK && m_buffer[2U] == MMDVM_NAK) { + LogError("Received a NAK to the SET_FM_PARAMS1 command from the modem"); + return false; + } + + return true; +} + +bool CModem::setFMAckParams() +{ + assert(m_serial != NULL); + + unsigned char buffer[80U]; + unsigned char len = 8U + m_fmRfAck.size(); + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = len; + buffer[2U] = MMDVM_FM_PARAMS2; + + buffer[3U] = m_fmAckSpeed; + buffer[4U] = m_fmAckFrequency / 10U; + buffer[5U] = m_fmAckMinTime; + buffer[6U] = m_fmAckDelay / 10U; + + buffer[7U] = (unsigned char)(m_fmAckLevel * 2.55F + 0.5F); + + for (unsigned int i = 0U; i < m_fmRfAck.size(); i++) + buffer[8U + i] = m_fmRfAck.at(i); + + // CUtils::dump(1U, "Written", buffer, len); + + int ret = m_serial->write(buffer, len); + if (ret != len) + return false; + + unsigned int count = 0U; + RESP_TYPE_MMDVM resp; + do { + CThread::sleep(10U); + + resp = getResponse(); + if (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK) { + count++; + if (count >= MAX_RESPONSES) { + LogError("The MMDVM is not responding to the SET_FM_PARAMS2 command"); + return false; + } + } + } while (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK); + + // CUtils::dump(1U, "Response", m_buffer, m_length); + + if (resp == RTM_OK && m_buffer[2U] == MMDVM_NAK) { + LogError("Received a NAK to the SET_FM_PARAMS2 command from the modem"); + return false; + } + + return true; +} + +bool CModem::setFMMiscParams() +{ + assert(m_serial != NULL); + + unsigned char buffer[20U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = 15U; + buffer[2U] = MMDVM_FM_PARAMS3; + + buffer[3U] = m_fmTimeout / 5U; + buffer[4U] = (unsigned char)(m_fmTimeoutLevel * 2.55F + 0.5F); + + buffer[5U] = (unsigned char)m_fmCtcssFrequency; + buffer[6U] = m_fmCtcssHighThreshold; + buffer[7U] = m_fmCtcssLowThreshold; + buffer[8U] = (unsigned char)(m_fmCtcssLevel * 2.55F + 0.5F); + + buffer[9U] = m_fmKerchunkTime; + buffer[10U] = m_fmHangTime; + + buffer[11U] = 0x00U; + if (m_fmUseCOS) + buffer[11U] |= 0x01U; + if (m_fmCOSInvert) + buffer[11U] |= 0x02U; + + buffer[12U] = m_fmRFAudioBoost; + + buffer[13U] = (unsigned char)(m_fmMaxDevLevel * 2.55F + 0.5F); + + buffer[14U] = (unsigned char)(m_rxLevel * 2.55F + 0.5F); + + // CUtils::dump(1U, "Written", buffer, 15U); + + int ret = m_serial->write(buffer, 15U); + if (ret != 15) + return false; + + unsigned int count = 0U; + RESP_TYPE_MMDVM resp; + do { + CThread::sleep(10U); + + resp = getResponse(); + if (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK) { + count++; + if (count >= MAX_RESPONSES) { + LogError("The MMDVM is not responding to the SET_FM_PARAMS3 command"); + return false; + } + } + } while (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK); + + // CUtils::dump(1U, "Response", m_buffer, m_length); + + if (resp == RTM_OK && m_buffer[2U] == MMDVM_NAK) { + LogError("Received a NAK to the SET_FM_PARAMS3 command from the modem"); + return false; + } + + return true; +} + void CModem::printDebug() { if (m_buffer[2U] == MMDVM_DEBUG1) { diff --git a/Modem.h b/Modem.h index 30af401..069fe46 100644 --- a/Modem.h +++ b/Modem.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 by Jonathan Naylor G4KLX + * Copyright (C) 2011-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 @@ -39,12 +39,18 @@ public: virtual void setSerialParams(const std::string& protocol, unsigned int address); virtual void setRFParams(unsigned int rxFrequency, int rxOffset, unsigned int txFrequency, int txOffset, int txDCOffset, int rxDCOffset, float rfLevel, unsigned int pocsagFrequency); - virtual void setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, bool p25Enabled, bool nxdnEnabled, bool pocsagEnabled); - virtual void setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel, float nxdnTXLevel, float pocsagLevel); + virtual void setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, bool p25Enabled, bool nxdnEnabled, bool pocsagEnabled, bool fmEnabled); + virtual void setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel, float nxdnTXLevel, float pocsagLevel, float fmTXLevel); virtual void setDMRParams(unsigned int colorCode); virtual void setYSFParams(bool loDev, unsigned int txHang); + virtual void setP25Params(unsigned int txHang); + virtual void setNXDNParams(unsigned int txHang); virtual void setTransparentDataParams(unsigned int sendFrameType); + virtual void setFMCallsignParams(const std::string& callsign, unsigned int callsignSpeed, unsigned int callsignFrequency, unsigned int callsignTime, unsigned int callsignHoldoff, float callsignHighLevel, float callsignLowLevel, bool callsignAtStart, bool callsignAtEnd, bool callsignAtLatch); + virtual void setFMAckParams(const std::string& rfAck, unsigned int ackSpeed, unsigned int ackFrequency, unsigned int ackMinTime, unsigned int ackDelay, float ackLevel); + virtual void setFMMiscParams(unsigned int timeout, float timeoutLevel, float ctcssFrequency, unsigned int ctcssHighThreshold, unsigned int ctcssLowThreshold, float ctcssLevel, unsigned int kerchunkTime, unsigned int hangTime, bool useCOS, bool cosInvert, unsigned int rfAudioBoost, float maxDevLevel); + virtual bool open(); virtual unsigned int readDStarData(unsigned char* data); @@ -71,6 +77,7 @@ public: virtual bool hasLockout() const; virtual bool hasError() const; + virtual bool writeConfig(); virtual bool writeDStarData(const unsigned char* data, unsigned int length); virtual bool writeDMRData1(const unsigned char* data, unsigned int length); virtual bool writeDMRData2(const unsigned char* data, unsigned int length); @@ -95,6 +102,7 @@ public: virtual bool writeSerial(const unsigned char* data, unsigned int length); + virtual unsigned char getMode() const; virtual bool setMode(unsigned char mode); virtual bool sendCWId(const std::string& callsign); @@ -112,6 +120,8 @@ private: unsigned int m_dmrColorCode; bool m_ysfLoDev; unsigned int m_ysfTXHang; + unsigned int m_p25TXHang; + unsigned int m_nxdnTXHang; bool m_duplex; bool m_rxInvert; bool m_txInvert; @@ -126,6 +136,7 @@ private: float m_p25TXLevel; float m_nxdnTXLevel; float m_pocsagTXLevel; + float m_fmTXLevel; float m_rfLevel; bool m_trace; bool m_debug; @@ -138,6 +149,7 @@ private: bool m_p25Enabled; bool m_nxdnEnabled; bool m_pocsagEnabled; + bool m_fmEnabled; int m_rxDCOffset; int m_txDCOffset; CSerialController* m_serial; @@ -174,12 +186,45 @@ private: bool m_cd; bool m_lockout; bool m_error; + unsigned char m_mode; HW_TYPE m_hwType; + std::string m_fmCallsign; + unsigned int m_fmCallsignSpeed; + unsigned int m_fmCallsignFrequency; + unsigned int m_fmCallsignTime; + unsigned int m_fmCallsignHoldoff; + float m_fmCallsignHighLevel; + float m_fmCallsignLowLevel; + bool m_fmCallsignAtStart; + bool m_fmCallsignAtEnd; + bool m_fmCallsignAtLatch; + std::string m_fmRfAck; + unsigned int m_fmAckSpeed; + unsigned int m_fmAckFrequency; + unsigned int m_fmAckMinTime; + unsigned int m_fmAckDelay; + float m_fmAckLevel; + unsigned int m_fmTimeout; + float m_fmTimeoutLevel; + float m_fmCtcssFrequency; + unsigned int m_fmCtcssHighThreshold; + unsigned int m_fmCtcssLowThreshold; + float m_fmCtcssLevel; + unsigned int m_fmKerchunkTime; + unsigned int m_fmHangTime; + bool m_fmUseCOS; + bool m_fmCOSInvert; + unsigned int m_fmRFAudioBoost; + float m_fmMaxDevLevel; + bool readVersion(); bool readStatus(); bool setConfig(); bool setFrequency(); + bool setFMCallsignParams(); + bool setFMAckParams(); + bool setFMMiscParams(); void printDebug(); diff --git a/NXDNNetwork.cpp b/NXDNNetwork.cpp index 9e26900..dcf215e 100644 --- a/NXDNNetwork.cpp +++ b/NXDNNetwork.cpp @@ -31,7 +31,7 @@ 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_port(gatewayPort), +m_addrlen(), m_debug(debug), m_enabled(false), m_buffer(1000U, "NXDN Network") @@ -39,7 +39,7 @@ m_buffer(1000U, "NXDN Network") assert(gatewayPort > 0U); assert(!gatewayAddress.empty()); - m_address = CUDPSocket::lookup(gatewayAddress); + CUDPSocket::lookup(gatewayAddress, gatewayPort, m_address, m_addrlen); } CNXDNNetwork::~CNXDNNetwork() @@ -50,7 +50,7 @@ bool CNXDNNetwork::open() { LogMessage("Opening NXDN network connection"); - if (m_address.s_addr == INADDR_NONE) + if (CUDPSocket::isnone(m_address)) return false; return m_socket.open(); @@ -100,25 +100,19 @@ bool CNXDNNetwork::write(const unsigned char* data, NXDN_NETWORK_MESSAGE_TYPE ty if (m_debug) CUtils::dump(1U, "NXDN Network Data Sent", buffer, 102U); - return m_socket.write(buffer, 102U, m_address, m_port); + return m_socket.write(buffer, 102U, m_address, m_addrlen); } void CNXDNNetwork::clock(unsigned int ms) { unsigned char buffer[BUFFER_LENGTH]; - in_addr address; - unsigned int port; - int length = m_socket.read(buffer, BUFFER_LENGTH, address, port); - if (length <= 0) + 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; - // Check if the data is for us - if (m_address.s_addr != address.s_addr || port != m_port) { - LogMessage("NXDN packet received from an invalid source, %08X != %08X and/or %u != %u", m_address.s_addr, address.s_addr, m_port, port); - return; - } - // Invalid packet type? if (::memcmp(buffer, "ICOM", 4U) != 0) return; diff --git a/NXDNNetwork.h b/NXDNNetwork.h index 3a5b784..ec428d9 100644 --- a/NXDNNetwork.h +++ b/NXDNNetwork.h @@ -57,8 +57,8 @@ public: private: CUDPSocket m_socket; - in_addr m_address; - unsigned int m_port; + sockaddr_storage m_address; + unsigned int m_addrlen; bool m_debug; bool m_enabled; CRingBuffer m_buffer; diff --git a/Nextion.cpp b/Nextion.cpp index 4f9c9ca..f15d6cf 100644 --- a/Nextion.cpp +++ b/Nextion.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016,2017,2018 by Jonathan Naylor G4KLX + * Copyright (C) 2016,2017,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 @@ -102,7 +102,6 @@ bool CNextion::open() return true; } - void CNextion::setIdleInt() { // a few bits borrowed from Lieven De Samblanx ON7LDS, NextionDriver @@ -240,6 +239,25 @@ void CNextion::setQuitInt() m_mode = MODE_QUIT; } +void CNextion::setFMInt() +{ + sendCommand("page MMDVM"); + sendCommandAction(1U); + + char command[20]; + if (m_brightness > 0) { + ::sprintf(command, "dim=%u", m_brightness); + sendCommand(command); + } + + sendCommand("t0.txt=\"FM\""); + sendCommandAction(15U); + + m_clockDisplayTimer.stop(); + + m_mode = MODE_FM; +} + void CNextion::writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector) { assert(my1 != NULL); diff --git a/Nextion.h b/Nextion.h index 1c70134..d9896e0 100644 --- a/Nextion.h +++ b/Nextion.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016,2017,2018 by Jonathan Naylor G4KLX + * Copyright (C) 2016,2017,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 @@ -41,6 +41,7 @@ protected: virtual void setErrorInt(const char* text); virtual void setLockoutInt(); virtual void setQuitInt(); + virtual void setFMInt(); virtual void writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector); virtual void writeDStarRSSIInt(unsigned char rssi); diff --git a/NullDisplay.cpp b/NullDisplay.cpp index 6219ec8..d08cf00 100644 --- a/NullDisplay.cpp +++ b/NullDisplay.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016,2018 by Jonathan Naylor G4KLX + * Copyright (C) 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 @@ -60,6 +60,10 @@ void CNullDisplay::setQuitInt() { } +void CNullDisplay::setFMInt() +{ +} + void CNullDisplay::writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector) { #if defined(RASPBERRY_PI) diff --git a/NullDisplay.h b/NullDisplay.h index 50f40b8..ac99dd8 100644 --- a/NullDisplay.h +++ b/NullDisplay.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016,2018 by Jonathan Naylor G4KLX + * Copyright (C) 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 @@ -38,6 +38,7 @@ protected: virtual void setErrorInt(const char* text); virtual void setLockoutInt(); virtual void setQuitInt(); + virtual void setFMInt(); virtual void writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector); virtual void clearDStarInt(); diff --git a/NullModem.h b/NullModem.h index 2698f47..a7ec68f 100644 --- a/NullModem.h +++ b/NullModem.h @@ -32,8 +32,8 @@ public: virtual void setSerialParams(const std::string& protocol, unsigned int address){}; virtual void setRFParams(unsigned int rxFrequency, int rxOffset, unsigned int txFrequency, int txOffset, int txDCOffset, int rxDCOffset, float rfLevel, unsigned int pocsagFrequency){}; - virtual void setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, bool p25Enabled, bool nxdnEnabled, bool pocsagEnabled){}; - virtual void setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel, float nxdnTXLevel, float pocsagLevel){}; + virtual void setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, bool p25Enabled, bool nxdnEnabled, bool pocsagEnabled, bool fmEnabled){}; + virtual void setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel, float nxdnTXLevel, float pocsagLevel, float fmTXLevel){}; virtual void setDMRParams(unsigned int colorCode){}; virtual void setYSFParams(bool loDev, unsigned int txHang){}; virtual void setTransparentDataParams(unsigned int sendFrameType){}; diff --git a/OLED.cpp b/OLED.cpp index 8dbfbe5..6f9b4ec 100644 --- a/OLED.cpp +++ b/OLED.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016,2017,2018 by Jonathan Naylor G4KLX + * Copyright (C) 2016,2017,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 @@ -306,6 +306,21 @@ void COLED::setQuitInt() m_display.display(); } +void COLED::setFMInt() +{ + m_mode = MODE_FM; + + m_display.clearDisplay(); + OLED_statusbar(); + + m_display.setCursor(0,30); + m_display.setTextSize(3); + m_display.print("FM"); + + m_display.setTextSize(1); + m_display.display(); +} + void COLED::writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector) { m_mode = MODE_DSTAR; diff --git a/OLED.h b/OLED.h index 6f40371..dec7b41 100644 --- a/OLED.h +++ b/OLED.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016,2017,2018 by Jonathan Naylor G4KLX + * Copyright (C) 2016,2017,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 @@ -50,6 +50,7 @@ public: virtual void setErrorInt(const char* text); virtual void setLockoutInt(); virtual void setQuitInt(); + virtual void setFMInt(); virtual void writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector); virtual void clearDStarInt(); diff --git a/P25Network.cpp b/P25Network.cpp index 14a0fd5..ed28fa6 100644 --- a/P25Network.cpp +++ b/P25Network.cpp @@ -90,13 +90,13 @@ const unsigned int BUFFER_LENGTH = 100U; CP25Network::CP25Network(const std::string& gatewayAddress, unsigned int gatewayPort, unsigned int localPort, bool debug) : m_socket(localPort), m_address(), -m_port(gatewayPort), +m_addrlen(), m_debug(debug), m_enabled(false), m_buffer(1000U, "P25 Network"), m_audio() { - m_address = CUDPSocket::lookup(gatewayAddress); + CUDPSocket::lookup(gatewayAddress, gatewayPort, m_address, m_addrlen); } CP25Network::~CP25Network() @@ -107,10 +107,10 @@ bool CP25Network::open() { LogMessage("Opening P25 network connection"); - if (m_address.s_addr == INADDR_NONE) + if (CUDPSocket::isnone(m_address)) return false; - return m_socket.open(); + return m_socket.open(m_address.ss_family); } bool CP25Network::writeLDU1(const unsigned char* ldu1, const CP25Data& control, const CP25LowSpeedData& lsd, bool end) @@ -126,7 +126,7 @@ bool CP25Network::writeLDU1(const unsigned char* ldu1, const CP25Data& control, if (m_debug) CUtils::dump(1U, "P25 Network LDU1 Sent", buffer, 22U); - bool ret = m_socket.write(buffer, 22U, m_address, m_port); + bool ret = m_socket.write(buffer, 22U, m_address, m_addrlen); if (!ret) return false; @@ -137,7 +137,7 @@ bool CP25Network::writeLDU1(const unsigned char* ldu1, const CP25Data& control, if (m_debug) CUtils::dump(1U, "P25 Network LDU1 Sent", buffer, 14U); - ret = m_socket.write(buffer, 14U, m_address, m_port); + ret = m_socket.write(buffer, 14U, m_address, m_addrlen); if (!ret) return false; @@ -150,7 +150,7 @@ bool CP25Network::writeLDU1(const unsigned char* ldu1, const CP25Data& control, if (m_debug) CUtils::dump(1U, "P25 Network LDU1 Sent", buffer, 17U); - ret = m_socket.write(buffer, 17U, m_address, m_port); + ret = m_socket.write(buffer, 17U, m_address, m_addrlen); if (!ret) return false; @@ -165,7 +165,7 @@ bool CP25Network::writeLDU1(const unsigned char* ldu1, const CP25Data& control, if (m_debug) CUtils::dump(1U, "P25 Network LDU1 Sent", buffer, 17U); - ret = m_socket.write(buffer, 17U, m_address, m_port); + ret = m_socket.write(buffer, 17U, m_address, m_addrlen); if (!ret) return false; @@ -180,7 +180,7 @@ bool CP25Network::writeLDU1(const unsigned char* ldu1, const CP25Data& control, if (m_debug) CUtils::dump(1U, "P25 Network LDU1 Sent", buffer, 17U); - ret = m_socket.write(buffer, 17U, m_address, m_port); + ret = m_socket.write(buffer, 17U, m_address, m_addrlen); if (!ret) return false; @@ -191,7 +191,7 @@ bool CP25Network::writeLDU1(const unsigned char* ldu1, const CP25Data& control, if (m_debug) CUtils::dump(1U, "P25 Network LDU1 Sent", buffer, 17U); - ret = m_socket.write(buffer, 17U, m_address, m_port); + ret = m_socket.write(buffer, 17U, m_address, m_addrlen); if (!ret) return false; @@ -202,7 +202,7 @@ bool CP25Network::writeLDU1(const unsigned char* ldu1, const CP25Data& control, if (m_debug) CUtils::dump(1U, "P25 Network LDU1 Sent", buffer, 17U); - ret = m_socket.write(buffer, 17U, m_address, m_port); + ret = m_socket.write(buffer, 17U, m_address, m_addrlen); if (!ret) return false; @@ -213,7 +213,7 @@ bool CP25Network::writeLDU1(const unsigned char* ldu1, const CP25Data& control, if (m_debug) CUtils::dump(1U, "P25 Network LDU1 Sent", buffer, 17U); - ret = m_socket.write(buffer, 17U, m_address, m_port); + ret = m_socket.write(buffer, 17U, m_address, m_addrlen); if (!ret) return false; @@ -226,7 +226,7 @@ bool CP25Network::writeLDU1(const unsigned char* ldu1, const CP25Data& control, if (m_debug) CUtils::dump(1U, "P25 Network LDU1 Sent", buffer, 16U); - ret = m_socket.write(buffer, 16U, m_address, m_port); + ret = m_socket.write(buffer, 16U, m_address, m_addrlen); if (!ret) return false; @@ -234,7 +234,7 @@ bool CP25Network::writeLDU1(const unsigned char* ldu1, const CP25Data& control, if (m_debug) CUtils::dump(1U, "P25 Network END Sent", REC80, 17U); - ret = m_socket.write(REC80, 17U, m_address, m_port); + ret = m_socket.write(REC80, 17U, m_address, m_addrlen); if (!ret) return false; } @@ -255,7 +255,7 @@ bool CP25Network::writeLDU2(const unsigned char* ldu2, const CP25Data& control, if (m_debug) CUtils::dump(1U, "P25 Network LDU2 Sent", buffer, 22U); - bool ret = m_socket.write(buffer, 22U, m_address, m_port); + bool ret = m_socket.write(buffer, 22U, m_address, m_addrlen); if (!ret) return false; @@ -266,7 +266,7 @@ bool CP25Network::writeLDU2(const unsigned char* ldu2, const CP25Data& control, if (m_debug) CUtils::dump(1U, "P25 Network LDU2 Sent", buffer, 14U); - ret = m_socket.write(buffer, 14U, m_address, m_port); + ret = m_socket.write(buffer, 14U, m_address, m_addrlen); if (!ret) return false; @@ -283,7 +283,7 @@ bool CP25Network::writeLDU2(const unsigned char* ldu2, const CP25Data& control, if (m_debug) CUtils::dump(1U, "P25 Network LDU2 Sent", buffer, 17U); - ret = m_socket.write(buffer, 17U, m_address, m_port); + ret = m_socket.write(buffer, 17U, m_address, m_addrlen); if (!ret) return false; @@ -297,7 +297,7 @@ bool CP25Network::writeLDU2(const unsigned char* ldu2, const CP25Data& control, if (m_debug) CUtils::dump(1U, "P25 Network LDU2 Sent", buffer, 17U); - ret = m_socket.write(buffer, 17U, m_address, m_port); + ret = m_socket.write(buffer, 17U, m_address, m_addrlen); if (!ret) return false; @@ -311,7 +311,7 @@ bool CP25Network::writeLDU2(const unsigned char* ldu2, const CP25Data& control, if (m_debug) CUtils::dump(1U, "P25 Network LDU2 Sent", buffer, 17U); - ret = m_socket.write(buffer, 17U, m_address, m_port); + ret = m_socket.write(buffer, 17U, m_address, m_addrlen); if (!ret) return false; @@ -326,7 +326,7 @@ bool CP25Network::writeLDU2(const unsigned char* ldu2, const CP25Data& control, if (m_debug) CUtils::dump(1U, "P25 Network LDU2 Sent", buffer, 17U); - ret = m_socket.write(buffer, 17U, m_address, m_port); + ret = m_socket.write(buffer, 17U, m_address, m_addrlen); if (!ret) return false; @@ -337,7 +337,7 @@ bool CP25Network::writeLDU2(const unsigned char* ldu2, const CP25Data& control, if (m_debug) CUtils::dump(1U, "P25 Network LDU2 Sent", buffer, 17U); - ret = m_socket.write(buffer, 17U, m_address, m_port); + ret = m_socket.write(buffer, 17U, m_address, m_addrlen); if (!ret) return false; @@ -348,7 +348,7 @@ bool CP25Network::writeLDU2(const unsigned char* ldu2, const CP25Data& control, if (m_debug) CUtils::dump(1U, "P25 Network LDU2 Sent", buffer, 17U); - ret = m_socket.write(buffer, 17U, m_address, m_port); + ret = m_socket.write(buffer, 17U, m_address, m_addrlen); if (!ret) return false; @@ -361,7 +361,7 @@ bool CP25Network::writeLDU2(const unsigned char* ldu2, const CP25Data& control, if (m_debug) CUtils::dump(1U, "P25 Network LDU2 Sent", buffer, 16U); - ret = m_socket.write(buffer, 16U, m_address, m_port); + ret = m_socket.write(buffer, 16U, m_address, m_addrlen); if (!ret) return false; @@ -369,7 +369,7 @@ bool CP25Network::writeLDU2(const unsigned char* ldu2, const CP25Data& control, if (m_debug) CUtils::dump(1U, "P25 Network END Sent", REC80, 17U); - ret = m_socket.write(REC80, 17U, m_address, m_port); + ret = m_socket.write(REC80, 17U, m_address, m_addrlen); if (!ret) return false; } @@ -381,18 +381,12 @@ void CP25Network::clock(unsigned int ms) { unsigned char buffer[BUFFER_LENGTH]; - in_addr address; - unsigned int port; - int length = m_socket.read(buffer, BUFFER_LENGTH, address, port); - if (length <= 0) + 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; - // Check if the data is for us - if (m_address.s_addr != address.s_addr || m_port != port) { - LogMessage("P25 packet received from an invalid source, %08X != %08X and/or %u != %u", m_address.s_addr, address.s_addr, m_port, port); - return; - } - if (!m_enabled) return; diff --git a/P25Network.h b/P25Network.h index 054c772..009c994 100644 --- a/P25Network.h +++ b/P25Network.h @@ -49,8 +49,8 @@ public: private: CUDPSocket m_socket; - in_addr m_address; - unsigned int m_port; + sockaddr_storage m_address; + unsigned int m_addrlen; bool m_debug; bool m_enabled; CRingBuffer m_buffer; diff --git a/POCSAGNetwork.cpp b/POCSAGNetwork.cpp index 682fdd1..e6b755a 100644 --- a/POCSAGNetwork.cpp +++ b/POCSAGNetwork.cpp @@ -31,12 +31,12 @@ const unsigned int BUFFER_LENGTH = 200U; CPOCSAGNetwork::CPOCSAGNetwork(const std::string& myAddress, unsigned int myPort, const std::string& gatewayAddress, unsigned int gatewayPort, bool debug) : m_socket(myAddress, myPort), m_address(), -m_port(gatewayPort), +m_addrlen(), m_debug(debug), m_enabled(false), m_buffer(1000U, "POCSAG Network") { - m_address = CUDPSocket::lookup(gatewayAddress); + CUDPSocket::lookup(gatewayAddress, gatewayPort, m_address, m_addrlen); } CPOCSAGNetwork::~CPOCSAGNetwork() @@ -47,7 +47,7 @@ bool CPOCSAGNetwork::open() { LogMessage("Opening POCSAG network connection"); - if (m_address.s_addr == INADDR_NONE) + if (CUDPSocket::isnone(m_address)) return false; return m_socket.open(); @@ -57,18 +57,12 @@ void CPOCSAGNetwork::clock(unsigned int ms) { unsigned char buffer[BUFFER_LENGTH]; - in_addr address; - unsigned int port; - int length = m_socket.read(buffer, BUFFER_LENGTH, address, port); - if (length <= 0) + 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; - // Check if the data is for us - if (m_address.s_addr != address.s_addr || m_port != port) { - LogMessage("POCSAG packet received from an invalid source, %08X != %08X and/or %u != %u", m_address.s_addr, address.s_addr, m_port, port); - return; - } - // Invalid packet type? if (::memcmp(buffer, "POCSAG", 6U) != 0) return; @@ -118,7 +112,7 @@ void CPOCSAGNetwork::enable(bool enabled) unsigned char c = enabled ? 0x00U : 0xFFU; - m_socket.write(&c, 1U, m_address, m_port); + m_socket.write(&c, 1U, m_address, m_addrlen); m_enabled = enabled; } diff --git a/POCSAGNetwork.h b/POCSAGNetwork.h index fe95203..dd3945b 100644 --- a/POCSAGNetwork.h +++ b/POCSAGNetwork.h @@ -46,8 +46,8 @@ public: private: CUDPSocket m_socket; - in_addr m_address; - unsigned int m_port; + sockaddr_storage m_address; + unsigned int m_addrlen; bool m_debug; bool m_enabled; CRingBuffer m_buffer; diff --git a/README.md b/README.md index 953e4ce..813e945 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,21 @@ -These are the source files for building the MMDVMHost, the program that interfaces to the MMDVM or DVMega on the one side, and a suitable network on the other. It supports D-Star, DMR, P25 Phase 1, NXDN, System Fusion, and POCSAG paging on the MMDVM, and D-Star, DMR, and System Fusion on the DVMega. +These are the source files for building the MMDVMHost, the program that +interfaces to the MMDVM or DVMega on the one side, and a suitable network on +the other. It supports D-Star, DMR, P25 Phase 1, NXDN, System Fusion, +POCSAG, and FM on the MMDVM, and D-Star, DMR, and System Fusion on the DVMega. -On the D-Star side the MMDVMHost interfaces with the ircDDB Gateway, on DMR it can connect to BrandMeister, DMR+, HB Link, XLX or [DMRGateway](https://github.com/g4klx/DMRGateway) (to connect to multiple DMR networks at once) on System Fusion it connects to the YSF Gateway to allow access to the FCS and YSF networks. On P25 it connects to the P25 Gateway. On NXDN it connects to the NXDN Gateway which provides access to the NXDN and NXCore talk groups. Finally it uses the DAPNET Gateway to access DAPNET to receive paging messages. +On the D-Star side the MMDVMHost interfaces with the ircDDB Gateway, on DMR it +can connect to BrandMeister, DMR+, TGIF, HB Link, XLX or +[DMRGateway](https://github.com/g4klx/DMRGateway) (to connect to multiple DMR +networks at once) on System Fusion it connects to the YSF Gateway to allow +access to the FCS and YSF networks. On P25 it connects to the P25 Gateway. On +NXDN it connects to the NXDN Gateway which provides access to the NXDN and +NXCore talk groups. It uses the DAPNET Gateway to access DAPNET to receive +paging messages. Finally it uses the FM Gateway to interface to existing FM +networks. -It builds on 32-bit and 64-bit Linux as well as on Windows using Visual Studio 2017 on x86 and x64. It can optionally control various Displays. Currently these are: +It builds on 32-bit and 64-bit Linux as well as on Windows using Visual Studio +2019 on x86 and x64. It can optionally control various Displays. Currently +these are: - HD44780 (sizes 2x16, 2x40, 4x16, 4x20) - Support for HD44780 via 4 bit GPIO connection (user selectable pins) @@ -13,14 +26,23 @@ It builds on 32-bit and 64-bit Linux as well as on Windows using Visual Studio 2 - OLED 128x64 (SSD1306) - LCDproc -The Nextion displays can connect to the UART on the Raspberry Pi, or via a USB to TTL serial converter like the FT-232RL. It may also be connected to the UART output of the MMDVM modem (Arduino Due, STM32, Teensy), or to the UART output on the UMP. +The Nextion displays can connect to the UART on the Raspberry Pi, or via a USB +to TTL serial converter like the FT-232RL. It may also be connected to the UART +output of the MMDVM modem (Arduino Due, STM32, Teensy), or to the UART output +on the UMP. -The HD44780 displays are integrated with wiringPi for Raspberry Pi based platforms. +The HD44780 displays are integrated with wiringPi for Raspberry Pi based +platforms. -The Hobbytronics TFT Display, which is a Pi-Hat, connects to the UART on the Raspbery Pi. +The Hobbytronics TFT Display, which is a Pi-Hat, connects to the UART on the +Raspbery Pi. -The OLED display needs a extra library see OLED.md +The OLED display needs an extra library see OLED.md -The LCDproc support enables the use of a multitude of other LCD screens. See the [supported devices](http://lcdproc.omnipotent.net/hardware.php3) page on the LCDproc website for more info. +The LCDproc support enables the use of a multitude of other LCD screens. See +the [supported devices](http://lcdproc.omnipotent.net/hardware.php3) page on +the LCDproc website for more info. -This software is licenced under the GPL v2 and is intended for amateur and educational use only. Use of this software for commercial purposes is strictly forbidden. +This software is licenced under the GPL v2 and is intended for amateur and +educational use only. Use of this software for commercial purposes is strictly +forbidden. diff --git a/RemoteCommand.cpp b/RemoteCommand.cpp index bf3fb1e..25b07fd 100644 --- a/RemoteCommand.cpp +++ b/RemoteCommand.cpp @@ -51,7 +51,7 @@ int main(int argc, char** argv) CRemoteCommand::CRemoteCommand(unsigned int port) : m_port(port) { - ::LogInitialise(".", "RemoteCommand", 2U, 2U); + ::LogInitialise(false, ".", "RemoteCommand", 2U, 2U); } CRemoteCommand::~CRemoteCommand() @@ -61,15 +61,17 @@ CRemoteCommand::~CRemoteCommand() int CRemoteCommand::send(const std::string& command) { + sockaddr_storage address; + unsigned int addrlen; + CUDPSocket::lookup("127.0.0.1", m_port, address, addrlen); + CUDPSocket socket(0U); - bool ret = socket.open(); + bool ret = socket.open(address.ss_family); if (!ret) return 1; - in_addr address = CUDPSocket::lookup("localhost"); - - ret = socket.write((unsigned char*)command.c_str(), command.length(), address, m_port); + ret = socket.write((unsigned char*)command.c_str(), command.length(), address, addrlen); if (!ret) { socket.close(); return 1; diff --git a/RemoteControl.cpp b/RemoteControl.cpp index afa1473..3c2d2a8 100644 --- a/RemoteControl.cpp +++ b/RemoteControl.cpp @@ -25,12 +25,15 @@ #include const unsigned int SET_MODE_ARGS = 2U; +const unsigned int ENABLE_ARGS = 2U; +const unsigned int DISABLE_ARGS = 2U; const unsigned int PAGE_ARGS = 3U; +const unsigned int CW_ARGS = 2U; const unsigned int BUFFER_LENGTH = 100U; -CRemoteControl::CRemoteControl(unsigned int port) : -m_socket(port), +CRemoteControl::CRemoteControl(const std::string address, unsigned int port) : +m_socket(address, port), m_command(RCD_NONE), m_args() { @@ -53,9 +56,9 @@ REMOTE_COMMAND CRemoteControl::getCommand() char command[BUFFER_LENGTH]; char buffer[BUFFER_LENGTH]; - in_addr address; - unsigned int port; - int ret = m_socket.read((unsigned char*)buffer, BUFFER_LENGTH, address, port); + sockaddr_storage address; + unsigned int addrlen; + int ret = m_socket.read((unsigned char*)buffer, BUFFER_LENGTH, address, addrlen); if (ret > 0) { buffer[ret] = '\0'; @@ -86,10 +89,39 @@ REMOTE_COMMAND CRemoteControl::getCommand() m_command = RCD_MODE_P25; else if (m_args.at(1U) == "nxdn") m_command = RCD_MODE_NXDN; + } else if (m_args.at(0U) == "enable" && m_args.size() >= ENABLE_ARGS) { + if (m_args.at(1U) == "dstar") + m_command = RCD_ENABLE_DSTAR; + else if (m_args.at(1U) == "dmr") + m_command = RCD_ENABLE_DMR; + else if (m_args.at(1U) == "ysf") + m_command = RCD_ENABLE_YSF; + else if (m_args.at(1U) == "p25") + m_command = RCD_ENABLE_P25; + else if (m_args.at(1U) == "nxdn") + m_command = RCD_ENABLE_NXDN; + else if (m_args.at(1U) == "fm") + m_command = RCD_ENABLE_FM; + } else if (m_args.at(0U) == "disable" && m_args.size() >= DISABLE_ARGS) { + if (m_args.at(1U) == "dstar") + m_command = RCD_DISABLE_DSTAR; + else if (m_args.at(1U) == "dmr") + m_command = RCD_DISABLE_DMR; + else if (m_args.at(1U) == "ysf") + m_command = RCD_DISABLE_YSF; + else if (m_args.at(1U) == "p25") + m_command = RCD_DISABLE_P25; + else if (m_args.at(1U) == "nxdn") + m_command = RCD_DISABLE_NXDN; + else if (m_args.at(1U) == "fm") + m_command = RCD_DISABLE_FM; } else if (m_args.at(0U) == "page" && m_args.size() >= PAGE_ARGS) { // Page command is in the form of "page " m_command = RCD_PAGE; - } + } else if (m_args.at(0U) == "cw" && m_args.size() >= CW_ARGS) { + // CW command is in the form of "cw " + m_command = RCD_CW; + } if (m_command == RCD_NONE) { m_args.clear(); @@ -115,6 +147,8 @@ unsigned int CRemoteControl::getArgCount() const return m_args.size() - SET_MODE_ARGS; case RCD_PAGE: return m_args.size() - 1U; + case RCD_CW: + return m_args.size() - 1U; default: return 0U; } @@ -135,6 +169,9 @@ std::string CRemoteControl::getArgString(unsigned int n) const case RCD_PAGE: n += 1U; break; + case RCD_CW: + n += 1U; + break; default: return ""; } diff --git a/RemoteControl.h b/RemoteControl.h index 479987a..c8d060d 100644 --- a/RemoteControl.h +++ b/RemoteControl.h @@ -33,12 +33,26 @@ enum REMOTE_COMMAND { RCD_MODE_YSF, RCD_MODE_P25, RCD_MODE_NXDN, - RCD_PAGE + RCD_MODE_FM, + RCD_ENABLE_DSTAR, + RCD_ENABLE_DMR, + RCD_ENABLE_YSF, + RCD_ENABLE_P25, + RCD_ENABLE_NXDN, + RCD_ENABLE_FM, + RCD_DISABLE_DSTAR, + RCD_DISABLE_DMR, + RCD_DISABLE_YSF, + RCD_DISABLE_P25, + RCD_DISABLE_NXDN, + RCD_DISABLE_FM, + RCD_PAGE, + RCD_CW }; class CRemoteControl { public: - CRemoteControl(unsigned int port); + CRemoteControl(const std::string address, unsigned int port); ~CRemoteControl(); bool open(); diff --git a/TFTSerial.cpp b/TFTSerial.cpp index c2338f3..59867b9 100644 --- a/TFTSerial.cpp +++ b/TFTSerial.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015,2016,2018 by Jonathan Naylor G4KLX + * Copyright (C) 2015,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 @@ -161,6 +161,22 @@ void CTFTSerial::setQuitInt() m_mode = MODE_QUIT; } +void CTFTSerial::setFMInt() +{ + // Clear the screen + clearScreen(); + + setFontSize(FONT_LARGE); + + // Draw MMDVM logo + displayBitmap(0U, 0U, "MMDVM_sm.bmp"); + + gotoPosPixel(20U, 60U); + displayText("FM"); + + m_mode = MODE_FM; +} + void CTFTSerial::writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector) { assert(my1 != NULL); diff --git a/TFTSerial.h b/TFTSerial.h index 296a4b1..314e555 100644 --- a/TFTSerial.h +++ b/TFTSerial.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015,2016,2018 by Jonathan Naylor G4KLX + * Copyright (C) 2015,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 @@ -40,6 +40,7 @@ protected: virtual void setErrorInt(const char* text); virtual void setLockoutInt(); virtual void setQuitInt(); + virtual void setFMInt(); virtual void writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector); virtual void clearDStarInt(); diff --git a/TFTSurenoo.cpp b/TFTSurenoo.cpp index a2eba9e..5f0ddbd 100644 --- a/TFTSurenoo.cpp +++ b/TFTSurenoo.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2019 by SASANO Takayoshi JG1UAA - * Copyright (C) 2015,2016,2018,2019 by Jonathan Naylor G4KLX + * Copyright (C) 2015,2016,2018,2019,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 @@ -174,6 +174,14 @@ void CTFTSurenoo::setQuitInt() m_mode = MODE_QUIT; } +void CTFTSurenoo::setFMInt() +{ + setModeLine(STR_MMDVM); + setStatusLine(statusLineNo(1), "FM"); + + m_mode = MODE_FM; +} + void CTFTSurenoo::writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector) { assert(my1 != NULL); diff --git a/TFTSurenoo.h b/TFTSurenoo.h index d058c3e..0c54c24 100644 --- a/TFTSurenoo.h +++ b/TFTSurenoo.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2019 by SASANO Takayoshi JG1UAA - * Copyright (C) 2015,2016,2018 by Jonathan Naylor G4KLX + * Copyright (C) 2015,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 @@ -42,6 +42,7 @@ protected: virtual void setErrorInt(const char* text); virtual void setLockoutInt(); virtual void setQuitInt(); + virtual void setFMInt(); virtual void writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector); virtual void clearDStarInt(); diff --git a/UDPSocket.cpp b/UDPSocket.cpp index ba0e35f..beec3ce 100644 --- a/UDPSocket.cpp +++ b/UDPSocket.cpp @@ -60,49 +60,96 @@ CUDPSocket::~CUDPSocket() #endif } -in_addr CUDPSocket::lookup(const std::string& hostname) +int CUDPSocket::lookup(const std::string& hostname, unsigned int port, sockaddr_storage &addr, unsigned int &address_length) { - in_addr addr; -#if defined(_WIN32) || defined(_WIN64) - unsigned long address = ::inet_addr(hostname.c_str()); - if (address != INADDR_NONE && address != INADDR_ANY) { - addr.s_addr = address; - return addr; + struct addrinfo hints; + + ::memset(&hints, 0, sizeof(hints)); + + return lookup(hostname, port, addr, address_length, hints); +} + +int CUDPSocket::lookup(const std::string& hostname, unsigned int port, sockaddr_storage &addr, unsigned int &address_length, struct addrinfo &hints) +{ + int err; + std::string portstr = std::to_string(port); + struct addrinfo *res; + + /* port is always digits, no needs to lookup service */ + hints.ai_flags |= AI_NUMERICSERV; + + err = getaddrinfo(hostname.empty() ? NULL : hostname.c_str(), portstr.c_str(), &hints, &res); + if (err) { + sockaddr_in *paddr = (sockaddr_in *)&addr; + ::memset(paddr, 0, address_length = sizeof(sockaddr_in)); + paddr->sin_family = AF_INET; + paddr->sin_port = htons(port); + paddr->sin_addr.s_addr = htonl(INADDR_NONE); + LogError("Cannot find address for host %s", hostname.c_str()); + return err; } - struct hostent* hp = ::gethostbyname(hostname.c_str()); - if (hp != NULL) { - ::memcpy(&addr, hp->h_addr_list[0], sizeof(struct in_addr)); - return addr; + ::memcpy(&addr, res->ai_addr, address_length = res->ai_addrlen); + + freeaddrinfo(res); + return 0; +} + +bool CUDPSocket::match(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) && + (in_1->sin_port == in_2->sin_port) ); + 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) && + (in6_1->sin6_port == in6_2->sin6_port) ); + default: + return false; } +} - LogError("Cannot find address for host %s", hostname.c_str()); +bool CUDPSocket::isnone(const sockaddr_storage &addr) +{ + struct sockaddr_in *in = (struct sockaddr_in *)&addr; - addr.s_addr = INADDR_NONE; - return addr; -#else - in_addr_t address = ::inet_addr(hostname.c_str()); - if (address != in_addr_t(-1)) { - addr.s_addr = address; - return addr; - } - - struct hostent* hp = ::gethostbyname(hostname.c_str()); - if (hp != NULL) { - ::memcpy(&addr, hp->h_addr_list[0], sizeof(struct in_addr)); - return addr; - } - - LogError("Cannot find address for host %s", hostname.c_str()); - - addr.s_addr = INADDR_NONE; - return addr; -#endif + return ( (addr.ss_family == AF_INET) && + (in->sin_addr.s_addr == htonl(INADDR_NONE)) ); } bool CUDPSocket::open() { - m_fd = ::socket(PF_INET, SOCK_DGRAM, 0); + return open(AF_UNSPEC); +} + +bool CUDPSocket::open(const unsigned int af) +{ + int err; + sockaddr_storage addr; + unsigned int addrlen; + struct addrinfo hints; + + ::memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = af; + + /* to determine protocol family, call lookup() first. */ + err = lookup(m_address, m_port, addr, addrlen, hints); + if (err) { + LogError("The local address is invalid - %s", m_address.c_str()); + return false; + } + + m_fd = ::socket(addr.ss_family, SOCK_DGRAM, 0); if (m_fd < 0) { #if defined(_WIN32) || defined(_WIN64) LogError("Cannot create the UDP socket, err: %lu", ::GetLastError()); @@ -113,24 +160,6 @@ bool CUDPSocket::open() } if (m_port > 0U) { - sockaddr_in addr; - ::memset(&addr, 0x00, sizeof(sockaddr_in)); - addr.sin_family = AF_INET; - addr.sin_port = htons(m_port); - addr.sin_addr.s_addr = htonl(INADDR_ANY); - - if (!m_address.empty()) { -#if defined(_WIN32) || defined(_WIN64) - addr.sin_addr.s_addr = ::inet_addr(m_address.c_str()); -#else - addr.sin_addr.s_addr = ::inet_addr(m_address.c_str()); -#endif - if (addr.sin_addr.s_addr == INADDR_NONE) { - LogError("The local address is invalid - %s", m_address.c_str()); - return false; - } - } - int reuse = 1; if (::setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) == -1) { #if defined(_WIN32) || defined(_WIN64) @@ -141,7 +170,7 @@ bool CUDPSocket::open() return false; } - if (::bind(m_fd, (sockaddr*)&addr, sizeof(sockaddr_in)) == -1) { + if (::bind(m_fd, (sockaddr*)&addr, addrlen) == -1) { #if defined(_WIN32) || defined(_WIN64) LogError("Cannot bind the UDP address, err: %lu", ::GetLastError()); #else @@ -154,7 +183,7 @@ bool CUDPSocket::open() return true; } -int CUDPSocket::read(unsigned char* buffer, unsigned int length, in_addr& address, unsigned int& port) +int CUDPSocket::read(unsigned char* buffer, unsigned int length, sockaddr_storage& address, unsigned int &address_length) { assert(buffer != NULL); assert(length > 0U); @@ -186,17 +215,16 @@ int CUDPSocket::read(unsigned char* buffer, unsigned int length, in_addr& addres if (ret == 0) return 0; - sockaddr_in addr; #if defined(_WIN32) || defined(_WIN64) - int size = sizeof(sockaddr_in); + int size = sizeof(sockaddr_storage); #else - socklen_t size = sizeof(sockaddr_in); + socklen_t size = sizeof(sockaddr_storage); #endif #if defined(_WIN32) || defined(_WIN64) - int len = ::recvfrom(m_fd, (char*)buffer, length, 0, (sockaddr *)&addr, &size); + int len = ::recvfrom(m_fd, (char*)buffer, length, 0, (sockaddr *)&address, &size); #else - ssize_t len = ::recvfrom(m_fd, (char*)buffer, length, 0, (sockaddr *)&addr, &size); + ssize_t len = ::recvfrom(m_fd, (char*)buffer, length, 0, (sockaddr *)&address, &size); #endif if (len <= 0) { #if defined(_WIN32) || defined(_WIN64) @@ -207,28 +235,19 @@ int CUDPSocket::read(unsigned char* buffer, unsigned int length, in_addr& addres return -1; } - address = addr.sin_addr; - port = ntohs(addr.sin_port); - + address_length = size; return len; } -bool CUDPSocket::write(const unsigned char* buffer, unsigned int length, const in_addr& address, unsigned int port) +bool CUDPSocket::write(const unsigned char* buffer, unsigned int length, const sockaddr_storage& address, unsigned int address_length) { assert(buffer != NULL); assert(length > 0U); - sockaddr_in addr; - ::memset(&addr, 0x00, sizeof(sockaddr_in)); - - addr.sin_family = AF_INET; - addr.sin_addr = address; - addr.sin_port = htons(port); - #if defined(_WIN32) || defined(_WIN64) - int ret = ::sendto(m_fd, (char *)buffer, length, 0, (sockaddr *)&addr, sizeof(sockaddr_in)); + int ret = ::sendto(m_fd, (char *)buffer, length, 0, (sockaddr *)&address, address_length); #else - ssize_t ret = ::sendto(m_fd, (char *)buffer, length, 0, (sockaddr *)&addr, sizeof(sockaddr_in)); + ssize_t ret = ::sendto(m_fd, (char *)buffer, length, 0, (sockaddr *)&address, address_length); #endif if (ret < 0) { #if defined(_WIN32) || defined(_WIN64) diff --git a/UDPSocket.h b/UDPSocket.h index e0af272..46b2370 100644 --- a/UDPSocket.h +++ b/UDPSocket.h @@ -31,7 +31,8 @@ #include #include #else -#include +#include +#include #endif class CUDPSocket { @@ -41,13 +42,17 @@ public: ~CUDPSocket(); bool open(); + bool open(const unsigned int af); - int read(unsigned char* buffer, unsigned int length, in_addr& address, unsigned int& port); - bool write(const unsigned char* buffer, unsigned int length, const in_addr& address, unsigned int port); + int read(unsigned char* buffer, unsigned int length, sockaddr_storage& address, unsigned int &address_length); + bool write(const unsigned char* buffer, unsigned int length, const sockaddr_storage& address, unsigned int address_length); void close(); - static in_addr lookup(const std::string& hostName); + 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 isnone(const sockaddr_storage &addr); private: std::string m_address; diff --git a/UserDB.cpp b/UserDB.cpp index 9984d63..8c7301b 100644 --- a/UserDB.cpp +++ b/UserDB.cpp @@ -42,7 +42,7 @@ bool CUserDB::lookup(unsigned int id, class CUserDBentry *entry) if (entry != NULL) *entry = m_table.at(id); else - m_table.at(id); + (void)m_table.at(id); rv = true; } catch (...) { @@ -116,8 +116,8 @@ bool CUserDB::makeindex(char* buf, std::unordered_map& index) } try { - index.at(keyRADIO_ID); - index.at(keyCALLSIGN); + (void)index.at(keyRADIO_ID); + (void)index.at(keyCALLSIGN); return true; } catch (...) { return false; @@ -144,8 +144,8 @@ void CUserDB::parse(char* buf, std::unordered_map& index) } try { - ptr.at(keyRADIO_ID); - ptr.at(keyCALLSIGN); + (void)ptr.at(keyRADIO_ID); + (void)ptr.at(keyCALLSIGN); } catch (...) { return; } diff --git a/Version.h b/Version.h index bbe810c..101ca94 100644 --- a/Version.h +++ b/Version.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 @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20190131"; +const char* VERSION = "20200608"; #endif diff --git a/YSFNetwork.cpp b/YSFNetwork.cpp index a8effba..ff5cab8 100644 --- a/YSFNetwork.cpp +++ b/YSFNetwork.cpp @@ -31,7 +31,7 @@ const unsigned int BUFFER_LENGTH = 200U; CYSFNetwork::CYSFNetwork(const std::string& myAddress, unsigned int myPort, const std::string& gatewayAddress, unsigned int gatewayPort, const std::string& callsign, bool debug) : m_socket(myAddress, myPort), m_address(), -m_port(gatewayPort), +m_addrlen(), m_callsign(), m_debug(debug), m_enabled(false), @@ -42,7 +42,7 @@ m_tag(NULL) m_callsign = callsign; m_callsign.resize(YSF_CALLSIGN_LENGTH, ' '); - m_address = CUDPSocket::lookup(gatewayAddress); + CUDPSocket::lookup(gatewayAddress, gatewayPort, m_address, m_addrlen); m_tag = new unsigned char[YSF_CALLSIGN_LENGTH]; ::memset(m_tag, ' ', YSF_CALLSIGN_LENGTH); @@ -57,7 +57,7 @@ bool CYSFNetwork::open() { LogMessage("Opening YSF network connection"); - if (m_address.s_addr == INADDR_NONE) + if (CUDPSocket::isnone(m_address)) return false; m_pollTimer.start(); @@ -97,7 +97,7 @@ bool CYSFNetwork::write(const unsigned char* src, const unsigned char* dest, con if (m_debug) CUtils::dump(1U, "YSF Network Data Sent", buffer, 155U); - return m_socket.write(buffer, 155U, m_address, m_port); + return m_socket.write(buffer, 155U, m_address, m_addrlen); } bool CYSFNetwork::writePoll() @@ -115,7 +115,7 @@ bool CYSFNetwork::writePoll() if (m_debug) CUtils::dump(1U, "YSF Network Poll Sent", buffer, 14U); - return m_socket.write(buffer, 14U, m_address, m_port); + return m_socket.write(buffer, 14U, m_address, m_addrlen); } void CYSFNetwork::clock(unsigned int ms) @@ -128,18 +128,12 @@ void CYSFNetwork::clock(unsigned int ms) unsigned char buffer[BUFFER_LENGTH]; - in_addr address; - unsigned int port; - int length = m_socket.read(buffer, BUFFER_LENGTH, address, port); - if (length <= 0) + 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; - // Check if the data is for us - if (m_address.s_addr != address.s_addr || m_port != port) { - LogMessage("YSF packet received from an invalid source, %08X != %08X and/or %u != %u", m_address.s_addr, address.s_addr, m_port, port); - return; - } - // Ignore incoming polls if (::memcmp(buffer, "YSFP", 4U) == 0) return; diff --git a/YSFNetwork.h b/YSFNetwork.h index e9a430f..292364d 100644 --- a/YSFNetwork.h +++ b/YSFNetwork.h @@ -48,8 +48,8 @@ public: private: CUDPSocket m_socket; - in_addr m_address; - unsigned int m_port; + sockaddr_storage m_address; + unsigned int m_addrlen; std::string m_callsign; bool m_debug; bool m_enabled;