diff --git a/Conf.cpp b/Conf.cpp index 3b117e3..83aa2c5 100644 --- a/Conf.cpp +++ b/Conf.cpp @@ -291,6 +291,7 @@ m_pocsagNetworkDebug(false), m_fmNetworkEnabled(false), m_fmNetworkProtocol("USRP"), m_fmNetworkSampleRate(48000U), +m_fmNetworkSquelchFile(), m_fmGatewayAddress(), m_fmGatewayPort(0U), m_fmLocalAddress(), @@ -1036,6 +1037,8 @@ bool CConf::read() m_fmNetworkProtocol = value; else if (::strcmp(key, "SampleRate") == 0) m_fmNetworkSampleRate = (unsigned int)::atoi(value); + else if (::strcmp(key, "SquelchFile") == 0) + m_fmNetworkSquelchFile = value; else if (::strcmp(key, "LocalAddress") == 0) m_fmLocalAddress = value; else if (::strcmp(key, "LocalPort") == 0) @@ -2281,6 +2284,11 @@ unsigned int CConf::getFMNetworkSampleRate() const return m_fmNetworkSampleRate; } +std::string CConf::getFMNetworkSquelchFile() const +{ + return m_fmNetworkSquelchFile; +} + std::string CConf::getFMGatewayAddress() const { return m_fmGatewayAddress; diff --git a/Conf.h b/Conf.h index fb82a7a..96f5773 100644 --- a/Conf.h +++ b/Conf.h @@ -304,6 +304,7 @@ public: bool getFMNetworkEnabled() const; std::string getFMNetworkProtocol() const; unsigned int getFMNetworkSampleRate() const; + std::string getFMNetworkSquelchFile() const; std::string getFMGatewayAddress() const; unsigned short getFMGatewayPort() const; std::string getFMLocalAddress() const; @@ -622,6 +623,7 @@ private: bool m_fmNetworkEnabled; std::string m_fmNetworkProtocol; unsigned int m_fmNetworkSampleRate; + std::string m_fmNetworkSquelchFile; std::string m_fmGatewayAddress; unsigned short m_fmGatewayPort; std::string m_fmLocalAddress; diff --git a/FMNetwork.cpp b/FMNetwork.cpp index 2bfdc8a..02ff5bf 100644 --- a/FMNetwork.cpp +++ b/FMNetwork.cpp @@ -25,23 +25,30 @@ #include #include +#include +#include +#include +#include + const unsigned int MMDVM_SAMPLERATE = 8000U; const unsigned int BUFFER_LENGTH = 1500U; -CFMNetwork::CFMNetwork(const std::string& callsign, const std::string& protocol, const std::string& localAddress, unsigned short localPort, const std::string& gatewayAddress, unsigned short gatewayPort, unsigned int sampleRate, bool debug) : +CFMNetwork::CFMNetwork(const std::string& callsign, const std::string& protocol, const std::string& localAddress, unsigned short localPort, const std::string& gatewayAddress, unsigned short gatewayPort, unsigned int sampleRate, const std::string& squelchFile, bool debug) : m_callsign(callsign), m_protocol(FMNP_USRP), m_socket(localAddress, localPort), m_addr(), m_addrLen(0U), m_sampleRate(sampleRate), +m_squelchFile(squelchFile), m_debug(debug), m_enabled(false), m_buffer(2000U, "FM Network"), m_seqNo(0U), m_resampler(NULL), -m_error(0) +m_error(0), +m_fd(-1) { assert(!callsign.empty()); assert(gatewayPort > 0U); @@ -78,6 +85,14 @@ bool CFMNetwork::open() LogMessage("Opening FM network connection"); + if (!m_squelchFile.empty()) { + m_fd = ::open(m_squelchFile.c_str(), O_WRONLY | O_SYNC); + if (m_fd == -1) { + LogError("Cannot open the squelch file: %s, errno=%d", m_squelchFile.c_str(), errno); + return false; + } + } + return m_socket.open(m_addr); } @@ -173,6 +188,12 @@ bool CFMNetwork::writeRawData(const float* in, unsigned int nIn) assert(in != NULL); assert(nIn > 0U); + if (m_seqNo == 0U) { + bool ret = writeRawStart(); + if (!ret) + return false; + } + unsigned char buffer[2000U]; unsigned int length = 0U; @@ -214,6 +235,8 @@ bool CFMNetwork::writeRawData(const float* in, unsigned int nIn) if (m_debug) CUtils::dump(1U, "FM Network Data Sent", buffer, length); + m_seqNo++; + return m_socket.write(buffer, length, m_addr, m_addrLen); } @@ -222,7 +245,7 @@ bool CFMNetwork::writeEnd() if (m_protocol == FMNP_USRP) return writeUSRPEnd(); else - return true; + return writeRawEnd(); } bool CFMNetwork::writeUSRPEnd() @@ -289,6 +312,21 @@ bool CFMNetwork::writeUSRPEnd() } } +bool CFMNetwork::writeRawEnd() +{ + m_seqNo = 0U; + + if (m_fd != -1) { + size_t n = ::write(m_fd, "Z", 1); + if (n != 1) { + LogError("Cannot write to the squelch file: %s, errno=%d", m_squelchFile.c_str(), errno); + return false; + } + } + + return true; +} + void CFMNetwork::clock(unsigned int ms) { unsigned char buffer[BUFFER_LENGTH]; @@ -404,6 +442,11 @@ void CFMNetwork::close() { m_socket.close(); + if (m_fd != -1) { + ::close(m_fd); + m_fd = -1; + } + LogMessage("Closing FM network connection"); } @@ -514,3 +557,16 @@ bool CFMNetwork::writeUSRPStart() } } +bool CFMNetwork::writeRawStart() +{ + if (m_fd != -1) { + size_t n = ::write(m_fd, "O", 1); + if (n != 1) { + LogError("Cannot write to the squelch file: %s, errno=%d", m_squelchFile.c_str(), errno); + return false; + } + } + + return true; +} + diff --git a/FMNetwork.h b/FMNetwork.h index 1eca534..9940f90 100644 --- a/FMNetwork.h +++ b/FMNetwork.h @@ -34,7 +34,7 @@ enum FM_NETWORK_PROTOCOL { class CFMNetwork { public: - CFMNetwork(const std::string& callsign, const std::string& protocol, const std::string& localAddress, unsigned short localPort, const std::string& gatewayAddress, unsigned short gatewayPort, unsigned int sampleRate, bool debug); + CFMNetwork(const std::string& callsign, const std::string& protocol, const std::string& localAddress, unsigned short localPort, const std::string& gatewayAddress, unsigned short gatewayPort, unsigned int sampleRate, const std::string& squelchFile, bool debug); ~CFMNetwork(); bool open(); @@ -60,19 +60,23 @@ private: sockaddr_storage m_addr; unsigned int m_addrLen; unsigned int m_sampleRate; + std::string m_squelchFile; bool m_debug; bool m_enabled; CRingBuffer m_buffer; unsigned int m_seqNo; SRC_STATE* m_resampler; int m_error; + int m_fd; bool writeUSRPStart(); + bool writeRawStart(); bool writeUSRPData(const float* data, unsigned int nSamples); bool writeRawData(const float* in, unsigned int nIn); bool writeUSRPEnd(); + bool writeRawEnd(); }; #endif diff --git a/MMDVM.ini b/MMDVM.ini index c72cdd8..9693e38 100644 --- a/MMDVM.ini +++ b/MMDVM.ini @@ -291,6 +291,8 @@ Enable=1 Protocol=USRP # SampleRate is only used in RAW mode SampleRate=48000 +# The squelch file is optional and only used in RAW mode +SquelchFile=/tmp/sql LocalAddress=127.0.0.1 LocalPort=3810 GatewayAddress=127.0.0.1 diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index b807133..4cc1c18 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -1887,6 +1887,7 @@ bool CMMDVMHost::createFMNetwork() std::string callsign = m_conf.getFMCallsign(); std::string protocol = m_conf.getFMNetworkProtocol(); unsigned int sampleRate = m_conf.getFMNetworkSampleRate(); + std::string squelchFile = m_conf.getFMNetworkSquelchFile(); std::string gatewayAddress = m_conf.getFMGatewayAddress(); unsigned short gatewayPort = m_conf.getFMGatewayPort(); std::string localAddress = m_conf.getFMLocalAddress(); @@ -1900,8 +1901,10 @@ bool CMMDVMHost::createFMNetwork() LogInfo("FM Network Parameters"); LogInfo(" Protocol: %s", protocol.c_str()); - if (protocol == "RAW") + if (protocol == "RAW") { LogInfo(" Sample Rate: %u", sampleRate); + LogInfo(" Squelch File: %s", squelchFile.empty() ? "(none)" : squelchFile.c_str()); + } LogInfo(" Gateway Address: %s", gatewayAddress.c_str()); LogInfo(" Gateway Port: %hu", gatewayPort); LogInfo(" Local Address: %s", localAddress.c_str()); @@ -1912,7 +1915,7 @@ bool CMMDVMHost::createFMNetwork() LogInfo(" RX Audio Gain: %.2f", rxAudioGain); LogInfo(" Mode Hang: %us", m_fmNetModeHang); - m_fmNetwork = new CFMNetwork(callsign, protocol, localAddress, localPort, gatewayAddress, gatewayPort, sampleRate, debug); + m_fmNetwork = new CFMNetwork(callsign, protocol, localAddress, localPort, gatewayAddress, gatewayPort, sampleRate, squelchFile, debug); bool ret = m_fmNetwork->open(); if (!ret) { diff --git a/Version.h b/Version.h index e8bf195..439756d 100644 --- a/Version.h +++ b/Version.h @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20231018"; +const char* VERSION = "20231025"; #endif