Allow the USRP audio format to be used natively by the FM networking.
This commit is contained in:
parent
7c14a6ec40
commit
fb0d1ef5e2
10
Conf.cpp
10
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;
|
||||
|
|
2
Conf.h
2
Conf.h
|
@ -296,6 +296,7 @@ public:
|
|||
|
||||
// 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 @@ private:
|
|||
bool m_pocsagNetworkDebug;
|
||||
|
||||
bool m_fmNetworkEnabled;
|
||||
std::string m_fmNetworkFormat;
|
||||
std::string m_fmGatewayAddress;
|
||||
unsigned int m_fmGatewayPort;
|
||||
std::string m_fmLocalAddress;
|
||||
|
|
151
FMNetwork.cpp
151
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[2000U];
|
||||
::memset(buffer, 0x00U, 2000U);
|
||||
|
||||
unsigned char buffer[1500U];
|
||||
::memset(buffer, 0x00U, 1500U);
|
||||
unsigned int length = 0U;
|
||||
|
||||
buffer[0U] = 'F';
|
||||
buffer[1U] = 'M';
|
||||
buffer[2U] = 'D';
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
13
FMNetwork.h
13
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 <cstdint>
|
||||
#include <string>
|
||||
|
||||
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 @@ public:
|
|||
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 @@ private:
|
|||
bool m_enabled;
|
||||
CRingBuffer<unsigned char> 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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in a new issue