mirror of
https://github.com/f4exb/sdrangel.git
synced 2025-11-14 20:23:29 -05:00
LoRa demodulator: implement basic messaging
This commit is contained in:
parent
d4ede8457b
commit
733edb2cb2
@ -8,6 +8,7 @@ set(lora_SOURCES
|
|||||||
lorademodbaseband.cpp
|
lorademodbaseband.cpp
|
||||||
loraplugin.cpp
|
loraplugin.cpp
|
||||||
lorademoddecoder.cpp
|
lorademoddecoder.cpp
|
||||||
|
lorademodmsg.cpp
|
||||||
lorademodgui.ui
|
lorademodgui.ui
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -18,6 +19,7 @@ set(lora_HEADERS
|
|||||||
lorademodsink.h
|
lorademodsink.h
|
||||||
lorademodbaseband.h
|
lorademodbaseband.h
|
||||||
lorademoddecoder.h
|
lorademoddecoder.h
|
||||||
|
lorademodmsg.h
|
||||||
loraplugin.h
|
loraplugin.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
|
// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
|
||||||
// written by Christian Daniel //
|
// written by Christian Daniel //
|
||||||
// (c) 2015 John Greb //
|
// (c) 2015 John Greb //
|
||||||
// (c) 2020 Edouard Griffiths //
|
// (c) 2020 Edouard Griffiths, F4EXB //
|
||||||
// //
|
// //
|
||||||
// This program is free software; you can redistribute it and/or modify //
|
// 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 //
|
// it under the terms of the GNU General Public License as published by //
|
||||||
@ -27,21 +27,26 @@
|
|||||||
#include "dsp/dspcommands.h"
|
#include "dsp/dspcommands.h"
|
||||||
#include "device/deviceapi.h"
|
#include "device/deviceapi.h"
|
||||||
|
|
||||||
|
#include "lorademodmsg.h"
|
||||||
#include "lorademod.h"
|
#include "lorademod.h"
|
||||||
|
|
||||||
MESSAGE_CLASS_DEFINITION(LoRaDemod::MsgConfigureLoRaDemod, Message)
|
MESSAGE_CLASS_DEFINITION(LoRaDemod::MsgConfigureLoRaDemod, Message)
|
||||||
|
MESSAGE_CLASS_DEFINITION(LoRaDemod::MsgReportDecodeBytes, Message)
|
||||||
|
MESSAGE_CLASS_DEFINITION(LoRaDemod::MsgReportDecodeString, Message)
|
||||||
|
|
||||||
const QString LoRaDemod::m_channelIdURI = "sdrangel.channel.lorademod";
|
const QString LoRaDemod::m_channelIdURI = "sdrangel.channel.lorademod";
|
||||||
const QString LoRaDemod::m_channelId = "LoRaDemod";
|
const QString LoRaDemod::m_channelId = "LoRaDemod";
|
||||||
|
|
||||||
LoRaDemod::LoRaDemod(DeviceAPI* deviceAPI) :
|
LoRaDemod::LoRaDemod(DeviceAPI* deviceAPI) :
|
||||||
ChannelAPI(m_channelIdURI, ChannelAPI::StreamSingleSink),
|
ChannelAPI(m_channelIdURI, ChannelAPI::StreamSingleSink),
|
||||||
m_deviceAPI(deviceAPI)
|
m_deviceAPI(deviceAPI),
|
||||||
|
m_basebandSampleRate(0)
|
||||||
{
|
{
|
||||||
setObjectName(m_channelId);
|
setObjectName(m_channelId);
|
||||||
|
|
||||||
m_thread = new QThread(this);
|
m_thread = new QThread(this);
|
||||||
m_basebandSink = new LoRaDemodBaseband();
|
m_basebandSink = new LoRaDemodBaseband();
|
||||||
|
m_basebandSink->setDecoderMessageQueue(getInputMessageQueue()); // Decoder held on the main thread
|
||||||
m_basebandSink->moveToThread(m_thread);
|
m_basebandSink->moveToThread(m_thread);
|
||||||
|
|
||||||
applySettings(m_settings, true);
|
applySettings(m_settings, true);
|
||||||
@ -93,6 +98,42 @@ bool LoRaDemod::handleMessage(const Message& cmd)
|
|||||||
LoRaDemodSettings settings = cfg.getSettings();
|
LoRaDemodSettings settings = cfg.getSettings();
|
||||||
applySettings(settings, cfg.getForce());
|
applySettings(settings, cfg.getForce());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (LoRaDemodMsg::MsgDecodeSymbols::match(cmd))
|
||||||
|
{
|
||||||
|
qDebug() << "LoRaDemod::handleMessage: MsgDecodeSymbols";
|
||||||
|
LoRaDemodMsg::MsgDecodeSymbols& msg = (LoRaDemodMsg::MsgDecodeSymbols&) cmd;
|
||||||
|
|
||||||
|
if (m_settings.m_codingScheme == LoRaDemodSettings::CodingLoRa)
|
||||||
|
{
|
||||||
|
QByteArray payload;
|
||||||
|
m_decoder.decodeSymbols(msg.getSymbols(), payload);
|
||||||
|
|
||||||
|
if (getMessageQueueToGUI())
|
||||||
|
{
|
||||||
|
MsgReportDecodeBytes *msgToGUI = MsgReportDecodeBytes::create(payload);
|
||||||
|
msgToGUI->setSyncWord(msg.getSyncWord());
|
||||||
|
msgToGUI->setSignalDb(msg.getSingalDb());
|
||||||
|
msgToGUI->setNoiseDb(msg.getNoiseDb());
|
||||||
|
getMessageQueueToGUI()->push(msgToGUI);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QString payload;
|
||||||
|
m_decoder.decodeSymbols(msg.getSymbols(), payload);
|
||||||
|
|
||||||
|
if (getMessageQueueToGUI())
|
||||||
|
{
|
||||||
|
MsgReportDecodeString *msgToGUI = MsgReportDecodeString::create(payload);
|
||||||
|
msgToGUI->setSyncWord(msg.getSyncWord());
|
||||||
|
msgToGUI->setSignalDb(msg.getSingalDb());
|
||||||
|
msgToGUI->setNoiseDb(msg.getNoiseDb());
|
||||||
|
getMessageQueueToGUI()->push(msgToGUI);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (DSPSignalNotification::match(cmd))
|
else if (DSPSignalNotification::match(cmd))
|
||||||
@ -150,8 +191,22 @@ void LoRaDemod::applySettings(const LoRaDemodSettings& settings, bool force)
|
|||||||
<< " m_title: " << settings.m_title
|
<< " m_title: " << settings.m_title
|
||||||
<< " force: " << force;
|
<< " force: " << force;
|
||||||
|
|
||||||
|
if ((settings.m_spreadFactor != m_settings.m_spreadFactor)
|
||||||
|
|| (settings.m_deBits != m_settings.m_deBits) || force) {
|
||||||
|
m_decoder.setNbSymbolBits(settings.m_spreadFactor - settings.m_deBits);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((settings.m_codingScheme != m_settings.m_codingScheme) || force) {
|
||||||
|
m_decoder.setCodingScheme(settings.m_codingScheme);
|
||||||
|
}
|
||||||
|
|
||||||
LoRaDemodBaseband::MsgConfigureLoRaDemodBaseband *msg = LoRaDemodBaseband::MsgConfigureLoRaDemodBaseband::create(settings, force);
|
LoRaDemodBaseband::MsgConfigureLoRaDemodBaseband *msg = LoRaDemodBaseband::MsgConfigureLoRaDemodBaseband::create(settings, force);
|
||||||
m_basebandSink->getInputMessageQueue()->push(msg);
|
m_basebandSink->getInputMessageQueue()->push(msg);
|
||||||
|
|
||||||
m_settings = settings;
|
m_settings = settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool LoRaDemod::getDemodActive() const
|
||||||
|
{
|
||||||
|
return m_basebandSink->getDemodActive();
|
||||||
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
///////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
|
// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
|
||||||
// (C) 2015 John Greb //
|
// (C) 2015 John Greb //
|
||||||
|
// (C) 2020 Edouard Griffiths, F4EXB //
|
||||||
// //
|
// //
|
||||||
// This program is free software; you can redistribute it and/or modify //
|
// 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 //
|
// it under the terms of the GNU General Public License as published by //
|
||||||
@ -26,6 +27,7 @@
|
|||||||
#include "util/message.h"
|
#include "util/message.h"
|
||||||
|
|
||||||
#include "lorademodbaseband.h"
|
#include "lorademodbaseband.h"
|
||||||
|
#include "lorademoddecoder.h"
|
||||||
|
|
||||||
class DeviceAPI;
|
class DeviceAPI;
|
||||||
class QThread;
|
class QThread;
|
||||||
@ -55,6 +57,81 @@ public:
|
|||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class MsgReportDecodeBytes : public Message {
|
||||||
|
MESSAGE_CLASS_DECLARATION
|
||||||
|
|
||||||
|
public:
|
||||||
|
const QByteArray& getBytes() const { return m_bytes; }
|
||||||
|
unsigned int getSyncWord() const { return m_syncWord; }
|
||||||
|
float getSingalDb() const { return m_signalDb; }
|
||||||
|
float getNoiseDb() const { return m_noiseDb; }
|
||||||
|
|
||||||
|
static MsgReportDecodeBytes* create(const QByteArray& bytes) {
|
||||||
|
return new MsgReportDecodeBytes(bytes);
|
||||||
|
}
|
||||||
|
void setSyncWord(unsigned int syncWord) {
|
||||||
|
m_syncWord = syncWord;
|
||||||
|
}
|
||||||
|
void setSignalDb(float db) {
|
||||||
|
m_signalDb = db;
|
||||||
|
}
|
||||||
|
void setNoiseDb(float db) {
|
||||||
|
m_noiseDb = db;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QByteArray m_bytes;
|
||||||
|
unsigned int m_syncWord;
|
||||||
|
float m_signalDb;
|
||||||
|
float m_noiseDb;
|
||||||
|
|
||||||
|
MsgReportDecodeBytes(const QByteArray& bytes) :
|
||||||
|
Message(),
|
||||||
|
m_bytes(bytes),
|
||||||
|
m_syncWord(0),
|
||||||
|
m_signalDb(0.0),
|
||||||
|
m_noiseDb(0.0)
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
class MsgReportDecodeString : public Message {
|
||||||
|
MESSAGE_CLASS_DECLARATION
|
||||||
|
|
||||||
|
public:
|
||||||
|
const QString& getString() const { return m_str; }
|
||||||
|
unsigned int getSyncWord() const { return m_syncWord; }
|
||||||
|
float getSingalDb() const { return m_signalDb; }
|
||||||
|
float getNoiseDb() const { return m_noiseDb; }
|
||||||
|
|
||||||
|
static MsgReportDecodeString* create(const QString& str)
|
||||||
|
{
|
||||||
|
return new MsgReportDecodeString(str);
|
||||||
|
}
|
||||||
|
void setSyncWord(unsigned int syncWord) {
|
||||||
|
m_syncWord = syncWord;
|
||||||
|
}
|
||||||
|
void setSignalDb(float db) {
|
||||||
|
m_signalDb = db;
|
||||||
|
}
|
||||||
|
void setNoiseDb(float db) {
|
||||||
|
m_noiseDb = db;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString m_str;
|
||||||
|
unsigned int m_syncWord;
|
||||||
|
float m_signalDb;
|
||||||
|
float m_noiseDb;
|
||||||
|
|
||||||
|
MsgReportDecodeString(const QString& str) :
|
||||||
|
Message(),
|
||||||
|
m_str(str),
|
||||||
|
m_syncWord(0),
|
||||||
|
m_signalDb(0.0),
|
||||||
|
m_noiseDb(0.0)
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
LoRaDemod(DeviceAPI* deviceAPI);
|
LoRaDemod(DeviceAPI* deviceAPI);
|
||||||
virtual ~LoRaDemod();
|
virtual ~LoRaDemod();
|
||||||
virtual void destroy() { delete this; }
|
virtual void destroy() { delete this; }
|
||||||
@ -82,6 +159,8 @@ public:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool getDemodActive() const;
|
||||||
|
|
||||||
static const QString m_channelIdURI;
|
static const QString m_channelIdURI;
|
||||||
static const QString m_channelId;
|
static const QString m_channelId;
|
||||||
|
|
||||||
@ -89,8 +168,9 @@ private:
|
|||||||
DeviceAPI *m_deviceAPI;
|
DeviceAPI *m_deviceAPI;
|
||||||
QThread *m_thread;
|
QThread *m_thread;
|
||||||
LoRaDemodBaseband* m_basebandSink;
|
LoRaDemodBaseband* m_basebandSink;
|
||||||
|
LoRaDemodDecoder m_decoder;
|
||||||
LoRaDemodSettings m_settings;
|
LoRaDemodSettings m_settings;
|
||||||
int m_basebandSampleRate;
|
int m_basebandSampleRate; //!< stored from device message used when starting baseband sink
|
||||||
|
|
||||||
void applySettings(const LoRaDemodSettings& settings, bool force = false);
|
void applySettings(const LoRaDemodSettings& settings, bool force = false);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -62,7 +62,9 @@ public:
|
|||||||
void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end);
|
void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end);
|
||||||
MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } //!< Get the queue for asynchronous inbound communication
|
MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } //!< Get the queue for asynchronous inbound communication
|
||||||
int getChannelSampleRate() const;
|
int getChannelSampleRate() const;
|
||||||
|
bool getDemodActive() const { return m_sink.getDemodActive(); }
|
||||||
void setBasebandSampleRate(int sampleRate);
|
void setBasebandSampleRate(int sampleRate);
|
||||||
|
void setDecoderMessageQueue(MessageQueue *messageQueue) { m_sink.setDecoderMessageQueue(messageQueue); }
|
||||||
void setSpectrumSink(BasebandSampleSink* spectrumSink) { m_sink.setSpectrumSink(spectrumSink); }
|
void setSpectrumSink(BasebandSampleSink* spectrumSink) { m_sink.setSpectrumSink(spectrumSink); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@ -99,7 +99,7 @@ void LoRaDemodDecoder::decodeSymbolsTTY(const std::vector<unsigned int>& symbols
|
|||||||
|
|
||||||
if (ttyState == TTYLetters) {
|
if (ttyState == TTYLetters) {
|
||||||
asciiChar = ttyLetters[ttyChar];
|
asciiChar = ttyLetters[ttyChar];
|
||||||
} else if (ttyState == TTYLetters) {
|
} else if (ttyState == TTYFigures) {
|
||||||
asciiChar = ttyFigures[ttyChar];
|
asciiChar = ttyFigures[ttyChar];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -16,8 +16,8 @@
|
|||||||
///////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#include "device/deviceuiset.h"
|
#include "device/deviceuiset.h"
|
||||||
#include <QDockWidget>
|
#include <QScrollBar>
|
||||||
#include <QMainWindow>
|
#include <QDebug>
|
||||||
|
|
||||||
#include "ui_lorademodgui.h"
|
#include "ui_lorademodgui.h"
|
||||||
#include "dsp/spectrumvis.h"
|
#include "dsp/spectrumvis.h"
|
||||||
@ -27,6 +27,7 @@
|
|||||||
#include "gui/glspectrumgui.h"
|
#include "gui/glspectrumgui.h"
|
||||||
#include "plugin/pluginapi.h"
|
#include "plugin/pluginapi.h"
|
||||||
#include "util/simpleserializer.h"
|
#include "util/simpleserializer.h"
|
||||||
|
#include "mainwindow.h"
|
||||||
|
|
||||||
#include "lorademod.h"
|
#include "lorademod.h"
|
||||||
#include "lorademodgui.h"
|
#include "lorademodgui.h"
|
||||||
@ -105,6 +106,23 @@ bool LoRaDemodGUI::handleMessage(const Message& message)
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
else if (LoRaDemod::MsgReportDecodeBytes::match(message))
|
||||||
|
{
|
||||||
|
const LoRaDemod::MsgReportDecodeBytes& msg = (LoRaDemod::MsgReportDecodeBytes&) message;
|
||||||
|
QByteArray bytes = msg.getBytes();
|
||||||
|
ui->hexText->setText(bytes.toHex());
|
||||||
|
ui->syncWord->setText((tr("%1").arg(msg.getSyncWord(), 2, 16)));
|
||||||
|
ui->sText->setText(tr("%1").arg(msg.getSingalDb(), 0, 'f', 1));
|
||||||
|
ui->snrText->setText(tr("%1").arg(msg.getSingalDb() - msg.getNoiseDb(), 0, 'f', 1));
|
||||||
|
}
|
||||||
|
else if (LoRaDemod::MsgReportDecodeString::match(message))
|
||||||
|
{
|
||||||
|
const LoRaDemod::MsgReportDecodeString& msg = (LoRaDemod::MsgReportDecodeString&) message;
|
||||||
|
addText(msg.getString());
|
||||||
|
ui->syncWord->setText((tr("%1").arg(msg.getSyncWord(), 2, 16)));
|
||||||
|
ui->sText->setText(tr("%1").arg(msg.getSingalDb(), 0, 'f', 1));
|
||||||
|
ui->snrText->setText(tr("%1").arg(msg.getSingalDb() - msg.getNoiseDb(), 0, 'f', 1));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@ -177,6 +195,38 @@ void LoRaDemodGUI::on_deBits_valueChanged(int value)
|
|||||||
applySettings();
|
applySettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LoRaDemodGUI::on_scheme_currentIndexChanged(int index)
|
||||||
|
{
|
||||||
|
m_settings.m_codingScheme = (LoRaDemodSettings::CodingScheme) index;
|
||||||
|
applySettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoRaDemodGUI::on_mute_toggled(bool checked)
|
||||||
|
{
|
||||||
|
m_settings.m_decodeActive = !checked;
|
||||||
|
applySettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoRaDemodGUI::on_clear_clicked(bool checked)
|
||||||
|
{
|
||||||
|
(void) checked;
|
||||||
|
ui->messageText->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoRaDemodGUI::on_eomSquelch_valueChanged(int value)
|
||||||
|
{
|
||||||
|
m_settings.m_eomSquelchTenths = value;
|
||||||
|
displaySquelch();
|
||||||
|
applySettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoRaDemodGUI::on_messageLength_valueChanged(int value)
|
||||||
|
{
|
||||||
|
m_settings.m_nbSymbolsMax = value;
|
||||||
|
ui->messageLengthText->setText(tr("%1").arg(m_settings.m_nbSymbolsMax));
|
||||||
|
applySettings();
|
||||||
|
}
|
||||||
|
|
||||||
void LoRaDemodGUI::onWidgetRolled(QWidget* widget, bool rollDown)
|
void LoRaDemodGUI::onWidgetRolled(QWidget* widget, bool rollDown)
|
||||||
{
|
{
|
||||||
(void) widget;
|
(void) widget;
|
||||||
@ -190,7 +240,8 @@ LoRaDemodGUI::LoRaDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseb
|
|||||||
m_deviceUISet(deviceUISet),
|
m_deviceUISet(deviceUISet),
|
||||||
m_channelMarker(this),
|
m_channelMarker(this),
|
||||||
m_basebandSampleRate(250000),
|
m_basebandSampleRate(250000),
|
||||||
m_doApplySettings(true)
|
m_doApplySettings(true),
|
||||||
|
m_tickCount(0)
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
setAttribute(Qt::WA_DeleteOnClose, true);
|
setAttribute(Qt::WA_DeleteOnClose, true);
|
||||||
@ -201,6 +252,8 @@ LoRaDemodGUI::LoRaDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseb
|
|||||||
m_LoRaDemod->setSpectrumSink(m_spectrumVis);
|
m_LoRaDemod->setSpectrumSink(m_spectrumVis);
|
||||||
m_LoRaDemod->setMessageQueueToGUI(getInputMessageQueue());
|
m_LoRaDemod->setMessageQueueToGUI(getInputMessageQueue());
|
||||||
|
|
||||||
|
connect(&MainWindow::getInstance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick()));
|
||||||
|
|
||||||
ui->glSpectrum->setDisplayWaterfall(true);
|
ui->glSpectrum->setDisplayWaterfall(true);
|
||||||
ui->glSpectrum->setDisplayMaxHold(true);
|
ui->glSpectrum->setDisplayMaxHold(true);
|
||||||
|
|
||||||
@ -208,6 +261,10 @@ LoRaDemodGUI::LoRaDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseb
|
|||||||
ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold));
|
ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold));
|
||||||
ui->deltaFrequency->setValueRange(false, 7, -9999999, 9999999);
|
ui->deltaFrequency->setValueRange(false, 7, -9999999, 9999999);
|
||||||
|
|
||||||
|
ui->messageText->setReadOnly(true);
|
||||||
|
ui->syncWord->setReadOnly(true);
|
||||||
|
ui->hexText->setReadOnly(true);
|
||||||
|
|
||||||
m_channelMarker.setMovable(true);
|
m_channelMarker.setMovable(true);
|
||||||
m_channelMarker.setVisible(true);
|
m_channelMarker.setVisible(true);
|
||||||
|
|
||||||
@ -276,10 +333,25 @@ void LoRaDemodGUI::displaySettings()
|
|||||||
ui->SpreadText->setText(tr("%1").arg(m_settings.m_spreadFactor));
|
ui->SpreadText->setText(tr("%1").arg(m_settings.m_spreadFactor));
|
||||||
ui->deBits->setValue(m_settings.m_deBits);
|
ui->deBits->setValue(m_settings.m_deBits);
|
||||||
ui->deBitsText->setText(tr("%1").arg(m_settings.m_deBits));
|
ui->deBitsText->setText(tr("%1").arg(m_settings.m_deBits));
|
||||||
|
ui->scheme->setCurrentIndex((int) m_settings.m_codingScheme);
|
||||||
|
ui->messageLengthText->setText(tr("%1").arg(m_settings.m_nbSymbolsMax));
|
||||||
|
ui->messageLength->setValue(m_settings.m_nbSymbolsMax);
|
||||||
ui->spectrumGUI->setFFTSize(m_settings.m_spreadFactor);
|
ui->spectrumGUI->setFFTSize(m_settings.m_spreadFactor);
|
||||||
|
displaySquelch();
|
||||||
blockApplySettings(false);
|
blockApplySettings(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LoRaDemodGUI::displaySquelch()
|
||||||
|
{
|
||||||
|
ui->eomSquelch->setValue(m_settings.m_eomSquelchTenths);
|
||||||
|
|
||||||
|
if (m_settings.m_eomSquelchTenths == ui->eomSquelch->maximum()) {
|
||||||
|
ui->eomSquelchText->setText("---");
|
||||||
|
} else {
|
||||||
|
ui->eomSquelchText->setText(tr("%1").arg(m_settings.m_eomSquelchTenths / 10.0, 0, 'f', 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void LoRaDemodGUI::setBandwidths()
|
void LoRaDemodGUI::setBandwidths()
|
||||||
{
|
{
|
||||||
int maxBandwidth = m_basebandSampleRate/LoRaDemodSettings::oversampling;
|
int maxBandwidth = m_basebandSampleRate/LoRaDemodSettings::oversampling;
|
||||||
@ -296,3 +368,35 @@ void LoRaDemodGUI::setBandwidths()
|
|||||||
ui->BWText->setText(QString("%1 Hz").arg(LoRaDemodSettings::bandwidths[index]));
|
ui->BWText->setText(QString("%1 Hz").arg(LoRaDemodSettings::bandwidths[index]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LoRaDemodGUI::addText(const QString& text)
|
||||||
|
{
|
||||||
|
QDateTime dt = QDateTime::currentDateTime();
|
||||||
|
QString dateStr = dt.toString("HH:mm:ss");
|
||||||
|
QTextCursor cursor = ui->messageText->textCursor();
|
||||||
|
cursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor);
|
||||||
|
if (!ui->messageText->document()->isEmpty()) {
|
||||||
|
cursor.insertText("\n");
|
||||||
|
}
|
||||||
|
cursor.insertText(tr("%1 %2").arg(dateStr).arg(text));
|
||||||
|
ui->messageText->verticalScrollBar()->setValue(ui->messageText->verticalScrollBar()->maximum());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void LoRaDemodGUI::tick()
|
||||||
|
{
|
||||||
|
if (m_tickCount < 10)
|
||||||
|
{
|
||||||
|
m_tickCount++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_tickCount = 0;
|
||||||
|
|
||||||
|
if (m_LoRaDemod->getDemodActive()) {
|
||||||
|
ui->mute->setStyleSheet("QToolButton { background-color : green; }");
|
||||||
|
} else {
|
||||||
|
ui->mute->setStyleSheet("QToolButton { background:rgb(79,79,79); }");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -59,9 +59,15 @@ private slots:
|
|||||||
void on_BW_valueChanged(int value);
|
void on_BW_valueChanged(int value);
|
||||||
void on_Spread_valueChanged(int value);
|
void on_Spread_valueChanged(int value);
|
||||||
void on_deBits_valueChanged(int value);
|
void on_deBits_valueChanged(int value);
|
||||||
|
void on_scheme_currentIndexChanged(int index);
|
||||||
|
void on_mute_toggled(bool checked);
|
||||||
|
void on_clear_clicked(bool checked);
|
||||||
|
void on_eomSquelch_valueChanged(int value);
|
||||||
|
void on_messageLength_valueChanged(int value);
|
||||||
void onWidgetRolled(QWidget* widget, bool rollDown);
|
void onWidgetRolled(QWidget* widget, bool rollDown);
|
||||||
void channelMarkerHighlightedByCursor();
|
void channelMarkerHighlightedByCursor();
|
||||||
void handleInputMessages();
|
void handleInputMessages();
|
||||||
|
void tick();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::LoRaDemodGUI* ui;
|
Ui::LoRaDemodGUI* ui;
|
||||||
@ -75,6 +81,7 @@ private:
|
|||||||
LoRaDemod* m_LoRaDemod;
|
LoRaDemod* m_LoRaDemod;
|
||||||
SpectrumVis* m_spectrumVis;
|
SpectrumVis* m_spectrumVis;
|
||||||
MessageQueue m_inputMessageQueue;
|
MessageQueue m_inputMessageQueue;
|
||||||
|
unsigned int m_tickCount;
|
||||||
|
|
||||||
explicit LoRaDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel, QWidget* parent = 0);
|
explicit LoRaDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel, QWidget* parent = 0);
|
||||||
virtual ~LoRaDemodGUI();
|
virtual ~LoRaDemodGUI();
|
||||||
@ -82,7 +89,9 @@ private:
|
|||||||
void blockApplySettings(bool block);
|
void blockApplySettings(bool block);
|
||||||
void applySettings(bool force = false);
|
void applySettings(bool force = false);
|
||||||
void displaySettings();
|
void displaySettings();
|
||||||
|
void displaySquelch();
|
||||||
void setBandwidths();
|
void setBandwidths();
|
||||||
|
void addText(const QString& text);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // INCLUDE_LoRaDEMODGUI_H
|
#endif // INCLUDE_LoRaDEMODGUI_H
|
||||||
|
|||||||
@ -6,14 +6,14 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>350</width>
|
<width>410</width>
|
||||||
<height>500</height>
|
<height>620</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>350</width>
|
<width>380</width>
|
||||||
<height>500</height>
|
<height>620</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="font">
|
<property name="font">
|
||||||
@ -30,14 +30,14 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>10</x>
|
<x>10</x>
|
||||||
<y>20</y>
|
<y>20</y>
|
||||||
<width>331</width>
|
<width>390</width>
|
||||||
<height>112</height>
|
<height>102</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>0</width>
|
<width>0</width>
|
||||||
<height>112</height>
|
<height>102</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
@ -74,7 +74,7 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>30</x>
|
<x>30</x>
|
||||||
<y>50</y>
|
<y>50</y>
|
||||||
<width>180</width>
|
<width>251</width>
|
||||||
<height>16</height>
|
<height>16</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
@ -102,7 +102,7 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>30</x>
|
<x>30</x>
|
||||||
<y>70</y>
|
<y>70</y>
|
||||||
<width>100</width>
|
<width>131</width>
|
||||||
<height>16</height>
|
<height>16</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
@ -131,7 +131,7 @@
|
|||||||
<widget class="QLabel" name="SpreadText">
|
<widget class="QLabel" name="SpreadText">
|
||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
<x>140</x>
|
<x>170</x>
|
||||||
<y>70</y>
|
<y>70</y>
|
||||||
<width>30</width>
|
<width>30</width>
|
||||||
<height>16</height>
|
<height>16</height>
|
||||||
@ -153,7 +153,7 @@
|
|||||||
<widget class="QLabel" name="BWText">
|
<widget class="QLabel" name="BWText">
|
||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
<x>240</x>
|
<x>300</x>
|
||||||
<y>50</y>
|
<y>50</y>
|
||||||
<width>80</width>
|
<width>80</width>
|
||||||
<height>16</height>
|
<height>16</height>
|
||||||
@ -175,7 +175,7 @@
|
|||||||
<widget class="QLabel" name="deBitsLabel">
|
<widget class="QLabel" name="deBitsLabel">
|
||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
<x>190</x>
|
<x>220</x>
|
||||||
<y>70</y>
|
<y>70</y>
|
||||||
<width>22</width>
|
<width>22</width>
|
||||||
<height>16</height>
|
<height>16</height>
|
||||||
@ -188,7 +188,7 @@
|
|||||||
<widget class="QLabel" name="deBitsText">
|
<widget class="QLabel" name="deBitsText">
|
||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
<x>290</x>
|
<x>350</x>
|
||||||
<y>70</y>
|
<y>70</y>
|
||||||
<width>30</width>
|
<width>30</width>
|
||||||
<height>16</height>
|
<height>16</height>
|
||||||
@ -210,14 +210,14 @@
|
|||||||
<widget class="QSlider" name="deBits">
|
<widget class="QSlider" name="deBits">
|
||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
<x>220</x>
|
<x>250</x>
|
||||||
<y>70</y>
|
<y>70</y>
|
||||||
<width>60</width>
|
<width>91</width>
|
||||||
<height>16</height>
|
<height>16</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Low data rate optimize (DE) bits</string>
|
<string>Distance Enhancement bits i.e. log2 of number of FFT bins per effective sample</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="minimum">
|
<property name="minimum">
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
@ -243,7 +243,7 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>10</x>
|
<x>10</x>
|
||||||
<y>10</y>
|
<y>10</y>
|
||||||
<width>311</width>
|
<width>371</width>
|
||||||
<height>26</height>
|
<height>26</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
@ -319,18 +319,378 @@
|
|||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="sLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>S</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="sText">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>30</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>De-chirped signal level</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>-50.0</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="snrLabel">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>35</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>SNR</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="snrText">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>25</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>De-chirped SNR level</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>10.0</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="sUnits">
|
||||||
|
<property name="text">
|
||||||
|
<string>dB</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
|
<widget class="QWidget" name="payloadContainer" native="true">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>10</x>
|
||||||
|
<y>130</y>
|
||||||
|
<width>390</width>
|
||||||
|
<height>160</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>160</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Payload</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QLabel" name="messageLabel">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>2</x>
|
||||||
|
<y>40</y>
|
||||||
|
<width>32</width>
|
||||||
|
<height>16</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Msg</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLineEdit" name="hexText">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>30</x>
|
||||||
|
<y>120</y>
|
||||||
|
<width>351</width>
|
||||||
|
<height>20</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLabel" name="hexLabel">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>2</x>
|
||||||
|
<y>120</y>
|
||||||
|
<width>32</width>
|
||||||
|
<height>16</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Hex</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QPlainTextEdit" name="messageText">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>30</x>
|
||||||
|
<y>40</y>
|
||||||
|
<width>351</width>
|
||||||
|
<height>75</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLabel" name="schemeLabel">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>2</x>
|
||||||
|
<y>10</y>
|
||||||
|
<width>50</width>
|
||||||
|
<height>16</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Scheme</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QComboBox" name="scheme">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>60</x>
|
||||||
|
<y>8</y>
|
||||||
|
<width>86</width>
|
||||||
|
<height>20</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>LoRa</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>ASCII</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>TTY</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
<widget class="QPushButton" name="clear">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>4</x>
|
||||||
|
<y>60</y>
|
||||||
|
<width>20</width>
|
||||||
|
<height>20</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>24</width>
|
||||||
|
<height>24</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Clear text</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="../../../sdrgui/resources/res.qrc">
|
||||||
|
<normaloff>:/sweep.png</normaloff>:/sweep.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="autoDefault">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QToolButton" name="mute">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>150</x>
|
||||||
|
<y>8</y>
|
||||||
|
<width>20</width>
|
||||||
|
<height>20</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Run/Stop decoder</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="../../../sdrgui/resources/res.qrc">
|
||||||
|
<normaloff>:/stop.png</normaloff>
|
||||||
|
<normalon>:/play.png</normalon>:/stop.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLabel" name="eomSquelchLabel">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>180</x>
|
||||||
|
<y>10</y>
|
||||||
|
<width>35</width>
|
||||||
|
<height>19</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>EOM</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QDial" name="eomSquelch">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>210</x>
|
||||||
|
<y>8</y>
|
||||||
|
<width>22</width>
|
||||||
|
<height>22</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>End Of Message squelch factor</string>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<number>40</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>121</number>
|
||||||
|
</property>
|
||||||
|
<property name="pageStep">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<number>60</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLabel" name="eomSquelchText">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>230</x>
|
||||||
|
<y>10</y>
|
||||||
|
<width>28</width>
|
||||||
|
<height>19</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>10.0</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLabel" name="messageLengthLabel">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>272</x>
|
||||||
|
<y>10</y>
|
||||||
|
<width>20</width>
|
||||||
|
<height>19</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>ML</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QDial" name="messageLength">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>290</x>
|
||||||
|
<y>8</y>
|
||||||
|
<width>22</width>
|
||||||
|
<height>22</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Message (payload) length in number of symbols</string>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<number>20</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>255</number>
|
||||||
|
</property>
|
||||||
|
<property name="pageStep">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<number>255</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLabel" name="messageLengthText">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>310</x>
|
||||||
|
<y>10</y>
|
||||||
|
<width>25</width>
|
||||||
|
<height>19</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>255</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLineEdit" name="syncWord">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>350</x>
|
||||||
|
<y>9</y>
|
||||||
|
<width>25</width>
|
||||||
|
<height>20</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="focusPolicy">
|
||||||
|
<enum>Qt::ClickFocus</enum>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Sync word (1 byte hex)</string>
|
||||||
|
</property>
|
||||||
|
<property name="inputMask">
|
||||||
|
<string>HH</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>00</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
<widget class="QWidget" name="spectrumContainer" native="true">
|
<widget class="QWidget" name="spectrumContainer" native="true">
|
||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
<x>10</x>
|
<x>10</x>
|
||||||
<y>140</y>
|
<y>300</y>
|
||||||
<width>331</width>
|
<width>390</width>
|
||||||
<height>341</height>
|
<height>310</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>373</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>De-chirped Spectrum</string>
|
<string>De-chirped Spectrum</string>
|
||||||
</property>
|
</property>
|
||||||
|
|||||||
20
plugins/channelrx/demodlora/lorademodmsg.cpp
Normal file
20
plugins/channelrx/demodlora/lorademodmsg.cpp
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright (C) 2020 Edouard Griffiths, F4EXB //
|
||||||
|
// //
|
||||||
|
// This program is free software; you can redistribute it and/or modify //
|
||||||
|
// it under the terms of the GNU General Public License as published by //
|
||||||
|
// the Free Software Foundation as version 3 of the License, or //
|
||||||
|
// (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 "lorademodmsg.h"
|
||||||
|
|
||||||
|
MESSAGE_CLASS_DEFINITION(LoRaDemodMsg::MsgDecodeSymbols, Message)
|
||||||
79
plugins/channelrx/demodlora/lorademodmsg.h
Normal file
79
plugins/channelrx/demodlora/lorademodmsg.h
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright (C) 2020 Edouard Griffiths, F4EXB //
|
||||||
|
// //
|
||||||
|
// This program is free software; you can redistribute it and/or modify //
|
||||||
|
// it under the terms of the GNU General Public License as published by //
|
||||||
|
// the Free Software Foundation as version 3 of the License, or //
|
||||||
|
// (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_LORADEMODMSG_H
|
||||||
|
#define INCLUDE_LORADEMODMSG_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include "util/message.h"
|
||||||
|
|
||||||
|
namespace LoRaDemodMsg
|
||||||
|
{
|
||||||
|
class MsgDecodeSymbols : public Message {
|
||||||
|
MESSAGE_CLASS_DECLARATION
|
||||||
|
|
||||||
|
public:
|
||||||
|
const std::vector<unsigned int>& getSymbols() const { return m_symbols; }
|
||||||
|
unsigned int getSyncWord() const { return m_syncWord; }
|
||||||
|
float getSingalDb() const { return m_signalDb; }
|
||||||
|
float getNoiseDb() const { return m_noiseDb; }
|
||||||
|
|
||||||
|
void pushBackSymbol(unsigned int symbol) {
|
||||||
|
m_symbols.push_back(symbol);
|
||||||
|
}
|
||||||
|
void popSymbol() {
|
||||||
|
m_symbols.pop_back();
|
||||||
|
}
|
||||||
|
void setSyncWord(unsigned char syncWord) {
|
||||||
|
m_syncWord = syncWord;
|
||||||
|
}
|
||||||
|
void setSignalDb(float db) {
|
||||||
|
m_signalDb = db;
|
||||||
|
}
|
||||||
|
void setNoiseDb(float db) {
|
||||||
|
m_noiseDb = db;
|
||||||
|
}
|
||||||
|
|
||||||
|
static MsgDecodeSymbols* create() {
|
||||||
|
return new MsgDecodeSymbols();
|
||||||
|
}
|
||||||
|
static MsgDecodeSymbols* create(const std::vector<unsigned int> symbols) {
|
||||||
|
return new MsgDecodeSymbols(symbols);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<unsigned int> m_symbols;
|
||||||
|
unsigned int m_syncWord;
|
||||||
|
float m_signalDb;
|
||||||
|
float m_noiseDb;
|
||||||
|
|
||||||
|
MsgDecodeSymbols() : //!< create an empty message
|
||||||
|
Message(),
|
||||||
|
m_syncWord(0),
|
||||||
|
m_signalDb(0.0),
|
||||||
|
m_noiseDb(0.0)
|
||||||
|
{}
|
||||||
|
MsgDecodeSymbols(const std::vector<unsigned int> symbols) : //!< create a message with symbols copy
|
||||||
|
Message(),
|
||||||
|
m_syncWord(0),
|
||||||
|
m_signalDb(0.0),
|
||||||
|
m_noiseDb(0.0)
|
||||||
|
{ m_symbols = symbols; }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // INCLUDE_LORADEMODMSG_H
|
||||||
@ -41,6 +41,10 @@ void LoRaDemodSettings::resetToDefaults()
|
|||||||
m_bandwidthIndex = 5;
|
m_bandwidthIndex = 5;
|
||||||
m_spreadFactor = 7;
|
m_spreadFactor = 7;
|
||||||
m_deBits = 0;
|
m_deBits = 0;
|
||||||
|
m_codingScheme = CodingLoRa;
|
||||||
|
m_decodeActive = true;
|
||||||
|
m_eomSquelchTenths = 60;
|
||||||
|
m_nbSymbolsMax = 255;
|
||||||
m_rgbColor = QColor(255, 0, 255).rgb();
|
m_rgbColor = QColor(255, 0, 255).rgb();
|
||||||
m_title = "LoRa Demodulator";
|
m_title = "LoRa Demodulator";
|
||||||
}
|
}
|
||||||
@ -62,6 +66,10 @@ QByteArray LoRaDemodSettings::serialize() const
|
|||||||
|
|
||||||
s.writeString(6, m_title);
|
s.writeString(6, m_title);
|
||||||
s.writeS32(7, m_deBits);
|
s.writeS32(7, m_deBits);
|
||||||
|
s.writeS32(8, m_codingScheme);
|
||||||
|
s.writeBool(9, m_decodeActive);
|
||||||
|
s.writeS32(10, m_eomSquelchTenths);
|
||||||
|
s.writeS32(11, m_nbSymbolsMax);
|
||||||
|
|
||||||
return s.final();
|
return s.final();
|
||||||
}
|
}
|
||||||
@ -79,6 +87,7 @@ bool LoRaDemodSettings::deserialize(const QByteArray& data)
|
|||||||
if(d.getVersion() == 1)
|
if(d.getVersion() == 1)
|
||||||
{
|
{
|
||||||
QByteArray bytetmp;
|
QByteArray bytetmp;
|
||||||
|
int tmp;
|
||||||
|
|
||||||
d.readS32(1, &m_inputFrequencyOffset, 0);
|
d.readS32(1, &m_inputFrequencyOffset, 0);
|
||||||
d.readS32(2, &m_bandwidthIndex, 0);
|
d.readS32(2, &m_bandwidthIndex, 0);
|
||||||
@ -96,6 +105,11 @@ bool LoRaDemodSettings::deserialize(const QByteArray& data)
|
|||||||
|
|
||||||
d.readString(6, &m_title, "LoRa Demodulator");
|
d.readString(6, &m_title, "LoRa Demodulator");
|
||||||
d.readS32(7, &m_deBits, 0);
|
d.readS32(7, &m_deBits, 0);
|
||||||
|
d.readS32(8, &tmp);
|
||||||
|
m_codingScheme = (CodingScheme) tmp;
|
||||||
|
d.readBool(9, &m_decodeActive, true);
|
||||||
|
d.readS32(10, &m_eomSquelchTenths, 60);
|
||||||
|
d.readS32(11, &m_nbSymbolsMax, 255);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,9 +30,9 @@ struct LoRaDemodSettings
|
|||||||
{
|
{
|
||||||
enum CodingScheme
|
enum CodingScheme
|
||||||
{
|
{
|
||||||
CodingTTY, //!< plain TTY (5 bits)
|
CodingLoRa, //!< Standard LoRa
|
||||||
CodingASCII, //!< plain ASCII (7 bits)
|
CodingASCII, //!< plain ASCII (7 bits)
|
||||||
CodingLoRa //!< Standard LoRa
|
CodingTTY //!< plain TTY (5 bits)
|
||||||
};
|
};
|
||||||
|
|
||||||
int m_inputFrequencyOffset;
|
int m_inputFrequencyOffset;
|
||||||
@ -40,6 +40,9 @@ struct LoRaDemodSettings
|
|||||||
int m_spreadFactor;
|
int m_spreadFactor;
|
||||||
int m_deBits; //!< Low data rate optmize (DE) bits
|
int m_deBits; //!< Low data rate optmize (DE) bits
|
||||||
CodingScheme m_codingScheme;
|
CodingScheme m_codingScheme;
|
||||||
|
bool m_decodeActive;
|
||||||
|
int m_eomSquelchTenths; //!< Squelch factor to trigger end of message (/10)
|
||||||
|
int m_nbSymbolsMax; //!< Maximum number of symbols in a payload
|
||||||
uint32_t m_rgbColor;
|
uint32_t m_rgbColor;
|
||||||
QString m_title;
|
QString m_title;
|
||||||
|
|
||||||
|
|||||||
@ -22,10 +22,14 @@
|
|||||||
#include "dsp/dsptypes.h"
|
#include "dsp/dsptypes.h"
|
||||||
#include "dsp/basebandsamplesink.h"
|
#include "dsp/basebandsamplesink.h"
|
||||||
#include "dsp/fftengine.h"
|
#include "dsp/fftengine.h"
|
||||||
|
#include "util/db.h"
|
||||||
|
|
||||||
|
#include "lorademodmsg.h"
|
||||||
#include "lorademodsink.h"
|
#include "lorademodsink.h"
|
||||||
|
|
||||||
LoRaDemodSink::LoRaDemodSink() :
|
LoRaDemodSink::LoRaDemodSink() :
|
||||||
|
m_decodeMsg(nullptr),
|
||||||
|
m_decoderMsgQueue(nullptr),
|
||||||
m_spectrumSink(nullptr),
|
m_spectrumSink(nullptr),
|
||||||
m_spectrumBuffer(nullptr),
|
m_spectrumBuffer(nullptr),
|
||||||
m_downChirps(nullptr),
|
m_downChirps(nullptr),
|
||||||
@ -33,6 +37,7 @@ LoRaDemodSink::LoRaDemodSink() :
|
|||||||
m_fftBuffer(nullptr),
|
m_fftBuffer(nullptr),
|
||||||
m_spectrumLine(nullptr)
|
m_spectrumLine(nullptr)
|
||||||
{
|
{
|
||||||
|
m_demodActive = false;
|
||||||
m_bandwidth = LoRaDemodSettings::bandwidths[0];
|
m_bandwidth = LoRaDemodSettings::bandwidths[0];
|
||||||
m_channelSampleRate = 96000;
|
m_channelSampleRate = 96000;
|
||||||
m_channelFrequencyOffset = 0;
|
m_channelFrequencyOffset = 0;
|
||||||
@ -134,6 +139,7 @@ void LoRaDemodSink::processSample(const Complex& ci)
|
|||||||
{
|
{
|
||||||
if (m_state == LoRaStateReset) // start over
|
if (m_state == LoRaStateReset) // start over
|
||||||
{
|
{
|
||||||
|
m_demodActive = false;
|
||||||
reset();
|
reset();
|
||||||
m_state = LoRaStateDetectPreamble;
|
m_state = LoRaStateDetectPreamble;
|
||||||
}
|
}
|
||||||
@ -147,21 +153,22 @@ void LoRaDemodSink::processSample(const Complex& ci)
|
|||||||
std::fill(m_fft->in()+m_fftLength, m_fft->in()+m_fftInterpolation*m_fftLength, Complex{0.0, 0.0});
|
std::fill(m_fft->in()+m_fftLength, m_fft->in()+m_fftInterpolation*m_fftLength, Complex{0.0, 0.0});
|
||||||
m_fft->transform();
|
m_fft->transform();
|
||||||
m_fftCounter = 0;
|
m_fftCounter = 0;
|
||||||
|
double magsq;
|
||||||
|
|
||||||
unsigned int imax = argmax(
|
unsigned int imax = argmax(
|
||||||
m_fft->out(),
|
m_fft->out(),
|
||||||
m_fftInterpolation,
|
m_fftInterpolation,
|
||||||
m_fftLength,
|
m_fftLength,
|
||||||
m_magsq,
|
magsq,
|
||||||
m_spectrumBuffer,
|
m_spectrumBuffer,
|
||||||
m_fftInterpolation
|
m_fftInterpolation
|
||||||
) / m_fftInterpolation;
|
) / m_fftInterpolation;
|
||||||
|
|
||||||
// Debug:
|
if (m_magsqQueue.size() > m_requiredPreambleChirps + 1) {
|
||||||
// if (m_spectrumSink) {
|
m_magsqQueue.pop();
|
||||||
// m_spectrumSink->feed(m_spectrumBuffer, m_nbSymbols);
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
|
m_magsqQueue.push(magsq);
|
||||||
m_argMaxHistory[m_argMaxHistoryCounter++] = imax;
|
m_argMaxHistory[m_argMaxHistoryCounter++] = imax;
|
||||||
|
|
||||||
if (m_argMaxHistoryCounter == m_requiredPreambleChirps)
|
if (m_argMaxHistoryCounter == m_requiredPreambleChirps)
|
||||||
@ -178,19 +185,23 @@ void LoRaDemodSink::processSample(const Complex& ci)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((preambleFound) && (m_magsq > 1e-9))
|
if ((preambleFound) && (magsq > 1e-9))
|
||||||
{
|
{
|
||||||
if (m_spectrumSink) {
|
if (m_spectrumSink) {
|
||||||
m_spectrumSink->feed(m_spectrumBuffer, m_nbSymbols);
|
m_spectrumSink->feed(m_spectrumBuffer, m_nbSymbols);
|
||||||
}
|
}
|
||||||
|
|
||||||
qDebug("LoRaDemodSink::processSample: preamble found: %u|%f", m_argMaxHistory[0], m_magsq);
|
qDebug("LoRaDemodSink::processSample: preamble found: %u|%f", m_argMaxHistory[0], magsq);
|
||||||
m_chirp = m_argMaxHistory[0];
|
m_chirp = m_argMaxHistory[0];
|
||||||
m_fftCounter = m_chirp;
|
m_fftCounter = m_chirp;
|
||||||
m_chirp0 = 0;
|
m_chirp0 = 0;
|
||||||
m_chirpCount = 0;
|
m_chirpCount = 0;
|
||||||
m_state = LoRaStatePreambleResyc;
|
m_state = LoRaStatePreambleResyc;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_magsqOffAvg(m_magsqQueue.front());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -205,6 +216,7 @@ void LoRaDemodSink::processSample(const Complex& ci)
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_fftCounter = 0;
|
m_fftCounter = 0;
|
||||||
|
m_demodActive = true;
|
||||||
m_state = LoRaStatePreamble;
|
m_state = LoRaStatePreamble;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -281,7 +293,6 @@ void LoRaDemodSink::processSample(const Complex& ci)
|
|||||||
m_fftCounter = m_fftLength - m_sfdSkip + zadj;
|
m_fftCounter = m_fftLength - m_sfdSkip + zadj;
|
||||||
m_chirp += zadj;
|
m_chirp += zadj;
|
||||||
//std::copy(m_fftBuffer+m_sfdSkip, m_fftBuffer+(m_fftLength-m_sfdSkip), m_fftBuffer); // prepare sliding fft
|
//std::copy(m_fftBuffer+m_sfdSkip, m_fftBuffer+(m_fftLength-m_sfdSkip), m_fftBuffer); // prepare sliding fft
|
||||||
m_magsq = magsqSFD;
|
|
||||||
m_state = LoRaStateSkipSFD; //LoRaStateSlideSFD;
|
m_state = LoRaStateSkipSFD; //LoRaStateSlideSFD;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -296,7 +307,7 @@ void LoRaDemodSink::processSample(const Complex& ci)
|
|||||||
}
|
}
|
||||||
|
|
||||||
qDebug("LoRaDemodSink::processSample: SFD search: up: %4u|%11.6f - down: %4u|%11.6f", imax, magsq, imaxSFD, magsqSFD);
|
qDebug("LoRaDemodSink::processSample: SFD search: up: %4u|%11.6f - down: %4u|%11.6f", imax, magsq, imaxSFD, magsqSFD);
|
||||||
m_magsq = magsq;
|
m_magsqOnAvg(magsq);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -311,12 +322,15 @@ void LoRaDemodSink::processSample(const Complex& ci)
|
|||||||
|
|
||||||
if (m_sfdSkipCounter == m_sfdFourths) // 1.25 SFD chips left
|
if (m_sfdSkipCounter == m_sfdFourths) // 1.25 SFD chips left
|
||||||
{
|
{
|
||||||
|
qDebug("LoRaDemodSink::processSample: SFD skipped");
|
||||||
m_chirp = m_chirp0;
|
m_chirp = m_chirp0;
|
||||||
m_fftCounter = 0;
|
m_fftCounter = 0;
|
||||||
m_chirpCount = 0;
|
m_chirpCount = 0;
|
||||||
int correction = 0;
|
int correction = 0;
|
||||||
qDebug("LoRaDemodSink::processSample: SFD skipped");
|
m_magsqMax = 0.0;
|
||||||
m_state = LoRaStateReadPayload; //LoRaStateReadPayload;
|
m_decodeMsg = LoRaDemodMsg::MsgDecodeSymbols::create();
|
||||||
|
m_decodeMsg->setSyncWord(m_syncWord);
|
||||||
|
m_state = LoRaStateReadPayload;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -353,11 +367,14 @@ void LoRaDemodSink::processSample(const Complex& ci)
|
|||||||
|
|
||||||
if (m_sfdSkipCounter == m_sfdFourths) // 1.25 SFD chips length
|
if (m_sfdSkipCounter == m_sfdFourths) // 1.25 SFD chips length
|
||||||
{
|
{
|
||||||
|
qDebug("LoRaDemodSink::processSample: SFD done");
|
||||||
m_chirp = m_chirp0;
|
m_chirp = m_chirp0;
|
||||||
m_fftCounter = 0;
|
m_fftCounter = 0;
|
||||||
m_chirpCount = 0;
|
m_chirpCount = 0;
|
||||||
int correction = 0;
|
int correction = 0;
|
||||||
qDebug("LoRaDemodSink::processSample: SFD done");
|
m_magsqMax = 0.0;
|
||||||
|
m_decodeMsg = LoRaDemodMsg::MsgDecodeSymbols::create();
|
||||||
|
m_decodeMsg->setSyncWord(m_syncWord);
|
||||||
m_state = LoRaStateReadPayload; //LoRaStateReadPayload;
|
m_state = LoRaStateReadPayload; //LoRaStateReadPayload;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -390,22 +407,47 @@ void LoRaDemodSink::processSample(const Complex& ci)
|
|||||||
m_spectrumSink->feed(m_spectrumBuffer, m_nbSymbols);
|
m_spectrumSink->feed(m_spectrumBuffer, m_nbSymbols);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((m_chirpCount == 0) || (10.0*magsq > m_magsq))
|
if (magsq > m_magsqMax) {
|
||||||
|
m_magsqMax = magsq;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_decodeMsg->pushBackSymbol(symbol);
|
||||||
|
|
||||||
|
if ((m_chirpCount == 0)
|
||||||
|
|| (m_settings.m_eomSquelchTenths == 121) // max - disable squelch
|
||||||
|
|| ((m_settings.m_eomSquelchTenths*magsq)/10.0 > m_magsqMax))
|
||||||
{
|
{
|
||||||
qDebug("LoRaDemodSink::processSample: symbol %02u: %4u|%11.6f", m_chirpCount, symbol, magsq);
|
qDebug("LoRaDemodSink::processSample: symbol %02u: %4u|%11.6f", m_chirpCount, symbol, magsq);
|
||||||
m_magsq = magsq;
|
m_magsqOnAvg(magsq);
|
||||||
m_chirpCount++;
|
m_chirpCount++;
|
||||||
|
|
||||||
if (m_chirpCount > 255)
|
if (m_chirpCount > m_settings.m_nbSymbolsMax)
|
||||||
{
|
{
|
||||||
qDebug("LoRaDemodSink::processSample: message length exceeded");
|
qDebug("LoRaDemodSink::processSample: message length exceeded");
|
||||||
m_state = LoRaStateReset;
|
m_state = LoRaStateReset;
|
||||||
|
m_decodeMsg->setSignalDb(CalcDb::dbPower(m_magsqOnAvg.asDouble() / (1<<m_settings.m_spreadFactor)));
|
||||||
|
m_decodeMsg->setNoiseDb(CalcDb::dbPower(m_magsqOffAvg.asDouble() / (1<<m_settings.m_spreadFactor)));
|
||||||
|
|
||||||
|
if (m_decoderMsgQueue && m_settings.m_decodeActive) {
|
||||||
|
m_decoderMsgQueue->push(m_decodeMsg);
|
||||||
|
} else {
|
||||||
|
delete m_decodeMsg;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
qDebug("LoRaDemodSink::processSample: end of message");
|
qDebug("LoRaDemodSink::processSample: end of message");
|
||||||
m_state = LoRaStateReset;
|
m_state = LoRaStateReset;
|
||||||
|
m_decodeMsg->popSymbol(); // last symbol is garbage
|
||||||
|
m_decodeMsg->setSignalDb(CalcDb::dbPower(m_magsqOnAvg.asDouble() / (1<<m_settings.m_spreadFactor)));
|
||||||
|
m_decodeMsg->setNoiseDb(CalcDb::dbPower(m_magsqOffAvg.asDouble() / (1<<m_settings.m_spreadFactor)));
|
||||||
|
|
||||||
|
if (m_decoderMsgQueue && m_settings.m_decodeActive) {
|
||||||
|
m_decoderMsgQueue->push(m_decodeMsg);
|
||||||
|
} else {
|
||||||
|
delete m_decodeMsg;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,17 +19,23 @@
|
|||||||
#define INCLUDE_LORADEMODSINK_H
|
#define INCLUDE_LORADEMODSINK_H
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
#include "dsp/channelsamplesink.h"
|
#include "dsp/channelsamplesink.h"
|
||||||
#include "dsp/nco.h"
|
#include "dsp/nco.h"
|
||||||
#include "dsp/interpolator.h"
|
#include "dsp/interpolator.h"
|
||||||
#include "util/message.h"
|
|
||||||
#include "dsp/fftwindow.h"
|
#include "dsp/fftwindow.h"
|
||||||
|
#include "util/message.h"
|
||||||
|
#include "util/movingaverage.h"
|
||||||
|
|
||||||
#include "lorademodsettings.h"
|
#include "lorademodsettings.h"
|
||||||
|
|
||||||
class BasebandSampleSink;
|
class BasebandSampleSink;
|
||||||
class FFTEngine;
|
class FFTEngine;
|
||||||
|
namespace LoRaDemodMsg {
|
||||||
|
class MsgDecodeSymbols;
|
||||||
|
}
|
||||||
|
class MessageQueue;
|
||||||
|
|
||||||
class LoRaDemodSink : public ChannelSampleSink {
|
class LoRaDemodSink : public ChannelSampleSink {
|
||||||
public:
|
public:
|
||||||
@ -38,6 +44,8 @@ public:
|
|||||||
|
|
||||||
virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end);
|
virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end);
|
||||||
|
|
||||||
|
bool getDemodActive() const { return m_demodActive; }
|
||||||
|
void setDecoderMessageQueue(MessageQueue *messageQueue) { m_decoderMsgQueue = messageQueue; }
|
||||||
void setSpectrumSink(BasebandSampleSink* spectrumSink) { m_spectrumSink = spectrumSink; }
|
void setSpectrumSink(BasebandSampleSink* spectrumSink) { m_spectrumSink = spectrumSink; }
|
||||||
void applyChannelSettings(int channelSampleRate, int bandwidth, int channelFrequencyOffset, bool force = false);
|
void applyChannelSettings(int channelSampleRate, int bandwidth, int channelFrequencyOffset, bool force = false);
|
||||||
void applySettings(const LoRaDemodSettings& settings, bool force = false);
|
void applySettings(const LoRaDemodSettings& settings, bool force = false);
|
||||||
@ -57,6 +65,9 @@ private:
|
|||||||
|
|
||||||
LoRaDemodSettings m_settings;
|
LoRaDemodSettings m_settings;
|
||||||
LoRaState m_state;
|
LoRaState m_state;
|
||||||
|
bool m_demodActive;
|
||||||
|
LoRaDemodMsg::MsgDecodeSymbols *m_decodeMsg;
|
||||||
|
MessageQueue *m_decoderMsgQueue;
|
||||||
int m_bandwidth;
|
int m_bandwidth;
|
||||||
int m_channelSampleRate;
|
int m_channelSampleRate;
|
||||||
int m_channelFrequencyOffset;
|
int m_channelFrequencyOffset;
|
||||||
@ -80,7 +91,10 @@ private:
|
|||||||
unsigned int m_argMaxHistoryCounter;
|
unsigned int m_argMaxHistoryCounter;
|
||||||
unsigned int m_preambleHistory[m_maxSFDSearchChirps];
|
unsigned int m_preambleHistory[m_maxSFDSearchChirps];
|
||||||
unsigned int m_syncWord;
|
unsigned int m_syncWord;
|
||||||
double m_magsq;
|
double m_magsqMax;
|
||||||
|
MovingAverageUtil<double, double, 10> m_magsqOnAvg;
|
||||||
|
MovingAverageUtil<double, double, 10> m_magsqOffAvg;
|
||||||
|
std::queue<double> m_magsqQueue;
|
||||||
unsigned int m_chirpCount; //!< Generic chirp counter
|
unsigned int m_chirpCount; //!< Generic chirp counter
|
||||||
unsigned int m_sfdSkip; //!< Number of samples in a SFD skip or slide (1/4) period
|
unsigned int m_sfdSkip; //!< Number of samples in a SFD skip or slide (1/4) period
|
||||||
unsigned int m_sfdSkipCounter; //!< Counter of skip or slide periods
|
unsigned int m_sfdSkipCounter; //!< Counter of skip or slide periods
|
||||||
|
|||||||
@ -1,3 +1,20 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright (C) 2019-2020 Edouard Griffiths, F4EXB //
|
||||||
|
// //
|
||||||
|
// This program is free software; you can redistribute it and/or modify //
|
||||||
|
// it under the terms of the GNU General Public License as published by //
|
||||||
|
// the Free Software Foundation as version 3 of the License, or //
|
||||||
|
// (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 <QtPlugin>
|
||||||
#include "plugin/pluginapi.h"
|
#include "plugin/pluginapi.h"
|
||||||
|
|
||||||
@ -17,7 +34,7 @@ const PluginDescriptor LoRaPlugin::m_pluginDescriptor = {
|
|||||||
|
|
||||||
LoRaPlugin::LoRaPlugin(QObject* parent) :
|
LoRaPlugin::LoRaPlugin(QObject* parent) :
|
||||||
QObject(parent),
|
QObject(parent),
|
||||||
m_pluginAPI(0)
|
m_pluginAPI(nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +1,20 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright (C) 2019-2020 Edouard Griffiths, F4EXB //
|
||||||
|
// //
|
||||||
|
// This program is free software; you can redistribute it and/or modify //
|
||||||
|
// it under the terms of the GNU General Public License as published by //
|
||||||
|
// the Free Software Foundation as version 3 of the License, or //
|
||||||
|
// (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_LoRaPLUGIN_H
|
#ifndef INCLUDE_LoRaPLUGIN_H
|
||||||
#define INCLUDE_LoRaPLUGIN_H
|
#define INCLUDE_LoRaPLUGIN_H
|
||||||
|
|
||||||
@ -13,7 +30,7 @@ class LoRaPlugin : public QObject, PluginInterface {
|
|||||||
Q_PLUGIN_METADATA(IID "sdrangel.channel.lorademod")
|
Q_PLUGIN_METADATA(IID "sdrangel.channel.lorademod")
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit LoRaPlugin(QObject* parent = NULL);
|
explicit LoRaPlugin(QObject* parent = nullptr);
|
||||||
|
|
||||||
const PluginDescriptor& getPluginDescriptor() const;
|
const PluginDescriptor& getPluginDescriptor() const;
|
||||||
void initPlugin(PluginAPI* pluginAPI);
|
void initPlugin(PluginAPI* pluginAPI);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user