diff --git a/FMControl.cpp b/FMControl.cpp index 8cb7183..bf54cfb 100644 --- a/FMControl.cpp +++ b/FMControl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020,2021 by Jonathan Naylor G4KLX + * Copyright (C) 2020,2021,2024 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 @@ -24,6 +24,8 @@ #include #endif +#include + #define SWAP_BYTES_16(a) (((a >> 8) & 0x00FFU) | ((a << 8) & 0xFF00U)) const float DEEMPHASIS_GAIN_DB = 8.0F; // Audio gain adjustment @@ -31,7 +33,7 @@ const float PREEMPHASIS_GAIN_DB = 0.0F; // Audio gain adjustment const float FILTER_GAIN_DB = 2.0F; // Audio gain adjustment const unsigned int FM_MASK = 0x00000FFFU; -CFMControl::CFMControl(CFMNetwork* network, float txAudioGain, float rxAudioGain, bool preEmphasisOn, bool deEmphasisOn) : +CFMControl::CFMControl(IFMNetwork* network, float txAudioGain, float rxAudioGain, bool preEmphasisOn, bool deEmphasisOn) : m_network(network), m_txAudioGain(txAudioGain), m_rxAudioGain(rxAudioGain), diff --git a/FMControl.h b/FMControl.h index 9344f77..0e4747f 100644 --- a/FMControl.h +++ b/FMControl.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020,2021 by Jonathan Naylor G4KLX + * Copyright (C) 2020,2021,2024 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 @@ -22,6 +22,7 @@ #include "FMNetwork.h" #include "Defines.h" #include "IIRDirectForm1Filter.h" +#include "RingBuffer.h" // Uncomment this to dump audio to a raw audio file // The file will be written in same folder as executable @@ -30,7 +31,7 @@ class CFMControl { public: - CFMControl(CFMNetwork* network, float txAudioGain, float rxAudioGain, bool preEmphasisOn, bool deEmphasisOn); + CFMControl(IFMNetwork* network, float txAudioGain, float rxAudioGain, bool preEmphasisOn, bool deEmphasisOn); ~CFMControl(); bool writeModem(const unsigned char* data, unsigned int length); @@ -42,7 +43,7 @@ public: void enable(bool enabled); private: - CFMNetwork* m_network; + IFMNetwork* m_network; float m_txAudioGain; float m_rxAudioGain; bool m_preEmphasisOn; diff --git a/FMIAXNetwork.cpp b/FMIAXNetwork.cpp new file mode 100644 index 0000000..8b7f79f --- /dev/null +++ b/FMIAXNetwork.cpp @@ -0,0 +1,392 @@ +/* + * Copyright (C) 2020,2021,2023,2024 by Jonathan Naylor G4KLX + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "FMIAXNetwork.h" +#include "Defines.h" +#include "Utils.h" +#include "Log.h" + +#include +#include +#include + +#include +#include +#include +#include + +const unsigned int BUFFER_LENGTH = 1500U; + +CFMIAXNetwork::CFMIAXNetwork(const std::string& callsign, const std::string& localAddress, unsigned short localPort, const std::string& gatewayAddress, unsigned short gatewayPort, bool debug) : +m_callsign(callsign), +m_socket(localAddress, localPort), +m_addr(), +m_addrLen(0U), +m_debug(debug), +m_enabled(false), +m_buffer(2000U, "FM Network"), +m_seqNo(0U) +{ + assert(!callsign.empty()); + assert(gatewayPort > 0U); + assert(!gatewayAddress.empty()); + + if (CUDPSocket::lookup(gatewayAddress, gatewayPort, m_addr, m_addrLen) != 0) + m_addrLen = 0U; + + // Remove any trailing letters in the callsign + size_t pos = callsign.find_first_of(' '); + if (pos != std::string::npos) + m_callsign = callsign.substr(0U, pos); +} + +CFMIAXNetwork::~CFMIAXNetwork() +{ +} + +bool CFMIAXNetwork::open() +{ + if (m_addrLen == 0U) { + LogError("Unable to resolve the address of the FM Gateway"); + return false; + } + + LogMessage("Opening FM USRP network connection"); + + return m_socket.open(m_addr); +} + +bool CFMIAXNetwork::writeData(const float* data, unsigned int nSamples) +{ + assert(data != NULL); + assert(nSamples > 0U); + + if (m_seqNo == 0U) { + bool ret = writeStart(); + if (!ret) + return false; + } + + unsigned char buffer[500U]; + ::memset(buffer, 0x00U, 500U); + + unsigned int length = 0U; + + buffer[length++] = 'U'; + buffer[length++] = 'S'; + buffer[length++] = 'R'; + buffer[length++] = 'P'; + + // Sequence number + buffer[length++] = (m_seqNo >> 24) & 0xFFU; + buffer[length++] = (m_seqNo >> 16) & 0xFFU; + buffer[length++] = (m_seqNo >> 8) & 0xFFU; + buffer[length++] = (m_seqNo >> 0) & 0xFFU; + + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + + // PTT on + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x01U; + + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + + // Type, 0 for audio + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + + for (unsigned int i = 0U; i < nSamples; i++) { + short val = short(data[i] * 32767.0F + 0.5F); // Changing audio format from float to S16LE + + buffer[length++] = (val >> 0) & 0xFFU; + buffer[length++] = (val >> 8) & 0xFFU; + } + + if (m_debug) + CUtils::dump(1U, "FM USRP Network Data Sent", buffer, length); + + m_seqNo++; + + return m_socket.write(buffer, length, m_addr, m_addrLen); +} + +bool CFMIAXNetwork::writeEnd() +{ + unsigned char buffer[500U]; + ::memset(buffer, 0x00U, 500U); + + unsigned int length = 0U; + + buffer[length++] = 'U'; + buffer[length++] = 'S'; + buffer[length++] = 'R'; + buffer[length++] = 'P'; + + // Sequence number + buffer[length++] = (m_seqNo >> 24) & 0xFFU; + buffer[length++] = (m_seqNo >> 16) & 0xFFU; + buffer[length++] = (m_seqNo >> 8) & 0xFFU; + buffer[length++] = (m_seqNo >> 0) & 0xFFU; + + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + + // PTT off + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + + // Type, 0 for audio + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + + length += 320U; + + m_seqNo = 0U; + + if (length > 0U) { + if (m_debug) + CUtils::dump(1U, "FM USRP Network Data Sent", buffer, length); + + return m_socket.write(buffer, length, m_addr, m_addrLen); + } else { + return true; + } +} + +void CFMIAXNetwork::clock(unsigned int ms) +{ + unsigned char buffer[BUFFER_LENGTH]; + + sockaddr_storage addr; + unsigned int addrlen; + int length = m_socket.read(buffer, BUFFER_LENGTH, addr, addrlen); + if (length <= 0) + return; + + // Check if the data is for us + if (!CUDPSocket::match(addr, m_addr, IMT_ADDRESS_AND_PORT)) { + LogMessage("FM USRP packet received from an invalid source"); + return; + } + + if (!m_enabled) + return; + + if (m_debug) + CUtils::dump(1U, "FM USRP Network Data Received", buffer, length); + + // Invalid packet type? + if (::memcmp(buffer, "USRP", 4U) != 0) + return; + + if (length < 32) + return; + + // The type is a big-endian 4-byte integer + unsigned int type = (buffer[20U] << 24) + + (buffer[21U] << 16) + + (buffer[22U] << 8) + + (buffer[23U] << 0); + + if (type == 0U) + m_buffer.addData(buffer + 32U, length - 32U); +} + +unsigned int CFMIAXNetwork::readData(float* out, unsigned int nOut) +{ + assert(out != NULL); + assert(nOut > 0U); + + unsigned int bytes = m_buffer.dataSize() / sizeof(unsigned short); + if (bytes == 0U) + return 0U; + + if (bytes < nOut) + nOut = bytes; + + unsigned char buffer[1500U]; + m_buffer.getData(buffer, nOut * sizeof(unsigned short)); + + for (unsigned int i = 0U; i < nOut; i++) { + short val = ((buffer[i * 2U + 0U] & 0xFFU) << 0) + ((buffer[i * 2U + 1U] & 0xFFU) << 8); + out[i] = float(val) / 65536.0F; + } + + return nOut; +} + +void CFMIAXNetwork::reset() +{ + m_buffer.clear(); +} + +void CFMIAXNetwork::close() +{ + m_socket.close(); + + LogMessage("Closing FM USRP network connection"); +} + +void CFMIAXNetwork::enable(bool enabled) +{ + if (enabled && !m_enabled) + reset(); + else if (!enabled && m_enabled) + reset(); + + m_enabled = enabled; +} + +bool CFMIAXNetwork::writeStart() +{ + unsigned char buffer[500U]; + ::memset(buffer, 0x00U, 500U); + + unsigned int length = 0U; + + buffer[length++] = 'U'; + buffer[length++] = 'S'; + buffer[length++] = 'R'; + buffer[length++] = 'P'; + + // Sequence number + buffer[length++] = (m_seqNo >> 24) & 0xFFU; + buffer[length++] = (m_seqNo >> 16) & 0xFFU; + buffer[length++] = (m_seqNo >> 8) & 0xFFU; + buffer[length++] = (m_seqNo >> 0) & 0xFFU; + + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + + // PTT off + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + + // Type, 2 for metadata + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x02U; + + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + + // TLV TAG for Metadata + buffer[length++] = 0x08U; + + // TLV Length + buffer[length++] = 3U + 4U + 3U + 1U + 1U + m_callsign.size() + 1U; + + // DMR Id + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + + // Rpt Id + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + + // Talk Group + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + + // Time Slot + buffer[length++] = 0x00U; + + // Color Code + buffer[length++] = 0x00U; + + // Callsign + for (std::string::const_iterator it = m_callsign.cbegin(); it != m_callsign.cend(); ++it) + buffer[length++] = *it; + + // End of Metadata + buffer[length++] = 0x00U; + + length = 70U; + + if (length > 0U) { + if (m_debug) + CUtils::dump(1U, "FM USRP Network Data Sent", buffer, length); + + return m_socket.write(buffer, length, m_addr, m_addrLen); + } else { + return true; + } +} + diff --git a/FMIAXNetwork.h b/FMIAXNetwork.h new file mode 100644 index 0000000..9cfb650 --- /dev/null +++ b/FMIAXNetwork.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2020,2021,2023,2024 by Jonathan Naylor G4KLX + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef FMIAXNetwork_H +#define FMIAXNetwork_H + +#include "FMNetwork.h" +#include "RingBuffer.h" +#include "UDPSocket.h" + +#include +#include + +class CFMIAXNetwork : public IFMNetwork { +public: + CFMIAXNetwork(const std::string& callsign, const std::string& localAddress, unsigned short localPort, const std::string& gatewayAddress, unsigned short gatewayPort, bool debug); + virtual ~CFMIAXNetwork(); + + virtual bool open(); + + virtual void enable(bool enabled); + + virtual bool writeData(const float* data, unsigned int nSamples); + + virtual bool writeEnd(); + + virtual unsigned int readData(float* out, unsigned int nOut); + + virtual void reset(); + + virtual void close(); + + virtual void clock(unsigned int ms); + +private: + std::string m_callsign; + CUDPSocket m_socket; + sockaddr_storage m_addr; + unsigned int m_addrLen; + bool m_debug; + bool m_enabled; + CRingBuffer m_buffer; + unsigned int m_seqNo; + + bool writeStart(); +}; + +#endif + diff --git a/FMNetwork.cpp b/FMNetwork.cpp index 02ff5bf..4b95197 100644 --- a/FMNetwork.cpp +++ b/FMNetwork.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020,2021,2023 by Jonathan Naylor G4KLX + * Copyright (C) 2020,2021,2023,2024 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 @@ -17,556 +17,8 @@ */ #include "FMNetwork.h" -#include "Defines.h" -#include "Utils.h" -#include "Log.h" -#include -#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, 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_fd(-1) +IFMNetwork::~IFMNetwork() { - assert(!callsign.empty()); - assert(gatewayPort > 0U); - assert(!gatewayAddress.empty()); - assert(sampleRate > 0U); - - if (CUDPSocket::lookup(gatewayAddress, gatewayPort, m_addr, m_addrLen) != 0) - m_addrLen = 0U; - - // Remove any trailing letters in the callsign - size_t pos = callsign.find_first_of(' '); - if (pos != std::string::npos) - m_callsign = callsign.substr(0U, pos); - - if (protocol == "RAW") - m_protocol = FMNP_RAW; - else - m_protocol = FMNP_USRP; - - m_resampler = ::src_new(SRC_SINC_FASTEST, 1, &m_error); -} - -CFMNetwork::~CFMNetwork() -{ - ::src_delete(m_resampler); -} - -bool CFMNetwork::open() -{ - if (m_addrLen == 0U) { - LogError("Unable to resolve the address of the FM Gateway"); - return false; - } - - 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); -} - -bool CFMNetwork::writeData(const float* data, unsigned int nSamples) -{ - assert(data != NULL); - assert(nSamples > 0U); - - if (m_protocol == FMNP_USRP) - return writeUSRPData(data, nSamples); - else if (m_protocol == FMNP_RAW) - return writeRawData(data, nSamples); - else - return false; -} - -bool CFMNetwork::writeUSRPData(const float* data, unsigned int nSamples) -{ - assert(data != NULL); - assert(nSamples > 0U); - - if (m_seqNo == 0U) { - bool ret = writeUSRPStart(); - if (!ret) - return false; - } - - unsigned char buffer[500U]; - ::memset(buffer, 0x00U, 500U); - - unsigned int length = 0U; - - buffer[length++] = 'U'; - buffer[length++] = 'S'; - buffer[length++] = 'R'; - buffer[length++] = 'P'; - - // Sequence number - buffer[length++] = (m_seqNo >> 24) & 0xFFU; - buffer[length++] = (m_seqNo >> 16) & 0xFFU; - buffer[length++] = (m_seqNo >> 8) & 0xFFU; - buffer[length++] = (m_seqNo >> 0) & 0xFFU; - - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - - // PTT on - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - buffer[length++] = 0x01U; - - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - - // Type, 0 for audio - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - - for (unsigned int i = 0U; i < nSamples; i++) { - short val = short(data[i] * 32767.0F + 0.5F); // Changing audio format from float to S16LE - - buffer[length++] = (val >> 0) & 0xFFU; - buffer[length++] = (val >> 8) & 0xFFU; - } - - if (m_debug) - CUtils::dump(1U, "FM Network Data Sent", buffer, length); - - m_seqNo++; - - return m_socket.write(buffer, length, m_addr, m_addrLen); -} - -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; - - if (m_sampleRate != MMDVM_SAMPLERATE) { - unsigned int nOut = (nIn * m_sampleRate) / MMDVM_SAMPLERATE; - - float out[1000U]; - - SRC_DATA data; - data.data_in = in; - data.data_out = out; - data.input_frames = nIn; - data.output_frames = nOut; - data.end_of_input = 0; - data.src_ratio = float(m_sampleRate) / float(MMDVM_SAMPLERATE); - - int ret = ::src_process(m_resampler, &data); - if (ret != 0) { - LogError("Error from the write resampler - %d - %s", ret, ::src_strerror(ret)); - return false; - } - - for (unsigned int i = 0U; i < nOut; i++) { - short val = short(out[i] * 32767.0F + 0.5F); // Changing audio format from float to S16LE - - buffer[length++] = (val >> 0) & 0xFFU; - buffer[length++] = (val >> 8) & 0xFFU; - } - } else { - for (unsigned int i = 0U; i < nIn; i++) { - short val = short(in[i] * 32767.0F + 0.5F); // Changing audio format from float to S16LE - - buffer[length++] = (val >> 0) & 0xFFU; - buffer[length++] = (val >> 8) & 0xFFU; - } - } - - if (m_debug) - CUtils::dump(1U, "FM Network Data Sent", buffer, length); - - m_seqNo++; - - return m_socket.write(buffer, length, m_addr, m_addrLen); -} - -bool CFMNetwork::writeEnd() -{ - if (m_protocol == FMNP_USRP) - return writeUSRPEnd(); - else - return writeRawEnd(); -} - -bool CFMNetwork::writeUSRPEnd() -{ - unsigned char buffer[500U]; - ::memset(buffer, 0x00U, 500U); - - unsigned int length = 0U; - - buffer[length++] = 'U'; - buffer[length++] = 'S'; - buffer[length++] = 'R'; - buffer[length++] = 'P'; - - // Sequence number - buffer[length++] = (m_seqNo >> 24) & 0xFFU; - buffer[length++] = (m_seqNo >> 16) & 0xFFU; - buffer[length++] = (m_seqNo >> 8) & 0xFFU; - buffer[length++] = (m_seqNo >> 0) & 0xFFU; - - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - - // PTT off - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - - // Type, 0 for audio - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - - length += 320U; - - m_seqNo = 0U; - - if (length > 0U) { - if (m_debug) - CUtils::dump(1U, "FM Network Data Sent", buffer, length); - - return m_socket.write(buffer, length, m_addr, m_addrLen); - } else { - return true; - } -} - -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]; - - sockaddr_storage addr; - unsigned int addrlen; - int length = m_socket.read(buffer, BUFFER_LENGTH, addr, addrlen); - if (length <= 0) - return; - - // Check if the data is for us - if (m_protocol == FMNP_USRP) { - if (!CUDPSocket::match(addr, m_addr, IMT_ADDRESS_AND_PORT)) { - LogMessage("FM packet received from an invalid source"); - return; - } - } else { - if (!CUDPSocket::match(addr, m_addr, IMT_ADDRESS_ONLY)) { - LogMessage("FM packet received from an invalid source"); - return; - } - } - - if (!m_enabled) - return; - - if (m_debug) - CUtils::dump(1U, "FM Network Data Received", buffer, length); - - if (m_protocol == FMNP_USRP) { - // Invalid packet type? - if (::memcmp(buffer, "USRP", 4U) != 0) - return; - - if (length < 32) - return; - - // The type is a big-endian 4-byte integer - unsigned int type = (buffer[20U] << 24) + - (buffer[21U] << 16) + - (buffer[22U] << 8) + - (buffer[23U] << 0); - - if (type == 0U) - m_buffer.addData(buffer + 32U, length - 32U); - } else if (m_protocol == FMNP_RAW) { - m_buffer.addData(buffer, length); - } -} - -unsigned int CFMNetwork::readData(float* out, unsigned int nOut) -{ - assert(out != NULL); - assert(nOut > 0U); - - unsigned int bytes = m_buffer.dataSize() / sizeof(unsigned short); - if (bytes == 0U) - return 0U; - - if ((m_protocol == FMNP_RAW) && (m_sampleRate != MMDVM_SAMPLERATE)) { - unsigned int nIn = (nOut * m_sampleRate) / MMDVM_SAMPLERATE; - - if (bytes < nIn) { - nIn = bytes; - nOut = (nIn * MMDVM_SAMPLERATE) / m_sampleRate; - } - - unsigned char buffer[2000U]; - m_buffer.getData(buffer, nIn * sizeof(unsigned short)); - - float in[1000U]; - - for (unsigned int i = 0U; i < nIn; i++) { - short val = ((buffer[i * 2U + 0U] & 0xFFU) << 0) + ((buffer[i * 2U + 1U] & 0xFFU) << 8); - in[i] = float(val) / 65536.0F; - } - - SRC_DATA data; - data.data_in = in; - data.data_out = out; - data.input_frames = nIn; - data.output_frames = nOut; - data.end_of_input = 0; - data.src_ratio = float(MMDVM_SAMPLERATE) / float(m_sampleRate); - - int ret = ::src_process(m_resampler, &data); - if (ret != 0) { - LogError("Error from the read resampler - %d - %s", ret, ::src_strerror(ret)); - return false; - } - } else { - if (bytes < nOut) - nOut = bytes; - - unsigned char buffer[1500U]; - m_buffer.getData(buffer, nOut * sizeof(unsigned short)); - - for (unsigned int i = 0U; i < nOut; i++) { - short val = ((buffer[i * 2U + 0U] & 0xFFU) << 0) + ((buffer[i * 2U + 1U] & 0xFFU) << 8); - out[i] = float(val) / 65536.0F; - } - } - - return nOut; -} - -void CFMNetwork::reset() -{ - m_buffer.clear(); -} - -void CFMNetwork::close() -{ - m_socket.close(); - - if (m_fd != -1) { - ::close(m_fd); - m_fd = -1; - } - - LogMessage("Closing FM network connection"); -} - -void CFMNetwork::enable(bool enabled) -{ - if (enabled && !m_enabled) - reset(); - else if (!enabled && m_enabled) - reset(); - - m_enabled = enabled; -} - -bool CFMNetwork::writeUSRPStart() -{ - unsigned char buffer[500U]; - ::memset(buffer, 0x00U, 500U); - - unsigned int length = 0U; - - buffer[length++] = 'U'; - buffer[length++] = 'S'; - buffer[length++] = 'R'; - buffer[length++] = 'P'; - - // Sequence number - buffer[length++] = (m_seqNo >> 24) & 0xFFU; - buffer[length++] = (m_seqNo >> 16) & 0xFFU; - buffer[length++] = (m_seqNo >> 8) & 0xFFU; - buffer[length++] = (m_seqNo >> 0) & 0xFFU; - - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - - // PTT off - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - - // Type, 2 for metadata - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - buffer[length++] = 0x02U; - - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - - // TLV TAG for Metadata - buffer[length++] = 0x08U; - - // TLV Length - buffer[length++] = 3U + 4U + 3U + 1U + 1U + m_callsign.size() + 1U; - - // DMR Id - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - - // Rpt Id - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - - // Talk Group - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - buffer[length++] = 0x00U; - - // Time Slot - buffer[length++] = 0x00U; - - // Color Code - buffer[length++] = 0x00U; - - // Callsign - for (std::string::const_iterator it = m_callsign.cbegin(); it != m_callsign.cend(); ++it) - buffer[length++] = *it; - - // End of Metadata - buffer[length++] = 0x00U; - - length = 70U; - - if (length > 0U) { - if (m_debug) - CUtils::dump(1U, "FM Network Data Sent", buffer, length); - - return m_socket.write(buffer, length, m_addr, m_addrLen); - } else { - return true; - } -} - -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 9940f90..3721c33 100644 --- a/FMNetwork.h +++ b/FMNetwork.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020,2021,2023 by Jonathan Naylor G4KLX + * Copyright (C) 2020,2021,2023,2024 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,64 +19,30 @@ #ifndef FMNetwork_H #define FMNetwork_H -#include "RingBuffer.h" -#include "UDPSocket.h" - -#include - #include #include -enum FM_NETWORK_PROTOCOL { - FMNP_USRP, - FMNP_RAW -}; - -class CFMNetwork { +class IFMNetwork { 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, const std::string& squelchFile, bool debug); - ~CFMNetwork(); + virtual ~IFMNetwork() = 0; - bool open(); + virtual bool open() = 0; - void enable(bool enabled); + virtual void enable(bool enabled) = 0; - bool writeData(const float* data, unsigned int nSamples); + virtual bool writeData(const float* data, unsigned int nSamples) = 0; - bool writeEnd(); + virtual bool writeEnd() = 0; - unsigned int readData(float* out, unsigned int nOut); + virtual unsigned int readData(float* out, unsigned int nOut) = 0; - void reset(); + virtual void reset() = 0; - void close(); + virtual void close() = 0; - void clock(unsigned int ms); + virtual void clock(unsigned int ms) = 0; private: - std::string m_callsign; - FM_NETWORK_PROTOCOL m_protocol; - CUDPSocket m_socket; - 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/FMRAWNetwork.cpp b/FMRAWNetwork.cpp new file mode 100644 index 0000000..da60b6f --- /dev/null +++ b/FMRAWNetwork.cpp @@ -0,0 +1,277 @@ +/* + * Copyright (C) 2020,2021,2023,2024 by Jonathan Naylor G4KLX + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "FMRAWNetwork.h" +#include "Defines.h" +#include "Utils.h" +#include "Log.h" + +#include +#include +#include + +#include +#include +#include +#include + +const unsigned int MMDVM_SAMPLERATE = 8000U; + +const unsigned int BUFFER_LENGTH = 1500U; + +CFMRAWNetwork::CFMRAWNetwork(const std::string& localAddress, unsigned short localPort, const std::string& gatewayAddress, unsigned short gatewayPort, unsigned int sampleRate, const std::string& squelchFile, bool debug) : +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_fd(-1) +{ + assert(gatewayPort > 0U); + assert(!gatewayAddress.empty()); + assert(sampleRate > 0U); + + if (CUDPSocket::lookup(gatewayAddress, gatewayPort, m_addr, m_addrLen) != 0) + m_addrLen = 0U; + + m_resampler = ::src_new(SRC_SINC_FASTEST, 1, &m_error); +} + +CFMRAWNetwork::~CFMRAWNetwork() +{ + ::src_delete(m_resampler); +} + +bool CFMRAWNetwork::open() +{ + if (m_addrLen == 0U) { + LogError("Unable to resolve the address of the FM Gateway"); + return false; + } + + LogMessage("Opening FM RAW 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); +} + +bool CFMRAWNetwork::writeData(const float* in, unsigned int nIn) +{ + assert(in != NULL); + assert(nIn > 0U); + + if (m_seqNo == 0U) { + bool ret = writeStart(); + if (!ret) + return false; + } + + unsigned char buffer[2000U]; + + unsigned int length = 0U; + + if (m_sampleRate != MMDVM_SAMPLERATE) { + unsigned int nOut = (nIn * m_sampleRate) / MMDVM_SAMPLERATE; + + float out[1000U]; + + SRC_DATA data; + data.data_in = in; + data.data_out = out; + data.input_frames = nIn; + data.output_frames = nOut; + data.end_of_input = 0; + data.src_ratio = float(m_sampleRate) / float(MMDVM_SAMPLERATE); + + int ret = ::src_process(m_resampler, &data); + if (ret != 0) { + LogError("Error from the write resampler - %d - %s", ret, ::src_strerror(ret)); + return false; + } + + for (unsigned int i = 0U; i < nOut; i++) { + short val = short(out[i] * 32767.0F + 0.5F); // Changing audio format from float to S16LE + + buffer[length++] = (val >> 0) & 0xFFU; + buffer[length++] = (val >> 8) & 0xFFU; + } + } else { + for (unsigned int i = 0U; i < nIn; i++) { + short val = short(in[i] * 32767.0F + 0.5F); // Changing audio format from float to S16LE + + buffer[length++] = (val >> 0) & 0xFFU; + buffer[length++] = (val >> 8) & 0xFFU; + } + } + + if (m_debug) + CUtils::dump(1U, "FM RAW Network Data Sent", buffer, length); + + m_seqNo++; + + return m_socket.write(buffer, length, m_addr, m_addrLen); +} + +bool CFMRAWNetwork::writeEnd() +{ + 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 CFMRAWNetwork::clock(unsigned int ms) +{ + unsigned char buffer[BUFFER_LENGTH]; + + sockaddr_storage addr; + unsigned int addrlen; + int length = m_socket.read(buffer, BUFFER_LENGTH, addr, addrlen); + if (length <= 0) + return; + + if (!CUDPSocket::match(addr, m_addr, IMT_ADDRESS_ONLY)) { + LogMessage("FM RAW packet received from an invalid source"); + return; + } + + if (!m_enabled) + return; + + if (m_debug) + CUtils::dump(1U, "FM RAW Network Data Received", buffer, length); + + m_buffer.addData(buffer, length); +} + +unsigned int CFMRAWNetwork::readData(float* out, unsigned int nOut) +{ + assert(out != NULL); + assert(nOut > 0U); + + unsigned int bytes = m_buffer.dataSize() / sizeof(unsigned short); + if (bytes == 0U) + return 0U; + + if (m_sampleRate != MMDVM_SAMPLERATE) { + unsigned int nIn = (nOut * m_sampleRate) / MMDVM_SAMPLERATE; + + if (bytes < nIn) { + nIn = bytes; + nOut = (nIn * MMDVM_SAMPLERATE) / m_sampleRate; + } + + unsigned char buffer[2000U]; + m_buffer.getData(buffer, nIn * sizeof(unsigned short)); + + float in[1000U]; + + for (unsigned int i = 0U; i < nIn; i++) { + short val = ((buffer[i * 2U + 0U] & 0xFFU) << 0) + ((buffer[i * 2U + 1U] & 0xFFU) << 8); + in[i] = float(val) / 65536.0F; + } + + SRC_DATA data; + data.data_in = in; + data.data_out = out; + data.input_frames = nIn; + data.output_frames = nOut; + data.end_of_input = 0; + data.src_ratio = float(MMDVM_SAMPLERATE) / float(m_sampleRate); + + int ret = ::src_process(m_resampler, &data); + if (ret != 0) { + LogError("Error from the read resampler - %d - %s", ret, ::src_strerror(ret)); + return false; + } + } else { + if (bytes < nOut) + nOut = bytes; + + unsigned char buffer[1500U]; + m_buffer.getData(buffer, nOut * sizeof(unsigned short)); + + for (unsigned int i = 0U; i < nOut; i++) { + short val = ((buffer[i * 2U + 0U] & 0xFFU) << 0) + ((buffer[i * 2U + 1U] & 0xFFU) << 8); + out[i] = float(val) / 65536.0F; + } + } + + return nOut; +} + +void CFMRAWNetwork::reset() +{ + m_buffer.clear(); +} + +void CFMRAWNetwork::close() +{ + m_socket.close(); + + if (m_fd != -1) { + ::close(m_fd); + m_fd = -1; + } + + LogMessage("Closing FM RAW network connection"); +} + +void CFMRAWNetwork::enable(bool enabled) +{ + if (enabled && !m_enabled) + reset(); + else if (!enabled && m_enabled) + reset(); + + m_enabled = enabled; +} + +bool CFMRAWNetwork::writeStart() +{ + 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/FMRAWNetwork.h b/FMRAWNetwork.h new file mode 100644 index 0000000..7012330 --- /dev/null +++ b/FMRAWNetwork.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2020,2021,2023,2024 by Jonathan Naylor G4KLX + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef FMRAWNetwork_H +#define FMRAWNetwork_H + +#include "FMNetwork.h" +#include "RingBuffer.h" +#include "UDPSocket.h" + +#include + +#include +#include + +class CFMRAWNetwork : public IFMNetwork { +public: + CFMRAWNetwork(const std::string& localAddress, unsigned short localPort, const std::string& gatewayAddress, unsigned short gatewayPort, unsigned int sampleRate, const std::string& squelchFile, bool debug); + virtual ~CFMRAWNetwork(); + + virtual bool open(); + + virtual void enable(bool enabled); + + virtual bool writeData(const float* in, unsigned int nIn); + + virtual bool writeEnd(); + + virtual unsigned int readData(float* out, unsigned int nOut); + + virtual void reset(); + + virtual void close(); + + virtual void clock(unsigned int ms); + +private: + CUDPSocket m_socket; + 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 writeStart(); +}; + +#endif + diff --git a/FMUSRPNetwork.cpp b/FMUSRPNetwork.cpp new file mode 100644 index 0000000..980d7a2 --- /dev/null +++ b/FMUSRPNetwork.cpp @@ -0,0 +1,392 @@ +/* + * Copyright (C) 2020,2021,2023,2024 by Jonathan Naylor G4KLX + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "FMUSRPNetwork.h" +#include "Defines.h" +#include "Utils.h" +#include "Log.h" + +#include +#include +#include + +#include +#include +#include +#include + +const unsigned int BUFFER_LENGTH = 1500U; + +CFMUSRPNetwork::CFMUSRPNetwork(const std::string& callsign, const std::string& localAddress, unsigned short localPort, const std::string& gatewayAddress, unsigned short gatewayPort, bool debug) : +m_callsign(callsign), +m_socket(localAddress, localPort), +m_addr(), +m_addrLen(0U), +m_debug(debug), +m_enabled(false), +m_buffer(2000U, "FM Network"), +m_seqNo(0U) +{ + assert(!callsign.empty()); + assert(gatewayPort > 0U); + assert(!gatewayAddress.empty()); + + if (CUDPSocket::lookup(gatewayAddress, gatewayPort, m_addr, m_addrLen) != 0) + m_addrLen = 0U; + + // Remove any trailing letters in the callsign + size_t pos = callsign.find_first_of(' '); + if (pos != std::string::npos) + m_callsign = callsign.substr(0U, pos); +} + +CFMUSRPNetwork::~CFMUSRPNetwork() +{ +} + +bool CFMUSRPNetwork::open() +{ + if (m_addrLen == 0U) { + LogError("Unable to resolve the address of the FM Gateway"); + return false; + } + + LogMessage("Opening FM USRP network connection"); + + return m_socket.open(m_addr); +} + +bool CFMUSRPNetwork::writeData(const float* data, unsigned int nSamples) +{ + assert(data != NULL); + assert(nSamples > 0U); + + if (m_seqNo == 0U) { + bool ret = writeStart(); + if (!ret) + return false; + } + + unsigned char buffer[500U]; + ::memset(buffer, 0x00U, 500U); + + unsigned int length = 0U; + + buffer[length++] = 'U'; + buffer[length++] = 'S'; + buffer[length++] = 'R'; + buffer[length++] = 'P'; + + // Sequence number + buffer[length++] = (m_seqNo >> 24) & 0xFFU; + buffer[length++] = (m_seqNo >> 16) & 0xFFU; + buffer[length++] = (m_seqNo >> 8) & 0xFFU; + buffer[length++] = (m_seqNo >> 0) & 0xFFU; + + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + + // PTT on + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x01U; + + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + + // Type, 0 for audio + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + + for (unsigned int i = 0U; i < nSamples; i++) { + short val = short(data[i] * 32767.0F + 0.5F); // Changing audio format from float to S16LE + + buffer[length++] = (val >> 0) & 0xFFU; + buffer[length++] = (val >> 8) & 0xFFU; + } + + if (m_debug) + CUtils::dump(1U, "FM USRP Network Data Sent", buffer, length); + + m_seqNo++; + + return m_socket.write(buffer, length, m_addr, m_addrLen); +} + +bool CFMUSRPNetwork::writeEnd() +{ + unsigned char buffer[500U]; + ::memset(buffer, 0x00U, 500U); + + unsigned int length = 0U; + + buffer[length++] = 'U'; + buffer[length++] = 'S'; + buffer[length++] = 'R'; + buffer[length++] = 'P'; + + // Sequence number + buffer[length++] = (m_seqNo >> 24) & 0xFFU; + buffer[length++] = (m_seqNo >> 16) & 0xFFU; + buffer[length++] = (m_seqNo >> 8) & 0xFFU; + buffer[length++] = (m_seqNo >> 0) & 0xFFU; + + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + + // PTT off + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + + // Type, 0 for audio + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + + length += 320U; + + m_seqNo = 0U; + + if (length > 0U) { + if (m_debug) + CUtils::dump(1U, "FM USRP Network Data Sent", buffer, length); + + return m_socket.write(buffer, length, m_addr, m_addrLen); + } else { + return true; + } +} + +void CFMUSRPNetwork::clock(unsigned int ms) +{ + unsigned char buffer[BUFFER_LENGTH]; + + sockaddr_storage addr; + unsigned int addrlen; + int length = m_socket.read(buffer, BUFFER_LENGTH, addr, addrlen); + if (length <= 0) + return; + + // Check if the data is for us + if (!CUDPSocket::match(addr, m_addr, IMT_ADDRESS_AND_PORT)) { + LogMessage("FM USRP packet received from an invalid source"); + return; + } + + if (!m_enabled) + return; + + if (m_debug) + CUtils::dump(1U, "FM USRP Network Data Received", buffer, length); + + // Invalid packet type? + if (::memcmp(buffer, "USRP", 4U) != 0) + return; + + if (length < 32) + return; + + // The type is a big-endian 4-byte integer + unsigned int type = (buffer[20U] << 24) + + (buffer[21U] << 16) + + (buffer[22U] << 8) + + (buffer[23U] << 0); + + if (type == 0U) + m_buffer.addData(buffer + 32U, length - 32U); +} + +unsigned int CFMUSRPNetwork::readData(float* out, unsigned int nOut) +{ + assert(out != NULL); + assert(nOut > 0U); + + unsigned int bytes = m_buffer.dataSize() / sizeof(unsigned short); + if (bytes == 0U) + return 0U; + + if (bytes < nOut) + nOut = bytes; + + unsigned char buffer[1500U]; + m_buffer.getData(buffer, nOut * sizeof(unsigned short)); + + for (unsigned int i = 0U; i < nOut; i++) { + short val = ((buffer[i * 2U + 0U] & 0xFFU) << 0) + ((buffer[i * 2U + 1U] & 0xFFU) << 8); + out[i] = float(val) / 65536.0F; + } + + return nOut; +} + +void CFMUSRPNetwork::reset() +{ + m_buffer.clear(); +} + +void CFMUSRPNetwork::close() +{ + m_socket.close(); + + LogMessage("Closing FM USRP network connection"); +} + +void CFMUSRPNetwork::enable(bool enabled) +{ + if (enabled && !m_enabled) + reset(); + else if (!enabled && m_enabled) + reset(); + + m_enabled = enabled; +} + +bool CFMUSRPNetwork::writeStart() +{ + unsigned char buffer[500U]; + ::memset(buffer, 0x00U, 500U); + + unsigned int length = 0U; + + buffer[length++] = 'U'; + buffer[length++] = 'S'; + buffer[length++] = 'R'; + buffer[length++] = 'P'; + + // Sequence number + buffer[length++] = (m_seqNo >> 24) & 0xFFU; + buffer[length++] = (m_seqNo >> 16) & 0xFFU; + buffer[length++] = (m_seqNo >> 8) & 0xFFU; + buffer[length++] = (m_seqNo >> 0) & 0xFFU; + + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + + // PTT off + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + + // Type, 2 for metadata + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x02U; + + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + + // TLV TAG for Metadata + buffer[length++] = 0x08U; + + // TLV Length + buffer[length++] = 3U + 4U + 3U + 1U + 1U + m_callsign.size() + 1U; + + // DMR Id + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + + // Rpt Id + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + + // Talk Group + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + buffer[length++] = 0x00U; + + // Time Slot + buffer[length++] = 0x00U; + + // Color Code + buffer[length++] = 0x00U; + + // Callsign + for (std::string::const_iterator it = m_callsign.cbegin(); it != m_callsign.cend(); ++it) + buffer[length++] = *it; + + // End of Metadata + buffer[length++] = 0x00U; + + length = 70U; + + if (length > 0U) { + if (m_debug) + CUtils::dump(1U, "FM USRP Network Data Sent", buffer, length); + + return m_socket.write(buffer, length, m_addr, m_addrLen); + } else { + return true; + } +} + diff --git a/FMUSRPNetwork.h b/FMUSRPNetwork.h new file mode 100644 index 0000000..5def554 --- /dev/null +++ b/FMUSRPNetwork.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2020,2021,2023,2024 by Jonathan Naylor G4KLX + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef FMUSRPNetwork_H +#define FMUSRPNetwork_H + +#include "FMNetwork.h" +#include "RingBuffer.h" +#include "UDPSocket.h" + +#include +#include + +class CFMUSRPNetwork : public IFMNetwork { +public: + CFMUSRPNetwork(const std::string& callsign, const std::string& localAddress, unsigned short localPort, const std::string& gatewayAddress, unsigned short gatewayPort, bool debug); + virtual ~CFMUSRPNetwork(); + + virtual bool open(); + + virtual void enable(bool enabled); + + virtual bool writeData(const float* data, unsigned int nSamples); + + virtual bool writeEnd(); + + virtual unsigned int readData(float* out, unsigned int nOut); + + virtual void reset(); + + virtual void close(); + + virtual void clock(unsigned int ms); + +private: + std::string m_callsign; + CUDPSocket m_socket; + sockaddr_storage m_addr; + unsigned int m_addrLen; + bool m_debug; + bool m_enabled; + CRingBuffer m_buffer; + unsigned int m_seqNo; + + bool writeStart(); +}; + +#endif + diff --git a/MMDVM.ini b/MMDVM.ini index 7883cf4..3459f16 100644 --- a/MMDVM.ini +++ b/MMDVM.ini @@ -287,7 +287,7 @@ Debug=0 [FM Network] Enable=1 -# Protocol may be USRP or RAW +# Protocol may be USRP, RAW, or IAX Protocol=USRP # SampleRate is only used in RAW mode SampleRate=48000 diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index c01cbf5..3cfb8a0 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2021,2023 by Jonathan Naylor G4KLX + * Copyright (C) 2015-2021,2023,2024 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 @@ -24,6 +24,9 @@ #include "RSSIInterpolator.h" #include "NullController.h" #include "UARTController.h" +#include "FMUSRPNetwork.h" +#include "FMRAWNetwork.h" +#include "FMIAXNetwork.h" #if defined(__linux__) #include "I2CController.h" #endif @@ -1915,7 +1918,16 @@ 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, squelchFile, debug); + if (protocol == "USRP") { + m_fmNetwork = new CFMUSRPNetwork(callsign, localAddress, localPort, gatewayAddress, gatewayPort, debug); + } else if (protocol == "RAW") { + m_fmNetwork = new CFMRAWNetwork(localAddress, localPort, gatewayAddress, gatewayPort, sampleRate, squelchFile, debug); + } else if (protocol == "IAX") { + m_fmNetwork = new CFMIAXNetwork(callsign, localAddress, localPort, gatewayAddress, gatewayPort, debug); + } else { + LogError("Invalid FM network protocol specified - %s", protocol.c_str()); + return false; + } bool ret = m_fmNetwork->open(); if (!ret) { diff --git a/MMDVMHost.h b/MMDVMHost.h index a97f72e..1e8286e 100644 --- a/MMDVMHost.h +++ b/MMDVMHost.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2021 by Jonathan Naylor G4KLX + * Copyright (C) 2015-2021,2024 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 @@ -78,7 +78,7 @@ private: INXDNNetwork* m_nxdnNetwork; CM17Network* m_m17Network; CPOCSAGNetwork* m_pocsagNetwork; - CFMNetwork* m_fmNetwork; + IFMNetwork* m_fmNetwork; CAX25Network* m_ax25Network; CDisplay* m_display; unsigned char m_mode; diff --git a/Makefile b/Makefile index aa7dec7..4cbd0c0 100644 --- a/Makefile +++ b/Makefile @@ -7,15 +7,16 @@ LIBS = -lpthread -lutil -lsamplerate LDFLAGS = -g -L/usr/local/lib OBJECTS = \ - AMBEFEC.o BCH.o AX25Control.o AX25Network.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o \ + AMBEFEC.o BCH.o AX25Control.o AX25Network.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o \ DMRDirectNetwork.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRGatewayNetwork.o DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o \ - DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o \ - Hamming.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o M17Control.o M17Convolution.o M17CRC.o M17LSF.o M17Network.o M17Utils.o MMDVMHost.o \ - Modem.o ModemPort.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullController.o NullDisplay.o NXDNAudio.o NXDNControl.o \ - NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o \ - NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o PseudoTTYController.o POCSAGControl.o \ - POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialPort.o SMeter.o StopWatch.o Sync.o SHA256.o TFTSurenoo.o Thread.o \ - Timer.o UARTController.o UDPController.o UDPSocket.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o + DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o FMControl.o FMNetwork.o FMIAXNetwork.o FMRAWNetwork.o \ + FMUSRPNetwork.o Golay2087.o Golay24128.o Hamming.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o M17Control.o M17Convolution.o M17CRC.o \ + M17LSF.o M17Network.o M17Utils.o MMDVMHost.o Modem.o ModemPort.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullController.o NullDisplay.o \ + NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o \ + NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o \ + PseudoTTYController.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialPort.o SMeter.o \ + StopWatch.o Sync.o SHA256.o TFTSurenoo.o Thread.o Timer.o UARTController.o UDPController.o UDPSocket.o UserDB.o UserDBentry.o Utils.o \ + YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost RemoteCommand diff --git a/Makefile.Pi.Adafruit b/Makefile.Pi.Adafruit index 1b4e15b..a805c98 100644 --- a/Makefile.Pi.Adafruit +++ b/Makefile.Pi.Adafruit @@ -10,14 +10,14 @@ LDFLAGS = -g -L/usr/local/lib OBJECTS = \ AMBEFEC.o AX25Control.o AX25Network.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o \ DMRDirectNetwork.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRGatewayNetwork.o DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o \ - DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o \ - Hamming.o HD44780.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o M17Control.o M17Convolution.o M17CRC.o M17LSF.o M17Network.o M17Utils.o \ - MMDVMHost.o Modem.o ModemPort.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullController.o NullDisplay.o NXDNAudio.o \ - NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o \ - NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o PseudoTTYController.o \ - POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialPort.o SMeter.o StopWatch.o Sync.o SHA256.o \ - TFTSurenoo.o Thread.o Timer.o UARTController.o UDPController.o UDPSocket.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o \ - YSFNetwork.o YSFPayload.o + DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o FMControl.o FMNetwork.o FMIAXNetwork.o FMRAWNetwork.o \ + FMUSRPNetwork.o Golay2087.o Golay24128.o Hamming.o HD44780.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o M17Control.o M17Convolution.o \ + M17CRC.o M17LSF.o M17Network.o M17Utils.o MMDVMHost.o Modem.o ModemPort.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullController.o NullDisplay.o \ + NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o \ + NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o \ + PseudoTTYController.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialPort.o SMeter.o \ + StopWatch.o Sync.o SHA256.o TFTSurenoo.o Thread.o Timer.o UARTController.o UDPController.o UDPSocket.o UserDB.o UserDBentry.o Utils.o \ + YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost RemoteCommand diff --git a/Makefile.Pi.HD44780 b/Makefile.Pi.HD44780 index 31a3159..8015aba 100644 --- a/Makefile.Pi.HD44780 +++ b/Makefile.Pi.HD44780 @@ -9,11 +9,11 @@ LDFLAGS = -g -L/usr/local/lib OBJECTS = \ AMBEFEC.o AX25Control.o AX25Network.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o \ DMRDirectNetwork.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRGatewayNetwork.o DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o \ - DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o \ - Hamming.o HD44780.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o M17Control.o M17Convolution.o M17CRC.o M17LSF.o M17Network.o M17Utils.o \ - MMDVMHost.o Modem.o ModemPort.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullController.o NullDisplay.o NXDNAudio.o \ - NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o \ - NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o PseudoTTYController.o \ + DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o FMControl.o FMNetwork.o FMIAXNetwork.o FMRAWNetwork.o \ + FMUSRPNetwork.o Golay2087.o Golay24128.o Hamming.o HD44780.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o M17Control.o M17Convolution.o \ + M17CRC.o M17LSF.o M17Network.o M17Utils.o MMDVMHost.o Modem.o ModemPort.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullController.o NullDisplay.o \ + NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o \ + NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o PseudoTTYController.o \ POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialPort.o SMeter.o StopWatch.o Sync.o SHA256.o \ TFTSurenoo.o Thread.o Timer.o UARTController.o UDPController.o UDPSocket.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o \ YSFNetwork.o YSFPayload.o diff --git a/Makefile.Pi.I2C b/Makefile.Pi.I2C index 44f436d..d0b1780 100644 --- a/Makefile.Pi.I2C +++ b/Makefile.Pi.I2C @@ -9,13 +9,14 @@ LDFLAGS = -g -L/usr/local/lib OBJECTS = \ AMBEFEC.o AX25Control.o AX25Network.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o \ DMRDirectNetwork.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRGatewayNetwork.o DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o \ - DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o \ - Hamming.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o M17Control.o M17Convolution.o M17CRC.o M17LSF.o M17Network.o M17Utils.o MMDVMHost.o \ - Modem.o ModemPort.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullController.o NullDisplay.o NXDNAudio.o NXDNControl.o \ - NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o \ - NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o PseudoTTYController.o POCSAGControl.o \ - POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialPort.o SMeter.o StopWatch.o Sync.o SHA256.o TFTSurenoo.o Thread.o \ - Timer.o UARTController.o UDPController.o UDPSocket.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o + DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o FMControl.o FMNetwork.o FMIAXNetwork.o FMRAWNetwork.o \ + FMUSRPNetwork.o Golay2087.o Golay24128.o Hamming.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o M17Control.o M17Convolution.o M17CRC.o \ + M17LSF.o M17Network.o M17Utils.o MMDVMHost.o Modem.o ModemPort.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullController.o NullDisplay.o \ + NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o \ + NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o \ + PseudoTTYController.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialPort.o SMeter.o \ + StopWatch.o Sync.o SHA256.o TFTSurenoo.o Thread.o Timer.o UARTController.o UDPController.o UDPSocket.o UserDB.o UserDBentry.o Utils.o \ + YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost RemoteCommand diff --git a/Makefile.Pi.OLED b/Makefile.Pi.OLED index 538ff64..2744ce3 100644 --- a/Makefile.Pi.OLED +++ b/Makefile.Pi.OLED @@ -13,14 +13,14 @@ LDFLAGS = -g -L/usr/local/lib OBJECTS = \ AMBEFEC.o AX25Control.o AX25Network.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o \ DMRDirectNetwork.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRGatewayNetwork.o DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o \ - DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o \ - Hamming.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o M17Control.o M17Convolution.o M17CRC.o M17LSF.o M17Network.o M17Utils.o MMDVMHost.o \ - Modem.o ModemPort.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullController.o NullDisplay.o NXDNAudio.o NXDNControl.o \ - NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o \ - NXDNUDCH.o OLED.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o PseudoTTYController.o \ - POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialPort.o SMeter.o StopWatch.o Sync.o SHA256.o \ - TFTSurenoo.o Thread.o Timer.o UARTController.o UDPController.o UDPSocket.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o \ - YSFNetwork.o YSFPayload.o + DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o FMControl.o FMNetwork.o FMIAXNetwork.o FMRAWNetwork.o \ + FMUSRPNetwork.o Golay2087.o Golay24128.o Hamming.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o M17Control.o M17Convolution.o M17CRC.o \ + M17LSF.o M17Network.o M17Utils.o MMDVMHost.o Modem.o ModemPort.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullController.o NullDisplay.o \ + NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o \ + NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o OLED.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o \ + PseudoTTYController.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialPort.o SMeter.o \ + StopWatch.o Sync.o SHA256.o TFTSurenoo.o Thread.o Timer.o UARTController.o UDPController.o UDPSocket.o UserDB.o UserDBentry.o Utils.o \ + YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost RemoteCommand diff --git a/Makefile.Pi.PCF8574 b/Makefile.Pi.PCF8574 index c1aa3d1..1eaa99c 100644 --- a/Makefile.Pi.PCF8574 +++ b/Makefile.Pi.PCF8574 @@ -10,11 +10,11 @@ LDFLAGS = -g -L/usr/local/lib OBJECTS = \ AMBEFEC.o AX25Control.o AX25Network.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o \ DMRDirectNetwork.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRGatewayNetwork.o DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o \ - DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o \ - Hamming.o HD44780.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o M17Control.o M17Convolution.o M17CRC.o M17LSF.o M17Network.o M17Utils.o \ - MMDVMHost.o Modem.o ModemPort.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullController.o NullDisplay.o NXDNAudio.o \ - NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o \ - NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o PseudoTTYController.o \ + DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o FMControl.o FMNetwork.o FMIAXNetwork.o FMRAWNetwork.o \ + FMUSRPNetwork.o Golay2087.o Golay24128.o Hamming.o HD44780.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o M17Control.o M17Convolution.o \ + M17CRC.o M17LSF.o M17Network.o M17Utils.o MMDVMHost.o Modem.o ModemPort.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullController.o NullDisplay.o \ + NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o \ + NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o PseudoTTYController.o \ POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialPort.o SMeter.o StopWatch.o Sync.o SHA256.o \ TFTSurenoo.o Thread.o Timer.o UARTController.o UDPController.o UDPSocket.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o \ YSFNetwork.o YSFPayload.o