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 fef87319c..7e054b43e 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 @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include #include @@ -56,7 +58,8 @@ 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_settingsMutex(QMutex::Recursive), + m_udpSocket(nullptr) { setObjectName(m_channelId); @@ -76,6 +79,7 @@ IEEE_802_15_4_Mod::IEEE_802_15_4_Mod(DeviceAPI *deviceAPI) : IEEE_802_15_4_Mod::~IEEE_802_15_4_Mod() { + closeUDP(); disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*))); delete m_networkManager; m_deviceAPI->removeChannelSourceAPI(this); @@ -193,6 +197,29 @@ void IEEE_802_15_4_Mod::applySettings(const IEEE_802_15_4_ModSettings& settings, reverseAPIKeys.append("repeatCount"); } + if ((settings.m_udpEnabled != m_settings.m_udpEnabled) || force) { + reverseAPIKeys.append("udpEnabled"); + } + + if ((settings.m_udpAddress != m_settings.m_udpAddress) || force) { + reverseAPIKeys.append("udpAddress"); + } + + if ((settings.m_udpPort != m_settings.m_udpPort) || force) { + 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 @@ -314,6 +341,15 @@ void IEEE_802_15_4_Mod::webapiUpdateChannelSettings( if (channelSettingsKeys.contains("repeatCount")) { settings.m_repeatCount = response.getIeee802154ModSettings()->getRepeatCount(); } + if (channelSettingsKeys.contains("udpEnabled")) { + settings.m_udpEnabled = response.getPacketDemodSettings()->getUdpEnabled(); + } + if (channelSettingsKeys.contains("udpAddress")) { + settings.m_udpAddress = *response.getPacketDemodSettings()->getUdpAddress(); + } + if (channelSettingsKeys.contains("udpPort")) { + settings.m_udpPort = response.getPacketDemodSettings()->getUdpPort(); + } if (channelSettingsKeys.contains("rgbColor")) { settings.m_rgbColor = response.getIeee802154ModSettings()->getRgbColor(); } @@ -401,6 +437,9 @@ void IEEE_802_15_4_Mod::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSetti response.getIeee802154ModSettings()->setRepeat(settings.m_repeat ? 1 : 0); response.getIeee802154ModSettings()->setRepeatDelay(settings.m_repeatDelay); response.getIeee802154ModSettings()->setRepeatCount(settings.m_repeatCount); + response.getIeee802154ModSettings()->setUdpEnabled(settings.m_udpEnabled); + response.getIeee802154ModSettings()->setUdpAddress(new QString(settings.m_udpAddress)); + response.getIeee802154ModSettings()->setUdpPort(settings.m_udpPort); response.getIeee802154ModSettings()->setRgbColor(settings.m_rgbColor); if (response.getIeee802154ModSettings()->getTitle()) { @@ -512,6 +551,15 @@ void IEEE_802_15_4_Mod::webapiFormatChannelSettings( if (channelSettingsKeys.contains("repeatCount") || force) { swgIEEE_802_15_4_ModSettings->setRepeatCount(settings.m_repeatCount); } + if (channelSettingsKeys.contains("udpEnabled") || force) { + swgIEEE_802_15_4_ModSettings->setUdpEnabled(settings.m_udpEnabled); + } + if (channelSettingsKeys.contains("udpAddress") || force) { + swgIEEE_802_15_4_ModSettings->setUdpAddress(new QString(settings.m_udpAddress)); + } + if (channelSettingsKeys.contains("udpPort") || force) { + swgIEEE_802_15_4_ModSettings->setUdpPort(settings.m_udpPort); + } if (channelSettingsKeys.contains("rgbColor") || force) { swgIEEE_802_15_4_ModSettings->setRgbColor(settings.m_rgbColor); } @@ -563,3 +611,36 @@ void IEEE_802_15_4_Mod::setScopeSink(BasebandSampleSink* scopeSink) { m_basebandSource->setScopeSink(scopeSink); } + +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(); + // Convert from binary to hex string + QString string = datagram.data().toHex(' '); + IEEE_802_15_4_Mod::MsgTXIEEE_802_15_4_Mod *msg = IEEE_802_15_4_Mod::MsgTXIEEE_802_15_4_Mod::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 0a57f783d..380fbaa78 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 @@ -36,6 +36,7 @@ class QNetworkAccessManager; class QNetworkReply; class QThread; +class QUdpSocket; class DeviceAPI; class IEEE_802_15_4_ModBaseband; @@ -163,6 +164,7 @@ private: QNetworkAccessManager *m_networkManager; QNetworkRequest m_networkRequest; + QUdpSocket *m_udpSocket; void applySettings(const IEEE_802_15_4_ModSettings& settings, bool force = false); void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response); @@ -179,9 +181,12 @@ 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_modgui.cpp b/plugins/channeltx/mod802.15.4/ieee_802_15_4_modgui.cpp index 0a8ee3868..83a8f528b 100644 --- a/plugins/channeltx/mod802.15.4/ieee_802_15_4_modgui.cpp +++ b/plugins/channeltx/mod802.15.4/ieee_802_15_4_modgui.cpp @@ -269,6 +269,24 @@ void IEEE_802_15_4_ModGUI::txSettingsSelect() } } +void IEEE_802_15_4_ModGUI::on_udpEnabled_clicked(bool checked) +{ + m_settings.m_udpEnabled = checked; + applySettings(); +} + +void IEEE_802_15_4_ModGUI::on_udpAddress_editingFinished() +{ + m_settings.m_udpAddress = ui->udpAddress->text(); + applySettings(); +} + +void IEEE_802_15_4_ModGUI::on_udpPort_editingFinished() +{ + m_settings.m_udpPort = ui->udpPort->text().toInt(); + applySettings(); +} + void IEEE_802_15_4_ModGUI::onWidgetRolled(QWidget* widget, bool rollDown) { (void) widget; @@ -514,6 +532,10 @@ void IEEE_802_15_4_ModGUI::displaySettings() ui->frame->setText(m_settings.m_data); + ui->udpEnabled->setChecked(m_settings.m_udpEnabled); + ui->udpAddress->setText(m_settings.m_udpAddress); + ui->udpPort->setText(QString::number(m_settings.m_udpPort)); + blockApplySettings(false); } diff --git a/plugins/channeltx/mod802.15.4/ieee_802_15_4_modgui.h b/plugins/channeltx/mod802.15.4/ieee_802_15_4_modgui.h index e679fa0fd..ae6cb71d5 100644 --- a/plugins/channeltx/mod802.15.4/ieee_802_15_4_modgui.h +++ b/plugins/channeltx/mod802.15.4/ieee_802_15_4_modgui.h @@ -102,6 +102,9 @@ private slots: void on_repeat_toggled(bool checked); void repeatSelect(); void txSettingsSelect(); + void on_udpEnabled_clicked(bool checked); + void on_udpAddress_editingFinished(); + void on_udpPort_editingFinished(); void onWidgetRolled(QWidget* widget, bool rollDown); void onMenuDialogCalled(const QPoint& p); diff --git a/plugins/channeltx/mod802.15.4/ieee_802_15_4_modgui.ui b/plugins/channeltx/mod802.15.4/ieee_802_15_4_modgui.ui index a945d2939..fb03165da 100644 --- a/plugins/channeltx/mod802.15.4/ieee_802_15_4_modgui.ui +++ b/plugins/channeltx/mod802.15.4/ieee_802_15_4_modgui.ui @@ -43,7 +43,7 @@ 2 2 341 - 121 + 151 @@ -410,6 +410,103 @@ + + + + + + Forward frames received via UDP + + + Qt::RightToLeft + + + UDP + + + + + + + + 120 + 0 + + + + Qt::ClickFocus + + + Destination UDP address + + + 000.000.000.000 + + + 127.0.0.1 + + + + + + + : + + + Qt::AlignCenter + + + + + + + + 50 + 0 + + + + + 50 + 16777215 + + + + Qt::ClickFocus + + + Destination UDP port + + + 00000 + + + 9997 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Horizontal + + + @@ -600,35 +697,12 @@ - - ButtonSwitch - QToolButton -
gui/buttonswitch.h
-
RollupWidget QWidget
gui/rollupwidget.h
1
- - ValueDialZ - QWidget -
gui/valuedialz.h
- 1 -
- - GLScope - QWidget -
gui/glscope.h
- 1 -
- - GLScopeGUI - QWidget -
gui/glscopegui.h
- 1 -
GLSpectrum QWidget @@ -641,12 +715,35 @@
gui/glspectrumgui.h
1
+ + ValueDialZ + QWidget +
gui/valuedialz.h
+ 1 +
+ + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
LevelMeterVU QWidget
gui/levelmeter.h
1
+ + GLScope + QWidget +
gui/glscope.h
+ 1 +
+ + GLScopeGUI + QWidget +
gui/glscopegui.h
+ 1 +
deltaFrequency diff --git a/plugins/channeltx/mod802.15.4/ieee_802_15_4_modsettings.cpp b/plugins/channeltx/mod802.15.4/ieee_802_15_4_modsettings.cpp index 7914a0d16..fd984cdc0 100644 --- a/plugins/channeltx/mod802.15.4/ieee_802_15_4_modsettings.cpp +++ b/plugins/channeltx/mod802.15.4/ieee_802_15_4_modsettings.cpp @@ -69,6 +69,9 @@ void IEEE_802_15_4_ModSettings::resetToDefaults() m_pulseShaping = RC; m_beta = 1.0f; m_symbolSpan = 6; + m_udpEnabled = false; + m_udpAddress = "127.0.0.1"; + m_udpPort = 9998; } bool IEEE_802_15_4_ModSettings::setPHY(QString phy) @@ -176,6 +179,9 @@ QByteArray IEEE_802_15_4_ModSettings::serialize() const s.writeS32(31, m_symbolSpan); s.writeS32(32, m_spectrumRate); s.writeS32(33, m_modulation); + s.writeBool(34, m_udpEnabled); + s.writeString(35, m_udpAddress); + s.writeU32(36, m_udpPort); return s.final(); } @@ -245,6 +251,14 @@ bool IEEE_802_15_4_ModSettings::deserialize(const QByteArray& data) d.readS32(31, &m_symbolSpan, 6); d.readS32(32, &m_spectrumRate, m_rfBandwidth); d.readS32(33, (qint32 *)&m_modulation, m_bitRate < 100000 ? IEEE_802_15_4_ModSettings::BPSK : IEEE_802_15_4_ModSettings::OQPSK); + d.readBool(34, &m_udpEnabled); + d.readString(35, &m_udpAddress, "127.0.0.1"); + d.readU32(36, &utmp); + if ((utmp > 1023) && (utmp < 65535)) { + m_udpPort = utmp; + } else { + m_udpPort = 9998; + } return true; } 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 a41c9a789..554fed6af 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 @@ -62,6 +62,9 @@ struct IEEE_802_15_4_ModSettings enum PulseShaping {RC, SINE} m_pulseShaping; float m_beta; int m_symbolSpan; + bool m_udpEnabled; + QString m_udpAddress; + uint16_t m_udpPort; 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 184a18e74..3a1b9a67a 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 @@ -577,7 +577,7 @@ void IEEE_802_15_4_ModSource::addTXFrame(QString data) // PHY payload crcStart = p; // Data - p = hexToBin(p, data); + p = hexToBin(p, data.trimmed()); // MAC FCS crc.calculate(crcStart, p-crcStart); crcValue = crc.get(); diff --git a/swagger/sdrangel/api/swagger/include/IEEE_802_15_4_Mod.yaml b/swagger/sdrangel/api/swagger/include/IEEE_802_15_4_Mod.yaml index d66fd9983..fe6d3ea39 100644 --- a/swagger/sdrangel/api/swagger/include/IEEE_802_15_4_Mod.yaml +++ b/swagger/sdrangel/api/swagger/include/IEEE_802_15_4_Mod.yaml @@ -25,6 +25,15 @@ IEEE_802_15_4_ModSettings: repeatCount: description: Number of times to repeat the frame (-1 for infinite). type: integer + udpEnabled: + description: Enable forwarding of frames via UDP + type: integer + udpAddress: + description: UDP address to listen for frames to transmit on + type: string + udpPort: + description: UDP port to listen for frames to transmit on + type: integer rgbColor: type: integer title: diff --git a/swagger/sdrangel/code/qt5/client/SWGIEEE_802_15_4_ModSettings.cpp b/swagger/sdrangel/code/qt5/client/SWGIEEE_802_15_4_ModSettings.cpp index e1c869c59..83376e39a 100644 --- a/swagger/sdrangel/code/qt5/client/SWGIEEE_802_15_4_ModSettings.cpp +++ b/swagger/sdrangel/code/qt5/client/SWGIEEE_802_15_4_ModSettings.cpp @@ -44,6 +44,12 @@ SWGIEEE_802_15_4_ModSettings::SWGIEEE_802_15_4_ModSettings() { m_repeat_delay_isSet = false; repeat_count = 0; m_repeat_count_isSet = false; + udp_enabled = 0; + m_udp_enabled_isSet = false; + udp_address = nullptr; + m_udp_address_isSet = false; + udp_port = 0; + m_udp_port_isSet = false; rgb_color = 0; m_rgb_color_isSet = false; title = nullptr; @@ -84,6 +90,12 @@ SWGIEEE_802_15_4_ModSettings::init() { m_repeat_delay_isSet = false; repeat_count = 0; m_repeat_count_isSet = false; + udp_enabled = 0; + m_udp_enabled_isSet = false; + udp_address = new QString(""); + m_udp_address_isSet = false; + udp_port = 0; + m_udp_port_isSet = false; rgb_color = 0; m_rgb_color_isSet = false; title = new QString(""); @@ -115,6 +127,11 @@ SWGIEEE_802_15_4_ModSettings::cleanup() { + if(udp_address != nullptr) { + delete udp_address; + } + + if(title != nullptr) { delete title; } @@ -155,6 +172,12 @@ SWGIEEE_802_15_4_ModSettings::fromJsonObject(QJsonObject &pJson) { ::SWGSDRangel::setValue(&repeat_count, pJson["repeatCount"], "qint32", ""); + ::SWGSDRangel::setValue(&udp_enabled, pJson["udpEnabled"], "qint32", ""); + + ::SWGSDRangel::setValue(&udp_address, pJson["udpAddress"], "QString", "QString"); + + ::SWGSDRangel::setValue(&udp_port, pJson["udpPort"], "qint32", ""); + ::SWGSDRangel::setValue(&rgb_color, pJson["rgbColor"], "qint32", ""); ::SWGSDRangel::setValue(&title, pJson["title"], "QString", "QString"); @@ -211,6 +234,15 @@ SWGIEEE_802_15_4_ModSettings::asJsonObject() { if(m_repeat_count_isSet){ obj->insert("repeatCount", QJsonValue(repeat_count)); } + if(m_udp_enabled_isSet){ + obj->insert("udpEnabled", QJsonValue(udp_enabled)); + } + if(udp_address != nullptr && *udp_address != QString("")){ + toJsonValue(QString("udpAddress"), udp_address, obj, QString("QString")); + } + if(m_udp_port_isSet){ + obj->insert("udpPort", QJsonValue(udp_port)); + } if(m_rgb_color_isSet){ obj->insert("rgbColor", QJsonValue(rgb_color)); } @@ -319,6 +351,36 @@ SWGIEEE_802_15_4_ModSettings::setRepeatCount(qint32 repeat_count) { this->m_repeat_count_isSet = true; } +qint32 +SWGIEEE_802_15_4_ModSettings::getUdpEnabled() { + return udp_enabled; +} +void +SWGIEEE_802_15_4_ModSettings::setUdpEnabled(qint32 udp_enabled) { + this->udp_enabled = udp_enabled; + this->m_udp_enabled_isSet = true; +} + +QString* +SWGIEEE_802_15_4_ModSettings::getUdpAddress() { + return udp_address; +} +void +SWGIEEE_802_15_4_ModSettings::setUdpAddress(QString* udp_address) { + this->udp_address = udp_address; + this->m_udp_address_isSet = true; +} + +qint32 +SWGIEEE_802_15_4_ModSettings::getUdpPort() { + return udp_port; +} +void +SWGIEEE_802_15_4_ModSettings::setUdpPort(qint32 udp_port) { + this->udp_port = udp_port; + this->m_udp_port_isSet = true; +} + qint32 SWGIEEE_802_15_4_ModSettings::getRgbColor() { return rgb_color; @@ -428,6 +490,15 @@ SWGIEEE_802_15_4_ModSettings::isSet(){ if(m_repeat_count_isSet){ isObjectUpdated = true; break; } + if(m_udp_enabled_isSet){ + isObjectUpdated = true; break; + } + if(udp_address && *udp_address != QString("")){ + isObjectUpdated = true; break; + } + if(m_udp_port_isSet){ + isObjectUpdated = true; break; + } if(m_rgb_color_isSet){ isObjectUpdated = true; break; } diff --git a/swagger/sdrangel/code/qt5/client/SWGIEEE_802_15_4_ModSettings.h b/swagger/sdrangel/code/qt5/client/SWGIEEE_802_15_4_ModSettings.h index 9eb3247c0..e32326b64 100644 --- a/swagger/sdrangel/code/qt5/client/SWGIEEE_802_15_4_ModSettings.h +++ b/swagger/sdrangel/code/qt5/client/SWGIEEE_802_15_4_ModSettings.h @@ -66,6 +66,15 @@ public: qint32 getRepeatCount(); void setRepeatCount(qint32 repeat_count); + qint32 getUdpEnabled(); + void setUdpEnabled(qint32 udp_enabled); + + QString* getUdpAddress(); + void setUdpAddress(QString* udp_address); + + qint32 getUdpPort(); + void setUdpPort(qint32 udp_port); + qint32 getRgbColor(); void setRgbColor(qint32 rgb_color); @@ -118,6 +127,15 @@ private: qint32 repeat_count; bool m_repeat_count_isSet; + qint32 udp_enabled; + bool m_udp_enabled_isSet; + + QString* udp_address; + bool m_udp_address_isSet; + + qint32 udp_port; + bool m_udp_port_isSet; + qint32 rgb_color; bool m_rgb_color_isSet;