diff --git a/Conf.cpp b/Conf.cpp index 7c9f478a3..d69d29751 100644 --- a/Conf.cpp +++ b/Conf.cpp @@ -283,6 +283,7 @@ m_pocsagLocalPort(0U), m_pocsagNetworkModeHang(3U), m_pocsagNetworkDebug(false), m_fmNetworkEnabled(false), +m_fmNetworkFormat("MMDVM"), m_fmGatewayAddress(), m_fmGatewayPort(0U), m_fmLocalAddress(), @@ -440,7 +441,7 @@ bool CConf::read() value++; } else { // if value is not quoted, remove after # (to make comment) - ::strtok(value, "#"); + (void)::strtok(value, "#"); } if (section == SECTION_GENERAL) { @@ -998,6 +999,8 @@ bool CConf::read() } else if (section == SECTION_FM_NETWORK) { if (::strcmp(key, "Enable") == 0) m_fmNetworkEnabled = ::atoi(value) == 1; + else if (::strcmp(key, "Format") == 0) + m_fmNetworkFormat = value; else if (::strcmp(key, "LocalAddress") == 0) m_fmLocalAddress = value; else if (::strcmp(key, "LocalPort") == 0) @@ -2197,6 +2200,11 @@ bool CConf::getFMNetworkEnabled() const return m_fmNetworkEnabled; } +std::string CConf::getFMNetworkFormat() const +{ + return m_fmNetworkFormat; +} + std::string CConf::getFMGatewayAddress() const { return m_fmGatewayAddress; diff --git a/Conf.h b/Conf.h index 430bbeb48..7a5c56a4f 100644 --- a/Conf.h +++ b/Conf.h @@ -296,6 +296,7 @@ class CConf // The FM Network section bool getFMNetworkEnabled() const; + std::string getFMNetworkFormat() const; std::string getFMGatewayAddress() const; unsigned int getFMGatewayPort() const; std::string getFMLocalAddress() const; @@ -603,6 +604,7 @@ class CConf bool m_pocsagNetworkDebug; bool m_fmNetworkEnabled; + std::string m_fmNetworkFormat; std::string m_fmGatewayAddress; unsigned int m_fmGatewayPort; std::string m_fmLocalAddress; diff --git a/FMNetwork.cpp b/FMNetwork.cpp index c10e3d8ae..d9aa0e511 100644 --- a/FMNetwork.cpp +++ b/FMNetwork.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 by Jonathan Naylor G4KLX + * Copyright (C) 2020,2021 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 @@ -27,7 +27,8 @@ const unsigned int BUFFER_LENGTH = 500U; -CFMNetwork::CFMNetwork(const std::string& localAddress, unsigned int localPort, const std::string& gatewayAddress, unsigned int gatewayPort, unsigned int sampleRate, bool debug) : +CFMNetwork::CFMNetwork(const std::string& format, const std::string& localAddress, unsigned int localPort, const std::string& gatewayAddress, unsigned int gatewayPort, unsigned int sampleRate, bool debug) : +m_format(FMF_MMDVM), m_socket(localAddress, localPort), m_addr(), m_addrLen(0U), @@ -35,7 +36,8 @@ m_sampleRate(sampleRate), m_debug(debug), m_enabled(false), m_buffer(2000U, "FM Network"), -m_pollTimer(1000U, 5U) +m_pollTimer(1000U, 5U), +m_seqNo(0U) { assert(gatewayPort > 0U); assert(!gatewayAddress.empty()); @@ -44,6 +46,9 @@ m_pollTimer(1000U, 5U) if (CUDPSocket::lookup(gatewayAddress, gatewayPort, m_addr, m_addrLen) != 0) m_addrLen = 0U; + if (format == "USRP") + m_format = FMF_USRP; + #if !defined(_WIN32) && !defined(_WIN64) int error; m_incoming = ::src_new(SRC_SINC_FASTEST, 1, &error); @@ -106,46 +111,97 @@ bool CFMNetwork::writeData(float* data, unsigned int nSamples) } #endif - unsigned int length = 3U; - - unsigned char buffer[1500U]; - ::memset(buffer, 0x00U, 1500U); - - buffer[0U] = 'F'; - buffer[1U] = 'M'; - buffer[2U] = 'D'; + unsigned char buffer[2000U]; + ::memset(buffer, 0x00U, 2000U); + + unsigned int length = 0U; + + if (m_format == FMF_USRP) { + 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, this may be wrong + 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; + } else { + buffer[length++] = 'F'; + buffer[length++] = 'M'; + buffer[length++] = 'D'; + } #if defined(_WIN32) || defined(_WIN64) - for (long i = 0L; i < nSamples; i++) { - short val = ( short)((data[i] ) * 32767.0F); // Changing audio format from U16BE to S16LE + for (unsigned int i = 0U; i < nSamples; i++) { + short val = short(data[i] * 32767.0F + 0.5F); // Changing audio format from float to S16LE #else for (long i = 0L; i < src.output_frames_gen; i++) { - short val = ( short)((src.data_out[i] ) * 32767.0F ); // Changing audio format from U16BE to S16LE + short val = short(src.data_out[i] * 32767.0F + 0.5F); // Changing audio format from float to S16LE #endif - buffer[length++] = (val >> 0) & 0xFFU; // changing from BE to LE - buffer[length++] = (val >> 8) & 0xFFU; // changing from BE to LE + 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::writeEOT() { - unsigned char buffer[10U]; - ::memset(buffer, 0x00U, 10U); + if (m_format == FMF_MMDVM) { + unsigned char buffer[10U]; + ::memset(buffer, 0x00U, 10U); - buffer[0U] = 'F'; - buffer[1U] = 'M'; - buffer[2U] = 'E'; + buffer[0U] = 'F'; + buffer[1U] = 'M'; + buffer[2U] = 'E'; - if (m_debug) - CUtils::dump(1U, "FM Network End of Transmission Sent", buffer, 3U); + if (m_debug) + CUtils::dump(1U, "FM Network End of Transmission Sent", buffer, 3U); - return m_socket.write(buffer, 3U, m_addr, m_addrLen); + return m_socket.write(buffer, 3U, m_addr, m_addrLen); + } + + return true; } void CFMNetwork::clock(unsigned int ms) @@ -170,21 +226,36 @@ void CFMNetwork::clock(unsigned int ms) // return; //} - // Ignore incoming polls - if (::memcmp(buffer, "FMP", 3U) == 0) - return; - - // Invalid packet type? - if (::memcmp(buffer, "FMD", 3U) != 0) - return; - if (!m_enabled) return; if (m_debug) CUtils::dump(1U, "FM Network Data Received", buffer, length); - m_buffer.addData(buffer + 3U, length - 3U); + if (m_format == FMF_USRP) { + // Invalid packet type? + if (::memcmp(buffer, "USRP", 4U) != 0) + 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 { + // Ignore incoming polls + if (::memcmp(buffer, "FMP", 3U) == 0) + return; + + // Invalid packet type? + if (::memcmp(buffer, "FMD", 3U) != 0) + return; + + m_buffer.addData(buffer + 3U, length - 3U); + } } unsigned int CFMNetwork::read(float* data, unsigned int nSamples) @@ -274,16 +345,18 @@ void CFMNetwork::enable(bool enabled) m_enabled = enabled; } -bool CFMNetwork::writePoll() +void CFMNetwork::writePoll() { - unsigned char buffer[3U]; + if (m_format == FMF_MMDVM) { + unsigned char buffer[3U]; - buffer[0U] = 'F'; - buffer[1U] = 'M'; - buffer[2U] = 'P'; + buffer[0U] = 'F'; + buffer[1U] = 'M'; + buffer[2U] = 'P'; - if (m_debug) - CUtils::dump(1U, "FM Network Poll Sent", buffer, 3U); + if (m_debug) + CUtils::dump(1U, "FM Network Poll Sent", buffer, 3U); - return m_socket.write(buffer, 3U, m_addr, m_addrLen); + m_socket.write(buffer, 3U, m_addr, m_addrLen); + } } diff --git a/FMNetwork.h b/FMNetwork.h index aa9975147..d7b1ff74d 100644 --- a/FMNetwork.h +++ b/FMNetwork.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 by Jonathan Naylor G4KLX + * Copyright (C) 2020,2021 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 @@ -30,9 +30,14 @@ #include #include +enum FM_FORMAT { + FMF_MMDVM, + FMF_USRP +}; + class CFMNetwork { public: - CFMNetwork(const std::string& myAddress, unsigned int myPort, const std::string& gatewayAddress, unsigned int gatewayPort, unsigned int sampleRate, bool debug); + CFMNetwork(const std::string& format, const std::string& myAddress, unsigned int myPort, const std::string& gatewayAddress, unsigned int gatewayPort, unsigned int sampleRate, bool debug); ~CFMNetwork(); bool open(); @@ -52,6 +57,7 @@ class CFMNetwork { void clock(unsigned int ms); private: + FM_FORMAT m_format; CUDPSocket m_socket; sockaddr_storage m_addr; unsigned int m_addrLen; @@ -60,12 +66,13 @@ class CFMNetwork { bool m_enabled; CRingBuffer m_buffer; CTimer m_pollTimer; + unsigned int m_seqNo; #if !defined(_WIN32) && !defined(_WIN64) SRC_STATE* m_incoming; SRC_STATE* m_outgoing; #endif - bool writePoll(); + void writePoll(); }; #endif diff --git a/MMDVM.ini b/MMDVM.ini index 8c89a5659..255c12d8c 100644 --- a/MMDVM.ini +++ b/MMDVM.ini @@ -275,6 +275,8 @@ Debug=0 [FM Network] Enable=1 +# Values are MMDVM and USRP +Format=USRP LocalAddress=127.0.0.1 LocalPort=3810 GatewayAddress=127.0.0.1 diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index 428aa1c66..b78d7e9e8 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -1796,6 +1796,7 @@ bool CMMDVMHost::createPOCSAGNetwork() bool CMMDVMHost::createFMNetwork() { + std::string format = m_conf.getFMNetworkFormat(); std::string gatewayAddress = m_conf.getFMGatewayAddress(); unsigned int gatewayPort = m_conf.getFMGatewayPort(); std::string localAddress = m_conf.getFMLocalAddress(); @@ -1805,6 +1806,7 @@ bool CMMDVMHost::createFMNetwork() bool debug = m_conf.getFMNetworkDebug(); LogInfo("FM Network Parameters"); + LogInfo(" Format: %s", format.c_str()); LogInfo(" Gateway Address: %s", gatewayAddress.c_str()); LogInfo(" Gateway Port: %u", gatewayPort); LogInfo(" Local Address: %s", localAddress.c_str()); @@ -1812,7 +1814,7 @@ bool CMMDVMHost::createFMNetwork() LogInfo(" Sample Rate: %u", sampleRate); LogInfo(" Mode Hang: %us", m_fmNetModeHang); - m_fmNetwork = new CFMNetwork(localAddress, localPort, gatewayAddress, gatewayPort, sampleRate, debug); + m_fmNetwork = new CFMNetwork(format, localAddress, localPort, gatewayAddress, gatewayPort, sampleRate, debug); bool ret = m_fmNetwork->open(); if (!ret) { diff --git a/Version.h b/Version.h index 7365a9379..028594f0e 100644 --- a/Version.h +++ b/Version.h @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20210312"; +const char* VERSION = "20210314"; #endif