1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-12-23 01:55:48 -05:00

Add IEEE 802.15.4 modulator

This commit is contained in:
Jon Beniston 2020-10-08 15:13:06 +01:00
parent 58a9fba076
commit 22ff79239e
49 changed files with 6025 additions and 9 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -5,6 +5,7 @@ add_subdirectory(modnfm)
add_subdirectory(modssb)
add_subdirectory(modwfm)
add_subdirectory(modpacket)
add_subdirectory(mod802.15.4)
add_subdirectory(udpsource)
add_subdirectory(localsource)
add_subdirectory(filesource)

View File

@ -0,0 +1,66 @@
project(mod_ieee_802_15_4)
set(mod_ieee_802_15_4_SOURCES
ieee_802_15_4_mod.cpp
ieee_802_15_4_modbaseband.cpp
ieee_802_15_4_modsource.cpp
ieee_802_15_4_modplugin.cpp
ieee_802_15_4_modsettings.cpp
ieee_802_15_4_modwebapiadapter.cpp
)
set(mod_ieee_802_15_4_HEADERS
ieee_802_15_4_mod.h
ieee_802_15_4_modbaseband.h
ieee_802_15_4_modsource.h
ieee_802_15_4_modplugin.h
ieee_802_15_4_modsettings.h
ieee_802_15_4_modwebapiadapter.h
ieee_802_15_4_macframe.h
)
include_directories(
${Boost_INCLUDE_DIRS}
${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client
)
if(NOT SERVER_MODE)
set(mod_ieee_802_15_4_SOURCES
${mod_ieee_802_15_4_SOURCES}
ieee_802_15_4_modgui.cpp
ieee_802_15_4_modgui.ui
ieee_802_15_4_modrepeatdialog.cpp
ieee_802_15_4_modrepeatdialog.ui
ieee_802_15_4_modtxsettingsdialog.cpp
ieee_802_15_4_modtxsettingsdialog.ui
)
set(mod_ieee_802_15_4_HEADERS
${mod_ieee_802_15_4_HEADERS}
ieee_802_15_4_modgui.h
ieee_802_15_4_modrepeatdialog.h
ieee_802_15_4_modtxsettingsdialog.h
)
set(TARGET_NAME modieee_802_15_4)
set(TARGET_LIB "Qt5::Widgets")
set(TARGET_LIB_GUI "sdrgui")
set(INSTALL_FOLDER ${INSTALL_PLUGINS_DIR})
else()
set(TARGET_NAME modieee_802_15_4srv)
set(TARGET_LIB "")
set(TARGET_LIB_GUI "")
set(INSTALL_FOLDER ${INSTALL_PLUGINSSRV_DIR})
endif()
add_library(${TARGET_NAME} SHARED
${mod_ieee_802_15_4_SOURCES}
)
target_link_libraries(${TARGET_NAME}
Qt5::Core
${TARGET_LIB}
sdrbase
${TARGET_LIB_GUI}
swagger
)
install(TARGETS ${TARGET_NAME} DESTINATION ${INSTALL_FOLDER})

View File

@ -0,0 +1,118 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Jon Beniston, M7RCE //
// //
// 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 //
// (at your option) any later version. //
// //
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_IEEE_802_15_4_MACFRAME_H
#define INCLUDE_IEEE_802_15_4_MACFRAME_H
#include <stdint.h>
#include <stdio.h>
// Frame control field values
#define IEEE_802_15_4_MAC_FRAME_TYPE_MASK 0x0003
#define IEEE_802_15_4_MAC_BEACON 0x0000
#define IEEE_802_15_4_MAC_DATA 0x0001
#define IEEE_802_15_4_MAC_ACK 0x0002
#define IEEE_802_15_4_MAC_COMMAND 0x0003
#define IEEE_802_15_4_MAC_SECURITY_ENABLED 0x0008
#define IEEE_802_15_4_MAC_FRAME_PENDING 0x0010
#define IEEE_802_15_4_MAC_ACK_REQUIRED 0x0020
#define IEEE_802_15_4_MAC_PAN_COMPRESSION 0x0040
#define IEEE_802_15_4_MAC_NO_SEQ_NUMBER 0x0100
#define IEEE_802_15_4_MAC_DEST_ADDRESS_MASK 0x0c00
#define IEEE_802_15_4_MAC_DEST_ADDRESS_NONE 0x0000
#define IEEE_802_15_4_MAC_DEST_ADDRESS_SHORT 0x0400
#define IEEE_802_15_4_MAC_DEST_ADDRESS_EXT 0x0c00
#define IEEE_802_15_4_MAC_SOURCE_ADDRESS_MASK 0xc000
#define IEEE_802_15_4_MAC_SOURCE_ADDRESS_NONE 0x0000
#define IEEE_802_15_4_MAC_SOURCE_ADDRESS_SHORT 0x4000
#define IEEE_802_15_4_MAC_SOURCE_ADDRESS_EXT 0xc000
#define IEEE_802_15_4_MAC_PAYLOAD_MAX_LENGTH 124
#define IEEE_802_15_5_MAX_EXT_ADDRESS_LENGTH 8
typedef uint8_t ieee_802_15_4_address[IEEE_802_15_5_MAX_EXT_ADDRESS_LENGTH];
struct IEEE_802_15_4_MacFrame
{
uint16_t m_frameControl;
uint8_t m_sequenceNumber;
uint16_t m_destPANID;
uint16_t m_destShortAddress;
ieee_802_15_4_address m_destAddress;
uint16_t m_sourcePANID;
uint16_t m_sourceShortAddress;
ieee_802_15_4_address m_sourceAddress;
uint8_t m_payload[IEEE_802_15_4_MAC_PAYLOAD_MAX_LENGTH];
uint8_t m_payloadLength;
IEEE_802_15_4_MacFrame()
{
if (false)
{
// Example ACK frame
m_frameControl = IEEE_802_15_4_MAC_ACK;
m_sequenceNumber = 0;
m_payloadLength = 0;
}
else
{
ieee_802_15_4_address dst = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
ieee_802_15_4_address src = {0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff};
// Example data frame
m_frameControl = IEEE_802_15_4_MAC_DATA | IEEE_802_15_4_MAC_DEST_ADDRESS_EXT | IEEE_802_15_4_MAC_SOURCE_ADDRESS_EXT;
m_sequenceNumber = 0;
m_destPANID = 0xbabe;
memcpy(m_destAddress, dst, sizeof(m_destAddress));
m_sourcePANID = 0xbabe;
memcpy(m_sourceAddress, src, sizeof(m_sourceAddress));
strcpy((char *)m_payload, "SDR Angel does 15.4");
m_payloadLength = strlen((char *)m_payload);
}
}
char *bytesToHex(char *buf, uint8_t *data, int len)
{
for (int i = 0; i < len; i++)
buf += sprintf(buf, "%02x ", data[i]);
return buf;
}
void toHexCharArray(char *buf)
{
buf += sprintf(buf, "%02x %02x %02x ", m_frameControl & 0xff, (m_frameControl >> 8) & 0xff, m_sequenceNumber);
if ((m_frameControl & IEEE_802_15_4_MAC_FRAME_TYPE_MASK) != IEEE_802_15_4_MAC_ACK)
buf += sprintf(buf, "%02x %02x ", m_destPANID & 0xff, (m_destPANID >> 8) & 0xff);
if ((m_frameControl & IEEE_802_15_4_MAC_DEST_ADDRESS_MASK) == IEEE_802_15_4_MAC_DEST_ADDRESS_EXT)
buf = bytesToHex(buf, m_destAddress, sizeof(m_destAddress));
else if ((m_frameControl & IEEE_802_15_4_MAC_DEST_ADDRESS_MASK) == IEEE_802_15_4_MAC_DEST_ADDRESS_SHORT)
buf += sprintf(buf, "%02x %02x ", m_destShortAddress & 0xff, (m_destShortAddress >> 8) & 0xff);
if (((m_frameControl & IEEE_802_15_4_MAC_FRAME_TYPE_MASK) != IEEE_802_15_4_MAC_ACK)
&& (!(m_frameControl & IEEE_802_15_4_MAC_PAN_COMPRESSION) || (m_destPANID != m_sourcePANID)))
buf += sprintf(buf, "%02x %02x ", m_sourcePANID & 0xff, (m_sourcePANID >> 8) & 0xff);
if ((m_frameControl & IEEE_802_15_4_MAC_SOURCE_ADDRESS_MASK) == IEEE_802_15_4_MAC_SOURCE_ADDRESS_EXT)
buf = bytesToHex(buf, m_sourceAddress, sizeof(m_sourceAddress));
else if ((m_frameControl & IEEE_802_15_4_MAC_SOURCE_ADDRESS_MASK) == IEEE_802_15_4_MAC_SOURCE_ADDRESS_SHORT)
buf += sprintf(buf, "%02x %02x ", m_sourceShortAddress & 0xff, (m_sourceShortAddress >> 8) & 0xff);
buf = bytesToHex(buf, m_payload, m_payloadLength);
}
};
#endif /* INCLUDE_IEEE_802_15_4_MACFRAME_H */

View File

@ -0,0 +1,525 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2016 Edouard Griffiths, F4EXB //
// Copyright (C) 2020 Jon Beniston, M7RCE //
// //
// 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 //
// (at your option) any later version. //
// //
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <QTime>
#include <QDebug>
#include <QMutexLocker>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QBuffer>
#include <QThread>
#include "SWGChannelSettings.h"
#include "SWGChannelReport.h"
#include "SWGChannelActions.h"
#include "SWGIEEE_802_15_4_ModReport.h"
#include "SWGIEEE_802_15_4_ModActions.h"
#include "SWGIEEE_802_15_4_ModActions_tx.h"
#include <stdio.h>
#include <complex.h>
#include <algorithm>
#include "dsp/dspengine.h"
#include "dsp/dspcommands.h"
#include "device/deviceapi.h"
#include "util/db.h"
#include "util/crc.h"
#include "ieee_802_15_4_modbaseband.h"
#include "ieee_802_15_4_mod.h"
MESSAGE_CLASS_DEFINITION(IEEE_802_15_4_Mod::MsgConfigureIEEE_802_15_4_Mod, Message)
MESSAGE_CLASS_DEFINITION(IEEE_802_15_4_Mod::MsgTXIEEE_802_15_4_Mod, Message)
const QString IEEE_802_15_4_Mod::m_channelIdURI = "sdrangel.channeltx.mod802.15.4";
const QString IEEE_802_15_4_Mod::m_channelId = "IEEE_802_15_4_Mod";
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)
{
setObjectName(m_channelId);
m_thread = new QThread(this);
m_basebandSource = new IEEE_802_15_4_ModBaseband();
m_basebandSource->setSpectrumSampleSink(&m_spectrumVis);
m_basebandSource->moveToThread(m_thread);
applySettings(m_settings, true);
m_deviceAPI->addChannelSource(this);
m_deviceAPI->addChannelSourceAPI(this);
m_networkManager = new QNetworkAccessManager();
connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
}
IEEE_802_15_4_Mod::~IEEE_802_15_4_Mod()
{
disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
delete m_networkManager;
m_deviceAPI->removeChannelSourceAPI(this);
m_deviceAPI->removeChannelSource(this);
delete m_basebandSource;
delete m_thread;
}
void IEEE_802_15_4_Mod::start()
{
qDebug("IEEE_802_15_4_Mod::start");
m_basebandSource->reset();
m_thread->start();
}
void IEEE_802_15_4_Mod::stop()
{
qDebug("IEEE_802_15_4_Mod::stop");
m_thread->exit();
m_thread->wait();
}
void IEEE_802_15_4_Mod::pull(SampleVector::iterator& begin, unsigned int nbSamples)
{
m_basebandSource->pull(begin, nbSamples);
}
bool IEEE_802_15_4_Mod::handleMessage(const Message& cmd)
{
if (MsgConfigureIEEE_802_15_4_Mod::match(cmd))
{
MsgConfigureIEEE_802_15_4_Mod& cfg = (MsgConfigureIEEE_802_15_4_Mod&) cmd;
qDebug() << "IEEE_802_15_4_Mod::handleMessage: MsgConfigureIEEE_802_15_4_Mod";
applySettings(cfg.getSettings(), cfg.getForce());
return true;
}
else if (MsgTXIEEE_802_15_4_Mod::match(cmd))
{
// Forward a copy to baseband
MsgTXIEEE_802_15_4_Mod* rep = new MsgTXIEEE_802_15_4_Mod((MsgTXIEEE_802_15_4_Mod&)cmd);
qDebug() << "IEEE_802_15_4_Mod::handleMessage: MsgTXIEEE_802_15_4_Mod";
m_basebandSource->getInputMessageQueue()->push(rep);
return true;
}
else if (DSPSignalNotification::match(cmd))
{
// Forward to the source
DSPSignalNotification& notif = (DSPSignalNotification&) cmd;
DSPSignalNotification* rep = new DSPSignalNotification(notif); // make a copy
qDebug() << "IEEE_802_15_4_Mod::handleMessage: DSPSignalNotification";
m_basebandSource->getInputMessageQueue()->push(rep);
// Forward to GUI
if (getMessageQueueToGUI())
{
DSPSignalNotification *notifToGUI = new DSPSignalNotification(notif);
getMessageQueueToGUI()->push(notifToGUI);
}
return true;
}
else
{
return false;
}
}
void IEEE_802_15_4_Mod::applySettings(const IEEE_802_15_4_ModSettings& settings, bool force)
{
qDebug() << "IEEE_802_15_4_Mod::applySettings:"
<< " m_inputFrequencyOffset: " << settings.m_inputFrequencyOffset
<< " m_rfBandwidth: " << settings.m_rfBandwidth
<< " m_gain: " << settings.m_gain
<< " m_channelMute: " << settings.m_channelMute
<< " m_repeat: " << settings.m_repeat
<< " m_repeatDelay: " << settings.m_repeatDelay
<< " m_repeatCount: " << settings.m_repeatCount
<< " m_useReverseAPI: " << settings.m_useReverseAPI
<< " m_reverseAPIAddress: " << settings.m_reverseAPIAddress
<< " m_reverseAPIAddress: " << settings.m_reverseAPIPort
<< " m_reverseAPIDeviceIndex: " << settings.m_reverseAPIDeviceIndex
<< " m_reverseAPIChannelIndex: " << settings.m_reverseAPIChannelIndex
<< " force: " << force;
QList<QString> reverseAPIKeys;
if ((settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) || force) {
reverseAPIKeys.append("inputFrequencyOffset");
}
if ((settings.m_rfBandwidth != m_settings.m_rfBandwidth) || force) {
reverseAPIKeys.append("rfBandwidth");
}
if ((settings.m_gain != m_settings.m_gain) || force) {
reverseAPIKeys.append("gain");
}
if ((settings.m_channelMute != m_settings.m_channelMute) || force) {
reverseAPIKeys.append("channelMute");
}
if ((settings.m_repeat != m_settings.m_repeat) || force) {
reverseAPIKeys.append("repeat");
}
if ((settings.m_repeatDelay != m_settings.m_repeatDelay) || force) {
reverseAPIKeys.append("repeatDelay");
}
if ((settings.m_repeatCount != m_settings.m_repeatCount) || force) {
reverseAPIKeys.append("repeatCount");
}
if (m_settings.m_streamIndex != settings.m_streamIndex)
{
if (m_deviceAPI->getSampleMIMO()) // change of stream is possible for MIMO devices only
{
m_deviceAPI->removeChannelSourceAPI(this);
m_deviceAPI->removeChannelSource(this, m_settings.m_streamIndex);
m_deviceAPI->addChannelSource(this, settings.m_streamIndex);
m_deviceAPI->addChannelSourceAPI(this);
}
reverseAPIKeys.append("streamIndex");
}
IEEE_802_15_4_ModBaseband::MsgConfigureIEEE_802_15_4_ModBaseband *msg = IEEE_802_15_4_ModBaseband::MsgConfigureIEEE_802_15_4_ModBaseband::create(settings, force);
m_basebandSource->getInputMessageQueue()->push(msg);
if (settings.m_useReverseAPI)
{
bool fullUpdate = ((m_settings.m_useReverseAPI != settings.m_useReverseAPI) && settings.m_useReverseAPI) ||
(m_settings.m_reverseAPIAddress != settings.m_reverseAPIAddress) ||
(m_settings.m_reverseAPIPort != settings.m_reverseAPIPort) ||
(m_settings.m_reverseAPIDeviceIndex != settings.m_reverseAPIDeviceIndex) ||
(m_settings.m_reverseAPIChannelIndex != settings.m_reverseAPIChannelIndex);
webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
}
m_settings = settings;
}
QByteArray IEEE_802_15_4_Mod::serialize() const
{
return m_settings.serialize();
}
bool IEEE_802_15_4_Mod::deserialize(const QByteArray& data)
{
bool success = true;
if (!m_settings.deserialize(data))
{
m_settings.resetToDefaults();
success = false;
}
MsgConfigureIEEE_802_15_4_Mod *msg = MsgConfigureIEEE_802_15_4_Mod::create(m_settings, true);
m_inputMessageQueue.push(msg);
return success;
}
int IEEE_802_15_4_Mod::webapiSettingsGet(
SWGSDRangel::SWGChannelSettings& response,
QString& errorMessage)
{
(void) errorMessage;
response.setIeee802154ModSettings(new SWGSDRangel::SWGIEEE_802_15_4_ModSettings());
response.getIeee802154ModSettings()->init();
webapiFormatChannelSettings(response, m_settings);
return 200;
}
int IEEE_802_15_4_Mod::webapiSettingsPutPatch(
bool force,
const QStringList& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings& response,
QString& errorMessage)
{
(void) errorMessage;
IEEE_802_15_4_ModSettings settings = m_settings;
webapiUpdateChannelSettings(settings, channelSettingsKeys, response);
MsgConfigureIEEE_802_15_4_Mod *msg = MsgConfigureIEEE_802_15_4_Mod::create(settings, force);
m_inputMessageQueue.push(msg);
if (m_guiMessageQueue) // forward to GUI if any
{
MsgConfigureIEEE_802_15_4_Mod *msgToGUI = MsgConfigureIEEE_802_15_4_Mod::create(settings, force);
m_guiMessageQueue->push(msgToGUI);
}
webapiFormatChannelSettings(response, settings);
return 200;
}
void IEEE_802_15_4_Mod::webapiUpdateChannelSettings(
IEEE_802_15_4_ModSettings& settings,
const QStringList& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings& response)
{
if (channelSettingsKeys.contains("inputFrequencyOffset")) {
settings.m_inputFrequencyOffset = response.getIeee802154ModSettings()->getInputFrequencyOffset();
}
if (channelSettingsKeys.contains("phy")) {
settings.setPHY(*response.getIeee802154ModSettings()->getPhy());
}
if (channelSettingsKeys.contains("rfBandwidth")) {
settings.m_rfBandwidth = response.getIeee802154ModSettings()->getRfBandwidth();
}
if (channelSettingsKeys.contains("gain")) {
settings.m_gain = response.getIeee802154ModSettings()->getGain();
}
if (channelSettingsKeys.contains("channelMute")) {
settings.m_channelMute = response.getIeee802154ModSettings()->getChannelMute() != 0;
}
if (channelSettingsKeys.contains("repeat")) {
settings.m_repeat = response.getIeee802154ModSettings()->getRepeat() != 0;
}
if (channelSettingsKeys.contains("repeatDelay")) {
settings.m_repeatDelay = response.getIeee802154ModSettings()->getRepeatDelay();
}
if (channelSettingsKeys.contains("repeatCount")) {
settings.m_repeatCount = response.getIeee802154ModSettings()->getRepeatCount();
}
if (channelSettingsKeys.contains("rgbColor")) {
settings.m_rgbColor = response.getIeee802154ModSettings()->getRgbColor();
}
if (channelSettingsKeys.contains("title")) {
settings.m_title = *response.getIeee802154ModSettings()->getTitle();
}
if (channelSettingsKeys.contains("streamIndex")) {
settings.m_streamIndex = response.getIeee802154ModSettings()->getStreamIndex();
}
if (channelSettingsKeys.contains("useReverseAPI")) {
settings.m_useReverseAPI = response.getIeee802154ModSettings()->getUseReverseApi() != 0;
}
if (channelSettingsKeys.contains("reverseAPIAddress")) {
settings.m_reverseAPIAddress = *response.getIeee802154ModSettings()->getReverseApiAddress();
}
if (channelSettingsKeys.contains("reverseAPIPort")) {
settings.m_reverseAPIPort = response.getIeee802154ModSettings()->getReverseApiPort();
}
if (channelSettingsKeys.contains("reverseAPIDeviceIndex")) {
settings.m_reverseAPIDeviceIndex = response.getIeee802154ModSettings()->getReverseApiDeviceIndex();
}
if (channelSettingsKeys.contains("reverseAPIChannelIndex")) {
settings.m_reverseAPIChannelIndex = response.getIeee802154ModSettings()->getReverseApiChannelIndex();
}
}
int IEEE_802_15_4_Mod::webapiReportGet(
SWGSDRangel::SWGChannelReport& response,
QString& errorMessage)
{
(void) errorMessage;
response.setIeee802154ModReport(new SWGSDRangel::SWGIEEE_802_15_4_ModReport());
response.getIeee802154ModReport()->init();
webapiFormatChannelReport(response);
return 200;
}
int IEEE_802_15_4_Mod::webapiActionsPost(
const QStringList& channelActionsKeys,
SWGSDRangel::SWGChannelActions& query,
QString& errorMessage)
{
SWGSDRangel::SWGIEEE_802_15_4_ModActions *swgIEEE_802_15_4_ModActions = query.getIeee802154ModActions();
if (swgIEEE_802_15_4_ModActions)
{
if (channelActionsKeys.contains("tx"))
{
SWGSDRangel::SWGIEEE_802_15_4_ModActions_tx* tx = swgIEEE_802_15_4_ModActions->getTx();
QString *dataP = tx->getData();
if (dataP != nullptr)
{
QString data(*dataP);
IEEE_802_15_4_Mod::MsgTXIEEE_802_15_4_Mod *msg = IEEE_802_15_4_Mod::MsgTXIEEE_802_15_4_Mod::create(data);
m_basebandSource->getInputMessageQueue()->push(msg);
return 202;
}
else
{
errorMessage = "Missing data to transmit";
return 400;
}
}
else
{
errorMessage = "Unknown action";
return 400;
}
}
else
{
errorMessage = "Missing IEEE_802_15_4_ModActions in query";
return 400;
}
}
void IEEE_802_15_4_Mod::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& response, const IEEE_802_15_4_ModSettings& settings)
{
response.getIeee802154ModSettings()->setInputFrequencyOffset(settings.m_inputFrequencyOffset);
response.getIeee802154ModSettings()->setPhy(new QString(settings.getPHY()));
response.getIeee802154ModSettings()->setRfBandwidth(settings.m_rfBandwidth);
response.getIeee802154ModSettings()->setGain(settings.m_gain);
response.getIeee802154ModSettings()->setChannelMute(settings.m_channelMute ? 1 : 0);
response.getIeee802154ModSettings()->setRepeat(settings.m_repeat ? 1 : 0);
response.getIeee802154ModSettings()->setRepeatDelay(settings.m_repeatDelay);
response.getIeee802154ModSettings()->setRepeatCount(settings.m_repeatCount);
response.getIeee802154ModSettings()->setRgbColor(settings.m_rgbColor);
if (response.getIeee802154ModSettings()->getTitle()) {
*response.getIeee802154ModSettings()->getTitle() = settings.m_title;
} else {
response.getIeee802154ModSettings()->setTitle(new QString(settings.m_title));
}
response.getIeee802154ModSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0);
if (response.getIeee802154ModSettings()->getReverseApiAddress()) {
*response.getIeee802154ModSettings()->getReverseApiAddress() = settings.m_reverseAPIAddress;
} else {
response.getIeee802154ModSettings()->setReverseApiAddress(new QString(settings.m_reverseAPIAddress));
}
response.getIeee802154ModSettings()->setReverseApiPort(settings.m_reverseAPIPort);
response.getIeee802154ModSettings()->setReverseApiDeviceIndex(settings.m_reverseAPIDeviceIndex);
response.getIeee802154ModSettings()->setReverseApiChannelIndex(settings.m_reverseAPIChannelIndex);
}
void IEEE_802_15_4_Mod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response)
{
response.getIeee802154ModReport()->setChannelPowerDb(CalcDb::dbPower(getMagSq()));
response.getIeee802154ModReport()->setChannelSampleRate(m_basebandSource->getChannelSampleRate());
}
void IEEE_802_15_4_Mod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const IEEE_802_15_4_ModSettings& settings, bool force)
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
swgChannelSettings->setDirection(1); // single source (Tx)
swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet());
swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex());
swgChannelSettings->setChannelType(new QString("IEEE_802_15_4_Mod"));
swgChannelSettings->setIeee802154ModSettings(new SWGSDRangel::SWGIEEE_802_15_4_ModSettings());
SWGSDRangel::SWGIEEE_802_15_4_ModSettings *swgIEEE_802_15_4_ModSettings = swgChannelSettings->getIeee802154ModSettings();
// transfer data that has been modified. When force is on transfer all data except reverse API data
if (channelSettingsKeys.contains("inputFrequencyOffset") || force) {
swgIEEE_802_15_4_ModSettings->setInputFrequencyOffset(settings.m_inputFrequencyOffset);
}
if (channelSettingsKeys.contains("rfBandwidth") || force) {
swgIEEE_802_15_4_ModSettings->setRfBandwidth(settings.m_rfBandwidth);
}
if (channelSettingsKeys.contains("gain") || force) {
swgIEEE_802_15_4_ModSettings->setGain(settings.m_gain);
}
if (channelSettingsKeys.contains("channelMute") || force) {
swgIEEE_802_15_4_ModSettings->setChannelMute(settings.m_channelMute ? 1 : 0);
}
if (channelSettingsKeys.contains("repeat") || force) {
swgIEEE_802_15_4_ModSettings->setRepeat(settings.m_repeat ? 1 : 0);
}
if (channelSettingsKeys.contains("repeatDelay") || force) {
swgIEEE_802_15_4_ModSettings->setRepeatDelay(settings.m_repeatDelay);
}
if (channelSettingsKeys.contains("repeatCount") || force) {
swgIEEE_802_15_4_ModSettings->setRepeatCount(settings.m_repeatCount);
}
if (channelSettingsKeys.contains("rgbColor") || force) {
swgIEEE_802_15_4_ModSettings->setRgbColor(settings.m_rgbColor);
}
if (channelSettingsKeys.contains("title") || force) {
swgIEEE_802_15_4_ModSettings->setTitle(new QString(settings.m_title));
}
if (channelSettingsKeys.contains("streamIndex") || force) {
swgIEEE_802_15_4_ModSettings->setStreamIndex(settings.m_streamIndex);
}
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIDeviceIndex)
.arg(settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void IEEE_802_15_4_Mod::networkManagerFinished(QNetworkReply *reply)
{
QNetworkReply::NetworkError replyError = reply->error();
if (replyError)
{
qWarning() << "IEEE_802_15_4_Mod::networkManagerFinished:"
<< " error(" << (int) replyError
<< "): " << replyError
<< ": " << reply->errorString();
}
else
{
QString answer = reply->readAll();
answer.chop(1); // remove last \n
qDebug("IEEE_802_15_4_Mod::networkManagerFinished: reply:\n%s", answer.toStdString().c_str());
}
reply->deleteLater();
}
double IEEE_802_15_4_Mod::getMagSq() const
{
return m_basebandSource->getMagSq();
}
void IEEE_802_15_4_Mod::setLevelMeter(QObject *levelMeter)
{
connect(m_basebandSource, SIGNAL(levelChanged(qreal, qreal, int)), levelMeter, SLOT(levelChanged(qreal, qreal, int)));
}
uint32_t IEEE_802_15_4_Mod::getNumberOfDeviceStreams() const
{
return m_deviceAPI->getNbSinkStreams();
}
void IEEE_802_15_4_Mod::setScopeSink(BasebandSampleSink* scopeSink)
{
m_basebandSource->setScopeSink(scopeSink);
}

View File

@ -0,0 +1,177 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2016-2019 Edouard Griffiths, F4EXB //
// Copyright (C) 2020 Jon Beniston, M7RCE //
// //
// 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 //
// (at your option) any later version. //
// //
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_IEEE_802_15_4_MOD_H
#define INCLUDE_IEEE_802_15_4_MOD_H
#include <vector>
#include <iostream>
#include <fstream>
#include <QMutex>
#include <QNetworkRequest>
#include "dsp/basebandsamplesource.h"
#include "dsp/spectrumvis.h"
#include "channel/channelapi.h"
#include "util/message.h"
#include "ieee_802_15_4_modsettings.h"
class QNetworkAccessManager;
class QNetworkReply;
class QThread;
class DeviceAPI;
class IEEE_802_15_4_ModBaseband;
class IEEE_802_15_4_Mod : public BasebandSampleSource, public ChannelAPI {
Q_OBJECT
public:
class MsgConfigureIEEE_802_15_4_Mod : public Message {
MESSAGE_CLASS_DECLARATION
public:
const IEEE_802_15_4_ModSettings& getSettings() const { return m_settings; }
bool getForce() const { return m_force; }
static MsgConfigureIEEE_802_15_4_Mod* create(const IEEE_802_15_4_ModSettings& settings, bool force)
{
return new MsgConfigureIEEE_802_15_4_Mod(settings, force);
}
private:
IEEE_802_15_4_ModSettings m_settings;
bool m_force;
MsgConfigureIEEE_802_15_4_Mod(const IEEE_802_15_4_ModSettings& settings, bool force) :
Message(),
m_settings(settings),
m_force(force)
{ }
};
class MsgTXIEEE_802_15_4_Mod : public Message {
MESSAGE_CLASS_DECLARATION
public:
static MsgTXIEEE_802_15_4_Mod* create(QString data)
{
return new MsgTXIEEE_802_15_4_Mod(data);
}
QString m_data;
private:
MsgTXIEEE_802_15_4_Mod(QString data) :
Message(),
m_data(data)
{ }
};
//=================================================================
IEEE_802_15_4_Mod(DeviceAPI *deviceAPI);
~IEEE_802_15_4_Mod();
virtual void destroy() { delete this; }
virtual void start();
virtual void stop();
virtual void pull(SampleVector::iterator& begin, unsigned int nbSamples);
virtual bool handleMessage(const Message& cmd);
virtual void getIdentifier(QString& id) { id = objectName(); }
virtual const QString& getURI() const { return m_channelIdURI; }
virtual void getTitle(QString& title) { title = m_settings.m_title; }
virtual qint64 getCenterFrequency() const { return m_settings.m_inputFrequencyOffset; }
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);
virtual int getNbSinkStreams() const { return 1; }
virtual int getNbSourceStreams() const { return 0; }
virtual qint64 getStreamCenterFrequency(int streamIndex, bool sinkElseSource) const
{
(void) streamIndex;
(void) sinkElseSource;
return m_settings.m_inputFrequencyOffset;
}
virtual int webapiSettingsGet(
SWGSDRangel::SWGChannelSettings& response,
QString& errorMessage);
virtual int webapiSettingsPutPatch(
bool force,
const QStringList& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings& response,
QString& errorMessage);
virtual int webapiReportGet(
SWGSDRangel::SWGChannelReport& response,
QString& errorMessage);
virtual int webapiActionsPost(
const QStringList& channelActionsKeys,
SWGSDRangel::SWGChannelActions& query,
QString& errorMessage);
static void webapiFormatChannelSettings(
SWGSDRangel::SWGChannelSettings& response,
const IEEE_802_15_4_ModSettings& settings);
static void webapiUpdateChannelSettings(
IEEE_802_15_4_ModSettings& settings,
const QStringList& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings& response);
SpectrumVis *getSpectrumVis() { return &m_spectrumVis; }
void setScopeSink(BasebandSampleSink* scopeSink);
double getMagSq() const;
void setLevelMeter(QObject *levelMeter);
uint32_t getNumberOfDeviceStreams() const;
static const QString m_channelIdURI;
static const QString m_channelId;
private:
DeviceAPI* m_deviceAPI;
QThread *m_thread;
IEEE_802_15_4_ModBaseband* m_basebandSource;
IEEE_802_15_4_ModSettings m_settings;
SpectrumVis m_spectrumVis;
SampleVector m_sampleBuffer;
QMutex m_settingsMutex;
QNetworkAccessManager *m_networkManager;
QNetworkRequest m_networkRequest;
void applySettings(const IEEE_802_15_4_ModSettings& settings, bool force = false);
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response);
void webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const IEEE_802_15_4_ModSettings& settings, bool force);
private slots:
void networkManagerFinished(QNetworkReply *reply);
};
#endif /* INCLUDE_IEEE_802_15_4_MOD_H */

View File

@ -0,0 +1,189 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2019 Edouard Griffiths, F4EXB //
// Copyright (C) 2020 Jon Beniston, M7RCE //
// //
// 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 //
// (at your option) any later version. //
// //
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <QDebug>
#include "dsp/upchannelizer.h"
#include "dsp/dspengine.h"
#include "dsp/dspcommands.h"
#include "ieee_802_15_4_modbaseband.h"
#include "ieee_802_15_4_mod.h"
MESSAGE_CLASS_DEFINITION(IEEE_802_15_4_ModBaseband::MsgConfigureIEEE_802_15_4_ModBaseband, Message)
IEEE_802_15_4_ModBaseband::IEEE_802_15_4_ModBaseband() :
m_mutex(QMutex::Recursive)
{
m_sampleFifo.resize(SampleSourceFifo::getSizePolicy(48000));
m_channelizer = new UpChannelizer(&m_source);
qDebug("IEEE_802_15_4_ModBaseband::IEEE_802_15_4_ModBaseband");
QObject::connect(
&m_sampleFifo,
&SampleSourceFifo::dataRead,
this,
&IEEE_802_15_4_ModBaseband::handleData,
Qt::QueuedConnection
);
connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
}
IEEE_802_15_4_ModBaseband::~IEEE_802_15_4_ModBaseband()
{
delete m_channelizer;
}
void IEEE_802_15_4_ModBaseband::reset()
{
QMutexLocker mutexLocker(&m_mutex);
m_sampleFifo.reset();
}
void IEEE_802_15_4_ModBaseband::pull(const SampleVector::iterator& begin, unsigned int nbSamples)
{
unsigned int part1Begin, part1End, part2Begin, part2End;
m_sampleFifo.read(nbSamples, part1Begin, part1End, part2Begin, part2End);
SampleVector& data = m_sampleFifo.getData();
if (part1Begin != part1End)
{
std::copy(
data.begin() + part1Begin,
data.begin() + part1End,
begin
);
}
unsigned int shift = part1End - part1Begin;
if (part2Begin != part2End)
{
std::copy(
data.begin() + part2Begin,
data.begin() + part2End,
begin + shift
);
}
}
void IEEE_802_15_4_ModBaseband::handleData()
{
QMutexLocker mutexLocker(&m_mutex);
SampleVector& data = m_sampleFifo.getData();
unsigned int ipart1begin;
unsigned int ipart1end;
unsigned int ipart2begin;
unsigned int ipart2end;
qreal rmsLevel, peakLevel;
int numSamples;
unsigned int remainder = m_sampleFifo.remainder();
while ((remainder > 0) && (m_inputMessageQueue.size() == 0))
{
m_sampleFifo.write(remainder, ipart1begin, ipart1end, ipart2begin, ipart2end);
if (ipart1begin != ipart1end) { // first part of FIFO data
processFifo(data, ipart1begin, ipart1end);
}
if (ipart2begin != ipart2end) { // second part of FIFO data (used when block wraps around)
processFifo(data, ipart2begin, ipart2end);
}
remainder = m_sampleFifo.remainder();
}
m_source.getLevels(rmsLevel, peakLevel, numSamples);
emit levelChanged(rmsLevel, peakLevel, numSamples);
}
void IEEE_802_15_4_ModBaseband::processFifo(SampleVector& data, unsigned int iBegin, unsigned int iEnd)
{
m_channelizer->prefetch(iEnd - iBegin);
m_channelizer->pull(data.begin() + iBegin, iEnd - iBegin);
}
void IEEE_802_15_4_ModBaseband::handleInputMessages()
{
Message* message;
while ((message = m_inputMessageQueue.pop()) != nullptr)
{
if (handleMessage(*message)) {
delete message;
}
}
}
bool IEEE_802_15_4_ModBaseband::handleMessage(const Message& cmd)
{
if (MsgConfigureIEEE_802_15_4_ModBaseband::match(cmd))
{
QMutexLocker mutexLocker(&m_mutex);
MsgConfigureIEEE_802_15_4_ModBaseband& cfg = (MsgConfigureIEEE_802_15_4_ModBaseband&) cmd;
qDebug() << "IEEE_802_15_4_ModBaseband::handleMessage: MsgConfigureIEEE_802_15_4_ModBaseband";
applySettings(cfg.getSettings(), cfg.getForce());
return true;
}
else if (IEEE_802_15_4_Mod::MsgTXIEEE_802_15_4_Mod::match(cmd))
{
IEEE_802_15_4_Mod::MsgTXIEEE_802_15_4_Mod& tx = (IEEE_802_15_4_Mod::MsgTXIEEE_802_15_4_Mod&) cmd;
m_source.addTXFrame(tx.m_data);
return true;
}
else if (DSPSignalNotification::match(cmd))
{
QMutexLocker mutexLocker(&m_mutex);
DSPSignalNotification& notif = (DSPSignalNotification&) cmd;
qDebug() << "IEEE_802_15_4_ModBaseband::handleMessage: DSPSignalNotification: basebandSampleRate: " << notif.getSampleRate();
m_sampleFifo.resize(SampleSourceFifo::getSizePolicy(notif.getSampleRate()));
m_channelizer->setBasebandSampleRate(notif.getSampleRate());
m_source.applyChannelSettings(m_channelizer->getChannelSampleRate(), m_channelizer->getChannelFrequencyOffset());
return true;
}
else
{
qDebug() << "IEEE_802_15_4_ModBaseband - Baseband got unknown message";
return false;
}
}
void IEEE_802_15_4_ModBaseband::applySettings(const IEEE_802_15_4_ModSettings& settings, bool force)
{
if ((settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) || force)
{
m_channelizer->setChannelization(m_channelizer->getChannelSampleRate(), settings.m_inputFrequencyOffset);
m_source.applyChannelSettings(m_channelizer->getChannelSampleRate(), m_channelizer->getChannelFrequencyOffset());
}
m_source.applySettings(settings, force);
m_settings = settings;
}
int IEEE_802_15_4_ModBaseband::getChannelSampleRate() const
{
return m_channelizer->getChannelSampleRate();
}

View File

@ -0,0 +1,98 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2019 Edouard Griffiths, F4EXB //
// Copyright (C) 2020 Jon Beniston, M7RCE //
// //
// 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 //
// (at your option) any later version. //
// //
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_IEEE_802_15_4_MODBASEBAND_H
#define INCLUDE_IEEE_802_15_4_MODBASEBAND_H
#include <QObject>
#include <QMutex>
#include "dsp/samplesourcefifo.h"
#include "util/message.h"
#include "util/messagequeue.h"
#include "ieee_802_15_4_modsource.h"
class UpChannelizer;
class IEEE_802_15_4_ModBaseband : public QObject
{
Q_OBJECT
public:
class MsgConfigureIEEE_802_15_4_ModBaseband : public Message {
MESSAGE_CLASS_DECLARATION
public:
const IEEE_802_15_4_ModSettings& getSettings() const { return m_settings; }
bool getForce() const { return m_force; }
static MsgConfigureIEEE_802_15_4_ModBaseband* create(const IEEE_802_15_4_ModSettings& settings, bool force)
{
return new MsgConfigureIEEE_802_15_4_ModBaseband(settings, force);
}
private:
IEEE_802_15_4_ModSettings m_settings;
bool m_force;
MsgConfigureIEEE_802_15_4_ModBaseband(const IEEE_802_15_4_ModSettings& settings, bool force) :
Message(),
m_settings(settings),
m_force(force)
{ }
};
IEEE_802_15_4_ModBaseband();
~IEEE_802_15_4_ModBaseband();
void reset();
void pull(const SampleVector::iterator& begin, unsigned int nbSamples);
MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } //!< Get the queue for asynchronous inbound communication
double getMagSq() const { return m_source.getMagSq(); }
int getChannelSampleRate() const;
void setSpectrumSampleSink(BasebandSampleSink* sampleSink) { m_source.setSpectrumSink(sampleSink); }
void setScopeSink(BasebandSampleSink* scopeSink) { m_source.setScopeSink(scopeSink); }
signals:
/**
* Level changed
* \param rmsLevel RMS level in range 0.0 - 1.0
* \param peakLevel Peak level in range 0.0 - 1.0
* \param numSamples Number of audio samples analyzed
*/
void levelChanged(qreal rmsLevel, qreal peakLevel, int numSamples);
private:
SampleSourceFifo m_sampleFifo;
UpChannelizer *m_channelizer;
IEEE_802_15_4_ModSource m_source;
MessageQueue m_inputMessageQueue; //!< Queue for asynchronous inbound communication
IEEE_802_15_4_ModSettings m_settings;
QMutex m_mutex;
void processFifo(SampleVector& data, unsigned int iBegin, unsigned int iEnd);
bool handleMessage(const Message& cmd);
void applySettings(const IEEE_802_15_4_ModSettings& settings, bool force = false);
private slots:
void handleInputMessages();
void handleData(); //!< Handle data when samples have to be processed
};
#endif // INCLUDE_IEEE_802_15_4_MODBASEBAND_H

View File

@ -0,0 +1,546 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2016 Edouard Griffiths, F4EXB //
// Copyright (C) 2020 Jon Beniston, M7RCE //
// //
// 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 //
// (at your option) any later version. //
// //
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <QDockWidget>
#include <QMainWindow>
#include <QFileDialog>
#include <QTime>
#include <QDebug>
#include "device/deviceuiset.h"
#include "plugin/pluginapi.h"
#include "util/simpleserializer.h"
#include "util/db.h"
#include "dsp/spectrumvis.h"
#include "dsp/scopevis.h"
#include "dsp/dspcommands.h"
#include "dsp/dspengine.h"
#include "gui/glspectrum.h"
#include "gui/crightclickenabler.h"
#include "gui/basicchannelsettingsdialog.h"
#include "gui/devicestreamselectiondialog.h"
#include "mainwindow.h"
#include "ui_IEEE_802_15_4_Modgui.h"
#include "ieee_802_15_4_modgui.h"
#include "ieee_802_15_4_modrepeatdialog.h"
#include "ieee_802_15_4_modtxsettingsdialog.h"
IEEE_802_15_4_ModGUI* IEEE_802_15_4_ModGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSource *channelTx)
{
IEEE_802_15_4_ModGUI* gui = new IEEE_802_15_4_ModGUI(pluginAPI, deviceUISet, channelTx);
return gui;
}
void IEEE_802_15_4_ModGUI::destroy()
{
delete this;
}
void IEEE_802_15_4_ModGUI::setName(const QString& name)
{
setObjectName(name);
}
QString IEEE_802_15_4_ModGUI::getName() const
{
return objectName();
}
qint64 IEEE_802_15_4_ModGUI::getCenterFrequency() const {
return m_channelMarker.getCenterFrequency();
}
void IEEE_802_15_4_ModGUI::setCenterFrequency(qint64 centerFrequency)
{
m_channelMarker.setCenterFrequency(centerFrequency);
applySettings();
}
void IEEE_802_15_4_ModGUI::resetToDefaults()
{
m_settings.resetToDefaults();
displaySettings();
applySettings(true);
}
QByteArray IEEE_802_15_4_ModGUI::serialize() const
{
return m_settings.serialize();
}
bool IEEE_802_15_4_ModGUI::deserialize(const QByteArray& data)
{
if(m_settings.deserialize(data)) {
displaySettings();
applySettings(true);
return true;
} else {
resetToDefaults();
return false;
}
}
bool IEEE_802_15_4_ModGUI::handleMessage(const Message& message)
{
if (DSPSignalNotification::match(message))
{
DSPSignalNotification& notif = (DSPSignalNotification&) message;
m_basebandSampleRate = notif.getSampleRate();
m_scopeVis->setLiveRate(m_basebandSampleRate);
checkSampleRate();
return true;
}
else if (IEEE_802_15_4_Mod::MsgConfigureIEEE_802_15_4_Mod::match(message))
{
const IEEE_802_15_4_Mod::MsgConfigureIEEE_802_15_4_Mod& cfg = (IEEE_802_15_4_Mod::MsgConfigureIEEE_802_15_4_Mod&) message;
m_settings = cfg.getSettings();
blockApplySettings(true);
displaySettings();
blockApplySettings(false);
return true;
}
else
{
return false;
}
}
void IEEE_802_15_4_ModGUI::channelMarkerChangedByCursor()
{
ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency());
m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency();
applySettings();
}
void IEEE_802_15_4_ModGUI::handleSourceMessages()
{
Message* message;
while ((message = getInputMessageQueue()->pop()) != 0)
{
if (handleMessage(*message))
{
delete message;
}
}
}
// Check sample rate is good enough and if not, display a warning in title
void IEEE_802_15_4_ModGUI::checkSampleRate()
{
int cr = m_settings.getChipRate();
if ((m_basebandSampleRate % cr) != 0)
setWindowTitle(m_channelMarker.getTitle() + " - Baseband sample rate is not an integer multiple of chip rate");
else if ((m_basebandSampleRate / cr) <= 2)
setWindowTitle(m_channelMarker.getTitle() + " - Baseband sample rate is too low");
else
setWindowTitle(m_channelMarker.getTitle());
}
void IEEE_802_15_4_ModGUI::on_deltaFrequency_changed(qint64 value)
{
m_channelMarker.setCenterFrequency(value);
m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency();
applySettings();
}
void IEEE_802_15_4_ModGUI::on_phy_currentIndexChanged(int value)
{
QString phy = ui->phy->currentText();
// If m_doApplySettings is set, we are here from a call to displaySettings,
// so we only want to display the current settings, not update them
// as though a user had selected a new PHY
if (m_doApplySettings)
m_settings.setPHY(phy);
ui->rfBWText->setText(QString("%1M").arg(m_settings.m_rfBandwidth / 1000000.0, 0, 'f', 1));
ui->rfBW->setValue(m_settings.m_rfBandwidth / 1000.0);
ui->glSpectrum->setCenterFrequency(0);
ui->glSpectrum->setSampleRate(m_settings.m_spectrumRate);
checkSampleRate();
applySettings();
// Remove custom PHY when deselected, as we no longer know how to set it
if (value < 6)
ui->phy->removeItem(6);
}
void IEEE_802_15_4_ModGUI::on_rfBW_valueChanged(int value)
{
float bw = value * 1000.0f;
ui->rfBWText->setText(QString("%1M").arg(value / 1000.0, 0, 'f', 1));
m_channelMarker.setBandwidth(bw);
m_settings.m_rfBandwidth = bw;
applySettings();
}
void IEEE_802_15_4_ModGUI::on_gain_valueChanged(int value)
{
ui->gainText->setText(QString("%1dB").arg(value));
m_settings.m_gain = value;
applySettings();
}
void IEEE_802_15_4_ModGUI::on_channelMute_toggled(bool checked)
{
m_settings.m_channelMute = checked;
applySettings();
}
void IEEE_802_15_4_ModGUI::on_txButton_clicked(bool checked)
{
transmit();
}
void IEEE_802_15_4_ModGUI::on_frame_returnPressed()
{
transmit();
}
void IEEE_802_15_4_ModGUI::on_frame_editingFinished()
{
m_settings.m_data = ui->frame->text();
applySettings();
}
void IEEE_802_15_4_ModGUI::on_repeat_toggled(bool checked)
{
m_settings.m_repeat = checked;
applySettings();
}
void IEEE_802_15_4_ModGUI::repeatSelect()
{
IEEE_802_15_4_ModRepeatDialog dialog(m_settings.m_repeatDelay, m_settings.m_repeatCount);
if (dialog.exec() == QDialog::Accepted)
{
m_settings.m_repeatDelay = dialog.m_repeatDelay;
m_settings.m_repeatCount = dialog.m_repeatCount;
applySettings();
}
}
void IEEE_802_15_4_ModGUI::txSettingsSelect()
{
IEEE_802_15_4_ModTXSettingsDialog dialog(m_settings.m_rampUpBits, m_settings.m_rampDownBits,
m_settings.m_rampRange, m_settings.m_modulateWhileRamping,
m_settings.m_modulation, m_settings.m_bitRate,
m_settings.m_pulseShaping, m_settings.m_beta, m_settings.m_symbolSpan,
m_settings.m_scramble, m_settings.m_polynomial,
m_settings.m_lpfTaps,
m_settings.m_bbNoise,
m_settings.m_writeToFile);
if (dialog.exec() == QDialog::Accepted)
{
m_settings.m_rampUpBits = dialog.m_rampUpBits;
m_settings.m_rampDownBits = dialog.m_rampDownBits;
m_settings.m_rampRange = dialog.m_rampRange;
m_settings.m_modulateWhileRamping = dialog.m_modulateWhileRamping;
m_settings.m_modulation = static_cast<IEEE_802_15_4_ModSettings::Modulation>(dialog.m_modulation);
m_settings.m_bitRate = dialog.m_bitRate;
m_settings.m_pulseShaping = static_cast<IEEE_802_15_4_ModSettings::PulseShaping>(dialog.m_pulseShaping);
m_settings.m_beta = dialog.m_beta;
m_settings.m_symbolSpan = dialog.m_symbolSpan;
m_settings.m_scramble = dialog.m_scramble;
m_settings.m_polynomial = dialog.m_polynomial;
m_settings.m_lpfTaps = dialog.m_lpfTaps;
m_settings.m_bbNoise = dialog.m_bbNoise;
m_settings.m_writeToFile = dialog.m_writeToFile;
displaySettings();
applySettings();
}
}
void IEEE_802_15_4_ModGUI::onWidgetRolled(QWidget* widget, bool rollDown)
{
(void) widget;
(void) rollDown;
}
void IEEE_802_15_4_ModGUI::onMenuDialogCalled(const QPoint &p)
{
if (m_contextMenuType == ContextMenuChannelSettings)
{
BasicChannelSettingsDialog dialog(&m_channelMarker, this);
dialog.setUseReverseAPI(m_settings.m_useReverseAPI);
dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress);
dialog.setReverseAPIPort(m_settings.m_reverseAPIPort);
dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex);
dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex);
dialog.move(p);
dialog.exec();
m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency();
m_settings.m_rgbColor = m_channelMarker.getColor().rgb();
m_settings.m_title = m_channelMarker.getTitle();
m_settings.m_useReverseAPI = dialog.useReverseAPI();
m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress();
m_settings.m_reverseAPIPort = dialog.getReverseAPIPort();
m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex();
m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex();
setWindowTitle(m_settings.m_title);
setTitleColor(m_settings.m_rgbColor);
applySettings();
}
else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine))
{
DeviceStreamSelectionDialog dialog(this);
dialog.setNumberOfStreams(m_IEEE_802_15_4_Mod->getNumberOfDeviceStreams());
dialog.setStreamIndex(m_settings.m_streamIndex);
dialog.move(p);
dialog.exec();
m_settings.m_streamIndex = dialog.getSelectedStreamIndex();
m_channelMarker.clearStreamIndexes();
m_channelMarker.addStreamIndex(m_settings.m_streamIndex);
displayStreamIndex();
applySettings();
}
resetContextMenuType();
}
IEEE_802_15_4_ModGUI::IEEE_802_15_4_ModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSource *channelTx, QWidget* parent) :
ChannelGUI(parent),
ui(new Ui::IEEE_802_15_4_ModGUI),
m_pluginAPI(pluginAPI),
m_deviceUISet(deviceUISet),
m_channelMarker(this),
m_doApplySettings(true),
m_basebandSampleRate(12000000)
{
ui->setupUi(this);
setAttribute(Qt::WA_DeleteOnClose, true);
connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool)));
connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &)));
m_IEEE_802_15_4_Mod = (IEEE_802_15_4_Mod*) channelTx;
m_IEEE_802_15_4_Mod->setMessageQueueToGUI(getInputMessageQueue());
connect(&MainWindow::getInstance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick()));
m_scopeVis = new ScopeVis(ui->glScope);
m_IEEE_802_15_4_Mod->setScopeSink(m_scopeVis);
ui->glScope->connectTimer(MainWindow::getInstance()->getMasterTimer());
connect(&MainWindow::getInstance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); // 50 ms
ui->scopeGUI->setBuddies(m_scopeVis->getInputMessageQueue(), m_scopeVis, ui->glScope);
// Scope settings to display the IQ waveforms
ui->scopeGUI->setPreTrigger(1);
ScopeVis::TraceData traceDataI, traceDataQ;
traceDataI.m_projectionType = Projector::ProjectionReal;
traceDataI.m_amp = 1.0; // for -1 to +1
traceDataI.m_ampIndex = 0;
traceDataI.m_ofs = 0.0; // vertical offset
traceDataI.m_ofsCoarse = 0;
traceDataQ.m_projectionType = Projector::ProjectionImag;
traceDataQ.m_amp = 1.0;
traceDataQ.m_ampIndex = 0;
traceDataQ.m_ofs = 0.0;
traceDataQ.m_ofsCoarse = 0;
ui->scopeGUI->changeTrace(0, traceDataI);
ui->scopeGUI->addTrace(traceDataQ);
ui->scopeGUI->setDisplayMode(GLScopeGUI::DisplayPol);
ui->scopeGUI->focusOnTrace(0); // re-focus to take changes into account in the GUI
ScopeVis::TriggerData triggerData;
triggerData.m_triggerLevel = 0.1;
triggerData.m_triggerLevelCoarse = 10;
triggerData.m_triggerPositiveEdge = true;
ui->scopeGUI->changeTrigger(0, triggerData);
ui->scopeGUI->focusOnTrigger(0); // re-focus to take changes into account in the GUI
m_scopeVis->setLiveRate(m_basebandSampleRate);
//m_scopeVis->setFreeRun(false); // FIXME: add method rather than call m_scopeVis->configure()
m_spectrumVis = m_IEEE_802_15_4_Mod->getSpectrumVis();
m_spectrumVis->setGLSpectrum(ui->glSpectrum);
ui->glSpectrum->setCenterFrequency(0);
ui->glSpectrum->setSampleRate(m_settings.m_spectrumRate);
ui->glSpectrum->setSsbSpectrum(false);
ui->glSpectrum->setDisplayCurrent(true);
ui->glSpectrum->setLsbDisplay(false);
ui->glSpectrum->setDisplayWaterfall(false);
ui->glSpectrum->setDisplayMaxHold(false);
ui->glSpectrum->setDisplayHistogram(false);
ui->glSpectrum->connectTimer(MainWindow::getInstance()->getMasterTimer());
CRightClickEnabler *repeatRightClickEnabler = new CRightClickEnabler(ui->repeat);
connect(repeatRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(repeatSelect()));
CRightClickEnabler *txRightClickEnabler = new CRightClickEnabler(ui->txButton);
connect(txRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(txSettingsSelect()));
ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03)));
ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold));
ui->deltaFrequency->setValueRange(false, 7, -9999999, 9999999);
m_channelMarker.blockSignals(true);
m_channelMarker.setColor(Qt::red);
m_channelMarker.setBandwidth(12500);
m_channelMarker.setCenterFrequency(0);
m_channelMarker.setTitle("802.15.4 Modulator");
m_channelMarker.setSourceOrSinkStream(false);
m_channelMarker.blockSignals(false);
m_channelMarker.setVisible(true); // activate signal on the last setting only
m_deviceUISet->addChannelMarker(&m_channelMarker);
m_deviceUISet->addRollupWidget(this);
connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor()));
connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleSourceMessages()));
m_IEEE_802_15_4_Mod->setLevelMeter(ui->volumeMeter);
m_settings.setChannelMarker(&m_channelMarker);
ui->spectrumGUI->setBuddies(m_spectrumVis, ui->glSpectrum);
displaySettings();
applySettings();
}
IEEE_802_15_4_ModGUI::~IEEE_802_15_4_ModGUI()
{
delete m_IEEE_802_15_4_Mod; // TODO: check this: when the GUI closes it has to delete the modulator
delete m_scopeVis;
delete ui;
}
void IEEE_802_15_4_ModGUI::transmit()
{
QString data = ui->frame->text();
ui->transmittedText->appendPlainText(data + "\n");
IEEE_802_15_4_Mod::MsgTXIEEE_802_15_4_Mod *msg = IEEE_802_15_4_Mod::MsgTXIEEE_802_15_4_Mod::create(data);
m_IEEE_802_15_4_Mod->getInputMessageQueue()->push(msg);
}
void IEEE_802_15_4_ModGUI::blockApplySettings(bool block)
{
m_doApplySettings = !block;
}
void IEEE_802_15_4_ModGUI::applySettings(bool force)
{
if (m_doApplySettings)
{
IEEE_802_15_4_Mod::MsgConfigureIEEE_802_15_4_Mod *msg = IEEE_802_15_4_Mod::MsgConfigureIEEE_802_15_4_Mod::create(m_settings, force);
m_IEEE_802_15_4_Mod->getInputMessageQueue()->push(msg);
}
}
void IEEE_802_15_4_ModGUI::displaySettings()
{
m_channelMarker.blockSignals(true);
m_channelMarker.setCenterFrequency(m_settings.m_inputFrequencyOffset);
m_channelMarker.setTitle(m_settings.m_title);
m_channelMarker.setBandwidth(m_settings.m_rfBandwidth);
m_channelMarker.blockSignals(false);
m_channelMarker.setColor(m_settings.m_rgbColor); // activate signal on the last setting only
setTitleColor(m_settings.m_rgbColor);
setWindowTitle(m_channelMarker.getTitle());
displayStreamIndex();
blockApplySettings(true);
ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency());
if ((m_settings.m_bitRate == 20000)
&& m_settings.m_subGHzBand
&& (m_settings.m_pulseShaping == IEEE_802_15_4_ModSettings::RC)
&& (m_settings.m_modulation == IEEE_802_15_4_ModSettings::BPSK))
ui->phy->setCurrentIndex(0);
else if ((m_settings.m_bitRate == 40000)
&& m_settings.m_subGHzBand
&& (m_settings.m_pulseShaping == IEEE_802_15_4_ModSettings::RC)
&& (m_settings.m_modulation == IEEE_802_15_4_ModSettings::BPSK))
ui->phy->setCurrentIndex(1);
else if ((m_settings.m_bitRate == 100000)
&& m_settings.m_subGHzBand
&& (m_settings.m_modulation == IEEE_802_15_4_ModSettings::OQPSK))
ui->phy->setCurrentIndex(2);
else if ((m_settings.m_bitRate == 250000)
&& m_settings.m_subGHzBand
&& (m_settings.m_pulseShaping == IEEE_802_15_4_ModSettings::SINE)
&& (m_settings.m_modulation == IEEE_802_15_4_ModSettings::OQPSK))
ui->phy->setCurrentIndex(3);
else if ((m_settings.m_bitRate == 250000)
&& m_settings.m_subGHzBand
&& (m_settings.m_pulseShaping == IEEE_802_15_4_ModSettings::RC)
&& (m_settings.m_modulation == IEEE_802_15_4_ModSettings::OQPSK))
ui->phy->setCurrentIndex(4);
else if ((m_settings.m_bitRate == 250000)
&& !m_settings.m_subGHzBand
&& (m_settings.m_pulseShaping == IEEE_802_15_4_ModSettings::SINE)
&& (m_settings.m_modulation == IEEE_802_15_4_ModSettings::OQPSK))
ui->phy->setCurrentIndex(5);
else
{
ui->phy->removeItem(6);
ui->phy->addItem(m_settings.getPHY());
ui->phy->setCurrentIndex(6);
}
ui->glSpectrum->setCenterFrequency(0);
ui->glSpectrum->setSampleRate(m_settings.m_spectrumRate);
ui->rfBWText->setText(QString("%1M").arg(m_settings.m_rfBandwidth / 1000000.0, 0, 'f', 1));
ui->rfBW->setValue(m_settings.m_rfBandwidth / 1000.0);
ui->gainText->setText(QString("%1").arg((double)m_settings.m_gain, 0, 'f', 1));
ui->gain->setValue(m_settings.m_gain);
ui->channelMute->setChecked(m_settings.m_channelMute);
ui->repeat->setChecked(m_settings.m_repeat);
ui->frame->setText(m_settings.m_data);
blockApplySettings(false);
}
void IEEE_802_15_4_ModGUI::displayStreamIndex()
{
if (m_deviceUISet->m_deviceMIMOEngine) {
setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex));
} else {
setStreamIndicator("S"); // single channel indicator
}
}
void IEEE_802_15_4_ModGUI::leaveEvent(QEvent*)
{
m_channelMarker.setHighlighted(false);
}
void IEEE_802_15_4_ModGUI::enterEvent(QEvent*)
{
m_channelMarker.setHighlighted(true);
}
void IEEE_802_15_4_ModGUI::tick()
{
double powDb = CalcDb::dbPower(m_IEEE_802_15_4_Mod->getMagSq());
m_channelPowerDbAvg(powDb);
ui->channelPower->setText(tr("%1 dB").arg(m_channelPowerDbAvg.asDouble(), 0, 'f', 1));
}

View File

@ -0,0 +1,112 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2016 Edouard Griffiths, F4EXB //
// Copyright (C) 2020 Jon Beniston, M7RCE //
// //
// 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 //
// (at your option) any later version. //
// //
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_IEEE_802_15_4_MODGUI_H
#define INCLUDE_IEEE_802_15_4_MODGUI_H
#include "channel/channelgui.h"
#include "dsp/channelmarker.h"
#include "util/movingaverage.h"
#include "util/messagequeue.h"
#include "ieee_802_15_4_mod.h"
#include "ieee_802_15_4_modsettings.h"
class PluginAPI;
class DeviceUISet;
class BasebandSampleSource;
class SpectrumVis;
class ScopeVis;
class ScopeVisXY;
namespace Ui {
class IEEE_802_15_4_ModGUI;
}
class IEEE_802_15_4_ModGUI : public ChannelGUI {
Q_OBJECT
public:
static IEEE_802_15_4_ModGUI* create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSource *channelTx);
virtual void destroy();
void setName(const QString& name);
QString getName() const;
virtual qint64 getCenterFrequency() const;
virtual void setCenterFrequency(qint64 centerFrequency);
void resetToDefaults();
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
virtual bool handleMessage(const Message& message);
public slots:
void channelMarkerChangedByCursor();
private:
Ui::IEEE_802_15_4_ModGUI* ui;
PluginAPI* m_pluginAPI;
DeviceUISet* m_deviceUISet;
ChannelMarker m_channelMarker;
IEEE_802_15_4_ModSettings m_settings;
bool m_doApplySettings;
SpectrumVis* m_spectrumVis;
ScopeVis* m_scopeVis;
int m_basebandSampleRate;
IEEE_802_15_4_Mod* m_IEEE_802_15_4_Mod;
MovingAverageUtil<double, double, 2> m_channelPowerDbAvg; // Less than other mods, as frames are short
MessageQueue m_inputMessageQueue;
explicit IEEE_802_15_4_ModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSource *channelTx, QWidget* parent = 0);
virtual ~IEEE_802_15_4_ModGUI();
void checkSampleRate();
void transmit();
void blockApplySettings(bool block);
void applySettings(bool force = false);
void displaySettings();
void displayStreamIndex();
void leaveEvent(QEvent*);
void enterEvent(QEvent*);
private slots:
void handleSourceMessages();
void on_deltaFrequency_changed(qint64 value);
void on_phy_currentIndexChanged(int value);
void on_rfBW_valueChanged(int index);
void on_gain_valueChanged(int value);
void on_channelMute_toggled(bool checked);
void on_txButton_clicked(bool checked);
void on_frame_editingFinished();
void on_frame_returnPressed();
void on_repeat_toggled(bool checked);
void repeatSelect();
void txSettingsSelect();
void onWidgetRolled(QWidget* widget, bool rollDown);
void onMenuDialogCalled(const QPoint& p);
void tick();
};
#endif /* INCLUDE_IEEE_802_15_4_MODGUI_H */

View File

@ -0,0 +1,666 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>IEEE_802_15_4_ModGUI</class>
<widget class="RollupWidget" name="IEEE_802_15_4_ModGUI">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>363</width>
<height>937</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="font">
<font>
<family>Liberation Sans</family>
<pointsize>9</pointsize>
</font>
</property>
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<property name="windowTitle">
<string>802.15.4 Modulator</string>
</property>
<widget class="QWidget" name="settingsContainer" native="true">
<property name="enabled">
<bool>true</bool>
</property>
<property name="geometry">
<rect>
<x>2</x>
<y>2</y>
<width>341</width>
<height>121</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>280</width>
<height>0</height>
</size>
</property>
<property name="windowTitle">
<string>Settings</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>3</number>
</property>
<property name="leftMargin">
<number>2</number>
</property>
<property name="topMargin">
<number>2</number>
</property>
<property name="rightMargin">
<number>2</number>
</property>
<property name="bottomMargin">
<number>2</number>
</property>
<item>
<layout class="QHBoxLayout" name="deltaFreqPowLayout">
<property name="topMargin">
<number>2</number>
</property>
<item>
<layout class="QHBoxLayout" name="deltaFrequencyLayout">
<item>
<widget class="QLabel" name="deltaFrequencyLabel">
<property name="minimumSize">
<size>
<width>16</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Df</string>
</property>
</widget>
</item>
<item>
<widget class="ValueDialZ" name="deltaFrequency" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>32</width>
<height>16</height>
</size>
</property>
<property name="font">
<font>
<family>Liberation Mono</family>
<pointsize>12</pointsize>
</font>
</property>
<property name="cursor">
<cursorShape>PointingHandCursor</cursorShape>
</property>
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<property name="toolTip">
<string>Demod shift frequency from center in Hz</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="deltaUnits">
<property name="text">
<string>Hz </string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="channelPower">
<property name="minimumSize">
<size>
<width>60</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Channel power</string>
</property>
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
<property name="text">
<string>-100.0 dB</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QToolButton" name="channelMute">
<property name="toolTip">
<string>Mute/Unmute channel</string>
</property>
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../../sdrgui/resources/res.qrc">
<normaloff>:/txon.png</normaloff>
<normalon>:/txoff.png</normalon>:/txon.png</iconset>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="rfBandwidthLayout">
<item>
<widget class="QComboBox" name="phy">
<property name="minimumSize">
<size>
<width>170</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>60</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>PHY bitrate and modulation</string>
</property>
<property name="currentText">
<string>20kbps BPSK</string>
</property>
<item>
<property name="text">
<string>20kbps BPSK</string>
</property>
</item>
<item>
<property name="text">
<string>40kbps BPSK</string>
</property>
</item>
<item>
<property name="text">
<string>100kbps &lt;1GHz O-QPSK</string>
</property>
</item>
<item>
<property name="text">
<string>250kbps &lt;1GHz O-QPSK (Sine)</string>
</property>
</item>
<item>
<property name="text">
<string>250kbps &lt;1GHz O-QPSK (RC)</string>
</property>
</item>
<item>
<property name="text">
<string>250kbps &gt;2GHz O-QPSK</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="rfBWLabel">
<property name="text">
<string>BW</string>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="rfBW">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>RF bandwidth</string>
</property>
<property name="minimum">
<number>300</number>
</property>
<property name="maximum">
<number>10000</number>
</property>
<property name="singleStep">
<number>100</number>
</property>
<property name="pageStep">
<number>100</number>
</property>
<property name="value">
<number>300</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="rfBWText">
<property name="minimumSize">
<size>
<width>30</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>2.0M</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="Line" name="line_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="volumeLayout">
<item>
<widget class="QLabel" name="gainLabel">
<property name="text">
<string>Gain</string>
</property>
</widget>
</item>
<item>
<widget class="QDial" name="gain">
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="toolTip">
<string>Gain</string>
</property>
<property name="minimum">
<number>-60</number>
</property>
<property name="maximum">
<number>0</number>
</property>
<property name="singleStep">
<number>5</number>
</property>
<property name="pageStep">
<number>1</number>
</property>
<property name="value">
<number>0</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="gainText">
<property name="minimumSize">
<size>
<width>30</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Audio input gain value</string>
</property>
<property name="statusTip">
<string/>
</property>
<property name="text">
<string>-80.0dB</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="LevelMeterVU" name="volumeMeter" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<family>Liberation Mono</family>
<pointsize>8</pointsize>
</font>
</property>
<property name="toolTip">
<string>Level (% full range) top trace: average, bottom trace: instantaneous peak, tip: peak hold</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="Line" name="line_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="frameDataLayout">
<item>
<widget class="QLabel" name="label">
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="text">
<string>Data</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="frame">
<property name="toolTip">
<string>Enter data to transmit as a series of hex bytes.</string>
</property>
<property name="text">
<string>00 00 01 00 00 00 00 00</string>
</property>
<property name="maxLength">
<number>256</number>
</property>
</widget>
</item>
<item>
<widget class="ButtonSwitch" name="repeat">
<property name="toolTip">
<string>Repeatedly transmit the frame. Right click for additional settings.</string>
</property>
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../../sdrgui/resources/res.qrc">
<normaloff>:/playloop.png</normaloff>:/playloop.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="txButton">
<property name="toolTip">
<string>Press to transmit the frame</string>
</property>
<property name="text">
<string>TX</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="logContainer" native="true">
<property name="geometry">
<rect>
<x>0</x>
<y>190</y>
<width>351</width>
<height>141</height>
</rect>
</property>
<property name="windowTitle">
<string>Transmitted Frames</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>2</number>
</property>
<property name="leftMargin">
<number>3</number>
</property>
<property name="topMargin">
<number>3</number>
</property>
<property name="rightMargin">
<number>3</number>
</property>
<property name="bottomMargin">
<number>3</number>
</property>
<item>
<widget class="QPlainTextEdit" name="transmittedText">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="scopeContainer" native="true">
<property name="geometry">
<rect>
<x>0</x>
<y>340</y>
<width>351</width>
<height>284</height>
</rect>
</property>
<property name="windowTitle">
<string>Baseband Waveform</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="spacing">
<number>2</number>
</property>
<property name="leftMargin">
<number>3</number>
</property>
<property name="topMargin">
<number>3</number>
</property>
<property name="rightMargin">
<number>3</number>
</property>
<property name="bottomMargin">
<number>3</number>
</property>
<item>
<widget class="GLScope" name="glScope" native="true">
<property name="minimumSize">
<size>
<width>200</width>
<height>250</height>
</size>
</property>
<property name="font">
<font>
<family>Liberation Mono</family>
<pointsize>8</pointsize>
</font>
</property>
</widget>
</item>
<item>
<widget class="GLScopeGUI" name="scopeGUI" native="true"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="spectrumContainer" native="true">
<property name="geometry">
<rect>
<x>0</x>
<y>630</y>
<width>351</width>
<height>284</height>
</rect>
</property>
<property name="windowTitle">
<string>Baseband Spectrum</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>2</number>
</property>
<property name="leftMargin">
<number>3</number>
</property>
<property name="topMargin">
<number>3</number>
</property>
<property name="rightMargin">
<number>3</number>
</property>
<property name="bottomMargin">
<number>3</number>
</property>
<item>
<widget class="GLSpectrum" name="glSpectrum" native="true">
<property name="minimumSize">
<size>
<width>200</width>
<height>250</height>
</size>
</property>
<property name="font">
<font>
<family>Liberation Mono</family>
<pointsize>8</pointsize>
</font>
</property>
</widget>
</item>
<item>
<widget class="GLSpectrumGUI" name="spectrumGUI" native="true"/>
</item>
</layout>
</widget>
</widget>
<customwidgets>
<customwidget>
<class>ButtonSwitch</class>
<extends>QToolButton</extends>
<header>gui/buttonswitch.h</header>
</customwidget>
<customwidget>
<class>RollupWidget</class>
<extends>QWidget</extends>
<header>gui/rollupwidget.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>ValueDialZ</class>
<extends>QWidget</extends>
<header>gui/valuedialz.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>GLScope</class>
<extends>QWidget</extends>
<header>gui/glscope.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>GLScopeGUI</class>
<extends>QWidget</extends>
<header>gui/glscopegui.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>GLSpectrum</class>
<extends>QWidget</extends>
<header>gui/glspectrum.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>GLSpectrumGUI</class>
<extends>QWidget</extends>
<header>gui/glspectrumgui.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>LevelMeterVU</class>
<extends>QWidget</extends>
<header>gui/levelmeter.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>deltaFrequency</tabstop>
<tabstop>channelMute</tabstop>
<tabstop>phy</tabstop>
<tabstop>rfBW</tabstop>
<tabstop>gain</tabstop>
<tabstop>frame</tabstop>
<tabstop>repeat</tabstop>
<tabstop>txButton</tabstop>
<tabstop>transmittedText</tabstop>
</tabstops>
<resources>
<include location="../../../sdrgui/resources/res.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -0,0 +1,90 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2016 Edouard Griffiths, F4EXB //
// Copyright (C) 2020 Jon Beniston, M7RCE //
// //
// 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 //
// (at your option) any later version. //
// //
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <QtPlugin>
#include "plugin/pluginapi.h"
#ifndef SERVER_MODE
#include "ieee_802_15_4_modgui.h"
#endif
#include "ieee_802_15_4_mod.h"
#include "ieee_802_15_4_modwebapiadapter.h"
#include "ieee_802_15_4_modplugin.h"
const PluginDescriptor IEEE_802_15_4_ModPlugin::m_pluginDescriptor = {
IEEE_802_15_4_Mod::m_channelId,
QString("802.15.4 Modulator"),
QString("4.19.1"),
QString("(c) Jon Beniston, M7RCE"),
QString("https://github.com/f4exb/sdrangel"),
true,
QString("https://github.com/f4exb/sdrangel")
};
IEEE_802_15_4_ModPlugin::IEEE_802_15_4_ModPlugin(QObject* parent) :
QObject(parent),
m_pluginAPI(0)
{
}
const PluginDescriptor& IEEE_802_15_4_ModPlugin::getPluginDescriptor() const
{
return m_pluginDescriptor;
}
void IEEE_802_15_4_ModPlugin::initPlugin(PluginAPI* pluginAPI)
{
m_pluginAPI = pluginAPI;
m_pluginAPI->registerTxChannel(IEEE_802_15_4_Mod::m_channelIdURI, IEEE_802_15_4_Mod::m_channelId, this);
}
void IEEE_802_15_4_ModPlugin::createTxChannel(DeviceAPI *deviceAPI, BasebandSampleSource **bs, ChannelAPI **cs) const
{
if (bs || cs)
{
IEEE_802_15_4_Mod *instance = new IEEE_802_15_4_Mod(deviceAPI);
if (bs) {
*bs = instance;
}
if (cs) {
*cs = instance;
}
}
}
#ifdef SERVER_MODE
ChannelGUI* IEEE_802_15_4_ModPlugin::createTxChannelGUI(
DeviceUISet *deviceUISet,
BasebandSampleSource *txChannel) const
{
return 0;
}
#else
ChannelGUI* IEEE_802_15_4_ModPlugin::createTxChannelGUI(DeviceUISet *deviceUISet, BasebandSampleSource *txChannel) const
{
return IEEE_802_15_4_ModGUI::create(m_pluginAPI, deviceUISet, txChannel);
}
#endif
ChannelWebAPIAdapter* IEEE_802_15_4_ModPlugin::createChannelWebAPIAdapter() const
{
return new IEEE_802_15_4_ModWebAPIAdapter();
}

View File

@ -0,0 +1,49 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2016 Edouard Griffiths, F4EXB //
// Copyright (C) 2020 Jon Beniston, M7RCE //
// //
// 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 //
// (at your option) any later version. //
// //
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_IEEE_802_15_4_MODPLUGIN_H
#define INCLUDE_IEEE_802_15_4_MODPLUGIN_H
#include <QObject>
#include "plugin/plugininterface.h"
class DeviceUISet;
class BasebandSampleSource;
class IEEE_802_15_4_ModPlugin : public QObject, PluginInterface {
Q_OBJECT
Q_INTERFACES(PluginInterface)
Q_PLUGIN_METADATA(IID "sdrangel.channeltx.mod802.15.4")
public:
explicit IEEE_802_15_4_ModPlugin(QObject* parent = 0);
const PluginDescriptor& getPluginDescriptor() const;
void initPlugin(PluginAPI* pluginAPI);
virtual void createTxChannel(DeviceAPI *deviceAPI, BasebandSampleSource **bs, ChannelAPI **cs) const;
virtual ChannelGUI* createTxChannelGUI(DeviceUISet *deviceUISet, BasebandSampleSource *rxChannel) const;
virtual ChannelWebAPIAdapter* createChannelWebAPIAdapter() const;
private:
static const PluginDescriptor m_pluginDescriptor;
PluginAPI* m_pluginAPI;
};
#endif // INCLUDE_IEEE_802_15_4_MODPLUGIN_H

View File

@ -0,0 +1,52 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Jon Beniston, M7RCE //
// //
// 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 //
// (at your option) any later version. //
// //
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include "ieee_802_15_4_modrepeatdialog.h"
#include "ieee_802_15_4_modsettings.h"
#include <QLineEdit>
IEEE_802_15_4_ModRepeatDialog::IEEE_802_15_4_ModRepeatDialog(float repeatDelay, int repeatCount, QWidget* parent) :
QDialog(parent),
ui(new Ui::IEEE_802_15_4_ModRepeatDialog)
{
ui->setupUi(this);
ui->repeatDelay->setValue(repeatDelay);
QLineEdit *edit = ui->repeatCount->lineEdit();
if (edit)
{
if (repeatCount == IEEE_802_15_4_ModSettings::infinitePackets)
edit->setText("Infinite");
else
edit->setText(QString("%1").arg(repeatCount));
}
}
IEEE_802_15_4_ModRepeatDialog::~IEEE_802_15_4_ModRepeatDialog()
{
delete ui;
}
void IEEE_802_15_4_ModRepeatDialog::accept()
{
m_repeatDelay = ui->repeatDelay->value();
QString text = ui->repeatCount->currentText();
if (!text.compare(QString("Infinite"), Qt::CaseInsensitive))
m_repeatCount = IEEE_802_15_4_ModSettings::infinitePackets;
else
m_repeatCount = text.toUInt();
QDialog::accept();
}

View File

@ -0,0 +1,40 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Jon Beniston, M7RCE //
// //
// 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 //
// (at your option) any later version. //
// //
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_IEEE_802_15_4_MODREPEATDIALOG_H
#define INCLUDE_IEEE_802_15_4_MODREPEATDIALOG_H
#include "ui_IEEE_802_15_4_Modrepeatdialog.h"
class IEEE_802_15_4_ModRepeatDialog : public QDialog {
Q_OBJECT
public:
explicit IEEE_802_15_4_ModRepeatDialog(float repeatDelay, int repeatCount, QWidget* parent = 0);
~IEEE_802_15_4_ModRepeatDialog();
float m_repeatDelay; // Delay in seconds between frames
int m_repeatCount; // Number of frames to transmit (-1 = infinite)
private slots:
void accept();
private:
Ui::IEEE_802_15_4_ModRepeatDialog* ui;
};
#endif // INCLUDE_IEEE_802_15_4_MODREPEATDIALOG_H

View File

@ -0,0 +1,134 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>IEEE_802_15_4_ModRepeatDialog</class>
<widget class="QDialog" name="IEEE_802_15_4_ModRepeatDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>351</width>
<height>115</height>
</rect>
</property>
<property name="font">
<font>
<family>Liberation Sans</family>
<pointsize>9</pointsize>
</font>
</property>
<property name="windowTitle">
<string>Frame Repeat Settings</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="groupBox">
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="repeatDelayLabel">
<property name="text">
<string>Delay between frames (s)</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="repeatCountLabel">
<property name="text">
<string>Frames to transmit</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="repeatCount">
<property name="toolTip">
<string>Number of frames to transmit</string>
</property>
<property name="editable">
<bool>true</bool>
</property>
<item>
<property name="text">
<string>Infinite</string>
</property>
</item>
<item>
<property name="text">
<string>10</string>
</property>
</item>
<item>
<property name="text">
<string>100</string>
</property>
</item>
<item>
<property name="text">
<string>1000</string>
</property>
</item>
</widget>
</item>
<item row="0" column="1">
<widget class="QDoubleSpinBox" name="repeatDelay">
<property name="decimals">
<number>3</number>
</property>
<property name="maximum">
<double>1000000.000000000000000</double>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<tabstops>
<tabstop>repeatDelay</tabstop>
<tabstop>repeatCount</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>IEEE_802_15_4_ModRepeatDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>IEEE_802_15_4_ModRepeatDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -0,0 +1,257 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2017 Edouard Griffiths, F4EXB //
// Copyright (C) 2020 Jon Beniston, M7RCE //
// //
// 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 //
// (at your option) any later version. //
// //
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <QColor>
#include <QDebug>
#include "dsp/dspengine.h"
#include "util/simpleserializer.h"
#include "settings/serializable.h"
#include "ieee_802_15_4_modsettings.h"
#include "ieee_802_15_4_macframe.h"
IEEE_802_15_4_ModSettings::IEEE_802_15_4_ModSettings()
{
resetToDefaults();
}
void IEEE_802_15_4_ModSettings::resetToDefaults()
{
IEEE_802_15_4_MacFrame macFrame;
char frame[1024];
macFrame.toHexCharArray(frame);
m_inputFrequencyOffset = 0;
m_modulation = BPSK;
m_bitRate = 20000;
m_subGHzBand = true;
m_rfBandwidth = 2.0f * 300000.0f;
m_gain = -1.0f; // To avoid overflow, which results in out-of-band RF
m_channelMute = false;
m_repeat = false;
m_repeatDelay = 1.0f;
m_repeatCount = infinitePackets;
m_rampUpBits = 0;
m_rampDownBits = 0;
m_rampRange = 0;
m_modulateWhileRamping = true;
m_lpfTaps = 301;
m_bbNoise = false;
m_writeToFile = false;
m_spectrumRate = m_rfBandwidth;
m_data = QString(frame);
m_rgbColor = QColor(255, 0, 0).rgb();
m_title = "802.15.4 Modulator";
m_streamIndex = 0;
m_useReverseAPI = false;
m_reverseAPIAddress = "127.0.0.1";
m_reverseAPIPort = 8888;
m_reverseAPIDeviceIndex = 0;
m_reverseAPIChannelIndex = 0;
m_scramble = false;
m_polynomial = 0x108;
m_pulseShaping = RC;
m_beta = 1.0f;
m_symbolSpan = 6;
}
bool IEEE_802_15_4_ModSettings::setPHY(QString phy)
{
int bitRate;
bool valid;
// First part of phy string should give bitrate in kbps
bitRate = phy.split("k")[0].toInt(&valid) * 1000;
if (!valid)
return false;
if (phy.contains("BPSK"))
{
m_bitRate = bitRate;
m_subGHzBand = true;
m_rfBandwidth = 2.0 * bitRate * 15.0;
m_spectrumRate = m_rfBandwidth;
m_modulation = IEEE_802_15_4_ModSettings::BPSK;
m_pulseShaping = RC;
m_beta = 1.0f;
m_symbolSpan = 6;
}
else if (phy.contains("O-QPSK"))
{
m_bitRate = bitRate;
m_subGHzBand = phy.contains("<1");
m_rfBandwidth = 2.0 * (bitRate / 4.0) * (m_subGHzBand ? 16.0 : 32.0);
m_spectrumRate = m_rfBandwidth;
m_modulation = IEEE_802_15_4_ModSettings::OQPSK;
if (phy.contains("RC"))
{
m_pulseShaping = RC;
m_beta = 0.8f;
m_symbolSpan = 6;
}
else
m_pulseShaping = SINE;
}
else
return false;
return true;
}
QString IEEE_802_15_4_ModSettings::getPHY() const
{
return QString("%1kbps %2").arg(m_bitRate/1000).arg(m_modulation == IEEE_802_15_4_ModSettings::BPSK ? "BPSK" : "O-QPSK");
}
int IEEE_802_15_4_ModSettings::getChipRate() const
{
int chipsPerSymbol, bitsPerSymbol;
if (m_modulation == BPSK)
{
chipsPerSymbol = 15;
bitsPerSymbol = 1;
}
else
{
bitsPerSymbol = 4;
chipsPerSymbol = m_subGHzBand ? 16 : 32;
}
return m_bitRate * chipsPerSymbol / bitsPerSymbol;
}
QByteArray IEEE_802_15_4_ModSettings::serialize() const
{
SimpleSerializer s(1);
s.writeS32(1, m_inputFrequencyOffset);
s.writeS32(2, m_bitRate);
s.writeReal(3, m_rfBandwidth);
s.writeBool(4, m_subGHzBand);
s.writeReal(5, m_gain);
s.writeBool(6, m_channelMute);
s.writeBool(7, m_repeat);
s.writeReal(8, m_repeatDelay);
s.writeS32(9, m_repeatCount);
s.writeS32(10, m_rampUpBits);
s.writeS32(11, m_rampDownBits);
s.writeS32(12, m_rampRange);
s.writeBool(13, m_modulateWhileRamping);
s.writeS32(14, m_lpfTaps);
s.writeBool(15, m_bbNoise);
s.writeBool(16, m_writeToFile);
s.writeString(17, m_data);
s.writeU32(18, m_rgbColor);
s.writeString(19, m_title);
if (m_channelMarker) {
s.writeBlob(20, m_channelMarker->serialize());
}
s.writeS32(21, m_streamIndex);
s.writeBool(22, m_useReverseAPI);
s.writeString(23, m_reverseAPIAddress);
s.writeU32(24, m_reverseAPIPort);
s.writeU32(25, m_reverseAPIDeviceIndex);
s.writeU32(26, m_reverseAPIChannelIndex);
s.writeBool(27, m_scramble);
s.writeS32(28, m_polynomial);
s.writeS32(29, m_pulseShaping);
s.writeReal(30, m_beta);
s.writeS32(31, m_symbolSpan);
s.writeS32(32, m_spectrumRate);
s.writeS32(33, m_modulation);
return s.final();
}
bool IEEE_802_15_4_ModSettings::deserialize(const QByteArray& data)
{
SimpleDeserializer d(data);
if(!d.isValid())
{
resetToDefaults();
return false;
}
if(d.getVersion() == 1)
{
QByteArray bytetmp;
qint32 tmp;
uint32_t utmp;
d.readS32(1, &tmp, 0);
m_inputFrequencyOffset = tmp;
d.readS32(2, &m_bitRate, 20000);
d.readReal(3, &m_rfBandwidth, 2.0f * 300000.0f);
d.readBool(4, &m_subGHzBand, m_bitRate <= 40000);
d.readReal(5, &m_gain, 0.0f);
d.readBool(6, &m_channelMute, false);
d.readBool(7, &m_repeat, false);
d.readReal(8, &m_repeatDelay, 1.0f);
d.readS32(9, &m_repeatCount, -1);
d.readS32(10, &m_rampUpBits, 8);
d.readS32(11, &m_rampDownBits, 8);
d.readS32(12, &m_rampRange, 8);
d.readBool(13, &m_modulateWhileRamping, true);
d.readS32(14, &m_lpfTaps, 301);
d.readBool(15, &m_bbNoise, false);
d.readBool(16, &m_writeToFile, false);
d.readString(17, &m_data, "");
d.readU32(18, &m_rgbColor);
d.readString(19, &m_title, "802.15.4 Modulator");
if (m_channelMarker) {
d.readBlob(20, &bytetmp);
m_channelMarker->deserialize(bytetmp);
}
d.readS32(21, &m_streamIndex, 0);
d.readBool(22, &m_useReverseAPI, false);
d.readString(23, &m_reverseAPIAddress, "127.0.0.1");
d.readU32(24, &utmp, 0);
if ((utmp > 1023) && (utmp < 65535)) {
m_reverseAPIPort = utmp;
} else {
m_reverseAPIPort = 8888;
}
d.readU32(25, &utmp, 0);
m_reverseAPIDeviceIndex = utmp > 99 ? 99 : utmp;
d.readU32(26, &utmp, 0);
m_reverseAPIChannelIndex = utmp > 99 ? 99 : utmp;
d.readBool(27, &m_scramble, false);
d.readS32(28, &m_polynomial, 0x108);
d.readS32(29, (qint32 *)&m_pulseShaping, RC);
d.readReal(30, &m_beta, 1.0f);
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);
return true;
}
else
{
qDebug() << "IEEE_802_15_4_ModSettings::deserialize: ERROR";
resetToDefaults();
return false;
}
}

View File

@ -0,0 +1,76 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2017 Edouard Griffiths, F4EXB //
// Copyright (C) 2020 Jon Beniston, M7RCE //
// //
// 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 //
// (at your option) any later version. //
// //
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_IEEE_802_15_4_MODSETTINGS_H
#define INCLUDE_IEEE_802_15_4_MODSETTINGS_H
#include <QByteArray>
#include <stdint.h>
#include "dsp/dsptypes.h"
class Serializable;
struct IEEE_802_15_4_ModSettings
{
static const int infinitePackets = -1;
qint64 m_inputFrequencyOffset;
enum Modulation {BPSK, OQPSK} m_modulation;
int m_bitRate;
bool m_subGHzBand;
Real m_rfBandwidth;
Real m_gain;
bool m_channelMute;
bool m_repeat;
Real m_repeatDelay;
int m_repeatCount;
int m_rampUpBits;
int m_rampDownBits;
int m_rampRange;
bool m_modulateWhileRamping;
int m_lpfTaps;
bool m_bbNoise;
bool m_writeToFile;
int m_spectrumRate;
QString m_data;
quint32 m_rgbColor;
QString m_title;
Serializable *m_channelMarker;
int m_streamIndex;
bool m_useReverseAPI;
QString m_reverseAPIAddress;
uint16_t m_reverseAPIPort;
uint16_t m_reverseAPIDeviceIndex;
uint16_t m_reverseAPIChannelIndex;
bool m_scramble;
int m_polynomial;
enum PulseShaping {RC, SINE} m_pulseShaping;
float m_beta;
int m_symbolSpan;
IEEE_802_15_4_ModSettings();
void resetToDefaults();
void setChannelMarker(Serializable *channelMarker) { m_channelMarker = channelMarker; }
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
bool setPHY(QString phy);
QString getPHY() const;
int getChipRate() const;
};
#endif /* INCLUDE_IEEE_802_15_4_MODSETTINGS_H */

View File

@ -0,0 +1,611 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2019 Edouard Griffiths, F4EXB //
// Copyright (C) 2020 Jon Beniston, M7RCE //
// //
// 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 //
// (at your option) any later version. //
// //
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <cctype>
#include <QDebug>
#include "dsp/basebandsamplesink.h"
#include "ieee_802_15_4_modsource.h"
#include "util/crc.h"
IEEE_802_15_4_ModSource::IEEE_802_15_4_ModSource() :
m_channelSampleRate(3000000),
m_spectrumRate(0),
m_channelFrequencyOffset(0),
m_magsq(0.0),
m_levelCalcCount(0),
m_peakLevel(0.0f),
m_levelSum(0.0f),
m_bitCount(0),
m_byteIdx(0),
m_bitIdx(0),
m_state(idle),
m_sampleIdx(0),
m_chipsPerSymbol(15),
m_bitsPerSymbol(1),
m_chipRate(300000),
m_sinLUT(nullptr),
m_spectrumSink(nullptr),
m_scopeSink(nullptr),
m_scrambler(0x108, 0x1fe, 0)
{
m_lowpass.create(301, m_channelSampleRate, 22000.0 / 2.0);
m_pulseShapeI.create(1, 6, m_channelSampleRate/300000, true);
m_pulseShapeQ.create(1, 6, m_channelSampleRate/300000, true);
applySettings(m_settings, true);
applyChannelSettings(m_channelSampleRate, m_channelFrequencyOffset, true);
}
IEEE_802_15_4_ModSource::~IEEE_802_15_4_ModSource()
{
delete m_sinLUT;
}
void IEEE_802_15_4_ModSource::pull(SampleVector::iterator begin, unsigned int nbSamples)
{
std::for_each(
begin,
begin + nbSamples,
[this](Sample& s) {
pullOne(s);
}
);
}
void IEEE_802_15_4_ModSource::pullOne(Sample& sample)
{
if (m_settings.m_channelMute)
{
sample.m_real = 0.0f;
sample.m_imag = 0.0f;
return;
}
// Calculate next sample
modulateSample();
// Shift to carrier frequency
Complex ci = m_modSample;
ci *= m_carrierNco.nextIQ();
// Calculate power
double magsq = ci.real() * ci.real() + ci.imag() * ci.imag();
m_movingAverage(magsq);
m_magsq = m_movingAverage.asDouble();
// Convert from float to fixed point
sample.m_real = (FixReal) (ci.real() * SDR_TX_SCALEF);
sample.m_imag = (FixReal) (ci.imag() * SDR_TX_SCALEF);
}
void IEEE_802_15_4_ModSource::prefetch(unsigned int nbSamples)
{
}
void IEEE_802_15_4_ModSource::sampleToSpectrum(Complex sample)
{
if (m_spectrumSink && (m_settings.m_spectrumRate > 0))
{
Complex out;
// Could use a simpler filter here, as currently m_spectrumRate is
// always an integer multiple of m_channelSampleRate
if (m_interpolator.decimate(&m_interpolatorDistanceRemain, sample, &out))
{
Real r = std::real(out) * SDR_TX_SCALEF;
Real i = std::imag(out) * SDR_TX_SCALEF;
m_sampleBuffer.push_back(Sample(r, i));
m_spectrumSink->feed(m_sampleBuffer.begin(), m_sampleBuffer.end(), false);
m_sampleBuffer.clear();
m_interpolatorDistanceRemain += m_interpolatorDistance;
}
}
}
void IEEE_802_15_4_ModSource::sampleToScope(Complex sample)
{
if (m_scopeSink)
{
Real r = std::real(sample) * SDR_RX_SCALEF;
Real i = std::imag(sample) * SDR_RX_SCALEF;
m_sampleBuffer.push_back(Sample(r, i));
m_scopeSink->feed(m_sampleBuffer.begin(), m_sampleBuffer.end(), true);
m_sampleBuffer.clear();
}
}
void IEEE_802_15_4_ModSource::modulateSample()
{
Real linearRampGain;
Real i, q;
if ((m_state == idle) || (m_state == wait))
{
Real audioMod = 0.0f;
m_modSample.real(audioMod);
m_modSample.imag(0);
calculateLevel(audioMod);
sampleToSpectrum(m_modSample);
sampleToScope(m_modSample);
if (m_state == wait)
{
m_waitCounter--;
if (m_waitCounter == 0)
initTX();
}
}
else
{
if (m_sampleIdx == 0)
{
if (chipsValid())
m_chips[m_chipOdd] = getChip();
// Should we start ramping down power?
if ((m_bitCount < m_settings.m_rampDownBits) || ((m_bitCount == 0) && !m_settings.m_rampDownBits))
{
m_state = ramp_down;
if (m_settings.m_rampDownBits > 0)
m_powRamp = -m_settings.m_rampRange/(m_settings.m_rampDownBits * (Real)m_samplesPerChip);
}
}
if (!m_settings.m_bbNoise)
{
if (m_settings.m_modulation == IEEE_802_15_4_ModSettings::BPSK)
{
// BPSK - Raised cosine pulse shaping
if ((m_sampleIdx == 1) && (m_state != ramp_down))
i = m_pulseShapeI.filter(m_chips[0] ? 1.0f : -1.0f);
else
i = m_pulseShapeI.filter(0.0f);
q = 0.0f;
}
else
{
if (m_settings.m_pulseShaping == IEEE_802_15_4_ModSettings::SINE)
{
// O-QPSK - Half-sine pulse shaping over 2 chips. Even chips on I, odd on Q. 1-chip out of phase.
i = (m_chips[0] ? 1.0f : -1.0f) * m_sinLUT[m_sampleIdx+(m_chipOdd ? m_samplesPerChip : 0)];
q = (m_chips[1] ? 1.0f : -1.0f) * m_sinLUT[m_sampleIdx+(m_chipOdd ? 0 : m_samplesPerChip)];
}
else
{
// O-QPSK - Raised cosine pulse shaping. Even chips on I, odd on Q. 1-chip out of phase.
if ((m_sampleIdx == 1) && (m_state != ramp_down) && !m_chipOdd)
i = m_pulseShapeI.filter(m_chips[0] ? 1.0f : -1.0f);
else
i = m_pulseShapeI.filter(0.0f);
if ((m_sampleIdx == 1) && (m_state != ramp_down) && m_chipOdd)
q = m_pulseShapeQ.filter(m_chips[1] ? 1.0f : -1.0f);
else
q = m_pulseShapeQ.filter(0.0f);
}
}
}
else
{
i = (Real)rand()/((Real)RAND_MAX)-0.5; // Noise to test filter frequency response
q = (Real)rand()/((Real)RAND_MAX)-0.5;
}
if (m_basebandFile.is_open())
m_basebandFile << m_chips[0] << "," << m_chips[1] << "," << m_chipOdd << "," << i << "," << q << "," << (m_sampleIdx+(m_chipOdd ? m_samplesPerChip : 0)) << "," << (m_sampleIdx+(m_chipOdd ? 0 : m_samplesPerChip)) << "\n";
m_sampleIdx++;
if (m_sampleIdx >= m_samplesPerChip)
{
m_sampleIdx = 0;
if (m_settings.m_modulation == IEEE_802_15_4_ModSettings::OQPSK)
m_chipOdd = !m_chipOdd;
}
linearRampGain = powf(10.0f, m_pow/20.0f);
m_modSample.real(m_linearGain * linearRampGain * i);
m_modSample.imag(m_linearGain * linearRampGain * q);
// Display baseband audio in spectrum analyser
sampleToSpectrum(m_modSample);
sampleToScope(m_modSample);
// Apply low pass filter to limit RF BW
m_modSample = m_lowpass.filter(m_modSample);
// Ramp up/down power at start/end of frame
if ((m_state == ramp_up) || (m_state == ramp_down))
{
m_pow += m_powRamp;
if ((m_state == ramp_up) && (m_pow >= 0.0f))
{
// Finished ramp up, transmit at full gain
m_state = tx;
m_pow = 0.0f;
}
else if ((m_state == ramp_down) && ( (m_settings.m_rampRange == 0)
|| (m_settings.m_rampDownBits == 0)
|| (m_pow <= -(Real)m_settings.m_rampRange)
))
{
m_state = idle;
// Do we need to retransmit the frame?
if (m_settings.m_repeat)
{
if (m_frameRepeatCount > 0)
m_frameRepeatCount--;
if ((m_frameRepeatCount == IEEE_802_15_4_ModSettings::infinitePackets) || (m_frameRepeatCount > 0))
{
if (m_settings.m_repeatDelay > 0.0f)
{
// Wait before retransmitting
m_state = wait;
m_waitCounter = m_settings.m_repeatDelay * m_channelSampleRate;
}
else
{
// Retransmit immediately
initTX();
}
}
}
}
}
Real s = std::real(m_modSample);
calculateLevel(s);
}
}
void IEEE_802_15_4_ModSource::calculateLevel(Real& sample)
{
if (m_levelCalcCount < m_levelNbSamples)
{
m_peakLevel = std::max(std::fabs(m_peakLevel), sample);
m_levelSum += sample * sample;
m_levelCalcCount++;
}
else
{
m_rmsLevel = sqrt(m_levelSum / m_levelNbSamples);
m_peakLevelOut = m_peakLevel;
m_peakLevel = 0.0f;
m_levelSum = 0.0f;
m_levelCalcCount = 0;
}
}
void IEEE_802_15_4_ModSource::applySettings(const IEEE_802_15_4_ModSettings& settings, bool force)
{
// Only recreate filters if settings have changed
if ((settings.m_lpfTaps != m_settings.m_lpfTaps) || (settings.m_rfBandwidth != m_settings.m_rfBandwidth) || force)
{
qDebug() << "IEEE_802_15_4_ModSource::applySettings: Creating new lpf with taps " << settings.m_lpfTaps << " rfBW " << settings.m_rfBandwidth;
m_lowpass.create(settings.m_lpfTaps, m_channelSampleRate, settings.m_rfBandwidth / 2.0);
}
if ((settings.m_spectrumRate != m_settings.m_spectrumRate) || force)
{
m_interpolatorDistanceRemain = 0;
m_interpolatorConsumed = false;
m_interpolatorDistance = (Real) m_channelSampleRate / (Real) settings.m_spectrumRate;
m_interpolator.create(48, settings.m_spectrumRate, settings.m_spectrumRate / 2.2, 3.0);
}
if (settings.m_modulation == IEEE_802_15_4_ModSettings::BPSK)
{
m_chipsPerSymbol = 15;
m_bitsPerSymbol = 1;
}
else
{
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)
|| (settings.m_subGHzBand != m_settings.m_subGHzBand)
|| force)
{
qDebug() << "IEEE_802_15_4_ModSource::applySettings: Recreating pulse shaping filter: "
<< " pulseShaping: " << m_settings.m_pulseShaping
<< " beta: " << settings.m_beta
<< " symbolSpan: " << settings.m_symbolSpan
<< " channelSampleRate:" << m_channelSampleRate
<< " 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);
}
if ((settings.m_polynomial != m_settings.m_polynomial) || force)
m_scrambler.setPolynomial(settings.m_polynomial);
m_settings = settings;
// Precalculate linear gain to save doing it in the loop
m_linearGain = powf(10.0f, m_settings.m_gain/20.0f);
}
void IEEE_802_15_4_ModSource::applyChannelSettings(int channelSampleRate, int channelFrequencyOffset, bool force)
{
qDebug() << "IEEE_802_15_4_ModSource::applyChannelSettings:"
<< " channelSampleRate: " << channelSampleRate
<< " channelFrequencyOffset: " << channelFrequencyOffset
<< " rfBandwidth: " << m_settings.m_rfBandwidth
<< " spectrumRate: " << m_settings.m_spectrumRate;
if ((channelFrequencyOffset != m_channelFrequencyOffset)
|| (channelSampleRate != m_channelSampleRate) || force)
{
m_carrierNco.setFreq(channelFrequencyOffset, channelSampleRate);
}
if ((m_channelSampleRate != channelSampleRate) || force)
{
qDebug() << "IEEE_802_15_4_ModSource::applyChannelSettings: Recreating filters";
m_lowpass.create(m_settings.m_lpfTaps, channelSampleRate, m_settings.m_rfBandwidth / 2.0);
qDebug() << "IEEE_802_15_4_ModSource::applyChannelSettings: Recreating pulse shaping filter: "
<< " pulseShaping: " << m_settings.m_pulseShaping
<< " beta: " << m_settings.m_beta
<< " symbolSpan: " << m_settings.m_symbolSpan
<< " channelSampleRate:" << channelSampleRate
<< " subGHzBand: " << m_settings.m_subGHzBand
<< " bitRate:" << m_settings.m_bitRate
<< " chipRate:" << m_chipRate;
if (m_settings.m_pulseShaping == IEEE_802_15_4_ModSettings::RC)
{
m_pulseShapeI.create(m_settings.m_beta, m_settings.m_symbolSpan, channelSampleRate/m_chipRate, true);
m_pulseShapeQ.create(m_settings.m_beta, m_settings.m_symbolSpan, channelSampleRate/m_chipRate, true);
}
else
createHalfSine(channelSampleRate, m_chipRate);
}
if ((m_channelSampleRate != channelSampleRate) || (m_spectrumRate != m_settings.m_spectrumRate) || force)
{
m_interpolatorDistanceRemain = 0;
m_interpolatorConsumed = false;
m_interpolatorDistance = (Real) channelSampleRate / (Real) m_settings.m_spectrumRate;
m_interpolator.create(48, m_settings.m_spectrumRate, m_settings.m_spectrumRate / 2.2, 3.0);
}
m_channelSampleRate = channelSampleRate;
m_channelFrequencyOffset = channelFrequencyOffset;
m_spectrumRate = m_settings.m_spectrumRate;
m_samplesPerChip = m_channelSampleRate / m_chipRate;
qDebug() << "m_samplesPerChip: " << m_samplesPerChip;
}
// Half-sine pulse shaping for O-QPSK
void IEEE_802_15_4_ModSource::createHalfSine(int sampleRate, int chipRate)
{
int samplesPerChip = sampleRate / chipRate;
double tc = 1.0 / chipRate;
if (m_sinLUT)
delete m_sinLUT;
m_sinLUT = new double[2*samplesPerChip];
for (int i = 0; i < 2*samplesPerChip; i++)
{
double t=i/(double)sampleRate;
m_sinLUT[i] = sin(M_PI*t/(2.0*tc));
}
}
bool IEEE_802_15_4_ModSource::chipsValid()
{
return (m_bitCount > 0) || (m_chipIdx < m_chipsPerSymbol);
}
// Symbol-to-chip mapping
int IEEE_802_15_4_ModSource::getChip()
{
int chip = 0;
if (m_chipIdx == 0)
m_symbol = getSymbol();
if (m_settings.m_bitRate <= 40000)
{
static const int chipsBpsk[2][15] = {
{1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0},
{0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1}
};
chip = chipsBpsk[m_symbol][m_chipIdx];
}
else if (m_settings.m_subGHzBand)
{
static const int chipsSubGHzOqpsk[16][16] = {
{0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1},
{0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1},
{0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0},
{1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0},
{0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0},
{1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1},
{1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1},
{1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0},
{0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0},
{0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0},
{0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1},
{1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1},
{0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1},
{1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0},
{1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0},
{1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1},
};
chip = chipsSubGHzOqpsk[m_symbol][m_chipIdx];
}
else
{
static const int chipsOqpsk[16][32] = {
{1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0},
{1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0},
{0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0},
{0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1},
{0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1},
{0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0},
{1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1},
{1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1},
{1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1},
{1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1},
{0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1},
{0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0},
{0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1},
{1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0},
{1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0}
};
chip = chipsOqpsk[m_symbol][m_chipIdx];
}
m_chipIdx++;
if (m_chipIdx >= m_chipsPerSymbol)
m_chipIdx = 0;
return chip;
}
int IEEE_802_15_4_ModSource::getSymbol()
{
int symbol;
if (m_bitCount > 0)
{
int mask = m_bitsPerSymbol == 1 ? 0x1 : 0xf;
symbol = (m_bits[m_byteIdx] >> m_bitIdx) & mask;
m_bitIdx += m_bitsPerSymbol;
m_bitCount -= m_bitsPerSymbol;
if (m_bitIdx == 8)
{
m_byteIdx++;
m_bitIdx = 0;
}
if (m_settings.m_modulation == IEEE_802_15_4_ModSettings::BPSK)
{
// Differential encoding
symbol = symbol ^ m_diffBit;
m_diffBit = symbol;
}
}
else
symbol = 0;
return symbol;
}
void IEEE_802_15_4_ModSource::initTX()
{
m_sampleIdx = 0;
m_chipOdd = false;
m_chips[0] = 0;
m_chips[1] = 0;
m_chipIdx = 0;
m_diffBit = 0;
m_byteIdx = 0;
m_bitIdx = 0;
m_bitCount = m_bitCountTotal; // Reset to allow retransmission
m_symbol = 0;
if (m_settings.m_rampUpBits == 0)
{
m_state = tx;
m_pow = 0.0f;
}
else
{
m_state = ramp_up;
m_pow = -(Real)m_settings.m_rampRange;
m_powRamp = m_settings.m_rampRange/(m_settings.m_rampUpBits * (Real)m_samplesPerChip);
}
m_scrambler.init();
}
uint8_t *IEEE_802_15_4_ModSource::hexToBin(uint8_t *p, QString data)
{
// Convert string containing space separated list of hex values to binary
QStringList list = data.split(" ");
for (int i = 0; i < list.size(); i++)
{
*p++ = list[i].toInt(nullptr, 16);
}
return p;
}
void IEEE_802_15_4_ModSource::addTXFrame(QString data)
{
uint8_t *crcStart;
uint8_t *p;
uint8_t *pLength;
crc16itut crc;
uint16_t crcValue;
int len;
// Create PHY frame
p = m_bits;
// Preamble
*p++ = 0x00;
*p++ = 0x00;
*p++ = 0x00;
*p++ = 0x00;
// SFD - start of frame delimiter
*p++ = 0xa7;
// PHR - length
pLength = p;
*p++ = 0;
// PHY payload
crcStart = p;
// Data
p = hexToBin(p, data);
// MAC FCS
crc.calculate(crcStart, p-crcStart);
crcValue = crc.get();
*p++ = crcValue & 0xff;
*p++ = (crcValue >> 8);
// Update length
*pLength = p - pLength - 1;
// Extra 0 to account for pulse shaping filter delay.
// Should probably just be a few chips
*p++ = 0x00;
// Dump frame
QByteArray qb((char *)m_bits, p-m_bits);
qDebug() << "TX: " << qb.toHex();
// Save number of bits in frame
m_bitCount = m_bitCountTotal = (p-&m_bits[0]) * 8;
m_frameRepeatCount = m_settings.m_repeatCount;
initTX();
if (m_settings.m_writeToFile)
m_basebandFile.open("IEEE_802_15_4_Mod.csv", std::ofstream::out);
else if (m_basebandFile.is_open())
m_basebandFile.close();
}

View File

@ -0,0 +1,145 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2019 Edouard Griffiths, F4EXB //
// Copyright (C) 2020 Jon Beniston, M7RCE //
// //
// 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 //
// (at your option) any later version. //
// //
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_IEEE_802_15_4_MODSOURCE_H
#define INCLUDE_IEEE_802_15_4_MODSOURCE_H
#include <QMutex>
#include <QDebug>
#include <iostream>
#include <fstream>
#include "dsp/channelsamplesource.h"
#include "dsp/nco.h"
#include "dsp/ncof.h"
#include "dsp/interpolator.h"
#include "dsp/lowpass.h"
#include "dsp/bandpass.h"
#include "dsp/highpass.h"
#include "dsp/raisedcosine.h"
#include "dsp/fmpreemphasis.h"
#include "util/lfsr.h"
#include "util/movingaverage.h"
#include "ieee_802_15_4_modsettings.h"
class BasebandSampleSink;
class IEEE_802_15_4_ModSource : public ChannelSampleSource
{
public:
IEEE_802_15_4_ModSource();
virtual ~IEEE_802_15_4_ModSource();
virtual void pull(SampleVector::iterator begin, unsigned int nbSamples);
virtual void pullOne(Sample& sample);
virtual void prefetch(unsigned int nbSamples);
double getMagSq() const { return m_magsq; }
void getLevels(qreal& rmsLevel, qreal& peakLevel, int& numSamples) const
{
rmsLevel = m_rmsLevel;
peakLevel = m_peakLevelOut;
numSamples = m_levelNbSamples;
}
void setSpectrumSink(BasebandSampleSink *sampleSink) { m_spectrumSink = sampleSink; }
void setScopeSink(BasebandSampleSink* 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);
uint8_t *hexToBin(uint8_t *p, QString data);
void addTXFrame(QString data);
private:
int m_channelSampleRate;
int m_channelFrequencyOffset;
int m_spectrumRate;
IEEE_802_15_4_ModSettings m_settings;
NCO m_carrierNco;
Real m_linearGain;
Complex m_modSample;
double *m_sinLUT;
int m_chips[2]; // Chips. Odd/even for O-QPSK
bool m_chipOdd;
int m_diffBit; // Output of differential coder
RaisedCosine<Real> m_pulseShapeI; // Pulse shaping filters
RaisedCosine<Real> m_pulseShapeQ;
Lowpass<Complex> m_lowpass; // Low pass filter to limit RF bandwidth
LFSR m_scrambler; // Scrambler
BasebandSampleSink* m_spectrumSink; // Spectrum GUI to display baseband waveform
BasebandSampleSink* m_scopeSink; // Scope GUI to display baseband waveform
SampleVector m_sampleBuffer;
Interpolator m_interpolator; // Interpolator to downsample to 4k in spectrum
Real m_interpolatorDistance;
Real m_interpolatorDistanceRemain;
bool m_interpolatorConsumed;
double m_magsq;
MovingAverageUtil<double, double, 16> m_movingAverage;
quint32 m_levelCalcCount;
qreal m_rmsLevel;
qreal m_peakLevelOut;
Real m_peakLevel;
Real m_levelSum;
static const int m_levelNbSamples = 480; // every 10ms assuming 48k Sa/s
int m_sampleIdx; // Sample index in to chip
int m_samplesPerChip; // Number of samples per chip
int m_chipsPerSymbol; // Number of chips per symbol
int m_bitsPerSymbol; // Number of bits per symbol
int m_chipRate;
int m_symbol;
int m_chipIdx;
Real m_pow; // In dB
Real m_powRamp; // In dB
enum IEEE_802_15_4_ModState {
idle, ramp_up, tx, ramp_down, wait
} m_state; // States for sample modulation
int m_frameRepeatCount;
uint64_t m_waitCounter; // Samples to wait before retransmission
uint8_t m_bits[4+1+1+127]; // Bits to transmit (preamble, SFD, length, payload)
int m_byteIdx; // Index in to m_bits
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
bool chipsValid(); // Are there any chips to transmit
int getSymbol();
int getChip();
void initTX();
void createHalfSine(int sampleRate, int chipRate);
void calculateLevel(Real& sample);
void modulateSample();
void sampleToSpectrum(Complex sample);
void sampleToScope(Complex sample);
};
#endif // INCLUDE_IEEE_802_15_4_MODSOURCE_H

View File

@ -0,0 +1,69 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Jon Beniston, M7RCE //
// //
// 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 //
// (at your option) any later version. //
// //
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include "ieee_802_15_4_modtxsettingsdialog.h"
IEEE_802_15_4_ModTXSettingsDialog::IEEE_802_15_4_ModTXSettingsDialog(int rampUpBits, int rampDownBits,
int rampRange, bool modulateWhileRamping, int modulation, int bitRate,
int pulseShaping, float beta, int symbolSpan,
bool scramble, int polynomial,
int lpfTaps, bool bbNoise, bool writeToFile,
QWidget* parent) :
QDialog(parent),
ui(new Ui::IEEE_802_15_4_ModTXSettingsDialog)
{
ui->setupUi(this);
ui->rampUp->setValue(rampUpBits);
ui->rampDown->setValue(rampDownBits);
ui->rampRange->setValue(rampRange);
ui->modulateWhileRamping->setChecked(modulateWhileRamping);
ui->modulation->setCurrentIndex(modulation);
ui->bitRate->setValue(bitRate);
ui->pulseShaping->setCurrentIndex(pulseShaping);
ui->beta->setValue(beta);
ui->symbolSpan->setValue(symbolSpan);
ui->scramble->setChecked(scramble);
ui->polynomial->setValue(polynomial);
ui->lpfTaps->setValue(lpfTaps);
ui->bbNoise->setChecked(bbNoise);
ui->writeToFile->setChecked(writeToFile);
}
IEEE_802_15_4_ModTXSettingsDialog::~IEEE_802_15_4_ModTXSettingsDialog()
{
delete ui;
}
void IEEE_802_15_4_ModTXSettingsDialog::accept()
{
m_rampUpBits = ui->rampUp->value();
m_rampDownBits = ui->rampDown->value();
m_rampRange = ui->rampRange->value();
m_modulateWhileRamping = ui->modulateWhileRamping->isChecked();
m_modulation = ui->modulation->currentIndex();
m_bitRate = ui->bitRate->value();
m_pulseShaping = ui->pulseShaping->currentIndex();
m_beta = ui->beta->value();
m_symbolSpan = ui->symbolSpan->value();
m_scramble = ui->scramble->isChecked();
m_polynomial = ui->polynomial->value();
m_lpfTaps = ui->lpfTaps->value();
m_bbNoise = ui->bbNoise->isChecked();
m_writeToFile = ui->writeToFile->isChecked();
QDialog::accept();
}

View File

@ -0,0 +1,57 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Jon Beniston, M7RCE //
// //
// 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 //
// (at your option) any later version. //
// //
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_IEEE_802_15_4_MODTXSETTINGSDIALOG_H
#define INCLUDE_IEEE_802_15_4_MODTXSETTINGSDIALOG_H
#include "ui_IEEE_802_15_4_Modtxsettingsdialog.h"
class IEEE_802_15_4_ModTXSettingsDialog : public QDialog {
Q_OBJECT
public:
explicit IEEE_802_15_4_ModTXSettingsDialog(int rampUpBits, int rampDownBits, int rampRange,
bool modulateWhileRamping, int modulation, int bitRate,
int pulseShaping, float beta, int symbolSpan,
bool scramble, int polynomial,
int lpfTaps, bool bbNoise, bool writeToFile,
QWidget* parent = 0);
~IEEE_802_15_4_ModTXSettingsDialog();
int m_rampUpBits;
int m_rampDownBits;
int m_rampRange;
bool m_modulateWhileRamping;
int m_modulation;
int m_bitRate;
int m_pulseShaping;
float m_beta;
int m_symbolSpan;
bool m_scramble;
int m_polynomial;
int m_lpfTaps;
bool m_bbNoise;
bool m_writeToFile;
private slots:
void accept();
private:
Ui::IEEE_802_15_4_ModTXSettingsDialog* ui;
};
#endif // INCLUDE_IEEE_802_15_4_MODTXSETTINGSDIALOG_H

View File

@ -0,0 +1,370 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>IEEE_802_15_4_ModTXSettingsDialog</class>
<widget class="QDialog" name="IEEE_802_15_4_ModTXSettingsDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>351</width>
<height>592</height>
</rect>
</property>
<property name="font">
<font>
<family>Liberation Sans</family>
<pointsize>9</pointsize>
</font>
</property>
<property name="windowTitle">
<string>802.15.4 Extra Settings</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="bitRateGroup">
<property name="title">
<string>Modulation</string>
</property>
<layout class="QFormLayout" name="formLayout_8">
<item row="1" column="0">
<widget class="QLabel" name="bitRateLabel">
<property name="text">
<string>Bitrate</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="bitRate">
<property name="toolTip">
<string>Bitrate (bits per second).</string>
</property>
<property name="maximum">
<number>500000</number>
</property>
<property name="value">
<number>40000</number>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="modulation">
<property name="toolTip">
<string>Modulaton type.</string>
</property>
<item>
<property name="text">
<string>BPSK</string>
</property>
</item>
<item>
<property name="text">
<string>O-QPSK</string>
</property>
</item>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="modulationLabel">
<property name="text">
<string>Modulation</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="lpfTapsLabel">
<property name="text">
<string>RF BW limit LPF taps</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="lpfTaps">
<property name="toolTip">
<string>Number of taps in LPF for RF BW filter.</string>
</property>
<property name="maximum">
<number>10000</number>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="fskGroup">
<property name="title">
<string>Pulse shaping</string>
</property>
<layout class="QFormLayout" name="formLayout_2">
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Pulse shaping</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="pulseShaping">
<item>
<property name="text">
<string>Raised Cosine</string>
</property>
</item>
<item>
<property name="text">
<string>Half sine</string>
</property>
</item>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="betaLabel">
<property name="text">
<string>Filter rolloff (beta)</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QDoubleSpinBox" name="beta">
<property name="toolTip">
<string>Roll-off of the filter</string>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="singleStep">
<double>0.250000000000000</double>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="symbolSpanLabel">
<property name="text">
<string>Filter symbol span</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QSpinBox" name="symbolSpan">
<property name="toolTip">
<string>Number of symbols over which filter is applied</string>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>20</number>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="scramblingGroup">
<property name="title">
<string>Scrambing</string>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QCheckBox" name="scramble">
<property name="toolTip">
<string>Enabling scrambling.</string>
</property>
<property name="text">
<string>Scramble</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="polynomialLabel">
<property name="text">
<string>Polynomial</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="polynomial">
<property name="toolTip">
<string>Polynomial of the scrambler. The +1 is implicit.</string>
</property>
<property name="prefix">
<string>0x</string>
</property>
<property name="maximum">
<number>2147483647</number>
</property>
<property name="value">
<number>67584</number>
</property>
<property name="displayIntegerBase">
<number>16</number>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="powerRampingGroup">
<property name="title">
<string>Power Ramping</string>
</property>
<layout class="QFormLayout" name="formLayout_6">
<item row="0" column="0">
<widget class="QLabel" name="rampUpLabel">
<property name="text">
<string>Ramp up bits</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="rampUp">
<property name="toolTip">
<string>Number of bits at start of frame during which output power is ramped up.</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="rampDownLabel">
<property name="text">
<string>Ramp down bits</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="rampDown">
<property name="toolTip">
<string>Number of bits at end of frame during which output power is ramped down.</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="rampRangeLabel">
<property name="text">
<string>Ramp range (dB)</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="rampRange">
<property name="toolTip">
<string>Range in dB over which power is ramped up or down. E.g. a value of 60 causes power to be ramped from -60dB to 0dB.</string>
</property>
<property name="maximum">
<number>120</number>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="modulateWhileRamping">
<property name="toolTip">
<string>Modulate during ramping.</string>
</property>
<property name="text">
<string>Modulate while ramping</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="debugGroup">
<property name="title">
<string>Debug</string>
</property>
<layout class="QFormLayout" name="formLayout_3">
<item row="0" column="0">
<widget class="QCheckBox" name="bbNoise">
<property name="toolTip">
<string>Generate white noise as baseband signal.</string>
</property>
<property name="text">
<string>Generate BB noise</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="writeToFile">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Write baseband signal to a CSV file named IEEE_802_15_4_Mod.csv</string>
</property>
<property name="text">
<string>Write baseband to CSV</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<tabstops>
<tabstop>modulation</tabstop>
<tabstop>bitRate</tabstop>
<tabstop>lpfTaps</tabstop>
<tabstop>pulseShaping</tabstop>
<tabstop>beta</tabstop>
<tabstop>symbolSpan</tabstop>
<tabstop>scramble</tabstop>
<tabstop>polynomial</tabstop>
<tabstop>rampUp</tabstop>
<tabstop>rampDown</tabstop>
<tabstop>rampRange</tabstop>
<tabstop>modulateWhileRamping</tabstop>
<tabstop>bbNoise</tabstop>
<tabstop>writeToFile</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>IEEE_802_15_4_ModTXSettingsDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>IEEE_802_15_4_ModTXSettingsDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -0,0 +1,52 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2019 Edouard Griffiths, F4EXB. //
// Copyright (C) 2020 Jon Beniston, M7RCE //
// //
// 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 //
// (at your option) any later version. //
// //
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include "SWGChannelSettings.h"
#include "ieee_802_15_4_mod.h"
#include "ieee_802_15_4_modwebapiadapter.h"
IEEE_802_15_4_ModWebAPIAdapter::IEEE_802_15_4_ModWebAPIAdapter()
{}
IEEE_802_15_4_ModWebAPIAdapter::~IEEE_802_15_4_ModWebAPIAdapter()
{}
int IEEE_802_15_4_ModWebAPIAdapter::webapiSettingsGet(
SWGSDRangel::SWGChannelSettings& response,
QString& errorMessage)
{
(void) errorMessage;
response.setIeee802154ModSettings(new SWGSDRangel::SWGIEEE_802_15_4_ModSettings());
response.getIeee802154ModSettings()->init();
IEEE_802_15_4_Mod::webapiFormatChannelSettings(response, m_settings);
return 200;
}
int IEEE_802_15_4_ModWebAPIAdapter::webapiSettingsPutPatch(
bool force,
const QStringList& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings& response,
QString& errorMessage)
{
(void) errorMessage;
IEEE_802_15_4_Mod::webapiUpdateChannelSettings(m_settings, channelSettingsKeys, response);
IEEE_802_15_4_Mod::webapiFormatChannelSettings(response, m_settings);
return 200;
}

View File

@ -0,0 +1,50 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2019 Edouard Griffiths, F4EXB. //
// Copyright (C) 2020 Jon Beniston, M7RCE //
// //
// 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 //
// (at your option) any later version. //
// //
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_IEEE_802_15_4_MODWEBAPIADAPTER_H
#define INCLUDE_IEEE_802_15_4_MODWEBAPIADAPTER_H
#include "channel/channelwebapiadapter.h"
#include "ieee_802_15_4_modsettings.h"
/**
* Standalone API adapter only for the settings
*/
class IEEE_802_15_4_ModWebAPIAdapter : public ChannelWebAPIAdapter {
public:
IEEE_802_15_4_ModWebAPIAdapter();
virtual ~IEEE_802_15_4_ModWebAPIAdapter();
virtual QByteArray serialize() const { return m_settings.serialize(); }
virtual bool deserialize(const QByteArray& data) { return m_settings.deserialize(data); }
virtual int webapiSettingsGet(
SWGSDRangel::SWGChannelSettings& response,
QString& errorMessage);
virtual int webapiSettingsPutPatch(
bool force,
const QStringList& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings& response,
QString& errorMessage);
private:
IEEE_802_15_4_ModSettings m_settings;
};
#endif // INCLUDE_IEEE_802_15_4_MODWEBAPIADAPTER_H

View File

@ -0,0 +1,84 @@
<h1>IEEE 802.15.4 modulator plugin</h1>
<h2>Introduction</h2>
This plugin can be used to transmit IEEE 802.15.4 frames. The 802.15.4 PHY & RF layers are used by networking layers such as ZigBee, 6LoWPAN and others.
<h2>Interface</h2>
![802.15.4 Modulator plugin GUI](../../../doc/img/IEEE_802_15_4_Mod_plugin.png)
<h3>1: Frequency shift from center frequency of transmission</h3>
Use the wheels to adjust the frequency shift in Hz from the center frequency of transmission. Left click on a digit sets the cursor position at this digit. Right click on a digit sets all digits on the right to zero. This effectively floors value at the digit position. Wheels are moved with the mousewheel while pointing at the wheel or by selecting the wheel with the left mouse click and using the keyboard arrows. Pressing shift simultaneously moves digit by 5 and pressing control moves it by 2.
<h3>2: Channel power</h3>
Average total power in dB relative to a +/- 1.0 amplitude signal generated in the pass band.
<h3>3: Channel mute</h3>
Use this button to toggle mute for this channel.
<h3>4: PHY</h3>
This specifies the parameters of the PHY (physical layer), including the bit rate and modulation that is used for the frame transmission. Supported PHYs are 20kbps BPSK, 40kbps BPSK, 100kpbs <1GHZ O-QPSK, 250kpbs <1GHz O-QPSK and 250kbps 2.4GHz O-QPSK.
These 802.15.4 PHYs use DSSS (Direct sequence spread spectrum), whereby multiple chips are transmitted per symbol. This means that a high sample rate (>3MSa/s) and large RF bandwidth is required. The baseband sample rate should be set to an integer multiple of the chip rate.
Each PHY is applicable only for specific frequency bands as detailed below:
Channel Page | Channels | Frequencies (MHz) | Bit rate (kbps) | Chip rate (kcps) | Modulation | Shaping | Min sample rate (MSa/s)
-------------|----------|--------------------|-----------------|------------------|------------|---------|---------------
0 | 0 | 868.3 | 20 | 300 | BPSK | RC r=1 | 1.2
0 | 1-10 | 906, 908... 926 | 40 | 600 | BPSK | RC r=1 | 2.4
0 | 11-26 | 2405, 2410... 2480 | 250 | 2000 | O-QPSK | Sine |
2 | 0 | 868.3 | 100 | 400 | O-QPSK | Sine/RC | 4
2 | 1-10 | 906, 908... 926 | 250 | 1000 | O-QPSK | Sine | 6
5 | 0-3 | 780, 782.. 786 | 250 | 1000 | O-QPSK | RC r=.8 | 6
11 | 0-6 | 2363, 2368... 2393 | 250 | 2000 | O-QPSK | Sine |
11 | 7-13 | 2367, 2372... 2397 | 250 | 2000 | O-QPSK | Sine |
11 | 14 | 2395 | 250 | 2000 | O-QPSK | Sine |
<h3>5: RF Bandwidth</h3>
This specifies the bandwidth of a LPF that is applied to the output signal to limit the RF bandwidth.
PHY | Occupied BW (99%) | Mesaured Occupied BW
----------------------------|-----------------------------------------
20kbps BPSK | 400kHz | 440kHz
40kbps BPSK | 760kHz | 940kHz
100kbps O-QPSK | 330kHz | 500kHz
250kbps <1GHz O-QPSK (Sine) | 1.200MHz | 1.8MHz
250kbps <1GHz O-QPSK (RC) | 1.200MHz | 1.4MHz
250kbps >2GHz O-QPSK | | 3.2MHz
<h3>6: Gain</h3>
Adjusts the gain in dB from -60 to 0dB. The gain should be set to ensure the level meter remains below 100%. If the baseband signal clips, this can lead to out-of-band spurious.
<h3>7: Level meter in %</h3>
- top bar (beige): average value
- bottom bar (brown): instantaneous peak value
- tip vertical bar (bright red): peak hold value
<h3>8: Data</h3>
The frame of data to send as hex bytes. For example, to send a MAC ACK frame, enter "02 00 00". The MAC CRC should not be included, as this is calculated and appended automatically.
<h3>9: Repeat</h3>
Check this button to repeatedly transmit a frame. Right click to open the dialog to adjust the delay between retransmission and number of times the frame should be repeated.
<h3>10: TX</h3>
Transmits a frame containing the payload set in the data field.
<h2>API</h2>
Full details of the API can be found in the Swagger documentation. Here is a quick example of how to transmit a frame from the command line:
curl -X POST "http://127.0.0.1:8091/sdrangel/deviceset/1/channel/0/actions" -d '{"channelType": "IEEE_802_15_4_Mod", "direction": 1, "IEEE_802_15_4_ModActions": { "tx": { "data": "02 00 00" }}}'
Or to set the PHY to 20kbps BPSK:
curl -X PATCH "http://127.0.0.1:8091/sdrangel/deviceset/1/channel/0/settings" -d '{"channelType": "IEEE_802_15_4_Mod", "direction": 1, "IEEE_802_15_4_ModSettings": {"phy": "20kbps BPSK"}}'

View File

@ -34,10 +34,13 @@ public:
// beta - roll-off factor
// symbolSpan - number of symbols over which the filter is spread
// samplesPerSymbol - number of samples per symbol
void create(double beta, int symbolSpan, int samplesPerSymbol)
// normaliseUpsampledAmplitude - when true, scale the filter such that an upsampled
// (by samplesPerSymbol) bipolar sequence (E.g. [1 0 0 -1 0 0..]) has maximum
// output values close to (1,-1)
void create(double beta, int symbolSpan, int samplesPerSymbol, bool normaliseUpsampledAmplitude = false)
{
int nTaps = symbolSpan * samplesPerSymbol + 1;
int i;
int i, j;
// check constraints
if(!(nTaps & 1)) {
@ -72,13 +75,36 @@ public:
}
// normalize
double sum = 0;
for(i = 0; i < (int)m_taps.size() - 1; i++)
sum += std::pow(m_taps[i], 2.0) * 2;
sum += std::pow(m_taps[i], 2.0);
sum = std::sqrt(sum);
for(i = 0; i < (int)m_taps.size(); i++)
m_taps[i] /= sum;
if (!normaliseUpsampledAmplitude)
{
// normalize energy
double sum = 0;
for(i = 0; i < (int)m_taps.size() - 1; i++)
sum += std::pow(m_taps[i], 2.0) * 2;
sum += std::pow(m_taps[i], 2.0);
sum = std::sqrt(sum);
for(i = 0; i < (int)m_taps.size(); i++)
m_taps[i] /= sum;
}
else
{
// Calculate maximum output of filter, assuming upsampled bipolar input E.g. [1 0 0 -1 0 0..]
// This doesn't necessarily include the centre tap, so we try each offset
double maxGain = 0.0;
for (i = 0; i < samplesPerSymbol; i++)
{
double g = 0.0;
for (j = 0; j < (int)m_taps.size() - 1; j += samplesPerSymbol)
g += std::fabs(2.0 * m_taps[j]);
if ((i & 1) == 0)
g += std::fabs(m_taps[j]);
if (g > maxGain)
maxGain = g;
}
// Scale up so maximum out is 1
for(i = 0; i < (int)m_taps.size(); i++)
m_taps[i] /= maxGain;
}
}
Type filter(Type sample)

View File

@ -87,6 +87,12 @@ public:
crc16ccitt() : crc(16, 0x1021, true, 0xffff, 0) {}
};
class SDRBASE_API crc16itut : public crc
{
public:
crc16itut() : crc(16, 0x1021, false, 0x0000, 0) {}
};
class SDRBASE_API crc16x25 : public crc
{
public:

View File

@ -102,4 +102,12 @@ public:
RandomizeCCSDS() : LFSR(0x95, 0xff, 7) {}
};
// 802.15.4 GFSK PHY
// Call randomize()
class SDRBASE_API Randomize_802_15_4_PN9 : public LFSR
{
public:
Randomize_802_15_4_PN9() : LFSR(0x108, 0x1fe, 0) {}
};
#endif

View File

@ -80,6 +80,7 @@ const QMap<QString, QString> WebAPIRequestMapper::m_channelURIToSettingsKey = {
{"sdrangel.channel.localsink", "LocalSinkSettings"}, // remap
{"sdrangel.channel.localsource", "LocalSourceSettings"},
{"sdrangel.channeltx.modpacket", "PacketModSettings"},
{"sdrangel.channeltx.mod802.15.4", "IEEE_802_15_4_ModSettings"},
{"sdrangel.demod.remotesink", "RemoteSinkSettings"},
{"sdrangel.channeltx.remotesource", "RemoteSourceSettings"},
{"sdrangel.channeltx.modssb", "SSBModSettings"},
@ -148,6 +149,7 @@ const QMap<QString, QString> WebAPIRequestMapper::m_channelTypeToSettingsKey = {
{"FreeDVDemod", "FreeDVDemodSettings"},
{"FreeDVMod", "FreeDVModSettings"},
{"FreqTracker", "FreqTrackerSettings"},
{"IEEE_802_15_4_Mod", "IEEE_802_15_4_ModSettings"},
{"NFMDemod", "NFMDemodSettings"},
{"NFMMod", "NFMModSettings"},
{"PacketMod", "PacketModSettings"},
@ -166,6 +168,7 @@ const QMap<QString, QString> WebAPIRequestMapper::m_channelTypeToSettingsKey = {
const QMap<QString, QString> WebAPIRequestMapper::m_channelTypeToActionsKey = {
{"FileSink", "FileSinkActions"},
{"FileSource", "FileSourceActions"},
{"IEEE_802_15_4_Mod", "IEEE_802_15_4_ModActions"},
{"PacketMod", "PacketModActions"}
};
@ -3776,6 +3779,11 @@ bool WebAPIRequestMapper::getChannelSettings(
channelSettings->setFreqTrackerSettings(new SWGSDRangel::SWGFreqTrackerSettings());
channelSettings->getFreqTrackerSettings()->fromJsonObject(settingsJsonObject);
}
else if (channelSettingsKey == "IEEE_802_15_4_ModSettings")
{
channelSettings->setIeee802154ModSettings(new SWGSDRangel::SWGIEEE_802_15_4_ModSettings());
channelSettings->getIeee802154ModSettings()->fromJsonObject(settingsJsonObject);
}
else if (channelSettingsKey == "NFMDemodSettings")
{
channelSettings->setNfmDemodSettings(new SWGSDRangel::SWGNFMDemodSettings());
@ -3878,6 +3886,11 @@ bool WebAPIRequestMapper::getChannelActions(
channelActions->setFileSourceActions(new SWGSDRangel::SWGFileSourceActions());
channelActions->getFileSourceActions()->fromJsonObject(actionsJsonObject);
}
else if (channelActionsKey == "IEEE_802_15_4_ModActions")
{
channelActions->setIeee802154ModActions(new SWGSDRangel::SWGIEEE_802_15_4_ModActions());
channelActions->getIeee802154ModActions()->fromJsonObject(actionsJsonObject);
}
else if (channelActionsKey == "PacketModActions")
{
channelActions->setPacketModActions(new SWGSDRangel::SWGPacketModActions());
@ -4320,6 +4333,7 @@ void WebAPIRequestMapper::resetChannelSettings(SWGSDRangel::SWGChannelSettings&
channelSettings.setAtvModSettings(nullptr);
channelSettings.setBfmDemodSettings(nullptr);
channelSettings.setDsdDemodSettings(nullptr);
channelSettings.setIeee802154ModSettings(nullptr);
channelSettings.setNfmDemodSettings(nullptr);
channelSettings.setNfmModSettings(nullptr);
channelSettings.setPacketModSettings(nullptr);
@ -4344,6 +4358,7 @@ void WebAPIRequestMapper::resetChannelReport(SWGSDRangel::SWGChannelReport& chan
channelReport.setDsdDemodReport(nullptr);
channelReport.setNfmDemodReport(nullptr);
channelReport.setNfmModReport(nullptr);
channelReport.setIeee802154ModReport(nullptr);
channelReport.setPacketModReport(nullptr);
channelReport.setRemoteSourceReport(nullptr);
channelReport.setSsbDemodReport(nullptr);
@ -4359,6 +4374,7 @@ void WebAPIRequestMapper::resetChannelActions(SWGSDRangel::SWGChannelActions& ch
channelActions.cleanup();
channelActions.setChannelType(nullptr);
channelActions.setFileSourceActions(nullptr);
channelActions.setIeee802154ModActions(nullptr);
channelActions.setPacketModActions(nullptr);
}

View File

@ -21,5 +21,7 @@ ChannelActions:
$ref: "http://swgserver:8081/api/swagger/include/FileSink.yaml#/FileSinkActions"
FileSourceActions:
$ref: "http://swgserver:8081/api/swagger/include/FileSource.yaml#/FileSourceActions"
IEEE_802_15_4_ModActions:
$ref: "http://swgserver:8081/api/swagger/include/IEEE_802_15_4_Mod.yaml#/IEEE_802_15_4_ModActions"
PacketModActions:
$ref: "http://swgserver:8081/api/swagger/include/PacketMod.yaml#/PacketModActions"

View File

@ -21,6 +21,8 @@ ChannelReport:
$ref: "http://swgserver:8081/api/swagger/include/BFMDemod.yaml#/BFMDemodReport"
DSDDemodReport:
$ref: "http://swgserver:8081/api/swagger/include/DSDDemod.yaml#/DSDDemodReport"
IEEE_802_15_4_ModReport:
$ref: "http://swgserver:8081/api/swagger/include/IEEE_802_15_4_Mod.yaml#/IEEE_802_15_4_ModReport"
FileSinkReport:
$ref: "http://swgserver:8081/api/swagger/include/FileSink.yaml#/FileSinkReport"
FileSourceReport:

View File

@ -43,6 +43,8 @@ ChannelSettings:
$ref: "http://swgserver:8081/api/swagger/include/FreeDVMod.yaml#/FreeDVModSettings"
FreqTrackerSettings:
$ref: "http://swgserver:8081/api/swagger/include/FreqTracker.yaml#/FreqTrackerSettings"
IEEE_802_15_4_ModSettings:
$ref: "http://swgserver:8081/api/swagger/include/IEEE_802_15_4_Mod.yaml#/IEEE_802_15_4_ModSettings"
NFMDemodSettings:
$ref: "http://swgserver:8081/api/swagger/include/NFMDemod.yaml#/NFMDemodSettings"
NFMModSettings:

View File

@ -0,0 +1,67 @@
IEEE_802_15_4_ModSettings:
description: IEEE_802_15_4_Mod
properties:
inputFrequencyOffset:
type: integer
format: int64
phy:
description: Physical layer. "20kbps BPSK", "40kbps BPSK", "100kbps <1GHz O-QPSK", "250kbps <1GHz O-QPSK (Sine)", "250kbps <1GHz O-QPSK (RC)", or "250kbps >2GHz O-QPSK".
type: string
rfBandwidth:
type: number
format: float
gain:
type: number
format: float
channelMute:
type: integer
repeat:
description: Whether to repeated transmit the frame (1 for yes, 0 for no).
type: integer
repeatDelay:
description: Delay between repeated transmissions.
type: number
format: float
repeatCount:
description: Number of times to repeat the frame (-1 for infinite).
type: integer
rgbColor:
type: integer
title:
type: string
streamIndex:
description: MIMO channel. Not relevant when connected to SI (single Rx).
type: integer
useReverseAPI:
description: Synchronize with reverse API (1 for yes, 0 for no)
type: integer
reverseAPIAddress:
type: string
reverseAPIPort:
type: integer
reverseAPIDeviceIndex:
type: integer
reverseAPIChannelIndex:
type: integer
IEEE_802_15_4_ModReport:
description: IEEE_802_15_4_Mod
properties:
channelPowerDB:
description: power transmitted in channel (dB)
type: number
format: float
channelSampleRate:
type: integer
IEEE_802_15_4_ModActions:
description: IEEE_802_15_4_Mod
properties:
tx:
type: object
properties:
data:
description: Hex coded bytes of data to transmit, excluding CRC (E.g for an ACK - 02 00 00).
type: string
description: >
Transmit a frame

View File

@ -40,6 +40,8 @@ SWGChannelActions::SWGChannelActions() {
m_file_sink_actions_isSet = false;
file_source_actions = nullptr;
m_file_source_actions_isSet = false;
ieee_802_15_4_mod_actions = nullptr;
m_ieee_802_15_4_mod_actions_isSet = false;
packet_mod_actions = nullptr;
m_packet_mod_actions_isSet = false;
}
@ -62,6 +64,8 @@ SWGChannelActions::init() {
m_file_sink_actions_isSet = false;
file_source_actions = new SWGFileSourceActions();
m_file_source_actions_isSet = false;
ieee_802_15_4_mod_actions = new SWGIEEE_802_15_4_ModActions();
m_ieee_802_15_4_mod_actions_isSet = false;
packet_mod_actions = new SWGPacketModActions();
m_packet_mod_actions_isSet = false;
}
@ -80,6 +84,9 @@ SWGChannelActions::cleanup() {
if(file_source_actions != nullptr) {
delete file_source_actions;
}
if(ieee_802_15_4_mod_actions != nullptr) {
delete ieee_802_15_4_mod_actions;
}
if(packet_mod_actions != nullptr) {
delete packet_mod_actions;
}
@ -108,6 +115,8 @@ SWGChannelActions::fromJsonObject(QJsonObject &pJson) {
::SWGSDRangel::setValue(&file_source_actions, pJson["FileSourceActions"], "SWGFileSourceActions", "SWGFileSourceActions");
::SWGSDRangel::setValue(&ieee_802_15_4_mod_actions, pJson["IEEE_802_15_4_ModActions"], "SWGIEEE_802_15_4_ModActions", "SWGIEEE_802_15_4_ModActions");
::SWGSDRangel::setValue(&packet_mod_actions, pJson["PacketModActions"], "SWGPacketModActions", "SWGPacketModActions");
}
@ -144,6 +153,9 @@ SWGChannelActions::asJsonObject() {
if((file_source_actions != nullptr) && (file_source_actions->isSet())){
toJsonValue(QString("FileSourceActions"), file_source_actions, obj, QString("SWGFileSourceActions"));
}
if((ieee_802_15_4_mod_actions != nullptr) && (ieee_802_15_4_mod_actions->isSet())){
toJsonValue(QString("IEEE_802_15_4_ModActions"), ieee_802_15_4_mod_actions, obj, QString("SWGIEEE_802_15_4_ModActions"));
}
if((packet_mod_actions != nullptr) && (packet_mod_actions->isSet())){
toJsonValue(QString("PacketModActions"), packet_mod_actions, obj, QString("SWGPacketModActions"));
}
@ -211,6 +223,16 @@ SWGChannelActions::setFileSourceActions(SWGFileSourceActions* file_source_action
this->m_file_source_actions_isSet = true;
}
SWGIEEE_802_15_4_ModActions*
SWGChannelActions::getIeee802154ModActions() {
return ieee_802_15_4_mod_actions;
}
void
SWGChannelActions::setIeee802154ModActions(SWGIEEE_802_15_4_ModActions* ieee_802_15_4_mod_actions) {
this->ieee_802_15_4_mod_actions = ieee_802_15_4_mod_actions;
this->m_ieee_802_15_4_mod_actions_isSet = true;
}
SWGPacketModActions*
SWGChannelActions::getPacketModActions() {
return packet_mod_actions;
@ -244,6 +266,9 @@ SWGChannelActions::isSet(){
if(file_source_actions && file_source_actions->isSet()){
isObjectUpdated = true; break;
}
if(ieee_802_15_4_mod_actions && ieee_802_15_4_mod_actions->isSet()){
isObjectUpdated = true; break;
}
if(packet_mod_actions && packet_mod_actions->isSet()){
isObjectUpdated = true; break;
}

View File

@ -24,6 +24,7 @@
#include "SWGFileSinkActions.h"
#include "SWGFileSourceActions.h"
#include "SWGIEEE_802_15_4_ModActions.h"
#include "SWGPacketModActions.h"
#include <QString>
@ -63,6 +64,9 @@ public:
SWGFileSourceActions* getFileSourceActions();
void setFileSourceActions(SWGFileSourceActions* file_source_actions);
SWGIEEE_802_15_4_ModActions* getIeee802154ModActions();
void setIeee802154ModActions(SWGIEEE_802_15_4_ModActions* ieee_802_15_4_mod_actions);
SWGPacketModActions* getPacketModActions();
void setPacketModActions(SWGPacketModActions* packet_mod_actions);
@ -88,6 +92,9 @@ private:
SWGFileSourceActions* file_source_actions;
bool m_file_source_actions_isSet;
SWGIEEE_802_15_4_ModActions* ieee_802_15_4_mod_actions;
bool m_ieee_802_15_4_mod_actions_isSet;
SWGPacketModActions* packet_mod_actions;
bool m_packet_mod_actions_isSet;

View File

@ -42,6 +42,8 @@ SWGChannelReport::SWGChannelReport() {
m_bfm_demod_report_isSet = false;
dsd_demod_report = nullptr;
m_dsd_demod_report_isSet = false;
ieee_802_15_4_mod_report = nullptr;
m_ieee_802_15_4_mod_report_isSet = false;
file_sink_report = nullptr;
m_file_sink_report_isSet = false;
file_source_report = nullptr;
@ -94,6 +96,8 @@ SWGChannelReport::init() {
m_bfm_demod_report_isSet = false;
dsd_demod_report = new SWGDSDDemodReport();
m_dsd_demod_report_isSet = false;
ieee_802_15_4_mod_report = new SWGIEEE_802_15_4_ModReport();
m_ieee_802_15_4_mod_report_isSet = false;
file_sink_report = new SWGFileSinkReport();
m_file_sink_report_isSet = false;
file_source_report = new SWGFileSourceReport();
@ -147,6 +151,9 @@ SWGChannelReport::cleanup() {
if(dsd_demod_report != nullptr) {
delete dsd_demod_report;
}
if(ieee_802_15_4_mod_report != nullptr) {
delete ieee_802_15_4_mod_report;
}
if(file_sink_report != nullptr) {
delete file_sink_report;
}
@ -219,6 +226,8 @@ SWGChannelReport::fromJsonObject(QJsonObject &pJson) {
::SWGSDRangel::setValue(&dsd_demod_report, pJson["DSDDemodReport"], "SWGDSDDemodReport", "SWGDSDDemodReport");
::SWGSDRangel::setValue(&ieee_802_15_4_mod_report, pJson["IEEE_802_15_4_ModReport"], "SWGIEEE_802_15_4_ModReport", "SWGIEEE_802_15_4_ModReport");
::SWGSDRangel::setValue(&file_sink_report, pJson["FileSinkReport"], "SWGFileSinkReport", "SWGFileSinkReport");
::SWGSDRangel::setValue(&file_source_report, pJson["FileSourceReport"], "SWGFileSourceReport", "SWGFileSourceReport");
@ -286,6 +295,9 @@ SWGChannelReport::asJsonObject() {
if((dsd_demod_report != nullptr) && (dsd_demod_report->isSet())){
toJsonValue(QString("DSDDemodReport"), dsd_demod_report, obj, QString("SWGDSDDemodReport"));
}
if((ieee_802_15_4_mod_report != nullptr) && (ieee_802_15_4_mod_report->isSet())){
toJsonValue(QString("IEEE_802_15_4_ModReport"), ieee_802_15_4_mod_report, obj, QString("SWGIEEE_802_15_4_ModReport"));
}
if((file_sink_report != nullptr) && (file_sink_report->isSet())){
toJsonValue(QString("FileSinkReport"), file_sink_report, obj, QString("SWGFileSinkReport"));
}
@ -405,6 +417,16 @@ SWGChannelReport::setDsdDemodReport(SWGDSDDemodReport* dsd_demod_report) {
this->m_dsd_demod_report_isSet = true;
}
SWGIEEE_802_15_4_ModReport*
SWGChannelReport::getIeee802154ModReport() {
return ieee_802_15_4_mod_report;
}
void
SWGChannelReport::setIeee802154ModReport(SWGIEEE_802_15_4_ModReport* ieee_802_15_4_mod_report) {
this->ieee_802_15_4_mod_report = ieee_802_15_4_mod_report;
this->m_ieee_802_15_4_mod_report_isSet = true;
}
SWGFileSinkReport*
SWGChannelReport::getFileSinkReport() {
return file_sink_report;
@ -581,6 +603,9 @@ SWGChannelReport::isSet(){
if(dsd_demod_report && dsd_demod_report->isSet()){
isObjectUpdated = true; break;
}
if(ieee_802_15_4_mod_report && ieee_802_15_4_mod_report->isSet()){
isObjectUpdated = true; break;
}
if(file_sink_report && file_sink_report->isSet()){
isObjectUpdated = true; break;
}

View File

@ -32,6 +32,7 @@
#include "SWGFreeDVDemodReport.h"
#include "SWGFreeDVModReport.h"
#include "SWGFreqTrackerReport.h"
#include "SWGIEEE_802_15_4_ModReport.h"
#include "SWGNFMDemodReport.h"
#include "SWGNFMModReport.h"
#include "SWGPacketModReport.h"
@ -83,6 +84,9 @@ public:
SWGDSDDemodReport* getDsdDemodReport();
void setDsdDemodReport(SWGDSDDemodReport* dsd_demod_report);
SWGIEEE_802_15_4_ModReport* getIeee802154ModReport();
void setIeee802154ModReport(SWGIEEE_802_15_4_ModReport* ieee_802_15_4_mod_report);
SWGFileSinkReport* getFileSinkReport();
void setFileSinkReport(SWGFileSinkReport* file_sink_report);
@ -153,6 +157,9 @@ private:
SWGDSDDemodReport* dsd_demod_report;
bool m_dsd_demod_report_isSet;
SWGIEEE_802_15_4_ModReport* ieee_802_15_4_mod_report;
bool m_ieee_802_15_4_mod_report_isSet;
SWGFileSinkReport* file_sink_report;
bool m_file_sink_report_isSet;

View File

@ -62,6 +62,8 @@ SWGChannelSettings::SWGChannelSettings() {
m_free_dv_mod_settings_isSet = false;
freq_tracker_settings = nullptr;
m_freq_tracker_settings_isSet = false;
ieee_802_15_4_mod_settings = nullptr;
m_ieee_802_15_4_mod_settings_isSet = false;
nfm_demod_settings = nullptr;
m_nfm_demod_settings_isSet = false;
nfm_mod_settings = nullptr;
@ -130,6 +132,8 @@ SWGChannelSettings::init() {
m_free_dv_mod_settings_isSet = false;
freq_tracker_settings = new SWGFreqTrackerSettings();
m_freq_tracker_settings_isSet = false;
ieee_802_15_4_mod_settings = new SWGIEEE_802_15_4_ModSettings();
m_ieee_802_15_4_mod_settings_isSet = false;
nfm_demod_settings = new SWGNFMDemodSettings();
m_nfm_demod_settings_isSet = false;
nfm_mod_settings = new SWGNFMModSettings();
@ -205,6 +209,9 @@ SWGChannelSettings::cleanup() {
if(freq_tracker_settings != nullptr) {
delete freq_tracker_settings;
}
if(ieee_802_15_4_mod_settings != nullptr) {
delete ieee_802_15_4_mod_settings;
}
if(nfm_demod_settings != nullptr) {
delete nfm_demod_settings;
}
@ -291,6 +298,8 @@ SWGChannelSettings::fromJsonObject(QJsonObject &pJson) {
::SWGSDRangel::setValue(&freq_tracker_settings, pJson["FreqTrackerSettings"], "SWGFreqTrackerSettings", "SWGFreqTrackerSettings");
::SWGSDRangel::setValue(&ieee_802_15_4_mod_settings, pJson["IEEE_802_15_4_ModSettings"], "SWGIEEE_802_15_4_ModSettings", "SWGIEEE_802_15_4_ModSettings");
::SWGSDRangel::setValue(&nfm_demod_settings, pJson["NFMDemodSettings"], "SWGNFMDemodSettings", "SWGNFMDemodSettings");
::SWGSDRangel::setValue(&nfm_mod_settings, pJson["NFMModSettings"], "SWGNFMModSettings", "SWGNFMModSettings");
@ -384,6 +393,9 @@ SWGChannelSettings::asJsonObject() {
if((freq_tracker_settings != nullptr) && (freq_tracker_settings->isSet())){
toJsonValue(QString("FreqTrackerSettings"), freq_tracker_settings, obj, QString("SWGFreqTrackerSettings"));
}
if((ieee_802_15_4_mod_settings != nullptr) && (ieee_802_15_4_mod_settings->isSet())){
toJsonValue(QString("IEEE_802_15_4_ModSettings"), ieee_802_15_4_mod_settings, obj, QString("SWGIEEE_802_15_4_ModSettings"));
}
if((nfm_demod_settings != nullptr) && (nfm_demod_settings->isSet())){
toJsonValue(QString("NFMDemodSettings"), nfm_demod_settings, obj, QString("SWGNFMDemodSettings"));
}
@ -597,6 +609,16 @@ SWGChannelSettings::setFreqTrackerSettings(SWGFreqTrackerSettings* freq_tracker_
this->m_freq_tracker_settings_isSet = true;
}
SWGIEEE_802_15_4_ModSettings*
SWGChannelSettings::getIeee802154ModSettings() {
return ieee_802_15_4_mod_settings;
}
void
SWGChannelSettings::setIeee802154ModSettings(SWGIEEE_802_15_4_ModSettings* ieee_802_15_4_mod_settings) {
this->ieee_802_15_4_mod_settings = ieee_802_15_4_mod_settings;
this->m_ieee_802_15_4_mod_settings_isSet = true;
}
SWGNFMDemodSettings*
SWGChannelSettings::getNfmDemodSettings() {
return nfm_demod_settings;
@ -783,6 +805,9 @@ SWGChannelSettings::isSet(){
if(freq_tracker_settings && freq_tracker_settings->isSet()){
isObjectUpdated = true; break;
}
if(ieee_802_15_4_mod_settings && ieee_802_15_4_mod_settings->isSet()){
isObjectUpdated = true; break;
}
if(nfm_demod_settings && nfm_demod_settings->isSet()){
isObjectUpdated = true; break;
}

View File

@ -35,6 +35,7 @@
#include "SWGFreeDVDemodSettings.h"
#include "SWGFreeDVModSettings.h"
#include "SWGFreqTrackerSettings.h"
#include "SWGIEEE_802_15_4_ModSettings.h"
#include "SWGLocalSinkSettings.h"
#include "SWGLocalSourceSettings.h"
#include "SWGNFMDemodSettings.h"
@ -119,6 +120,9 @@ public:
SWGFreqTrackerSettings* getFreqTrackerSettings();
void setFreqTrackerSettings(SWGFreqTrackerSettings* freq_tracker_settings);
SWGIEEE_802_15_4_ModSettings* getIeee802154ModSettings();
void setIeee802154ModSettings(SWGIEEE_802_15_4_ModSettings* ieee_802_15_4_mod_settings);
SWGNFMDemodSettings* getNfmDemodSettings();
void setNfmDemodSettings(SWGNFMDemodSettings* nfm_demod_settings);
@ -213,6 +217,9 @@ private:
SWGFreqTrackerSettings* freq_tracker_settings;
bool m_freq_tracker_settings_isSet;
SWGIEEE_802_15_4_ModSettings* ieee_802_15_4_mod_settings;
bool m_ieee_802_15_4_mod_settings_isSet;
SWGNFMDemodSettings* nfm_demod_settings;
bool m_nfm_demod_settings_isSet;

View File

@ -0,0 +1,110 @@
/**
* SDRangel
* This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1, USRP and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time ---
*
* OpenAPI spec version: 4.15.0
* Contact: f4exb06@gmail.com
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
#include "SWGIEEE_802_15_4_ModActions.h"
#include "SWGHelpers.h"
#include <QJsonDocument>
#include <QJsonArray>
#include <QObject>
#include <QDebug>
namespace SWGSDRangel {
SWGIEEE_802_15_4_ModActions::SWGIEEE_802_15_4_ModActions(QString* json) {
init();
this->fromJson(*json);
}
SWGIEEE_802_15_4_ModActions::SWGIEEE_802_15_4_ModActions() {
tx = nullptr;
m_tx_isSet = false;
}
SWGIEEE_802_15_4_ModActions::~SWGIEEE_802_15_4_ModActions() {
this->cleanup();
}
void
SWGIEEE_802_15_4_ModActions::init() {
tx = new SWGIEEE_802_15_4_ModActions_tx();
m_tx_isSet = false;
}
void
SWGIEEE_802_15_4_ModActions::cleanup() {
if(tx != nullptr) {
delete tx;
}
}
SWGIEEE_802_15_4_ModActions*
SWGIEEE_802_15_4_ModActions::fromJson(QString &json) {
QByteArray array (json.toStdString().c_str());
QJsonDocument doc = QJsonDocument::fromJson(array);
QJsonObject jsonObject = doc.object();
this->fromJsonObject(jsonObject);
return this;
}
void
SWGIEEE_802_15_4_ModActions::fromJsonObject(QJsonObject &pJson) {
::SWGSDRangel::setValue(&tx, pJson["tx"], "SWGIEEE_802_15_4_ModActions_tx", "SWGIEEE_802_15_4_ModActions_tx");
}
QString
SWGIEEE_802_15_4_ModActions::asJson ()
{
QJsonObject* obj = this->asJsonObject();
QJsonDocument doc(*obj);
QByteArray bytes = doc.toJson();
delete obj;
return QString(bytes);
}
QJsonObject*
SWGIEEE_802_15_4_ModActions::asJsonObject() {
QJsonObject* obj = new QJsonObject();
if((tx != nullptr) && (tx->isSet())){
toJsonValue(QString("tx"), tx, obj, QString("SWGIEEE_802_15_4_ModActions_tx"));
}
return obj;
}
SWGIEEE_802_15_4_ModActions_tx*
SWGIEEE_802_15_4_ModActions::getTx() {
return tx;
}
void
SWGIEEE_802_15_4_ModActions::setTx(SWGIEEE_802_15_4_ModActions_tx* tx) {
this->tx = tx;
this->m_tx_isSet = true;
}
bool
SWGIEEE_802_15_4_ModActions::isSet(){
bool isObjectUpdated = false;
do{
if(tx && tx->isSet()){
isObjectUpdated = true; break;
}
}while(false);
return isObjectUpdated;
}
}

View File

@ -0,0 +1,59 @@
/**
* SDRangel
* This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1, USRP and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time ---
*
* OpenAPI spec version: 4.15.0
* Contact: f4exb06@gmail.com
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
/*
* SWGIEEE_802_15_4_ModActions.h
*
* IEEE_802_15_4_Mod
*/
#ifndef SWGIEEE_802_15_4_ModActions_H_
#define SWGIEEE_802_15_4_ModActions_H_
#include <QJsonObject>
#include "SWGIEEE_802_15_4_ModActions_tx.h"
#include "SWGObject.h"
#include "export.h"
namespace SWGSDRangel {
class SWG_API SWGIEEE_802_15_4_ModActions: public SWGObject {
public:
SWGIEEE_802_15_4_ModActions();
SWGIEEE_802_15_4_ModActions(QString* json);
virtual ~SWGIEEE_802_15_4_ModActions();
void init();
void cleanup();
virtual QString asJson () override;
virtual QJsonObject* asJsonObject() override;
virtual void fromJsonObject(QJsonObject &json) override;
virtual SWGIEEE_802_15_4_ModActions* fromJson(QString &jsonString) override;
SWGIEEE_802_15_4_ModActions_tx* getTx();
void setTx(SWGIEEE_802_15_4_ModActions_tx* tx);
virtual bool isSet() override;
private:
SWGIEEE_802_15_4_ModActions_tx* tx;
bool m_tx_isSet;
};
}
#endif /* SWGIEEE_802_15_4_ModActions_H_ */

View File

@ -0,0 +1,110 @@
/**
* SDRangel
* This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1, USRP and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time ---
*
* OpenAPI spec version: 4.15.0
* Contact: f4exb06@gmail.com
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
#include "SWGIEEE_802_15_4_ModActions_tx.h"
#include "SWGHelpers.h"
#include <QJsonDocument>
#include <QJsonArray>
#include <QObject>
#include <QDebug>
namespace SWGSDRangel {
SWGIEEE_802_15_4_ModActions_tx::SWGIEEE_802_15_4_ModActions_tx(QString* json) {
init();
this->fromJson(*json);
}
SWGIEEE_802_15_4_ModActions_tx::SWGIEEE_802_15_4_ModActions_tx() {
data = nullptr;
m_data_isSet = false;
}
SWGIEEE_802_15_4_ModActions_tx::~SWGIEEE_802_15_4_ModActions_tx() {
this->cleanup();
}
void
SWGIEEE_802_15_4_ModActions_tx::init() {
data = new QString("");
m_data_isSet = false;
}
void
SWGIEEE_802_15_4_ModActions_tx::cleanup() {
if(data != nullptr) {
delete data;
}
}
SWGIEEE_802_15_4_ModActions_tx*
SWGIEEE_802_15_4_ModActions_tx::fromJson(QString &json) {
QByteArray array (json.toStdString().c_str());
QJsonDocument doc = QJsonDocument::fromJson(array);
QJsonObject jsonObject = doc.object();
this->fromJsonObject(jsonObject);
return this;
}
void
SWGIEEE_802_15_4_ModActions_tx::fromJsonObject(QJsonObject &pJson) {
::SWGSDRangel::setValue(&data, pJson["data"], "QString", "QString");
}
QString
SWGIEEE_802_15_4_ModActions_tx::asJson ()
{
QJsonObject* obj = this->asJsonObject();
QJsonDocument doc(*obj);
QByteArray bytes = doc.toJson();
delete obj;
return QString(bytes);
}
QJsonObject*
SWGIEEE_802_15_4_ModActions_tx::asJsonObject() {
QJsonObject* obj = new QJsonObject();
if(data != nullptr && *data != QString("")){
toJsonValue(QString("data"), data, obj, QString("QString"));
}
return obj;
}
QString*
SWGIEEE_802_15_4_ModActions_tx::getData() {
return data;
}
void
SWGIEEE_802_15_4_ModActions_tx::setData(QString* data) {
this->data = data;
this->m_data_isSet = true;
}
bool
SWGIEEE_802_15_4_ModActions_tx::isSet(){
bool isObjectUpdated = false;
do{
if(data && *data != QString("")){
isObjectUpdated = true; break;
}
}while(false);
return isObjectUpdated;
}
}

View File

@ -0,0 +1,59 @@
/**
* SDRangel
* This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1, USRP and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time ---
*
* OpenAPI spec version: 4.15.0
* Contact: f4exb06@gmail.com
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
/*
* SWGIEEE_802_15_4_ModActions_tx.h
*
* Transmit a frame
*/
#ifndef SWGIEEE_802_15_4_ModActions_tx_H_
#define SWGIEEE_802_15_4_ModActions_tx_H_
#include <QJsonObject>
#include <QString>
#include "SWGObject.h"
#include "export.h"
namespace SWGSDRangel {
class SWG_API SWGIEEE_802_15_4_ModActions_tx: public SWGObject {
public:
SWGIEEE_802_15_4_ModActions_tx();
SWGIEEE_802_15_4_ModActions_tx(QString* json);
virtual ~SWGIEEE_802_15_4_ModActions_tx();
void init();
void cleanup();
virtual QString asJson () override;
virtual QJsonObject* asJsonObject() override;
virtual void fromJsonObject(QJsonObject &json) override;
virtual SWGIEEE_802_15_4_ModActions_tx* fromJson(QString &jsonString) override;
QString* getData();
void setData(QString* data);
virtual bool isSet() override;
private:
QString* data;
bool m_data_isSet;
};
}
#endif /* SWGIEEE_802_15_4_ModActions_tx_H_ */

View File

@ -0,0 +1,131 @@
/**
* SDRangel
* This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1, USRP and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time ---
*
* OpenAPI spec version: 4.15.0
* Contact: f4exb06@gmail.com
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
#include "SWGIEEE_802_15_4_ModReport.h"
#include "SWGHelpers.h"
#include <QJsonDocument>
#include <QJsonArray>
#include <QObject>
#include <QDebug>
namespace SWGSDRangel {
SWGIEEE_802_15_4_ModReport::SWGIEEE_802_15_4_ModReport(QString* json) {
init();
this->fromJson(*json);
}
SWGIEEE_802_15_4_ModReport::SWGIEEE_802_15_4_ModReport() {
channel_power_db = 0.0f;
m_channel_power_db_isSet = false;
channel_sample_rate = 0;
m_channel_sample_rate_isSet = false;
}
SWGIEEE_802_15_4_ModReport::~SWGIEEE_802_15_4_ModReport() {
this->cleanup();
}
void
SWGIEEE_802_15_4_ModReport::init() {
channel_power_db = 0.0f;
m_channel_power_db_isSet = false;
channel_sample_rate = 0;
m_channel_sample_rate_isSet = false;
}
void
SWGIEEE_802_15_4_ModReport::cleanup() {
}
SWGIEEE_802_15_4_ModReport*
SWGIEEE_802_15_4_ModReport::fromJson(QString &json) {
QByteArray array (json.toStdString().c_str());
QJsonDocument doc = QJsonDocument::fromJson(array);
QJsonObject jsonObject = doc.object();
this->fromJsonObject(jsonObject);
return this;
}
void
SWGIEEE_802_15_4_ModReport::fromJsonObject(QJsonObject &pJson) {
::SWGSDRangel::setValue(&channel_power_db, pJson["channelPowerDB"], "float", "");
::SWGSDRangel::setValue(&channel_sample_rate, pJson["channelSampleRate"], "qint32", "");
}
QString
SWGIEEE_802_15_4_ModReport::asJson ()
{
QJsonObject* obj = this->asJsonObject();
QJsonDocument doc(*obj);
QByteArray bytes = doc.toJson();
delete obj;
return QString(bytes);
}
QJsonObject*
SWGIEEE_802_15_4_ModReport::asJsonObject() {
QJsonObject* obj = new QJsonObject();
if(m_channel_power_db_isSet){
obj->insert("channelPowerDB", QJsonValue(channel_power_db));
}
if(m_channel_sample_rate_isSet){
obj->insert("channelSampleRate", QJsonValue(channel_sample_rate));
}
return obj;
}
float
SWGIEEE_802_15_4_ModReport::getChannelPowerDb() {
return channel_power_db;
}
void
SWGIEEE_802_15_4_ModReport::setChannelPowerDb(float channel_power_db) {
this->channel_power_db = channel_power_db;
this->m_channel_power_db_isSet = true;
}
qint32
SWGIEEE_802_15_4_ModReport::getChannelSampleRate() {
return channel_sample_rate;
}
void
SWGIEEE_802_15_4_ModReport::setChannelSampleRate(qint32 channel_sample_rate) {
this->channel_sample_rate = channel_sample_rate;
this->m_channel_sample_rate_isSet = true;
}
bool
SWGIEEE_802_15_4_ModReport::isSet(){
bool isObjectUpdated = false;
do{
if(m_channel_power_db_isSet){
isObjectUpdated = true; break;
}
if(m_channel_sample_rate_isSet){
isObjectUpdated = true; break;
}
}while(false);
return isObjectUpdated;
}
}

View File

@ -0,0 +1,64 @@
/**
* SDRangel
* This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1, USRP and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time ---
*
* OpenAPI spec version: 4.15.0
* Contact: f4exb06@gmail.com
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
/*
* SWGIEEE_802_15_4_ModReport.h
*
* IEEE_802_15_4_Mod
*/
#ifndef SWGIEEE_802_15_4_ModReport_H_
#define SWGIEEE_802_15_4_ModReport_H_
#include <QJsonObject>
#include "SWGObject.h"
#include "export.h"
namespace SWGSDRangel {
class SWG_API SWGIEEE_802_15_4_ModReport: public SWGObject {
public:
SWGIEEE_802_15_4_ModReport();
SWGIEEE_802_15_4_ModReport(QString* json);
virtual ~SWGIEEE_802_15_4_ModReport();
void init();
void cleanup();
virtual QString asJson () override;
virtual QJsonObject* asJsonObject() override;
virtual void fromJsonObject(QJsonObject &json) override;
virtual SWGIEEE_802_15_4_ModReport* fromJson(QString &jsonString) override;
float getChannelPowerDb();
void setChannelPowerDb(float channel_power_db);
qint32 getChannelSampleRate();
void setChannelSampleRate(qint32 channel_sample_rate);
virtual bool isSet() override;
private:
float channel_power_db;
bool m_channel_power_db_isSet;
qint32 channel_sample_rate;
bool m_channel_sample_rate_isSet;
};
}
#endif /* SWGIEEE_802_15_4_ModReport_H_ */

View File

@ -0,0 +1,459 @@
/**
* SDRangel
* This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1, USRP and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time ---
*
* OpenAPI spec version: 4.15.0
* Contact: f4exb06@gmail.com
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
#include "SWGIEEE_802_15_4_ModSettings.h"
#include "SWGHelpers.h"
#include <QJsonDocument>
#include <QJsonArray>
#include <QObject>
#include <QDebug>
namespace SWGSDRangel {
SWGIEEE_802_15_4_ModSettings::SWGIEEE_802_15_4_ModSettings(QString* json) {
init();
this->fromJson(*json);
}
SWGIEEE_802_15_4_ModSettings::SWGIEEE_802_15_4_ModSettings() {
input_frequency_offset = 0L;
m_input_frequency_offset_isSet = false;
phy = nullptr;
m_phy_isSet = false;
rf_bandwidth = 0.0f;
m_rf_bandwidth_isSet = false;
gain = 0.0f;
m_gain_isSet = false;
channel_mute = 0;
m_channel_mute_isSet = false;
repeat = 0;
m_repeat_isSet = false;
repeat_delay = 0.0f;
m_repeat_delay_isSet = false;
repeat_count = 0;
m_repeat_count_isSet = false;
rgb_color = 0;
m_rgb_color_isSet = false;
title = nullptr;
m_title_isSet = false;
stream_index = 0;
m_stream_index_isSet = false;
use_reverse_api = 0;
m_use_reverse_api_isSet = false;
reverse_api_address = nullptr;
m_reverse_api_address_isSet = false;
reverse_api_port = 0;
m_reverse_api_port_isSet = false;
reverse_api_device_index = 0;
m_reverse_api_device_index_isSet = false;
reverse_api_channel_index = 0;
m_reverse_api_channel_index_isSet = false;
}
SWGIEEE_802_15_4_ModSettings::~SWGIEEE_802_15_4_ModSettings() {
this->cleanup();
}
void
SWGIEEE_802_15_4_ModSettings::init() {
input_frequency_offset = 0L;
m_input_frequency_offset_isSet = false;
phy = new QString("");
m_phy_isSet = false;
rf_bandwidth = 0.0f;
m_rf_bandwidth_isSet = false;
gain = 0.0f;
m_gain_isSet = false;
channel_mute = 0;
m_channel_mute_isSet = false;
repeat = 0;
m_repeat_isSet = false;
repeat_delay = 0.0f;
m_repeat_delay_isSet = false;
repeat_count = 0;
m_repeat_count_isSet = false;
rgb_color = 0;
m_rgb_color_isSet = false;
title = new QString("");
m_title_isSet = false;
stream_index = 0;
m_stream_index_isSet = false;
use_reverse_api = 0;
m_use_reverse_api_isSet = false;
reverse_api_address = new QString("");
m_reverse_api_address_isSet = false;
reverse_api_port = 0;
m_reverse_api_port_isSet = false;
reverse_api_device_index = 0;
m_reverse_api_device_index_isSet = false;
reverse_api_channel_index = 0;
m_reverse_api_channel_index_isSet = false;
}
void
SWGIEEE_802_15_4_ModSettings::cleanup() {
if(phy != nullptr) {
delete phy;
}
if(title != nullptr) {
delete title;
}
if(reverse_api_address != nullptr) {
delete reverse_api_address;
}
}
SWGIEEE_802_15_4_ModSettings*
SWGIEEE_802_15_4_ModSettings::fromJson(QString &json) {
QByteArray array (json.toStdString().c_str());
QJsonDocument doc = QJsonDocument::fromJson(array);
QJsonObject jsonObject = doc.object();
this->fromJsonObject(jsonObject);
return this;
}
void
SWGIEEE_802_15_4_ModSettings::fromJsonObject(QJsonObject &pJson) {
::SWGSDRangel::setValue(&input_frequency_offset, pJson["inputFrequencyOffset"], "qint64", "");
::SWGSDRangel::setValue(&phy, pJson["phy"], "QString", "QString");
::SWGSDRangel::setValue(&rf_bandwidth, pJson["rfBandwidth"], "float", "");
::SWGSDRangel::setValue(&gain, pJson["gain"], "float", "");
::SWGSDRangel::setValue(&channel_mute, pJson["channelMute"], "qint32", "");
::SWGSDRangel::setValue(&repeat, pJson["repeat"], "qint32", "");
::SWGSDRangel::setValue(&repeat_delay, pJson["repeatDelay"], "float", "");
::SWGSDRangel::setValue(&repeat_count, pJson["repeatCount"], "qint32", "");
::SWGSDRangel::setValue(&rgb_color, pJson["rgbColor"], "qint32", "");
::SWGSDRangel::setValue(&title, pJson["title"], "QString", "QString");
::SWGSDRangel::setValue(&stream_index, pJson["streamIndex"], "qint32", "");
::SWGSDRangel::setValue(&use_reverse_api, pJson["useReverseAPI"], "qint32", "");
::SWGSDRangel::setValue(&reverse_api_address, pJson["reverseAPIAddress"], "QString", "QString");
::SWGSDRangel::setValue(&reverse_api_port, pJson["reverseAPIPort"], "qint32", "");
::SWGSDRangel::setValue(&reverse_api_device_index, pJson["reverseAPIDeviceIndex"], "qint32", "");
::SWGSDRangel::setValue(&reverse_api_channel_index, pJson["reverseAPIChannelIndex"], "qint32", "");
}
QString
SWGIEEE_802_15_4_ModSettings::asJson ()
{
QJsonObject* obj = this->asJsonObject();
QJsonDocument doc(*obj);
QByteArray bytes = doc.toJson();
delete obj;
return QString(bytes);
}
QJsonObject*
SWGIEEE_802_15_4_ModSettings::asJsonObject() {
QJsonObject* obj = new QJsonObject();
if(m_input_frequency_offset_isSet){
obj->insert("inputFrequencyOffset", QJsonValue(input_frequency_offset));
}
if(phy != nullptr && *phy != QString("")){
toJsonValue(QString("phy"), phy, obj, QString("QString"));
}
if(m_rf_bandwidth_isSet){
obj->insert("rfBandwidth", QJsonValue(rf_bandwidth));
}
if(m_gain_isSet){
obj->insert("gain", QJsonValue(gain));
}
if(m_channel_mute_isSet){
obj->insert("channelMute", QJsonValue(channel_mute));
}
if(m_repeat_isSet){
obj->insert("repeat", QJsonValue(repeat));
}
if(m_repeat_delay_isSet){
obj->insert("repeatDelay", QJsonValue(repeat_delay));
}
if(m_repeat_count_isSet){
obj->insert("repeatCount", QJsonValue(repeat_count));
}
if(m_rgb_color_isSet){
obj->insert("rgbColor", QJsonValue(rgb_color));
}
if(title != nullptr && *title != QString("")){
toJsonValue(QString("title"), title, obj, QString("QString"));
}
if(m_stream_index_isSet){
obj->insert("streamIndex", QJsonValue(stream_index));
}
if(m_use_reverse_api_isSet){
obj->insert("useReverseAPI", QJsonValue(use_reverse_api));
}
if(reverse_api_address != nullptr && *reverse_api_address != QString("")){
toJsonValue(QString("reverseAPIAddress"), reverse_api_address, obj, QString("QString"));
}
if(m_reverse_api_port_isSet){
obj->insert("reverseAPIPort", QJsonValue(reverse_api_port));
}
if(m_reverse_api_device_index_isSet){
obj->insert("reverseAPIDeviceIndex", QJsonValue(reverse_api_device_index));
}
if(m_reverse_api_channel_index_isSet){
obj->insert("reverseAPIChannelIndex", QJsonValue(reverse_api_channel_index));
}
return obj;
}
qint64
SWGIEEE_802_15_4_ModSettings::getInputFrequencyOffset() {
return input_frequency_offset;
}
void
SWGIEEE_802_15_4_ModSettings::setInputFrequencyOffset(qint64 input_frequency_offset) {
this->input_frequency_offset = input_frequency_offset;
this->m_input_frequency_offset_isSet = true;
}
QString*
SWGIEEE_802_15_4_ModSettings::getPhy() {
return phy;
}
void
SWGIEEE_802_15_4_ModSettings::setPhy(QString* phy) {
this->phy = phy;
this->m_phy_isSet = true;
}
float
SWGIEEE_802_15_4_ModSettings::getRfBandwidth() {
return rf_bandwidth;
}
void
SWGIEEE_802_15_4_ModSettings::setRfBandwidth(float rf_bandwidth) {
this->rf_bandwidth = rf_bandwidth;
this->m_rf_bandwidth_isSet = true;
}
float
SWGIEEE_802_15_4_ModSettings::getGain() {
return gain;
}
void
SWGIEEE_802_15_4_ModSettings::setGain(float gain) {
this->gain = gain;
this->m_gain_isSet = true;
}
qint32
SWGIEEE_802_15_4_ModSettings::getChannelMute() {
return channel_mute;
}
void
SWGIEEE_802_15_4_ModSettings::setChannelMute(qint32 channel_mute) {
this->channel_mute = channel_mute;
this->m_channel_mute_isSet = true;
}
qint32
SWGIEEE_802_15_4_ModSettings::getRepeat() {
return repeat;
}
void
SWGIEEE_802_15_4_ModSettings::setRepeat(qint32 repeat) {
this->repeat = repeat;
this->m_repeat_isSet = true;
}
float
SWGIEEE_802_15_4_ModSettings::getRepeatDelay() {
return repeat_delay;
}
void
SWGIEEE_802_15_4_ModSettings::setRepeatDelay(float repeat_delay) {
this->repeat_delay = repeat_delay;
this->m_repeat_delay_isSet = true;
}
qint32
SWGIEEE_802_15_4_ModSettings::getRepeatCount() {
return repeat_count;
}
void
SWGIEEE_802_15_4_ModSettings::setRepeatCount(qint32 repeat_count) {
this->repeat_count = repeat_count;
this->m_repeat_count_isSet = true;
}
qint32
SWGIEEE_802_15_4_ModSettings::getRgbColor() {
return rgb_color;
}
void
SWGIEEE_802_15_4_ModSettings::setRgbColor(qint32 rgb_color) {
this->rgb_color = rgb_color;
this->m_rgb_color_isSet = true;
}
QString*
SWGIEEE_802_15_4_ModSettings::getTitle() {
return title;
}
void
SWGIEEE_802_15_4_ModSettings::setTitle(QString* title) {
this->title = title;
this->m_title_isSet = true;
}
qint32
SWGIEEE_802_15_4_ModSettings::getStreamIndex() {
return stream_index;
}
void
SWGIEEE_802_15_4_ModSettings::setStreamIndex(qint32 stream_index) {
this->stream_index = stream_index;
this->m_stream_index_isSet = true;
}
qint32
SWGIEEE_802_15_4_ModSettings::getUseReverseApi() {
return use_reverse_api;
}
void
SWGIEEE_802_15_4_ModSettings::setUseReverseApi(qint32 use_reverse_api) {
this->use_reverse_api = use_reverse_api;
this->m_use_reverse_api_isSet = true;
}
QString*
SWGIEEE_802_15_4_ModSettings::getReverseApiAddress() {
return reverse_api_address;
}
void
SWGIEEE_802_15_4_ModSettings::setReverseApiAddress(QString* reverse_api_address) {
this->reverse_api_address = reverse_api_address;
this->m_reverse_api_address_isSet = true;
}
qint32
SWGIEEE_802_15_4_ModSettings::getReverseApiPort() {
return reverse_api_port;
}
void
SWGIEEE_802_15_4_ModSettings::setReverseApiPort(qint32 reverse_api_port) {
this->reverse_api_port = reverse_api_port;
this->m_reverse_api_port_isSet = true;
}
qint32
SWGIEEE_802_15_4_ModSettings::getReverseApiDeviceIndex() {
return reverse_api_device_index;
}
void
SWGIEEE_802_15_4_ModSettings::setReverseApiDeviceIndex(qint32 reverse_api_device_index) {
this->reverse_api_device_index = reverse_api_device_index;
this->m_reverse_api_device_index_isSet = true;
}
qint32
SWGIEEE_802_15_4_ModSettings::getReverseApiChannelIndex() {
return reverse_api_channel_index;
}
void
SWGIEEE_802_15_4_ModSettings::setReverseApiChannelIndex(qint32 reverse_api_channel_index) {
this->reverse_api_channel_index = reverse_api_channel_index;
this->m_reverse_api_channel_index_isSet = true;
}
bool
SWGIEEE_802_15_4_ModSettings::isSet(){
bool isObjectUpdated = false;
do{
if(m_input_frequency_offset_isSet){
isObjectUpdated = true; break;
}
if(phy && *phy != QString("")){
isObjectUpdated = true; break;
}
if(m_rf_bandwidth_isSet){
isObjectUpdated = true; break;
}
if(m_gain_isSet){
isObjectUpdated = true; break;
}
if(m_channel_mute_isSet){
isObjectUpdated = true; break;
}
if(m_repeat_isSet){
isObjectUpdated = true; break;
}
if(m_repeat_delay_isSet){
isObjectUpdated = true; break;
}
if(m_repeat_count_isSet){
isObjectUpdated = true; break;
}
if(m_rgb_color_isSet){
isObjectUpdated = true; break;
}
if(title && *title != QString("")){
isObjectUpdated = true; break;
}
if(m_stream_index_isSet){
isObjectUpdated = true; break;
}
if(m_use_reverse_api_isSet){
isObjectUpdated = true; break;
}
if(reverse_api_address && *reverse_api_address != QString("")){
isObjectUpdated = true; break;
}
if(m_reverse_api_port_isSet){
isObjectUpdated = true; break;
}
if(m_reverse_api_device_index_isSet){
isObjectUpdated = true; break;
}
if(m_reverse_api_channel_index_isSet){
isObjectUpdated = true; break;
}
}while(false);
return isObjectUpdated;
}
}

View File

@ -0,0 +1,149 @@
/**
* SDRangel
* This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1, USRP and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time ---
*
* OpenAPI spec version: 4.15.0
* Contact: f4exb06@gmail.com
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
/*
* SWGIEEE_802_15_4_ModSettings.h
*
* IEEE_802_15_4_Mod
*/
#ifndef SWGIEEE_802_15_4_ModSettings_H_
#define SWGIEEE_802_15_4_ModSettings_H_
#include <QJsonObject>
#include <QString>
#include "SWGObject.h"
#include "export.h"
namespace SWGSDRangel {
class SWG_API SWGIEEE_802_15_4_ModSettings: public SWGObject {
public:
SWGIEEE_802_15_4_ModSettings();
SWGIEEE_802_15_4_ModSettings(QString* json);
virtual ~SWGIEEE_802_15_4_ModSettings();
void init();
void cleanup();
virtual QString asJson () override;
virtual QJsonObject* asJsonObject() override;
virtual void fromJsonObject(QJsonObject &json) override;
virtual SWGIEEE_802_15_4_ModSettings* fromJson(QString &jsonString) override;
qint64 getInputFrequencyOffset();
void setInputFrequencyOffset(qint64 input_frequency_offset);
QString* getPhy();
void setPhy(QString* phy);
float getRfBandwidth();
void setRfBandwidth(float rf_bandwidth);
float getGain();
void setGain(float gain);
qint32 getChannelMute();
void setChannelMute(qint32 channel_mute);
qint32 getRepeat();
void setRepeat(qint32 repeat);
float getRepeatDelay();
void setRepeatDelay(float repeat_delay);
qint32 getRepeatCount();
void setRepeatCount(qint32 repeat_count);
qint32 getRgbColor();
void setRgbColor(qint32 rgb_color);
QString* getTitle();
void setTitle(QString* title);
qint32 getStreamIndex();
void setStreamIndex(qint32 stream_index);
qint32 getUseReverseApi();
void setUseReverseApi(qint32 use_reverse_api);
QString* getReverseApiAddress();
void setReverseApiAddress(QString* reverse_api_address);
qint32 getReverseApiPort();
void setReverseApiPort(qint32 reverse_api_port);
qint32 getReverseApiDeviceIndex();
void setReverseApiDeviceIndex(qint32 reverse_api_device_index);
qint32 getReverseApiChannelIndex();
void setReverseApiChannelIndex(qint32 reverse_api_channel_index);
virtual bool isSet() override;
private:
qint64 input_frequency_offset;
bool m_input_frequency_offset_isSet;
QString* phy;
bool m_phy_isSet;
float rf_bandwidth;
bool m_rf_bandwidth_isSet;
float gain;
bool m_gain_isSet;
qint32 channel_mute;
bool m_channel_mute_isSet;
qint32 repeat;
bool m_repeat_isSet;
float repeat_delay;
bool m_repeat_delay_isSet;
qint32 repeat_count;
bool m_repeat_count_isSet;
qint32 rgb_color;
bool m_rgb_color_isSet;
QString* title;
bool m_title_isSet;
qint32 stream_index;
bool m_stream_index_isSet;
qint32 use_reverse_api;
bool m_use_reverse_api_isSet;
QString* reverse_api_address;
bool m_reverse_api_address_isSet;
qint32 reverse_api_port;
bool m_reverse_api_port_isSet;
qint32 reverse_api_device_index;
bool m_reverse_api_device_index_isSet;
qint32 reverse_api_channel_index;
bool m_reverse_api_channel_index_isSet;
};
}
#endif /* SWGIEEE_802_15_4_ModSettings_H_ */

View File

@ -99,6 +99,10 @@
#include "SWGGain.h"
#include "SWGHackRFInputSettings.h"
#include "SWGHackRFOutputSettings.h"
#include "SWGIEEE_802_15_4_ModActions.h"
#include "SWGIEEE_802_15_4_ModActions_tx.h"
#include "SWGIEEE_802_15_4_ModReport.h"
#include "SWGIEEE_802_15_4_ModSettings.h"
#include "SWGInstanceChannelsResponse.h"
#include "SWGInstanceConfigResponse.h"
#include "SWGInstanceDevicesResponse.h"
@ -454,6 +458,18 @@ namespace SWGSDRangel {
if(QString("SWGHackRFOutputSettings").compare(type) == 0) {
return new SWGHackRFOutputSettings();
}
if(QString("SWGIEEE_802_15_4_ModActions").compare(type) == 0) {
return new SWGIEEE_802_15_4_ModActions();
}
if(QString("SWGIEEE_802_15_4_ModActions_tx").compare(type) == 0) {
return new SWGIEEE_802_15_4_ModActions_tx();
}
if(QString("SWGIEEE_802_15_4_ModReport").compare(type) == 0) {
return new SWGIEEE_802_15_4_ModReport();
}
if(QString("SWGIEEE_802_15_4_ModSettings").compare(type) == 0) {
return new SWGIEEE_802_15_4_ModSettings();
}
if(QString("SWGInstanceChannelsResponse").compare(type) == 0) {
return new SWGInstanceChannelsResponse();
}