diff --git a/plugins/channeltx/mod802.15.4/ieee_802_15_4_mod.cpp b/plugins/channeltx/mod802.15.4/ieee_802_15_4_mod.cpp index 87d8c36c7..d2555f89f 100644 --- a/plugins/channeltx/mod802.15.4/ieee_802_15_4_mod.cpp +++ b/plugins/channeltx/mod802.15.4/ieee_802_15_4_mod.cpp @@ -50,7 +50,6 @@ MESSAGE_CLASS_DEFINITION(IEEE_802_15_4_Mod::MsgConfigureIEEE_802_15_4_Mod, Message) MESSAGE_CLASS_DEFINITION(IEEE_802_15_4_Mod::MsgTxHexString, Message) -MESSAGE_CLASS_DEFINITION(IEEE_802_15_4_Mod::MsgTxBytes, Message) const char* const IEEE_802_15_4_Mod::m_channelIdURI = "sdrangel.channeltx.mod802.15.4"; const char* const IEEE_802_15_4_Mod::m_channelId = "IEEE_802_15_4_Mod"; @@ -59,8 +58,7 @@ IEEE_802_15_4_Mod::IEEE_802_15_4_Mod(DeviceAPI *deviceAPI) : ChannelAPI(m_channelIdURI, ChannelAPI::StreamSingleSource), m_deviceAPI(deviceAPI), m_spectrumVis(SDR_TX_SCALEF), - m_settingsMutex(QMutex::Recursive), - m_udpSocket(nullptr) + m_settingsMutex(QMutex::Recursive) { setObjectName(m_channelId); @@ -80,7 +78,7 @@ IEEE_802_15_4_Mod::IEEE_802_15_4_Mod(DeviceAPI *deviceAPI) : IEEE_802_15_4_Mod::~IEEE_802_15_4_Mod() { - closeUDP(); + // closeUDP(); disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*))); delete m_networkManager; m_deviceAPI->removeChannelSourceAPI(this); @@ -214,17 +212,6 @@ void IEEE_802_15_4_Mod::applySettings(const IEEE_802_15_4_ModSettings& settings, reverseAPIKeys.append("udpPort"); } - if ((settings.m_udpEnabled != m_settings.m_udpEnabled) - || (settings.m_udpAddress != m_settings.m_udpAddress) - || (settings.m_udpPort != m_settings.m_udpPort) - || force) - { - if (settings.m_udpEnabled) - openUDP(settings); - else - closeUDP(); - } - if (m_settings.m_streamIndex != settings.m_streamIndex) { if (m_deviceAPI->getSampleMIMO()) // change of stream is possible for MIMO devices only @@ -623,44 +610,3 @@ ScopeVis *IEEE_802_15_4_Mod::getScopeSink() { return m_basebandSource->getScopeSink(); } - -void IEEE_802_15_4_Mod::openUDP(const IEEE_802_15_4_ModSettings& settings) -{ - closeUDP(); - m_udpSocket = new QUdpSocket(); - if (!m_udpSocket->bind(QHostAddress(settings.m_udpAddress), settings.m_udpPort)) - qCritical() << "IEEE_802_15_4_Mod::openUDP: Failed to bind to port " << settings.m_udpAddress << ":" << settings.m_udpPort << ". Error: " << m_udpSocket->error(); - else - qDebug() << "IEEE_802_15_4_Mod::openUDP: Listening for packets on " << settings.m_udpAddress << ":" << settings.m_udpPort; - connect(m_udpSocket, &QUdpSocket::readyRead, this, &IEEE_802_15_4_Mod::udpRx); -} - -void IEEE_802_15_4_Mod::closeUDP() -{ - if (m_udpSocket != nullptr) - { - disconnect(m_udpSocket, &QUdpSocket::readyRead, this, &IEEE_802_15_4_Mod::udpRx); - delete m_udpSocket; - m_udpSocket = nullptr; - } -} - -void IEEE_802_15_4_Mod::udpRx() -{ - while (m_udpSocket->hasPendingDatagrams()) - { - QNetworkDatagram datagram = m_udpSocket->receiveDatagram(); - if (m_settings.m_udpBytesFormat) - { - IEEE_802_15_4_Mod::MsgTxBytes *msg = IEEE_802_15_4_Mod::MsgTxBytes::create(datagram.data()); - m_basebandSource->getInputMessageQueue()->push(msg); - } - else - { - // Convert from binary to hex string - QString string = datagram.data().toHex(' '); - IEEE_802_15_4_Mod::MsgTxHexString *msg = IEEE_802_15_4_Mod::MsgTxHexString::create(string); - m_basebandSource->getInputMessageQueue()->push(msg); - } - } -} diff --git a/plugins/channeltx/mod802.15.4/ieee_802_15_4_mod.h b/plugins/channeltx/mod802.15.4/ieee_802_15_4_mod.h index a614855c2..07f207181 100644 --- a/plugins/channeltx/mod802.15.4/ieee_802_15_4_mod.h +++ b/plugins/channeltx/mod802.15.4/ieee_802_15_4_mod.h @@ -87,24 +87,6 @@ public: { } }; - class MsgTxBytes : public Message { - MESSAGE_CLASS_DECLARATION - - public: - static MsgTxBytes* create(QByteArray data) { - return new MsgTxBytes(data); - } - - QByteArray m_data; - - private: - - MsgTxBytes(QByteArray data) : - Message(), - m_data(data) - { } - }; - //================================================================= IEEE_802_15_4_Mod(DeviceAPI *deviceAPI); @@ -183,7 +165,7 @@ private: QNetworkAccessManager *m_networkManager; QNetworkRequest m_networkRequest; - QUdpSocket *m_udpSocket; + // QUdpSocket *m_udpSocket; void applySettings(const IEEE_802_15_4_ModSettings& settings, bool force = false); void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response); @@ -200,12 +182,9 @@ private: const IEEE_802_15_4_ModSettings& settings, bool force ); - void openUDP(const IEEE_802_15_4_ModSettings& settings); - void closeUDP(); private slots: void networkManagerFinished(QNetworkReply *reply); - void udpRx(); }; diff --git a/plugins/channeltx/mod802.15.4/ieee_802_15_4_modbaseband.cpp b/plugins/channeltx/mod802.15.4/ieee_802_15_4_modbaseband.cpp index 03fd02ecb..17d914019 100644 --- a/plugins/channeltx/mod802.15.4/ieee_802_15_4_modbaseband.cpp +++ b/plugins/channeltx/mod802.15.4/ieee_802_15_4_modbaseband.cpp @@ -153,13 +153,6 @@ bool IEEE_802_15_4_ModBaseband::handleMessage(const Message& cmd) return true; } - else if (IEEE_802_15_4_Mod::MsgTxBytes::match(cmd)) - { - IEEE_802_15_4_Mod::MsgTxBytes& tx = (IEEE_802_15_4_Mod::MsgTxBytes&) cmd; - m_source.addTxFrame(tx.m_data); - - return true; - } else if (DSPSignalNotification::match(cmd)) { QMutexLocker mutexLocker(&m_mutex); @@ -188,6 +181,26 @@ void IEEE_802_15_4_ModBaseband::applySettings(const IEEE_802_15_4_ModSettings& s m_source.applySettings(settings, force); + if ((settings.m_udpEnabled != m_settings.m_udpEnabled) + || (settings.m_udpAddress != m_settings.m_udpAddress) + || (settings.m_udpPort != m_settings.m_udpPort) + || force) + { + qDebug() << "IEEE_802_15_4_ModBaseband::applySettings:" + << " m_udpEnabled" << settings.m_udpEnabled + << " m_udpAddress: " << settings.m_udpAddress + << " m_udpPort" << settings.m_udpPort; + + IEEE_802_15_4_ModSource::MsgCloseUDP *msg = IEEE_802_15_4_ModSource::MsgCloseUDP::create(); + m_source.getInputMessageQueue()->push(msg); + + if (settings.m_udpEnabled) + { + IEEE_802_15_4_ModSource::MsgOpenUDP *msg = IEEE_802_15_4_ModSource::MsgOpenUDP::create(settings.m_udpAddress, settings.m_udpPort); + m_source.getInputMessageQueue()->push(msg); + } + } + m_settings = settings; } diff --git a/plugins/channeltx/mod802.15.4/ieee_802_15_4_modsettings.h b/plugins/channeltx/mod802.15.4/ieee_802_15_4_modsettings.h index 194fa010d..077eb471f 100644 --- a/plugins/channeltx/mod802.15.4/ieee_802_15_4_modsettings.h +++ b/plugins/channeltx/mod802.15.4/ieee_802_15_4_modsettings.h @@ -66,6 +66,7 @@ struct IEEE_802_15_4_ModSettings bool m_udpBytesFormat; //!< true for bytes payload QString m_udpAddress; uint16_t m_udpPort; + static const int m_udpBufferSize = 100000; IEEE_802_15_4_ModSettings(); void resetToDefaults(); diff --git a/plugins/channeltx/mod802.15.4/ieee_802_15_4_modsource.cpp b/plugins/channeltx/mod802.15.4/ieee_802_15_4_modsource.cpp index 2c5f96305..6f6b4b672 100644 --- a/plugins/channeltx/mod802.15.4/ieee_802_15_4_modsource.cpp +++ b/plugins/channeltx/mod802.15.4/ieee_802_15_4_modsource.cpp @@ -18,12 +18,17 @@ #include #include +#include +#include #include "dsp/basebandsamplesink.h" #include "dsp/scopevis.h" #include "ieee_802_15_4_modsource.h" #include "util/crc.h" +MESSAGE_CLASS_DEFINITION(IEEE_802_15_4_ModSource::MsgCloseUDP, Message) +MESSAGE_CLASS_DEFINITION(IEEE_802_15_4_ModSource::MsgOpenUDP, Message) + IEEE_802_15_4_ModSource::IEEE_802_15_4_ModSource() : m_channelSampleRate(3000000), m_channelFrequencyOffset(0), @@ -45,7 +50,8 @@ IEEE_802_15_4_ModSource::IEEE_802_15_4_ModSource() : m_state(idle), m_byteIdx(0), m_bitIdx(0), - m_bitCount(0) + m_bitCount(0), + m_udpSocket(nullptr) { m_lowpass.create(301, m_channelSampleRate, 22000.0 / 2.0); m_pulseShapeI.create(1, 6, m_channelSampleRate/300000, true); @@ -54,10 +60,12 @@ IEEE_802_15_4_ModSource::IEEE_802_15_4_ModSource() : m_scopeSampleBuffer.resize(m_scopeSampleBufferSize); applySettings(m_settings, true); applyChannelSettings(m_channelSampleRate, m_channelFrequencyOffset, true); + connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); } IEEE_802_15_4_ModSource::~IEEE_802_15_4_ModSource() { + closeUDP(); delete[] m_sinLUT; } @@ -328,16 +336,24 @@ void IEEE_802_15_4_ModSource::applySettings(const IEEE_802_15_4_ModSettings& set m_bitsPerSymbol = 4; m_chipsPerSymbol = settings.m_subGHzBand ? 16 : 32; } + m_chipRate = settings.m_bitRate * m_chipsPerSymbol / m_bitsPerSymbol; m_samplesPerChip = m_channelSampleRate / m_chipRate; qDebug() << "m_samplesPerChip: " << m_samplesPerChip; - if (m_channelSampleRate % m_chipRate != 0) - qCritical("Sample rate is not an integer multiple of the chip rate"); - if (m_samplesPerChip <= 2) - qCritical("Sample rate is not a high enough multiple of the chip rate"); - if ((settings.m_pulseShaping != m_settings.m_pulseShaping) || (settings.m_beta != m_settings.m_beta) || (settings.m_symbolSpan != m_settings.m_symbolSpan) - || (settings.m_bitRate != m_settings.m_bitRate) || (settings.m_modulation != m_settings.m_modulation) + if (m_channelSampleRate % m_chipRate != 0) { + qCritical("Sample rate is not an integer multiple of the chip rate"); + } + + if (m_samplesPerChip <= 2) { + qCritical("Sample rate is not a high enough multiple of the chip rate"); + } + + if ((settings.m_pulseShaping != m_settings.m_pulseShaping) + || (settings.m_beta != m_settings.m_beta) + || (settings.m_symbolSpan != m_settings.m_symbolSpan) + || (settings.m_bitRate != m_settings.m_bitRate) + || (settings.m_modulation != m_settings.m_modulation) || (settings.m_subGHzBand != m_settings.m_subGHzBand) || force) { @@ -349,16 +365,21 @@ void IEEE_802_15_4_ModSource::applySettings(const IEEE_802_15_4_ModSettings& set << " subGHzBand: " << settings.m_subGHzBand << " bitRate:" << settings.m_bitRate << " chipRate:" << m_chipRate; + if (settings.m_pulseShaping == IEEE_802_15_4_ModSettings::RC) { m_pulseShapeI.create(settings.m_beta, m_settings.m_symbolSpan, m_channelSampleRate/m_chipRate, true); m_pulseShapeQ.create(settings.m_beta, m_settings.m_symbolSpan, m_channelSampleRate/m_chipRate, true); } else - createHalfSine(m_channelSampleRate, m_chipRate); + { + createHalfSine(m_channelSampleRate, m_chipRate); + } } - if ((settings.m_polynomial != m_settings.m_polynomial) || force) + + if ((settings.m_polynomial != m_settings.m_polynomial) || force) { m_scrambler.setPolynomial(settings.m_polynomial); + } m_settings = settings; @@ -613,7 +634,6 @@ void IEEE_802_15_4_ModSource::addTxFrame(const QByteArray& data) // Dump frame QByteArray qb((char *)m_bits, p-m_bits); - qDebug() << "IEEE_802_15_4_ModSource::addTxFrame: Tx: " << qb.toHex(); // Save number of bits in frame m_bitCount = m_bitCountTotal = (p-&m_bits[0]) * 8; @@ -621,8 +641,93 @@ void IEEE_802_15_4_ModSource::addTxFrame(const QByteArray& data) m_frameRepeatCount = m_settings.m_repeatCount; initTX(); - if (m_settings.m_writeToFile) + if (m_settings.m_writeToFile) { m_basebandFile.open("IEEE_802_15_4_Mod.csv", std::ofstream::out); - else if (m_basebandFile.is_open()) + } else if (m_basebandFile.is_open()) { m_basebandFile.close(); + } +} + +void IEEE_802_15_4_ModSource::handleInputMessages() +{ + Message* message; + + while ((message = m_inputMessageQueue.pop()) != nullptr) + { + if (handleMessage(*message)) { + delete message; + } + } +} + +bool IEEE_802_15_4_ModSource::handleMessage(const Message& msg) +{ + if (MsgOpenUDP::match(msg)) + { + qDebug("IEEE_802_15_4_ModSource::handleMessage: MsgOpenUDP"); + const MsgOpenUDP& cmd = (const MsgOpenUDP&) msg; + openUDP(cmd.getUDPAddress(), cmd.getUDPPort()); + return true; + } + else if (MsgCloseUDP::match(msg)) + { + qDebug("IEEE_802_15_4_ModSource::handleMessage: MsgCloseUDP"); + closeUDP(); + return true; + } + else + { + return false; + } +} + +void IEEE_802_15_4_ModSource::closeUDP() +{ + if (m_udpSocket != nullptr) + { + disconnect(m_udpSocket, &QUdpSocket::readyRead, this, &IEEE_802_15_4_ModSource::udpRx); + delete m_udpSocket; + m_udpSocket = nullptr; + } +} + +void IEEE_802_15_4_ModSource::openUDP(const QString& udpAddress, uint16_t udpPort) +{ + m_udpSocket = new QUdpSocket(); + + if (m_udpSocket->bind(QHostAddress(udpAddress), udpPort)) + { + connect(m_udpSocket, &QUdpSocket::readyRead, this, &IEEE_802_15_4_ModSource::udpRx); + qDebug() << "IEEE_802_15_4_ModSource::openUDP: Listening for packets on " + << udpAddress << ":" + << udpPort; + m_udpSocket->setSocketOption(QAbstractSocket::ReceiveBufferSizeSocketOption, IEEE_802_15_4_ModSettings::m_udpBufferSize); + } + else + { + qCritical() << "IEEE_802_15_4_Mod::openUDP: Failed to bind to port " + << udpAddress << ":" + << udpPort + << ". Error: " << m_udpSocket->error(); + } +} + +void IEEE_802_15_4_ModSource::udpRx() +{ + while (m_udpSocket->hasPendingDatagrams()) + { + QNetworkDatagram datagram = m_udpSocket->receiveDatagram(); + QByteArray data = datagram.data(); + qDebug() << "IEEE_802_15_4_ModSource::udpRx: " << data.toHex(); + + if (m_settings.m_udpBytesFormat) + { + addTxFrame(data); + } + else + { + QString string = data.toHex(' '); + addTxFrame(string); + } + } } diff --git a/plugins/channeltx/mod802.15.4/ieee_802_15_4_modsource.h b/plugins/channeltx/mod802.15.4/ieee_802_15_4_modsource.h index 38187029d..4199fa111 100644 --- a/plugins/channeltx/mod802.15.4/ieee_802_15_4_modsource.h +++ b/plugins/channeltx/mod802.15.4/ieee_802_15_4_modsource.h @@ -34,15 +34,55 @@ #include "dsp/fmpreemphasis.h" #include "util/lfsr.h" #include "util/movingaverage.h" +#include "util/message.h" #include "ieee_802_15_4_modsettings.h" class BasebandSampleSink; class ScopeVis; +class QUdpSocket; -class IEEE_802_15_4_ModSource : public ChannelSampleSource +class IEEE_802_15_4_ModSource : public QObject, public ChannelSampleSource { + Q_OBJECT public: + class MsgCloseUDP : public Message { + MESSAGE_CLASS_DECLARATION + + public: + static MsgCloseUDP* create() { + return new MsgCloseUDP(); + } + + private: + + MsgCloseUDP() : + Message() + { } + }; + + class MsgOpenUDP : public Message { + MESSAGE_CLASS_DECLARATION + + public: + static MsgOpenUDP* create(const QString& udpAddress, uint16_t udpPort) { + return new MsgOpenUDP(udpAddress, udpPort); + } + + const QString& getUDPAddress() const { return m_udpAddress; } + uint16_t getUDPPort() const { return m_udpPort; } + + private: + QString m_udpAddress; + uint16_t m_udpPort; + + MsgOpenUDP(const QString& udpAddress, uint16_t udpPort) : + Message(), + m_udpAddress(udpAddress), + m_udpPort(udpPort) + { } + }; + IEEE_802_15_4_ModSource(); virtual ~IEEE_802_15_4_ModSource(); @@ -57,10 +97,12 @@ public: peakLevel = m_peakLevelOut; numSamples = m_levelNbSamples; } + MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } //!< Get the queue for asynchronous inbound communication void setSpectrumSink(BasebandSampleSink *sampleSink) { m_spectrumSink = sampleSink; } void setScopeSink(ScopeVis* scopeSink) { m_scopeSink = scopeSink; } void applySettings(const IEEE_802_15_4_ModSettings& settings, bool force = false); void applyChannelSettings(int channelSampleRate, int channelFrequencyOffset, bool force = false); + bool handleMessage(const Message& cmd); void addTxFrame(const QString& data); void addTxFrame(const QByteArray& data); @@ -130,14 +172,17 @@ private: int m_bitIdx; // Index in to current byte of m_bits int m_bitCount; // Count of number of valid bits in m_bits int m_bitCountTotal; - std::ofstream m_basebandFile; // For debug output of baseband waveform + QUdpSocket *m_udpSocket; + MessageQueue m_inputMessageQueue; //!< Queue for asynchronous inbound communication bool chipsValid(); // Are there any chips to transmit int getSymbol(); int getChip(); void convert(const QString dataStr, QByteArray& data); void initTX(); + void openUDP(const QString& udpAddress, uint16_t udpPort); + void closeUDP(); void createHalfSine(int sampleRate, int chipRate); void calculateLevel(Real& sample); @@ -145,6 +190,9 @@ private: void sampleToSpectrum(Complex sample); void sampleToScope(Complex sample); +private slots: + void handleInputMessages(); + void udpRx(); }; #endif // INCLUDE_IEEE_802_15_4_MODSOURCE_H