diff --git a/plugins/channeltx/udpsink/udpsink.cpp b/plugins/channeltx/udpsink/udpsink.cpp index d878c4a9d..257ea259a 100644 --- a/plugins/channeltx/udpsink/udpsink.cpp +++ b/plugins/channeltx/udpsink/udpsink.cpp @@ -41,10 +41,12 @@ UDPSink::~UDPSink() void UDPSink::start() { + m_udpHandler.start(); } void UDPSink::stop() { + m_udpHandler.stop(); } void UDPSink::pull(Sample& sample) @@ -94,8 +96,20 @@ void UDPSink::pull(Sample& sample) void UDPSink::modulateSample() { - m_modSample.real(0.0f); // TODO - m_modSample.imag(0.0f); + //Real t; + Sample s; + + if (m_running.m_sampleFormat == FormatS16LE) + { + m_udpHandler.readSample(s); + m_modSample.real(s.m_real); + m_modSample.imag(s.m_imag); + } + else + { + m_modSample.real(0.0f); + m_modSample.imag(0.0f); + } } bool UDPSink::handleMessage(const Message& cmd) @@ -135,6 +149,8 @@ bool UDPSink::handleMessage(const Message& cmd) m_config.m_udpPort = cfg.getUDPPort(); m_config.m_channelMute = cfg.getChannelMute(); + apply(false); + m_settingsMutex.unlock(); qDebug() << "UDPSink::handleMessage: MsgUDPSinkConfigure:" @@ -202,5 +218,18 @@ void UDPSink::apply(bool force) m_settingsMutex.unlock(); } + if ((m_config.m_udpAddressStr != m_running.m_udpAddressStr) || + (m_config.m_udpPort != m_running.m_udpPort) || force) + { + m_udpHandler.configureUDPLink(m_config.m_udpAddressStr, m_config.m_udpPort); + } + + if ((m_config.m_channelMute != m_running.m_channelMute) || force) + { + if (!m_config.m_channelMute) { + m_udpHandler.resetReadIndex(); + } + } + m_running = m_config; } diff --git a/plugins/channeltx/udpsink/udpsink.h b/plugins/channeltx/udpsink/udpsink.h index 9af96b31b..c246bb86a 100644 --- a/plugins/channeltx/udpsink/udpsink.h +++ b/plugins/channeltx/udpsink/udpsink.h @@ -26,6 +26,8 @@ #include "dsp/nco.h" #include "util/message.h" +#include "udpsinkudphandler.h" + class UDPSinkGUI; class UDPSink : public BasebandSampleSource { @@ -187,6 +189,8 @@ private: double m_magsq; MovingAverage m_movingAverage; + UDPSinkUDPHandler m_udpHandler; + QMutex m_settingsMutex; void apply(bool force); diff --git a/plugins/channeltx/udpsink/udpsinkudphandler.cpp b/plugins/channeltx/udpsink/udpsinkudphandler.cpp new file mode 100644 index 000000000..4708d661e --- /dev/null +++ b/plugins/channeltx/udpsink/udpsinkudphandler.cpp @@ -0,0 +1,158 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2017 Edouard Griffiths, F4EXB // +// // +// 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 as version 3 of the License, or // +// // +// 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 V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include + +#include "udpsinkudphandler.h" + +UDPSinkUDPHandler::UDPSinkUDPHandler() : + m_dataSocket(0), + m_dataAddress(QHostAddress::LocalHost), + m_remoteAddress(QHostAddress::LocalHost), + m_dataPort(9999), + m_dataConnected(false), + m_udpReadBytes(0), + m_writeIndex(0), + m_readFrameIndex(m_nbUDPFrames/2), + m_readIndex(0) +{ +} + +UDPSinkUDPHandler::~UDPSinkUDPHandler() +{ +} + +void UDPSinkUDPHandler::start() +{ + qDebug("UDPSinkUDPHandler::start"); + + if (!m_dataSocket) + { + m_dataSocket = new QUdpSocket(this); + } + + if (!m_dataConnected) + { + connect(m_dataSocket, SIGNAL(readyRead()), this, SLOT(dataReadyRead()), Qt::QueuedConnection); // , Qt::QueuedConnection + + if (m_dataSocket->bind(m_dataAddress, m_dataPort)) + { + qDebug("UDPSinkUDPHandler::start: bind data socket to %s:%d", m_dataAddress.toString().toStdString().c_str(), m_dataPort); + m_dataConnected = true; + } + else + { + qWarning("UDPSinkUDPHandler::start: cannot bind data port %d", m_dataPort); + disconnect(m_dataSocket, SIGNAL(readyRead()), this, SLOT(dataReadyRead())); + m_dataConnected = false; + } + } +} + +void UDPSinkUDPHandler::stop() +{ + qDebug("UDPSinkUDPHandler::stop"); + + if (m_dataConnected) + { + m_dataConnected = false; + disconnect(m_dataSocket, SIGNAL(readyRead()), this, SLOT(dataReadyRead())); + } + + if (m_dataSocket) + { + delete m_dataSocket; + m_dataSocket = 0; + } +} + +void UDPSinkUDPHandler::dataReadyRead() +{ + while (m_dataSocket->hasPendingDatagrams() && m_dataConnected) + { + qint64 pendingDataSize = m_dataSocket->pendingDatagramSize(); + m_udpReadBytes += m_dataSocket->readDatagram(&m_udpTmpBuf[m_udpReadBytes], pendingDataSize, &m_remoteAddress, 0); + + if (m_udpReadBytes == m_udpBlockSize) { + moveData(); + m_udpReadBytes = 0; + } + } +} + +void UDPSinkUDPHandler::moveData() +{ + memcpy(m_udpBuf[m_writeIndex], m_udpTmpBuf, m_udpBlockSize); + + if (m_writeIndex < m_nbUDPFrames - 1) { + m_writeIndex++; + } else { + m_writeIndex = 0; + } +} + +void UDPSinkUDPHandler::readSample(Real &t) +{ + memcpy(&t, &m_udpBuf[m_readFrameIndex][m_readIndex], sizeof(Real)); + advanceReadPointer((int) sizeof(Real)); +} + +void UDPSinkUDPHandler::readSample(Sample &s) +{ + memcpy(&s, &m_udpBuf[m_readFrameIndex][m_readIndex], sizeof(Sample)); + advanceReadPointer((int) sizeof(Sample)); +} + +void UDPSinkUDPHandler::advanceReadPointer(int nbBytes) +{ + if (m_readIndex < m_udpBlockSize - 2*nbBytes) + { + m_readIndex += nbBytes; + } + else + { + m_readIndex = 0; + + if (m_readFrameIndex < m_nbUDPFrames - 1) { + m_readFrameIndex++; + } else { + m_readFrameIndex = 0; + } + } +} + +void UDPSinkUDPHandler::configureUDPLink(const QString& address, quint16 port) +{ + qDebug("UDPSinkUDPHandler::configureUDPLink: %s:%d", address.toStdString().c_str(), port); + bool addressOK = m_dataAddress.setAddress(address); + + if (!addressOK) + { + qWarning("UDPSinkUDPHandler::configureUDPLink: invalid address %s. Set to localhost.", address.toStdString().c_str()); + m_dataAddress = QHostAddress::LocalHost; + } + + stop(); + m_dataPort = port; + resetReadIndex(); + start(); +} + +void UDPSinkUDPHandler::resetReadIndex() +{ + m_readFrameIndex = (m_writeIndex + (m_nbUDPFrames/2)) % m_nbUDPFrames; + m_readIndex = 0; +} diff --git a/plugins/channeltx/udpsink/udpsinkudphandler.h b/plugins/channeltx/udpsink/udpsinkudphandler.h new file mode 100644 index 000000000..f261ad168 --- /dev/null +++ b/plugins/channeltx/udpsink/udpsinkudphandler.h @@ -0,0 +1,67 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2017 Edouard Griffiths, F4EXB // +// // +// 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 as version 3 of the License, or // +// // +// 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 V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef PLUGINS_CHANNELTX_UDPSINK_UDPSINKUDPHANDLER_H_ +#define PLUGINS_CHANNELTX_UDPSINK_UDPSINKUDPHANDLER_H_ + +#include +#include +#include +#include + +#include "dsp/dsptypes.h" + +class UDPSinkUDPHandler : public QObject +{ + Q_OBJECT +public: + UDPSinkUDPHandler(); + virtual ~UDPSinkUDPHandler(); + + void start(); + void stop(); + void configureUDPLink(const QString& address, quint16 port); + void resetReadIndex(); + + void readSample(Real &t); + void readSample(Sample &s); + + static const int m_udpBlockSize = 512; // UDP block size in number of bytes + static const int m_nbUDPFrames = 32; // number of frames of block size in the UDP buffer + +public slots: + void dataReadyRead(); + +private: + void moveData(); + void advanceReadPointer(int nbBytes); + + QUdpSocket *m_dataSocket; + QHostAddress m_dataAddress; + QHostAddress m_remoteAddress; + quint16 m_dataPort; + bool m_dataConnected; + char m_udpTmpBuf[m_udpBlockSize]; + qint64 m_udpReadBytes; + char m_udpBuf[m_nbUDPFrames][m_udpBlockSize]; + int m_writeIndex; + int m_readFrameIndex; + int m_readIndex; +}; + + + +#endif /* PLUGINS_CHANNELTX_UDPSINK_UDPSINKUDPHANDLER_H_ */