mirror of
https://github.com/f4exb/sdrangel.git
synced 2026-05-02 04:04:02 -04:00
Merge branch 'f4exb:master' into inmarsat
This commit is contained in:
commit
d4c187602f
@ -19,6 +19,6 @@
|
||||
|
||||
#include "devicehackrfshared.h"
|
||||
|
||||
MESSAGE_CLASS_DEFINITION(DeviceHackRFShared::MsgSynchronizeFrequency, Message)
|
||||
MESSAGE_CLASS_DEFINITION(DeviceHackRFShared::MsgSynchronizeSampleRate, Message)
|
||||
|
||||
const unsigned int DeviceHackRFShared::m_sampleFifoMinRate = 48000; // 48kS/s knee
|
||||
|
||||
@ -28,24 +28,24 @@
|
||||
class DEVICES_API DeviceHackRFShared
|
||||
{
|
||||
public:
|
||||
class DEVICES_API MsgSynchronizeFrequency : public Message
|
||||
class DEVICES_API MsgSynchronizeSampleRate : public Message
|
||||
{
|
||||
MESSAGE_CLASS_DECLARATION
|
||||
|
||||
public:
|
||||
uint64_t getFrequency() const { return m_frequency; }
|
||||
uint64_t getDeviceSampleRate() const { return m_deviceSampleRate; }
|
||||
|
||||
static MsgSynchronizeFrequency *create(uint64_t frequency)
|
||||
static MsgSynchronizeSampleRate *create(uint64_t deviceSampleRate)
|
||||
{
|
||||
return new MsgSynchronizeFrequency(frequency);
|
||||
return new MsgSynchronizeSampleRate(deviceSampleRate);
|
||||
}
|
||||
|
||||
private:
|
||||
uint64_t m_frequency;
|
||||
uint64_t m_deviceSampleRate;
|
||||
|
||||
MsgSynchronizeFrequency(uint64_t frequency) :
|
||||
MsgSynchronizeSampleRate(uint64_t deviceSampleRate) :
|
||||
Message(),
|
||||
m_frequency(frequency)
|
||||
m_deviceSampleRate(deviceSampleRate)
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 76 KiB |
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 137 KiB |
Binary file not shown.
@ -217,6 +217,7 @@ void BFMDemod::applySettings(const BFMDemodSettings& settings, bool force)
|
||||
<< " m_inputFrequencyOffset: " << settings.m_inputFrequencyOffset
|
||||
<< " m_rfBandwidth: " << settings.m_rfBandwidth
|
||||
<< " m_afBandwidth: " << settings.m_afBandwidth
|
||||
<< " m_deEmphasis: " << settings.getDeEmphasisTimeConstant()
|
||||
<< " m_volume: " << settings.m_volume
|
||||
<< " m_squelch: " << settings.m_squelch
|
||||
<< " m_audioStereo: " << settings.m_audioStereo
|
||||
@ -236,6 +237,9 @@ void BFMDemod::applySettings(const BFMDemodSettings& settings, bool force)
|
||||
if ((settings.m_volume != m_settings.m_volume) || force) {
|
||||
reverseAPIKeys.append("volume");
|
||||
}
|
||||
if ((settings.m_audioMute != m_settings.m_audioMute) || force) {
|
||||
reverseAPIKeys.append("audioMute");
|
||||
}
|
||||
if ((settings.m_audioStereo != m_settings.m_audioStereo) || force) {
|
||||
reverseAPIKeys.append("audioStereo");
|
||||
}
|
||||
@ -254,6 +258,9 @@ void BFMDemod::applySettings(const BFMDemodSettings& settings, bool force)
|
||||
if ((settings.m_rfBandwidth != m_settings.m_rfBandwidth) || force) {
|
||||
reverseAPIKeys.append("rfBandwidth");
|
||||
}
|
||||
if ((settings.m_deEmphasis != m_settings.m_deEmphasis) || force) {
|
||||
reverseAPIKeys.append("deEmphasis");
|
||||
}
|
||||
if ((settings.m_squelch != m_settings.m_squelch) || force) {
|
||||
reverseAPIKeys.append("squelch");
|
||||
}
|
||||
@ -383,12 +390,22 @@ void BFMDemod::webapiUpdateChannelSettings(
|
||||
if (channelSettingsKeys.contains("afBandwidth")) {
|
||||
settings.m_afBandwidth = response.getBfmDemodSettings()->getAfBandwidth();
|
||||
}
|
||||
if (channelSettingsKeys.contains("deEmphasis"))
|
||||
{
|
||||
int deEmphasis = response.getBfmDemodSettings()->getDeEmphasis();
|
||||
if (deEmphasis >= 0 && deEmphasis < 2) {
|
||||
settings.m_deEmphasis = static_cast<BFMDemodSettings::DeEmphasis>(deEmphasis);
|
||||
}
|
||||
}
|
||||
if (channelSettingsKeys.contains("volume")) {
|
||||
settings.m_volume = response.getBfmDemodSettings()->getVolume();
|
||||
}
|
||||
if (channelSettingsKeys.contains("squelch")) {
|
||||
settings.m_squelch = response.getBfmDemodSettings()->getSquelch();
|
||||
}
|
||||
if (channelSettingsKeys.contains("audioMute")) {
|
||||
settings.m_audioMute = response.getBfmDemodSettings()->getAudioMute() != 0;
|
||||
}
|
||||
if (channelSettingsKeys.contains("audioStereo")) {
|
||||
settings.m_audioStereo = response.getBfmDemodSettings()->getAudioStereo() != 0;
|
||||
}
|
||||
@ -455,8 +472,10 @@ void BFMDemod::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& resp
|
||||
response.getBfmDemodSettings()->setInputFrequencyOffset(settings.m_inputFrequencyOffset);
|
||||
response.getBfmDemodSettings()->setRfBandwidth(settings.m_rfBandwidth);
|
||||
response.getBfmDemodSettings()->setAfBandwidth(settings.m_afBandwidth);
|
||||
response.getBfmDemodSettings()->setDeEmphasis(static_cast<int>(settings.m_deEmphasis));
|
||||
response.getBfmDemodSettings()->setVolume(settings.m_volume);
|
||||
response.getBfmDemodSettings()->setSquelch(settings.m_squelch);
|
||||
response.getBfmDemodSettings()->setAudioMute(settings.m_audioMute ? 1 : 0);
|
||||
response.getBfmDemodSettings()->setAudioStereo(settings.m_audioStereo ? 1 : 0);
|
||||
response.getBfmDemodSettings()->setLsbStereo(settings.m_lsbStereo ? 1 : 0);
|
||||
response.getBfmDemodSettings()->setShowPilot(settings.m_showPilot ? 1 : 0);
|
||||
@ -665,12 +684,18 @@ void BFMDemod::webapiFormatChannelSettings(
|
||||
if (channelSettingsKeys.contains("afBandwidth") || force) {
|
||||
swgBFMDemodSettings->setAfBandwidth(settings.m_afBandwidth);
|
||||
}
|
||||
if (channelSettingsKeys.contains("deEmphasis") || force) {
|
||||
swgBFMDemodSettings->setDeEmphasis(static_cast<int>(settings.m_deEmphasis));
|
||||
}
|
||||
if (channelSettingsKeys.contains("volume") || force) {
|
||||
swgBFMDemodSettings->setVolume(settings.m_volume);
|
||||
}
|
||||
if (channelSettingsKeys.contains("squelch") || force) {
|
||||
swgBFMDemodSettings->setSquelch(settings.m_squelch);
|
||||
}
|
||||
if (channelSettingsKeys.contains("audioMute") || force) {
|
||||
swgBFMDemodSettings->setAudioMute(settings.m_audioMute ? 1 : 0);
|
||||
}
|
||||
if (channelSettingsKeys.contains("audioStereo") || force) {
|
||||
swgBFMDemodSettings->setAudioStereo(settings.m_audioStereo ? 1 : 0);
|
||||
}
|
||||
|
||||
@ -179,6 +179,12 @@ void BFMDemodGUI::on_afBW_valueChanged(int value)
|
||||
applySettings();
|
||||
}
|
||||
|
||||
void BFMDemodGUI::on_deEmphasis_currentIndexChanged(int index)
|
||||
{
|
||||
m_settings.m_deEmphasis = static_cast<BFMDemodSettings::DeEmphasis>(index);
|
||||
applySettings();
|
||||
}
|
||||
|
||||
void BFMDemodGUI::on_volume_valueChanged(int value)
|
||||
{
|
||||
ui->volumeText->setText(QString("%1").arg(value / 10.0, 0, 'f', 1));
|
||||
@ -193,6 +199,12 @@ void BFMDemodGUI::on_squelch_valueChanged(int value)
|
||||
applySettings();
|
||||
}
|
||||
|
||||
void BFMDemodGUI::on_audioMute_toggled(bool mute)
|
||||
{
|
||||
m_settings.m_audioMute = mute;
|
||||
applySettings();
|
||||
}
|
||||
|
||||
void BFMDemodGUI::on_audioStereo_toggled(bool stereo)
|
||||
{
|
||||
if (!stereo)
|
||||
@ -512,6 +524,7 @@ void BFMDemodGUI::displaySettings()
|
||||
ui->squelch->setValue(m_settings.m_squelch);
|
||||
ui->squelchText->setText(QString("%1 dB").arg(m_settings.m_squelch));
|
||||
|
||||
ui->audioMute->setChecked(m_settings.m_audioMute);
|
||||
ui->audioStereo->setChecked(m_settings.m_audioStereo);
|
||||
ui->lsbStereo->setChecked(m_settings.m_lsbStereo);
|
||||
ui->showPilot->setChecked(m_settings.m_showPilot);
|
||||
@ -879,8 +892,10 @@ void BFMDemodGUI::makeUIConnections()
|
||||
QObject::connect(ui->deltaFrequency, &ValueDialZ::changed, this, &BFMDemodGUI::on_deltaFrequency_changed);
|
||||
QObject::connect(ui->rfBW, &QSlider::valueChanged, this, &BFMDemodGUI::on_rfBW_valueChanged);
|
||||
QObject::connect(ui->afBW, &QSlider::valueChanged, this, &BFMDemodGUI::on_afBW_valueChanged);
|
||||
QObject::connect(ui->deEmphasis, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &BFMDemodGUI::on_deEmphasis_currentIndexChanged);
|
||||
QObject::connect(ui->volume, &QSlider::valueChanged, this, &BFMDemodGUI::on_volume_valueChanged);
|
||||
QObject::connect(ui->squelch, &QSlider::valueChanged, this, &BFMDemodGUI::on_squelch_valueChanged);
|
||||
QObject::connect(ui->audioMute, &QToolButton::toggled, this, &BFMDemodGUI::on_audioMute_toggled);
|
||||
QObject::connect(ui->audioStereo, &QToolButton::toggled, this, &BFMDemodGUI::on_audioStereo_toggled);
|
||||
QObject::connect(ui->lsbStereo, &ButtonSwitch::toggled, this, &BFMDemodGUI::on_lsbStereo_toggled);
|
||||
QObject::connect(ui->showPilot, &ButtonSwitch::clicked, this, &BFMDemodGUI::on_showPilot_clicked);
|
||||
|
||||
@ -108,8 +108,10 @@ private slots:
|
||||
void on_deltaFrequency_changed(qint64 value);
|
||||
void on_rfBW_valueChanged(int value);
|
||||
void on_afBW_valueChanged(int value);
|
||||
void on_deEmphasis_currentIndexChanged(int index);
|
||||
void on_volume_valueChanged(int value);
|
||||
void on_squelch_valueChanged(int value);
|
||||
void on_audioMute_toggled(bool mute);
|
||||
void on_audioStereo_toggled(bool stereo);
|
||||
void on_lsbStereo_toggled(bool lsb);
|
||||
void on_showPilot_clicked();
|
||||
|
||||
@ -267,6 +267,24 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="audioMute">
|
||||
<property name="toolTip">
|
||||
<string>Mute/Unmute audio</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../sdrgui/resources/res.qrc">
|
||||
<normaloff>:/sound_on.png</normaloff>
|
||||
<normalon>:/sound_off.png</normalon>:/sound_on.png</iconset>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
@ -400,6 +418,37 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="deEmphasisLabel">
|
||||
<property name="text">
|
||||
<string>De-emph</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="deEmphasis">
|
||||
<property name="toolTip">
|
||||
<string>De-emphasis time constant</string>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>50us</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>75us</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
@ -1883,11 +1932,6 @@
|
||||
</widget>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>ButtonSwitch</class>
|
||||
<extends>QToolButton</extends>
|
||||
<header>gui/buttonswitch.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>RollupContents</class>
|
||||
<extends>QWidget</extends>
|
||||
@ -1900,6 +1944,11 @@
|
||||
<header>gui/valuedialz.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>ButtonSwitch</class>
|
||||
<extends>QToolButton</extends>
|
||||
<header>gui/buttonswitch.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>LevelMeterSignalDB</class>
|
||||
<extends>QWidget</extends>
|
||||
|
||||
@ -46,10 +46,12 @@ void BFMDemodSettings::resetToDefaults()
|
||||
m_afBandwidth = 15000;
|
||||
m_volume = 2.0;
|
||||
m_squelch = -60.0;
|
||||
m_audioMute = false;
|
||||
m_audioStereo = false;
|
||||
m_lsbStereo = false;
|
||||
m_showPilot = false;
|
||||
m_rdsActive = false;
|
||||
m_deEmphasis = DeEmphasis50us;
|
||||
m_rgbColor = QColor(80, 120, 228).rgb();
|
||||
m_title = "Broadcast FM Demod";
|
||||
m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName;
|
||||
@ -101,6 +103,8 @@ QByteArray BFMDemodSettings::serialize() const
|
||||
s.writeS32(22, m_workspaceIndex);
|
||||
s.writeBlob(23, m_geometryBytes);
|
||||
s.writeBool(24, m_hidden);
|
||||
s.writeBool(25, m_audioMute);
|
||||
s.writeS32(26, m_deEmphasis);
|
||||
|
||||
return s.final();
|
||||
}
|
||||
@ -178,6 +182,9 @@ bool BFMDemodSettings::deserialize(const QByteArray& data)
|
||||
d.readS32(22, &m_workspaceIndex, 0);
|
||||
d.readBlob(23, &m_geometryBytes);
|
||||
d.readBool(24, &m_hidden, false);
|
||||
d.readBool(25, &m_audioMute, false);
|
||||
d.readS32(26, &tmp, DeEmphasis50us);
|
||||
m_deEmphasis = static_cast<DeEmphasis>(tmp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -27,15 +27,23 @@ class Serializable;
|
||||
|
||||
struct BFMDemodSettings
|
||||
{
|
||||
enum DeEmphasis
|
||||
{
|
||||
DeEmphasis50us,
|
||||
DeEmphasis75us,
|
||||
};
|
||||
|
||||
qint64 m_inputFrequencyOffset;
|
||||
Real m_rfBandwidth;
|
||||
Real m_afBandwidth;
|
||||
Real m_volume;
|
||||
Real m_squelch;
|
||||
bool m_audioMute;
|
||||
bool m_audioStereo;
|
||||
bool m_lsbStereo;
|
||||
bool m_showPilot;
|
||||
bool m_rdsActive;
|
||||
DeEmphasis m_deEmphasis;
|
||||
quint32 m_rgbColor;
|
||||
QString m_title;
|
||||
QString m_audioDeviceName;
|
||||
@ -75,6 +83,19 @@ struct BFMDemodSettings
|
||||
return (3*rfBW)/2;
|
||||
}
|
||||
}
|
||||
|
||||
double getDeEmphasisTimeConstant() const
|
||||
{
|
||||
switch (m_deEmphasis)
|
||||
{
|
||||
case DeEmphasis50us:
|
||||
return 50e-6;
|
||||
case DeEmphasis75us:
|
||||
return 75e-6;
|
||||
default:
|
||||
return 50e-6;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -30,7 +30,6 @@
|
||||
#include "rdsparser.h"
|
||||
#include "bfmdemodsink.h"
|
||||
|
||||
const Real BFMDemodSink::default_deemphasis = 50.0; // 50 us
|
||||
const int BFMDemodSink::default_excursion = 750000; // +/- 75 kHz
|
||||
|
||||
BFMDemodSink::BFMDemodSink() :
|
||||
@ -41,8 +40,8 @@ BFMDemodSink::BFMDemodSink() :
|
||||
m_audioBufferFill(0),
|
||||
m_audioFifo(48000),
|
||||
m_pilotPLL(19000/384000, 50/384000, 0.01),
|
||||
m_deemphasisFilterX(default_deemphasis * 48000 * 1.0e-6),
|
||||
m_deemphasisFilterY(default_deemphasis * 48000 * 1.0e-6),
|
||||
m_deemphasisFilterX(m_settings.getDeEmphasisTimeConstant() * 48000),
|
||||
m_deemphasisFilterY(m_settings.getDeEmphasisTimeConstant() * 48000),
|
||||
m_fmExcursion(default_excursion)
|
||||
{
|
||||
m_magsq = 0.0f;
|
||||
@ -67,8 +66,8 @@ BFMDemodSink::BFMDemodSink() :
|
||||
|
||||
m_rfFilter = new fftfilt(-50000.0 / 384000.0, 50000.0 / 384000.0, filtFftLen);
|
||||
|
||||
m_deemphasisFilterX.configure(default_deemphasis * m_audioSampleRate * 1.0e-6);
|
||||
m_deemphasisFilterY.configure(default_deemphasis * m_audioSampleRate * 1.0e-6);
|
||||
m_deemphasisFilterX.configure(m_settings.getDeEmphasisTimeConstant() * m_audioSampleRate);
|
||||
m_deemphasisFilterY.configure(m_settings.getDeEmphasisTimeConstant() * m_audioSampleRate);
|
||||
m_phaseDiscri.setFMScaling(384000/m_fmExcursion);
|
||||
|
||||
m_audioBuffer.resize(1<<14);
|
||||
@ -96,6 +95,10 @@ void BFMDemodSink::feed(const SampleVector::const_iterator& begin, const SampleV
|
||||
|
||||
m_sampleBuffer.clear();
|
||||
|
||||
if (m_settings.m_audioMute) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (SampleVector::const_iterator it = begin; it != end; ++it)
|
||||
{
|
||||
Complex c(it->real() / SDR_RX_SCALEF, it->imag() / SDR_RX_SCALEF);
|
||||
@ -283,8 +286,8 @@ void BFMDemodSink::applyAudioSampleRate(int sampleRate)
|
||||
m_interpolatorStereoDistanceRemain = (Real) m_channelSampleRate / sampleRate;
|
||||
m_interpolatorStereoDistance = (Real) m_channelSampleRate / (Real) sampleRate;
|
||||
|
||||
m_deemphasisFilterX.configure(default_deemphasis * sampleRate * 1.0e-6);
|
||||
m_deemphasisFilterY.configure(default_deemphasis * sampleRate * 1.0e-6);
|
||||
m_deemphasisFilterX.configure(m_settings.getDeEmphasisTimeConstant() * sampleRate);
|
||||
m_deemphasisFilterY.configure(m_settings.getDeEmphasisTimeConstant() * sampleRate);
|
||||
|
||||
m_audioSampleRate = sampleRate;
|
||||
}
|
||||
@ -333,6 +336,7 @@ void BFMDemodSink::applySettings(const BFMDemodSettings& settings, bool force)
|
||||
<< " m_inputFrequencyOffset: " << settings.m_inputFrequencyOffset
|
||||
<< " m_rfBandwidth: " << settings.m_rfBandwidth
|
||||
<< " m_afBandwidth: " << settings.m_afBandwidth
|
||||
<< " m_deEmphasis: " << settings.getDeEmphasisTimeConstant()
|
||||
<< " m_volume: " << settings.m_volume
|
||||
<< " m_squelch: " << settings.m_squelch
|
||||
<< " m_audioStereo: " << settings.m_audioStereo
|
||||
@ -344,8 +348,16 @@ void BFMDemodSink::applySettings(const BFMDemodSettings& settings, bool force)
|
||||
<< " m_useReverseAPI: " << settings.m_useReverseAPI
|
||||
<< " force: " << force;
|
||||
|
||||
if ((settings.m_audioStereo && (settings.m_audioStereo != m_settings.m_audioStereo)) || force) {
|
||||
if ((settings.m_audioStereo && (settings.m_audioStereo != m_settings.m_audioStereo)) || force)
|
||||
{
|
||||
m_pilotPLL.configure(19000.0/m_channelSampleRate, 50.0/m_channelSampleRate, 0.01);
|
||||
applyAudioSampleRate(m_audioSampleRate); // re-apply audio sample rate to reconfigure interpolators
|
||||
}
|
||||
|
||||
if ((settings.getDeEmphasisTimeConstant() != m_settings.getDeEmphasisTimeConstant()) || force)
|
||||
{
|
||||
m_deemphasisFilterX.configure(settings.getDeEmphasisTimeConstant() * m_audioSampleRate);
|
||||
m_deemphasisFilterY.configure(settings.getDeEmphasisTimeConstant() * m_audioSampleRate);
|
||||
}
|
||||
|
||||
if ((settings.m_afBandwidth != m_settings.m_afBandwidth) || force)
|
||||
|
||||
@ -155,7 +155,6 @@ private:
|
||||
|
||||
LowPassFilterRC m_deemphasisFilterX;
|
||||
LowPassFilterRC m_deemphasisFilterY;
|
||||
static const Real default_deemphasis;
|
||||
|
||||
Real m_fmExcursion;
|
||||
static const int default_excursion;
|
||||
|
||||
@ -48,25 +48,36 @@ This is the power of the reconstructed stereo pilot signal.
|
||||
|
||||
Use this button to activate or de-activate RDS decoding
|
||||
|
||||
<h3>A.8: Level meter in dB</h3>
|
||||
<h3>A.8: Audio mute</h3>
|
||||
|
||||
Use this button to mute or unmute audio
|
||||
|
||||
<h3>A.9: Level meter in dB</h3>
|
||||
|
||||
- top bar (green): average value
|
||||
- bottom bar (blue green): instantaneous peak value
|
||||
- tip vertical bar (bright green): peak hold value
|
||||
|
||||
<h3>A.9: RF Bandwidth</h3>
|
||||
<h3>A.10: RF Bandwidth</h3>
|
||||
|
||||
This is the bandwidth in kHz of the channel signal before demodulation. It can be set in steps: 80, 100, 120, 140, 160, 180, 200, 220 and 250 kHz. Inspect the baseband spectrum (B) to adjust for best quality.
|
||||
|
||||
<h3>A.10: AF bandwidth</h3>
|
||||
<h3>A.11: AF bandwidth</h3>
|
||||
|
||||
This is the AF bandwidth in kHz. It can be varied continuously between 1 and 20 kHz in steps of 1 kHz.
|
||||
|
||||
<h3>A.11: AF volume</h3>
|
||||
<h3>A.12: De-emphasis</h3>
|
||||
|
||||
Select the de-emphasis time constant:
|
||||
|
||||
- **50us**: for Europe, Australia...
|
||||
- **75us**: for North America, Japan...
|
||||
|
||||
<h3>A.13: AF volume</h3>
|
||||
|
||||
This is the relative AF volume from 0 to 10.
|
||||
|
||||
<h3>A.12: Squelch</h3>
|
||||
<h3>A.14: Squelch</h3>
|
||||
|
||||
Adjust squelch in dB.
|
||||
|
||||
|
||||
@ -9,6 +9,7 @@ set(demodft8_SOURCES
|
||||
ft8plugin.cpp
|
||||
ft8buffer.cpp
|
||||
ft8demodworker.cpp
|
||||
pskreporterworker.cpp
|
||||
)
|
||||
|
||||
set(demodft8_HEADERS
|
||||
@ -19,7 +20,8 @@ set(demodft8_HEADERS
|
||||
ft8demodwebapiadapter.h
|
||||
ft8plugin.h
|
||||
ft8buffer.h
|
||||
ft8demodworker.h;
|
||||
ft8demodworker.h
|
||||
pskreporterworker.h
|
||||
)
|
||||
|
||||
include_directories(
|
||||
|
||||
@ -329,6 +329,18 @@ void FT8Demod::applySettings(const FT8DemodSettings& settings, bool force)
|
||||
if ((m_settings.m_verifyOSD != settings.m_verifyOSD) || force) {
|
||||
reverseAPIKeys.append("verifyOSD");
|
||||
}
|
||||
if ((m_settings.m_enablePSKReporter != settings.m_enablePSKReporter) || force) {
|
||||
reverseAPIKeys.append("enablePSKReporter");
|
||||
}
|
||||
if ((m_settings.m_pskReporterCallsign != settings.m_pskReporterCallsign) || force) {
|
||||
reverseAPIKeys.append("pskReporterCallsign");
|
||||
}
|
||||
if ((m_settings.m_pskReporterLocator != settings.m_pskReporterLocator) || force) {
|
||||
reverseAPIKeys.append("pskReporterLocator");
|
||||
}
|
||||
if ((m_settings.m_pskReporterSoftware != settings.m_pskReporterSoftware) || force) {
|
||||
reverseAPIKeys.append("pskReporterSoftware");
|
||||
}
|
||||
|
||||
if (m_settings.m_streamIndex != settings.m_streamIndex)
|
||||
{
|
||||
@ -525,6 +537,18 @@ void FT8Demod::webapiUpdateChannelSettings(
|
||||
if (channelSettingsKeys.contains("verifyOSD")) {
|
||||
settings.m_verifyOSD = response.getFt8DemodSettings()->getVerifyOsd() != 0;
|
||||
}
|
||||
if (channelSettingsKeys.contains("enablePSKReporter")) {
|
||||
settings.m_enablePSKReporter = response.getFt8DemodSettings()->getEnablePskReporter() != 0;
|
||||
}
|
||||
if (channelSettingsKeys.contains("pskReporterCallsign")) {
|
||||
settings.m_pskReporterCallsign = *response.getFt8DemodSettings()->getPskReporterCallsign();
|
||||
}
|
||||
if (channelSettingsKeys.contains("pskReporterLocator")) {
|
||||
settings.m_pskReporterLocator = *response.getFt8DemodSettings()->getPskReporterLocator();
|
||||
}
|
||||
if (channelSettingsKeys.contains("pskReporterSoftware")) {
|
||||
settings.m_pskReporterSoftware = *response.getFt8DemodSettings()->getPskReporterSoftware();
|
||||
}
|
||||
if (channelSettingsKeys.contains("rgbColor")) {
|
||||
settings.m_rgbColor = response.getFt8DemodSettings()->getRgbColor();
|
||||
}
|
||||
@ -589,6 +613,10 @@ void FT8Demod::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& resp
|
||||
response.getFt8DemodSettings()->setOsdDepth(settings.m_osdDepth);
|
||||
response.getFt8DemodSettings()->setOsdLdpcThreshold(settings.m_osdLDPCThreshold);
|
||||
response.getFt8DemodSettings()->setUseOsd(settings.m_verifyOSD ? 1 : 0);
|
||||
response.getFt8DemodSettings()->setEnablePskReporter(settings.m_enablePSKReporter ? 1 : 0);
|
||||
response.getFt8DemodSettings()->setPskReporterCallsign(new QString(settings.m_pskReporterCallsign));
|
||||
response.getFt8DemodSettings()->setPskReporterLocator(new QString(settings.m_pskReporterLocator));
|
||||
response.getFt8DemodSettings()->setPskReporterSoftware(new QString(settings.m_pskReporterSoftware));
|
||||
response.getFt8DemodSettings()->setRgbColor(settings.m_rgbColor);
|
||||
|
||||
if (response.getFt8DemodSettings()->getTitle()) {
|
||||
@ -784,6 +812,18 @@ void FT8Demod::webapiFormatChannelSettings(
|
||||
if (channelSettingsKeys.contains("verifyOSD") || force) {
|
||||
swgFT8DemodSettings->setVerifyOsd(settings.m_verifyOSD ? 1 : 0);
|
||||
}
|
||||
if (channelSettingsKeys.contains("enablePSKReporter") || force) {
|
||||
swgFT8DemodSettings->setEnablePskReporter(settings.m_enablePSKReporter ? 1 : 0);
|
||||
}
|
||||
if (channelSettingsKeys.contains("pskReporterCallsign") || force) {
|
||||
swgFT8DemodSettings->setPskReporterCallsign(new QString(settings.m_pskReporterCallsign));
|
||||
}
|
||||
if (channelSettingsKeys.contains("pskReporterLocator") || force) {
|
||||
swgFT8DemodSettings->setPskReporterLocator(new QString(settings.m_pskReporterLocator));
|
||||
}
|
||||
if (channelSettingsKeys.contains("pskReporterSoftware") || force) {
|
||||
swgFT8DemodSettings->setPskReporterSoftware(new QString(settings.m_pskReporterSoftware));
|
||||
}
|
||||
if (channelSettingsKeys.contains("rgbColor") || force) {
|
||||
swgFT8DemodSettings->setRgbColor(settings.m_rgbColor);
|
||||
}
|
||||
|
||||
@ -24,6 +24,7 @@
|
||||
#include "maincore.h"
|
||||
|
||||
#include "ft8demodworker.h"
|
||||
#include "pskreporterworker.h"
|
||||
#include "ft8demodbaseband.h"
|
||||
|
||||
MESSAGE_CLASS_DEFINITION(FT8DemodBaseband::MsgConfigureFT8DemodBaseband, Message)
|
||||
@ -48,12 +49,7 @@ FT8DemodBaseband::FT8DemodBaseband() :
|
||||
m_ft8DemodWorker,
|
||||
&QObject::deleteLater
|
||||
);
|
||||
QObject::connect(
|
||||
m_workerThread,
|
||||
&QThread::finished,
|
||||
m_ft8DemodWorker,
|
||||
&QThread::deleteLater
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
this,
|
||||
&FT8DemodBaseband::bufferReady,
|
||||
@ -64,6 +60,20 @@ FT8DemodBaseband::FT8DemodBaseband() :
|
||||
|
||||
m_workerThread->start();
|
||||
|
||||
m_pskReporterThread = new QThread();
|
||||
m_pskReporterWorker = new PskReporterWorker();
|
||||
m_ft8DemodWorker->setPSKReportingMessageQueue(m_pskReporterWorker->getInputMessageQueue());
|
||||
m_pskReporterWorker->moveToThread(m_pskReporterThread);
|
||||
|
||||
QObject::connect(
|
||||
m_pskReporterThread,
|
||||
&QThread::finished,
|
||||
m_pskReporterWorker,
|
||||
&QObject::deleteLater
|
||||
);
|
||||
|
||||
m_pskReporterThread->start();
|
||||
|
||||
QObject::connect(
|
||||
&m_sampleFifo,
|
||||
&SampleSinkFifo::dataReady,
|
||||
@ -84,6 +94,8 @@ FT8DemodBaseband::~FT8DemodBaseband()
|
||||
m_workerThread->exit();
|
||||
m_workerThread->wait();
|
||||
delete[] m_ft8WorkerBuffer;
|
||||
m_pskReporterThread->exit();
|
||||
m_pskReporterThread->wait();
|
||||
}
|
||||
|
||||
void FT8DemodBaseband::reset()
|
||||
@ -96,7 +108,7 @@ void FT8DemodBaseband::reset()
|
||||
void FT8DemodBaseband::setMessageQueueToGUI(MessageQueue *messageQueue)
|
||||
{
|
||||
m_messageQueueToGUI = messageQueue;
|
||||
m_ft8DemodWorker->setReportingMessageQueue(m_messageQueueToGUI);
|
||||
m_ft8DemodWorker->setGUIReportingMessageQueue(m_messageQueueToGUI);
|
||||
}
|
||||
|
||||
void FT8DemodBaseband::setChannel(ChannelAPI *channel)
|
||||
@ -237,6 +249,22 @@ void FT8DemodBaseband::applySettings(const FT8DemodSettings& settings, bool forc
|
||||
m_ft8DemodWorker->setLogMessages(settings.m_logMessages);
|
||||
}
|
||||
|
||||
if ((settings.m_enablePSKReporter != m_settings.m_enablePSKReporter) || force) {
|
||||
m_ft8DemodWorker->setEnablePskReporter(settings.m_enablePSKReporter);
|
||||
}
|
||||
|
||||
if ((settings.m_pskReporterCallsign != m_settings.m_pskReporterCallsign) || force) {
|
||||
m_pskReporterWorker->setMyCallsign(settings.m_pskReporterCallsign);
|
||||
}
|
||||
|
||||
if ((settings.m_pskReporterLocator != m_settings.m_pskReporterLocator) || force) {
|
||||
m_pskReporterWorker->setMyLocator(settings.m_pskReporterLocator);
|
||||
}
|
||||
|
||||
if ((settings.m_pskReporterSoftware != m_settings.m_pskReporterSoftware) || force) {
|
||||
m_pskReporterWorker->setDecoderInfo(settings.m_pskReporterSoftware);
|
||||
}
|
||||
|
||||
if ((settings.m_nbDecoderThreads != m_settings.m_nbDecoderThreads) || force) {
|
||||
m_ft8DemodWorker->setNbDecoderThreads(settings.m_nbDecoderThreads);
|
||||
}
|
||||
|
||||
@ -36,6 +36,7 @@ class ChannelAPI;
|
||||
class SpectrumVis;
|
||||
class QThread;
|
||||
class FT8DemodWorker;
|
||||
class PskReporterWorker;
|
||||
|
||||
class FT8DemodBaseband : public QObject
|
||||
{
|
||||
@ -102,6 +103,8 @@ private:
|
||||
int m_tickCount;
|
||||
QThread *m_workerThread;
|
||||
FT8DemodWorker *m_ft8DemodWorker;
|
||||
QThread *m_pskReporterThread;
|
||||
PskReporterWorker *m_pskReporterWorker;
|
||||
int16_t *m_ft8WorkerBuffer;
|
||||
qint64 m_deviceCenterFrequency;
|
||||
QRecursiveMutex m_mutex;
|
||||
|
||||
@ -528,6 +528,30 @@ void FT8DemodGUI::on_settings_clicked()
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (settingsKeys.contains("enablePSKReporter"))
|
||||
{
|
||||
m_settings.m_enablePSKReporter = settings.m_enablePSKReporter;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (settingsKeys.contains("pskReporterCallsign"))
|
||||
{
|
||||
m_settings.m_pskReporterCallsign = settings.m_pskReporterCallsign;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (settingsKeys.contains("pskReporterLocator"))
|
||||
{
|
||||
m_settings.m_pskReporterLocator = settings.m_pskReporterLocator;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (settingsKeys.contains("pskReporterSoftware"))
|
||||
{
|
||||
m_settings.m_pskReporterSoftware = settings.m_pskReporterSoftware;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (settingsKeys.contains("bandPresets"))
|
||||
{
|
||||
m_settings.m_bandPresets = settings.m_bandPresets;
|
||||
|
||||
@ -19,9 +19,12 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <QColor>
|
||||
#include <QCoreApplication>
|
||||
|
||||
#include "util/simpleserializer.h"
|
||||
#include "settings/serializable.h"
|
||||
#include "maincore.h"
|
||||
#include "util/maidenhead.h"
|
||||
#include "ft8demodsettings.h"
|
||||
|
||||
const int FT8DemodSettings::m_ft8SampleRate = 12000;
|
||||
@ -66,6 +69,10 @@ void FT8DemodSettings::resetToDefaults()
|
||||
m_workspaceIndex = 0;
|
||||
m_hidden = false;
|
||||
m_filterIndex = 0;
|
||||
m_enablePSKReporter = false;
|
||||
m_pskReporterCallsign = getDefaultReporterCallsign();
|
||||
m_pskReporterLocator = getDefaultReporterLocator();
|
||||
m_pskReporterSoftware = "SDRangel FT8 Demod";
|
||||
resetBandPresets();
|
||||
}
|
||||
|
||||
@ -133,6 +140,10 @@ QByteArray FT8DemodSettings::serialize() const
|
||||
s.writeBlob(26, m_geometryBytes);
|
||||
s.writeBool(27, m_hidden);
|
||||
s.writeU32(29, m_filterIndex);
|
||||
s.writeBool(30, m_enablePSKReporter);
|
||||
s.writeString(31, m_pskReporterCallsign);
|
||||
s.writeString(32, m_pskReporterLocator);
|
||||
s.writeString(33, m_pskReporterSoftware);
|
||||
|
||||
for (unsigned int i = 0; i < 10; i++)
|
||||
{
|
||||
@ -214,6 +225,10 @@ bool FT8DemodSettings::deserialize(const QByteArray& data)
|
||||
d.readBool(27, &m_hidden, false);
|
||||
d.readU32(29, &utmp, 0);
|
||||
m_filterIndex = utmp < 10 ? utmp : 0;
|
||||
d.readBool(30, &m_enablePSKReporter, false);
|
||||
d.readString(31, &m_pskReporterCallsign, getDefaultReporterCallsign());
|
||||
d.readString(32, &m_pskReporterLocator, getDefaultReporterLocator());
|
||||
d.readString(33, &m_pskReporterSoftware, getDefaultReporterSoftware());
|
||||
|
||||
for (unsigned int i = 0; (i < 10); i++)
|
||||
{
|
||||
@ -252,3 +267,20 @@ QDataStream& operator>>(QDataStream& in, FT8DemodBandPreset& bandPreset)
|
||||
in >> bandPreset.m_channelOffset;
|
||||
return in;
|
||||
}
|
||||
|
||||
QString FT8DemodSettings::getDefaultReporterCallsign() const
|
||||
{
|
||||
return MainCore::instance()->getSettings().getStationName();
|
||||
}
|
||||
|
||||
QString FT8DemodSettings::getDefaultReporterLocator() const
|
||||
{
|
||||
float lat = MainCore::instance()->getSettings().getLatitude();
|
||||
float lon = MainCore::instance()->getSettings().getLongitude();
|
||||
return Maidenhead::toMaidenhead(lat, lon);
|
||||
}
|
||||
|
||||
QString FT8DemodSettings::getDefaultReporterSoftware() const
|
||||
{
|
||||
return QCoreApplication::applicationName() + " " + QCoreApplication::applicationVersion();
|
||||
}
|
||||
|
||||
@ -97,6 +97,10 @@ public:
|
||||
std::vector<FT8DemodFilterSettings> m_filterBank;
|
||||
unsigned int m_filterIndex;
|
||||
QList<FT8DemodBandPreset> m_bandPresets;
|
||||
bool m_enablePSKReporter;
|
||||
QString m_pskReporterCallsign;
|
||||
QString m_pskReporterLocator;
|
||||
QString m_pskReporterSoftware;
|
||||
|
||||
Serializable *m_channelMarker;
|
||||
Serializable *m_spectrumGUI;
|
||||
@ -110,6 +114,9 @@ public:
|
||||
QByteArray serialize() const;
|
||||
bool deserialize(const QByteArray& data);
|
||||
void resetBandPresets();
|
||||
QString getDefaultReporterCallsign() const;
|
||||
QString getDefaultReporterLocator() const;
|
||||
QString getDefaultReporterSoftware() const;
|
||||
|
||||
static const int m_ft8SampleRate;
|
||||
static const int m_minPowerThresholdDB;
|
||||
|
||||
@ -35,6 +35,10 @@ FT8DemodSettingsDialog::FT8DemodSettingsDialog(FT8DemodSettings& settings, QStri
|
||||
ui->osdLDPCThreshold->setValue(m_settings.m_osdLDPCThreshold);
|
||||
ui->osdLDPCThresholdText->setText(tr("%1").arg(m_settings.m_osdLDPCThreshold));
|
||||
ui->verifyOSD->setChecked(m_settings.m_verifyOSD);
|
||||
ui->enablePSKReporter->setChecked(m_settings.m_enablePSKReporter);
|
||||
ui->reportingStation->setText(m_settings.m_pskReporterCallsign);
|
||||
ui->reportingLocator->setText(m_settings.m_pskReporterLocator);
|
||||
ui->reportingSoftware->setText(m_settings.m_pskReporterSoftware);
|
||||
resizeBandsTable();
|
||||
populateBandsTable();
|
||||
connect(ui->bands, &QTableWidget::cellChanged, this, &FT8DemodSettingsDialog::textCellChanged);
|
||||
@ -162,6 +166,65 @@ void FT8DemodSettingsDialog::on_verifyOSD_stateChanged(int state)
|
||||
}
|
||||
}
|
||||
|
||||
void FT8DemodSettingsDialog::on_enablePSKReporter_toggled(bool checked)
|
||||
{
|
||||
m_settings.m_enablePSKReporter = checked;
|
||||
|
||||
if (!m_settingsKeys.contains("enablePSKReporter")) {
|
||||
m_settingsKeys.append("enablePSKReporter");
|
||||
}
|
||||
}
|
||||
|
||||
void FT8DemodSettingsDialog::on_pskReporterCallsign_editingFinished()
|
||||
{
|
||||
m_settings.m_pskReporterCallsign = ui->reportingStation->text();
|
||||
|
||||
if (!m_settingsKeys.contains("pskReporterCallsign")) {
|
||||
m_settingsKeys.append("pskReporterCallsign");
|
||||
}
|
||||
}
|
||||
|
||||
void FT8DemodSettingsDialog::on_pskReporterLocator_editingFinished()
|
||||
{
|
||||
m_settings.m_pskReporterLocator = ui->reportingLocator->text();
|
||||
|
||||
if (!m_settingsKeys.contains("pskReporterLocator")) {
|
||||
m_settingsKeys.append("pskReporterLocator");
|
||||
}
|
||||
}
|
||||
|
||||
void FT8DemodSettingsDialog::on_pskReporterSoftware_editingFinished()
|
||||
{
|
||||
m_settings.m_pskReporterSoftware = ui->reportingSoftware->text();
|
||||
|
||||
if (!m_settingsKeys.contains("pskReporterSoftware")) {
|
||||
m_settingsKeys.append("pskReporterSoftware");
|
||||
}
|
||||
}
|
||||
|
||||
void FT8DemodSettingsDialog::on_reportingDefaults_clicked()
|
||||
{
|
||||
ui->reportingStation->setText(m_settings.getDefaultReporterCallsign());
|
||||
ui->reportingLocator->setText(m_settings.getDefaultReporterLocator());
|
||||
ui->reportingSoftware->setText(m_settings.getDefaultReporterSoftware());
|
||||
|
||||
m_settings.m_pskReporterCallsign = ui->reportingStation->text();
|
||||
m_settings.m_pskReporterLocator = ui->reportingLocator->text();
|
||||
m_settings.m_pskReporterSoftware = ui->reportingSoftware->text();
|
||||
|
||||
if (!m_settingsKeys.contains("pskReporterCallsign")) {
|
||||
m_settingsKeys.append("pskReporterCallsign");
|
||||
}
|
||||
|
||||
if (!m_settingsKeys.contains("pskReporterLocator")) {
|
||||
m_settingsKeys.append("pskReporterLocator");
|
||||
}
|
||||
|
||||
if (!m_settingsKeys.contains("pskReporterSoftware")) {
|
||||
m_settingsKeys.append("pskReporterSoftware");
|
||||
}
|
||||
}
|
||||
|
||||
void FT8DemodSettingsDialog::on_addBand_clicked()
|
||||
{
|
||||
int currentRow = ui->bands->currentRow();
|
||||
|
||||
@ -62,6 +62,11 @@ private slots:
|
||||
void on_osdDepth_valueChanged(int value);
|
||||
void on_osdLDPCThreshold_valueChanged(int value);
|
||||
void on_verifyOSD_stateChanged(int state);
|
||||
void on_enablePSKReporter_toggled(bool checked);
|
||||
void on_pskReporterCallsign_editingFinished();
|
||||
void on_pskReporterLocator_editingFinished();
|
||||
void on_pskReporterSoftware_editingFinished();
|
||||
void on_reportingDefaults_clicked();
|
||||
void on_addBand_clicked();
|
||||
void on_deleteBand_clicked();
|
||||
void on_moveBandUp_clicked();
|
||||
|
||||
@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>349</width>
|
||||
<height>333</height>
|
||||
<width>343</width>
|
||||
<height>423</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="font">
|
||||
@ -229,6 +229,104 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="reporterGroup">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>PSK reporter</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<property name="bottomMargin">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="enablePSKReporter">
|
||||
<property name="toolTip">
|
||||
<string>Enable sending reception reports to PSK reporter</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enable</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="reportingStationLabel">
|
||||
<property name="text">
|
||||
<string>Sta</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="reportingStation">
|
||||
<property name="toolTip">
|
||||
<string>Reporting (your) station</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="reportingLocatorLabel">
|
||||
<property name="text">
|
||||
<string>Loc</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="reportingLocator">
|
||||
<property name="toolTip">
|
||||
<string>Reporting (your) locator</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="reportingSoftwareLabel">
|
||||
<property name="text">
|
||||
<string>Soft</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="reportingSoftware">
|
||||
<property name="toolTip">
|
||||
<string>Reporting (your) software</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="reportingDefaults">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>24</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Reset reporter values to defaults</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../sdrgui/resources/res.qrc">
|
||||
<normaloff>:/recycle.png</normaloff>:/recycle.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="bandsGroup">
|
||||
<property name="title">
|
||||
|
||||
@ -141,6 +141,8 @@ QString FT8DemodWorker::FT8Callback::get_name()
|
||||
|
||||
FT8DemodWorker::FT8DemodWorker() :
|
||||
m_recordSamples(false),
|
||||
m_logMessages(false),
|
||||
m_enablePskReporter(false),
|
||||
m_nbDecoderThreads(6),
|
||||
m_decoderTimeBudget(0.5),
|
||||
m_useOSD(false),
|
||||
@ -151,7 +153,8 @@ FT8DemodWorker::FT8DemodWorker() :
|
||||
m_highFreq(3000),
|
||||
m_invalidSequence(true),
|
||||
m_baseFrequency(0),
|
||||
m_reportingMessageQueue(nullptr),
|
||||
m_guiReportingMessageQueue(nullptr),
|
||||
m_pskReportingMessageQueue(nullptr),
|
||||
m_channel(nullptr)
|
||||
{
|
||||
QString relPath = "ft8/save";
|
||||
@ -237,8 +240,12 @@ void FT8DemodWorker::processBuffer(int16_t *buffer, QDateTime periodTS)
|
||||
qDebug("FT8DemodWorker::processBuffer: done: at %6.3f %d messages",
|
||||
m_baseFrequency / 1000000.0, (int)ft8Callback.getReportMessage()->getFT8Messages().size());
|
||||
|
||||
if (m_reportingMessageQueue) {
|
||||
m_reportingMessageQueue->push(new MsgReportFT8Messages(*ft8Callback.getReportMessage()));
|
||||
if (m_guiReportingMessageQueue) {
|
||||
m_guiReportingMessageQueue->push(new MsgReportFT8Messages(*ft8Callback.getReportMessage()));
|
||||
}
|
||||
|
||||
if (m_enablePskReporter && m_pskReportingMessageQueue) {
|
||||
m_pskReportingMessageQueue->push(new MsgReportFT8Messages(*ft8Callback.getReportMessage()));
|
||||
}
|
||||
|
||||
QList<ObjectPipe*> mapPipes;
|
||||
|
||||
@ -41,6 +41,7 @@ public:
|
||||
void processBuffer(int16_t *buffer, QDateTime periodTS);
|
||||
void setRecordSamples(bool recordSamples) { m_recordSamples = recordSamples; }
|
||||
void setLogMessages(bool logMessages) { m_logMessages = logMessages; }
|
||||
void setEnablePskReporter(bool enablePskReporter) { m_enablePskReporter = enablePskReporter; }
|
||||
void setNbDecoderThreads(int nbDecoderThreads) { m_nbDecoderThreads = nbDecoderThreads; }
|
||||
void setDecoderTimeBudget(float decoderTimeBudget) { m_decoderTimeBudget = decoderTimeBudget; }
|
||||
void setUseOSD(bool useOSD) { m_useOSD = useOSD; }
|
||||
@ -49,7 +50,8 @@ public:
|
||||
void setVerifyOSD(bool verifyOSD) { m_verifyOSD = verifyOSD; }
|
||||
void setLowFrequency(int lowFreq) { m_lowFreq = lowFreq; }
|
||||
void setHighFrequency(int highFreq) { m_highFreq = highFreq; }
|
||||
void setReportingMessageQueue(MessageQueue *messageQueue) { m_reportingMessageQueue = messageQueue; }
|
||||
void setGUIReportingMessageQueue(MessageQueue *messageQueue) { m_guiReportingMessageQueue = messageQueue; }
|
||||
void setPSKReportingMessageQueue(MessageQueue *messageQueue) { m_pskReportingMessageQueue = messageQueue; }
|
||||
void invalidateSequence() { m_invalidSequence = true; }
|
||||
void setBaseFrequency(qint64 baseFrequency) { m_baseFrequency = baseFrequency; }
|
||||
void setChannel(ChannelAPI *channel) { m_channel = channel; }
|
||||
@ -92,6 +94,7 @@ private:
|
||||
QString m_logsPath;
|
||||
bool m_recordSamples;
|
||||
bool m_logMessages;
|
||||
bool m_enablePskReporter;
|
||||
int m_nbDecoderThreads;
|
||||
float m_decoderTimeBudget;
|
||||
bool m_useOSD;
|
||||
@ -104,7 +107,8 @@ private:
|
||||
qint64 m_baseFrequency;
|
||||
FT8::FT8Decoder m_ft8Decoder;
|
||||
FT8::Packing m_packing;
|
||||
MessageQueue *m_reportingMessageQueue;
|
||||
MessageQueue *m_guiReportingMessageQueue;
|
||||
MessageQueue *m_pskReportingMessageQueue;
|
||||
ChannelAPI *m_channel;
|
||||
QSet<QString> m_validCallsigns;
|
||||
};
|
||||
|
||||
287
plugins/channelrx/demodft8/pskreporterworker.cpp
Normal file
287
plugins/channelrx/demodft8/pskreporterworker.cpp
Normal file
@ -0,0 +1,287 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2026 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
|
||||
// //
|
||||
// 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 <QHostInfo>
|
||||
#include <QRandomGenerator>
|
||||
#include "util/ft8message.h"
|
||||
#include "pskreporterworker.h"
|
||||
|
||||
const char PskReporterWorker::hostname[] = "report.pskreporter.info";
|
||||
const char PskReporterWorker::service[] = "4739";
|
||||
const char PskReporterWorker::test_service[] = "14739";
|
||||
const char PskReporterWorker::txMode[] = "FT8";
|
||||
const unsigned char PskReporterWorker::rxDescriptor[] = {
|
||||
0x00, 0x03, // Template Set ID
|
||||
0x00, 0x24, // Length
|
||||
0x99, 0x92, // Link ID
|
||||
0x00, 0x03, // Field Count
|
||||
0x00, 0x00, // Scope Field Count
|
||||
0x80, 0x02, // Receiver Callsign ID
|
||||
0xFF, 0xFF, // Variable field length
|
||||
0x00, 0x00, 0x76, 0x8F, // Enterprise number
|
||||
0x80, 0x04, // Receiver Locator ID
|
||||
0xFF, 0xFF, // Variable field length
|
||||
0x00, 0x00, 0x76, 0x8F, // Enterprise number
|
||||
0x80, 0x08, // Receiver Decoder Software ID
|
||||
0xFF, 0xFF, // Variable field length
|
||||
0x00, 0x00, 0x76, 0x8F, // Enterprise number
|
||||
0x00, 0x00 // Padding
|
||||
}; // "PSKREPORTER_RX"
|
||||
const unsigned char PskReporterWorker::txDescriptor[] = {
|
||||
0x00, 0x02, // Template Set ID
|
||||
0x00, 0x3C, // Length
|
||||
0x99, 0x93, // Link ID
|
||||
0x00, 0x07, // Field Count
|
||||
0x80, 0x01, // Sender Callsign ID
|
||||
0xFF, 0xFF, // Variable field length
|
||||
0x00, 0x00, 0x76, 0x8F, // Enterprise number
|
||||
0x80, 0x05, // Sender Frequency ID
|
||||
0x00, 0x04, // Fixed length (4)
|
||||
0x00, 0x00, 0x76, 0x8F, // Enterprise number
|
||||
0x80, 0x06, // Sender SNR ID
|
||||
0x00, 0x01, // Fixed length (1)
|
||||
0x00, 0x00, 0x76, 0x8F, // Enterprise number
|
||||
0x80, 0x0A, // Sender Mode ID
|
||||
0xFF, 0xFF, // Variable field length
|
||||
0x00, 0x00, 0x76, 0x8F, // Enterprise number
|
||||
0x80, 0x03, // Sender Locator ID
|
||||
0xFF, 0xFF, // Variable field length
|
||||
0x00, 0x00, 0x76, 0x8F, // Enterprise number
|
||||
0x80, 0x0B, // Information Source ID
|
||||
0x00, 0x01, // Fixed length (1)
|
||||
0x00, 0x00, 0x76, 0x8F, // Enterprise number
|
||||
0x00, 0x96, // DateTimeSeconds ID
|
||||
0x00, 0x04 // Field Length
|
||||
}; // "PSKREPORTER_TX"
|
||||
|
||||
PskReporterWorker::PskReporterWorker() :
|
||||
m_udpSocket(new QUdpSocket(this))
|
||||
{
|
||||
connect(&m_reportQueue, &MessageQueue::messageEnqueued,
|
||||
this, &PskReporterWorker::handleInputMessages);
|
||||
m_lastReportTime = QDateTime::currentDateTimeUtc();
|
||||
m_identifier = QRandomGenerator::global()->generate(); // random number for the identifier for this session
|
||||
}
|
||||
|
||||
void PskReporterWorker::processFT8Messages(const QList<FT8Message>& ft8Messages, qint64 baseFrequency)
|
||||
{
|
||||
m_ft8MessageQueue.append(ft8Messages); // Queue messages for processing
|
||||
qDebug("PskReporterWorker::processFT8Messages: queued %d messages", ft8Messages.size());
|
||||
|
||||
// Avoid reporting too frequently - 5 minutes interval is the recommended value
|
||||
if (m_lastReportTime.secsTo(QDateTime::currentDateTimeUtc()) < 5*60) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_lastReportTime = QDateTime::currentDateTimeUtc();
|
||||
uint32_t txPtr = 4;
|
||||
std::fill(std::begin(txInfoData), std::end(txInfoData), 0);
|
||||
|
||||
while (!m_ft8MessageQueue.isEmpty())
|
||||
{
|
||||
FT8Message msg = m_ft8MessageQueue.dequeue();
|
||||
|
||||
if (m_reportedCalls.contains(msg.call2)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
m_reportedCalls.insert(msg.call2);
|
||||
|
||||
if (txPtr > 1200)
|
||||
{
|
||||
sendMessageToPskReporter(txPtr);
|
||||
txPtr = 4;
|
||||
std::fill(std::begin(txInfoData), std::end(txInfoData), 0);
|
||||
}
|
||||
|
||||
// Station callsign
|
||||
*(uint8_t *)&txInfoData[txPtr] = (uint8_t) msg.call2.size();
|
||||
txPtr += 1;
|
||||
memcpy(&txInfoData[txPtr], msg.call2.toStdString().c_str(), msg.call2.size());
|
||||
txPtr += msg.call2.size();
|
||||
|
||||
// Station frequency
|
||||
uint32_t freq = static_cast<uint32_t>(baseFrequency + msg.df);
|
||||
freq = SwapEndian32(freq);
|
||||
memcpy(&txInfoData[txPtr], &freq, 4);
|
||||
txPtr +=4;
|
||||
|
||||
// Station SNR
|
||||
int8_t snr = static_cast<int8_t>(msg.snr);
|
||||
memcpy(&txInfoData[txPtr], &snr, 1);
|
||||
txPtr +=1;
|
||||
|
||||
// Station Mode
|
||||
const size_t modeLen = strlen(txMode);
|
||||
*(uint8_t *)&txInfoData[txPtr] = (uint8_t)modeLen;
|
||||
txPtr += 1;
|
||||
memcpy(&txInfoData[txPtr], txMode, modeLen);
|
||||
txPtr += modeLen;
|
||||
|
||||
// Station locator
|
||||
*(uint8_t *)&txInfoData[txPtr] = (uint8_t) msg.loc.size();
|
||||
txPtr += 1;
|
||||
memcpy(&txInfoData[txPtr], msg.loc.toStdString().c_str(), msg.loc.size());
|
||||
txPtr += msg.loc.size();
|
||||
|
||||
/* Station Info -- Static length (1) */
|
||||
*(uint8_t *)&txInfoData[txPtr] = (uint8_t)1;
|
||||
txPtr += 1;
|
||||
|
||||
// Message timestamp -- Static length (4)
|
||||
uint32_t timestamp = static_cast<uint32_t>(msg.ts.toSecsSinceEpoch());
|
||||
timestamp = SwapEndian32(timestamp);
|
||||
memcpy(&txInfoData[txPtr], ×tamp, 4);
|
||||
txPtr +=4;
|
||||
}
|
||||
|
||||
sendMessageToPskReporter(txPtr);
|
||||
m_reportedCalls.clear();
|
||||
m_reportSequenceNumber++;
|
||||
}
|
||||
|
||||
void PskReporterWorker::sendMessageToPskReporter(uint32_t txPtr)
|
||||
{
|
||||
// Implement PSK Reporter message sending here
|
||||
if (txInfoData[4] == 0) {
|
||||
return; // No data to send
|
||||
}
|
||||
|
||||
// Prepare and send the UDP message to PSK Reporter server
|
||||
const uint32_t headerSize = 16;
|
||||
char headerData[headerSize] = {0};
|
||||
uint32_t hPtr = 0;
|
||||
|
||||
*(uint16_t *)&headerData[hPtr] = SwapEndian16(0x000A);
|
||||
hPtr += 2;
|
||||
hPtr += 2; // Skip the size block, adjust later
|
||||
|
||||
uint32_t timestamp = QDateTime::currentDateTimeUtc().toSecsSinceEpoch();
|
||||
*(uint32_t *)&headerData[hPtr] = SwapEndian32(timestamp);
|
||||
hPtr += 4;
|
||||
|
||||
*(uint32_t *)&headerData[hPtr] = SwapEndian32(m_reportSequenceNumber);
|
||||
hPtr += 4;
|
||||
|
||||
*(uint32_t *)&headerData[hPtr] = SwapEndian32(m_identifier);
|
||||
hPtr += 4;
|
||||
|
||||
char rxInfoData[256] = {0};
|
||||
uint32_t rxPtr = 0;
|
||||
|
||||
*(uint16_t *)&rxInfoData[rxPtr] = SwapEndian16(0x9992);
|
||||
rxPtr += 2;
|
||||
rxPtr += 2; // Skip the size block, adjust later
|
||||
|
||||
// Receiver callsign
|
||||
*(uint8_t *)&rxInfoData[rxPtr] = (uint8_t) m_myCallsign.size();
|
||||
rxPtr += 1;
|
||||
memcpy(&rxInfoData[rxPtr], m_myCallsign.toStdString().c_str(), m_myCallsign.size());
|
||||
rxPtr += m_myCallsign.size();
|
||||
|
||||
// Receiver locator
|
||||
*(uint8_t *)&rxInfoData[rxPtr] = (uint8_t) m_myLocator.size();
|
||||
rxPtr += 1;
|
||||
memcpy(&rxInfoData[rxPtr], m_myLocator.toStdString().c_str(), m_myLocator.size());
|
||||
rxPtr += m_myLocator.size();
|
||||
|
||||
// Receiver decoder software
|
||||
*(uint8_t *)&rxInfoData[rxPtr] = (uint8_t) m_decoderInfo.size();
|
||||
rxPtr += 1;
|
||||
memcpy(&rxInfoData[rxPtr], m_decoderInfo.toStdString().c_str(), m_decoderInfo.size());
|
||||
rxPtr += m_decoderInfo.size();
|
||||
|
||||
// Padding to 4-byte boundary
|
||||
if ((rxPtr % 4) > 0)
|
||||
rxPtr += (4 - (rxPtr % 4));
|
||||
|
||||
// Padding to 4-byte boundary
|
||||
if ((txPtr % 4) > 0)
|
||||
txPtr += (4 - (txPtr % 4));
|
||||
|
||||
*(uint16_t *)&txInfoData[0] = SwapEndian16(0x9993);
|
||||
|
||||
/* Adjust the block sizes */
|
||||
uint32_t fullBlockSize = headerSize + sizeof(rxDescriptor) + sizeof(txDescriptor) + rxPtr + txPtr;
|
||||
*(uint16_t *)&rxInfoData[2] = SwapEndian16(rxPtr);
|
||||
*(uint16_t *)&txInfoData[2] = SwapEndian16(txPtr);
|
||||
*(uint16_t *)&headerData[2] = SwapEndian16(fullBlockSize);
|
||||
|
||||
/* Assemble the block to send over UDP */
|
||||
char *fullBlockData = new char[fullBlockSize];
|
||||
uint32_t ptrBlock = 0;
|
||||
memcpy(&fullBlockData[ptrBlock], headerData, headerSize); ptrBlock += headerSize;
|
||||
memcpy(&fullBlockData[ptrBlock], rxDescriptor, sizeof(rxDescriptor)); ptrBlock += sizeof(rxDescriptor);
|
||||
memcpy(&fullBlockData[ptrBlock], txDescriptor, sizeof(txDescriptor)); ptrBlock += sizeof(txDescriptor);
|
||||
memcpy(&fullBlockData[ptrBlock], rxInfoData, rxPtr); ptrBlock += rxPtr;
|
||||
memcpy(&fullBlockData[ptrBlock], txInfoData, txPtr); ptrBlock += txPtr;
|
||||
|
||||
/* Send via UDP */
|
||||
const char* servicePort = m_isTestMode ? test_service : service;
|
||||
QHostAddress hostAddress;
|
||||
|
||||
// Resolve hostname
|
||||
QHostInfo hostInfo = QHostInfo::fromName(hostname);
|
||||
|
||||
if (!hostInfo.addresses().isEmpty()) {
|
||||
hostAddress = hostInfo.addresses().first();
|
||||
|
||||
// Send the datagram
|
||||
qint64 bytesSent = m_udpSocket->writeDatagram(fullBlockData, fullBlockSize, hostAddress, QString(servicePort).toUInt());
|
||||
|
||||
if (bytesSent == -1) {
|
||||
qWarning("PskReporterWorker::sendMessageToPskReporter: Failed to send UDP datagram: %s",
|
||||
qPrintable(m_udpSocket->errorString()));
|
||||
} else {
|
||||
qDebug("PskReporterWorker::sendMessageToPskReporter: Sent %lld bytes to %s:%s",
|
||||
bytesSent, hostname, servicePort);
|
||||
}
|
||||
} else {
|
||||
qWarning("PskReporterWorker::sendMessageToPskReporter: Failed to resolve hostname: %s", hostname);
|
||||
}
|
||||
|
||||
delete[] fullBlockData;
|
||||
}
|
||||
|
||||
bool PskReporterWorker::handleMessage(const Message& message)
|
||||
{
|
||||
if (MsgReportFT8Messages::match(message))
|
||||
{
|
||||
const MsgReportFT8Messages& ft8Msg = static_cast<const MsgReportFT8Messages&>(message);
|
||||
const QList<FT8Message>& ft8Messages = ft8Msg.getFT8Messages();
|
||||
qint64 baseFrequency = ft8Msg.getBaseFrequency();
|
||||
// Process FT8 messages for PSK Reporter here
|
||||
processFT8Messages(ft8Messages, baseFrequency);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void PskReporterWorker::handleInputMessages()
|
||||
{
|
||||
Message* message = m_reportQueue.pop();
|
||||
|
||||
if (message == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!handleMessage(*message)) {
|
||||
delete message;
|
||||
}
|
||||
}
|
||||
92
plugins/channelrx/demodft8/pskreporterworker.h
Normal file
92
plugins/channelrx/demodft8/pskreporterworker.h
Normal file
@ -0,0 +1,92 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2026 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
|
||||
// //
|
||||
// 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_PSKREPORTERWORKER_H
|
||||
#define INCLUDE_PSKREPORTERWORKER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
#include <QSet>
|
||||
#include <QQueue>
|
||||
#include <QUdpSocket>
|
||||
|
||||
#include "util/ft8message.h"
|
||||
#include "util/message.h"
|
||||
#include "util/messagequeue.h"
|
||||
|
||||
|
||||
class PskReporterWorker : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
PskReporterWorker();
|
||||
~PskReporterWorker() = default;
|
||||
MessageQueue* getInputMessageQueue() { return &m_reportQueue; }
|
||||
void setMyCallsign(const QString& callsign) { m_myCallsign = callsign; }
|
||||
void setMyLocator(const QString& locator) { m_myLocator = locator; }
|
||||
void setDecoderInfo(const QString& decoderInfo) { m_decoderInfo = decoderInfo; }
|
||||
void setTestMode(bool isTestMode) { m_isTestMode = isTestMode; }
|
||||
|
||||
private:
|
||||
struct decoder_results {
|
||||
char call[13];
|
||||
char loc[7];
|
||||
int32_t freq;
|
||||
int32_t snr;
|
||||
};
|
||||
|
||||
QString m_myCallsign;
|
||||
QString m_myLocator;
|
||||
QString m_decoderInfo;
|
||||
bool m_isTestMode = false;
|
||||
MessageQueue m_reportQueue;
|
||||
QQueue<FT8Message> m_ft8MessageQueue;
|
||||
QSet<QString> m_reportedCalls;
|
||||
uint32_t m_reportSequenceNumber = 1;
|
||||
QDateTime m_lastReportTime;
|
||||
QUdpSocket* m_udpSocket;
|
||||
uint32_t m_identifier;
|
||||
|
||||
char txInfoData[1500];
|
||||
|
||||
static const char hostname[];
|
||||
static const char service[];
|
||||
static const char test_service[];
|
||||
static const char txMode[];
|
||||
static const unsigned char rxDescriptor[];
|
||||
static const unsigned char txDescriptor[];
|
||||
|
||||
void processFT8Messages(const QList<FT8Message>& ft8Messages, qint64 baseFrequency);
|
||||
void sendMessageToPskReporter(uint32_t txPtr);
|
||||
bool handleMessage(const Message& message);
|
||||
|
||||
inline uint16_t SwapEndian16(uint16_t val) {
|
||||
return (val<<8) | (val>>8);
|
||||
}
|
||||
|
||||
|
||||
inline uint32_t SwapEndian32(uint32_t val) {
|
||||
return (val<<24) | ((val<<8) & 0x00ff0000) | ((val>>8) & 0x0000ff00) | (val>>24);
|
||||
}
|
||||
|
||||
private slots:
|
||||
void handleInputMessages();
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // INCLUDE_PSKREPORTERWORKER_H
|
||||
@ -235,7 +235,27 @@ Sets the minimum number of correct LDPC bits (out of 83) necessary to trigger OS
|
||||
|
||||
OSD search may find invalid solutions as mentioned above. When checking this option the callsigns in messages not passed through OSD (thus very certainly valid) are stored for the life of the plugin. When OSD is engaged the second callsign field which is always a callsign is checked against this list and if the callsign is not found the message is rejected. This is quite efficient in removing false messages when OSD is engaged although some valid messages may be removed.
|
||||
|
||||
<h4>C.1.7: Band presets table</h4>
|
||||
<h4>C.1.7: Report to PSK reporter</h4>
|
||||
|
||||
Sends received calls details to the PSK reporter (report.pskreporter.info port 4739) via UDP packets. Reports are sent every 5 minutes.
|
||||
|
||||
<h4>C.1.8: Reporting station callsign</h4>
|
||||
|
||||
This is the callsign of your station as it will be reported (may be an Amateur Radio callsign or something else). By default it takes the value for "Sation name" in the "Preferences > My Position..." in the main window.
|
||||
|
||||
<h4>C.1.9: Reporting station Maindenhead locator</h4>
|
||||
|
||||
This is the Maidenhead locator as it will be reported. By default it is calculated from the "Latitude" and "Longitude" values in the "Preferences > My Position..." in the main window.
|
||||
|
||||
<h4>C.1.10: Reporting station software</h4>
|
||||
|
||||
This is the decoding Software name and version as it will be reported in the "Using" field. By default it takes the value shown at the bottom right of the main SDRangel window.
|
||||
|
||||
<h4>C.1.11: Revert to default values</h4>
|
||||
|
||||
Use this push button to revert to default values for the reporting station details.
|
||||
|
||||
<h4>C.1.12: Band presets table</h4>
|
||||
|
||||
This table shows the band presets values that will appear in (C.5)
|
||||
|
||||
@ -245,23 +265,23 @@ This table shows the band presets values that will appear in (C.5)
|
||||
|
||||
You can edit these values by clicking on the cell in the table.
|
||||
|
||||
<h4>C.1.8: Add preset</h4>
|
||||
<h4>C.1.13: Add preset</h4>
|
||||
|
||||
Use this button to create a new preset. It will take the values from the row of the selected cell in the table (if selected) and put the new preset at the bottom of the table
|
||||
|
||||
<h4>C.1.9: Delete preset</h4>
|
||||
<h4>C.1.14: Delete preset</h4>
|
||||
|
||||
Delete the preset designated by the selected cell in the table.
|
||||
|
||||
<h4>C.1.10: Move up preset</h4>
|
||||
<h4>C.1.15: Move up preset</h4>
|
||||
|
||||
Move up the preset designated by the selected cell in the table.
|
||||
|
||||
<h4>C.1.11: Move down preset</h4>
|
||||
<h4>C.1.16: Move down preset</h4>
|
||||
|
||||
Move down the preset designated by the selected cell in the table.
|
||||
|
||||
<h4>C.1.12: Restore defaults</h4>
|
||||
<h4>C.1.17: Restore defaults</h4>
|
||||
|
||||
This restores the default band preset values:
|
||||
|
||||
@ -283,10 +303,10 @@ This restores the default band preset values:
|
||||
|
||||
Channel offsets are all set to 0 kHz.
|
||||
|
||||
<h4>C.1.13 Commit changes</h4>
|
||||
<h4>C.1.18 Commit changes</h4>
|
||||
|
||||
Click on the "OK" button to commit changes and close dialog.
|
||||
|
||||
<h4>C.1.14 Cancel changes</h4>
|
||||
<h4>C.1.19 Cancel changes</h4>
|
||||
|
||||
Click on the "Cancel" button to close dialog without making changes.
|
||||
|
||||
@ -17,8 +17,8 @@
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "libavcodec/avcodec.h"
|
||||
#include "libavformat/avformat.h"
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavformat/avformat.h>
|
||||
|
||||
#include <libavutil/channel_layout.h>
|
||||
#include <libavutil/common.h>
|
||||
@ -33,6 +33,8 @@ extern "C"
|
||||
|
||||
#include <opencv2/opencv.hpp> // Add OpenCV for text overlay
|
||||
|
||||
#include <QDateTime>
|
||||
|
||||
#include "tsgenerator.h"
|
||||
|
||||
const double TSGenerator::rate_qpsk[11][4] = {{1.0, 4.0, 12.0, 2}, {1.0, 3.0, 12.0, 2}, {2.0, 5.0, 12.0, 2}, {1.0, 2.0, 12.0, 2}, {3.0, 5.0, 12.0, 2}, {2.0, 3.0, 10.0, 2}, {3.0, 4.0, 12.0, 2}, {4.0, 5.0, 12.0, 2}, {5.0, 6.0, 10.0, 2}, {8.0, 9.0, 8.0, 2}, {9.0, 10.0, 8.0, 1}};
|
||||
@ -174,19 +176,19 @@ AVFrame* TSGenerator::load_image_to_yuv_with_opencv(const char* filename, int wi
|
||||
}
|
||||
|
||||
// 2. OPTIONAL: Overlay timestamp
|
||||
if (overlay_timestamp) {
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto time_t = std::chrono::system_clock::to_time_t(now);
|
||||
char time_str[32];
|
||||
struct tm time_buffer; // Your own buffer
|
||||
std::strftime(time_str, sizeof(time_str), "%H:%M:%S", localtime_r(&time_t, &time_buffer));
|
||||
if (overlay_timestamp)
|
||||
{
|
||||
QString time_str = QDateTime::currentDateTime().toString("HH:mm:ss");
|
||||
char time_cstr[32];
|
||||
strncpy(time_cstr, time_str.toStdString().c_str(), sizeof(time_cstr) - 1);
|
||||
time_cstr[sizeof(time_cstr) - 1] = '\0';
|
||||
|
||||
// Draw black background box first
|
||||
cv::rectangle(rgb_image, cv::Point(15, 28), cv::Point(170, 65),
|
||||
cv::Scalar(0, 0, 0), -1);
|
||||
|
||||
// Draw white timestamp text
|
||||
cv::putText(rgb_image, time_str, cv::Point(20, 55),
|
||||
cv::putText(rgb_image, time_cstr, cv::Point(20, 55),
|
||||
cv::FONT_HERSHEY_SIMPLEX, 1.0, cv::Scalar(255, 255, 255), 2);
|
||||
}
|
||||
|
||||
@ -374,7 +376,11 @@ void TSGenerator::encode_frame_to_ts(AVFormatContext* oc, AVCodecContext* codec_
|
||||
}
|
||||
|
||||
// Write callback - stores TS packets in memory
|
||||
#if LIBAVFORMAT_VERSION_INT < ((61 << 16) | (0 << 8) | 0)
|
||||
int TSGenerator::write_packet_cb(void* opaque, uint8_t* buf, int buf_size)
|
||||
#else
|
||||
int TSGenerator::write_packet_cb(void* opaque, const uint8_t* buf, int buf_size)
|
||||
#endif
|
||||
{
|
||||
std::vector<uint8_t>* buffer = static_cast<std::vector<uint8_t>*>(opaque);
|
||||
buffer->insert(buffer->end(), buf, buf + buf_size);
|
||||
|
||||
@ -21,6 +21,7 @@
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <libavformat/version.h>
|
||||
|
||||
#include "datvmodsettings.h"
|
||||
|
||||
@ -67,7 +68,11 @@ private:
|
||||
int setup_ts_context(AVFormatContext** oc, AVCodecContext* codec_ctx);
|
||||
void encode_frame_to_ts(AVFormatContext* oc, AVCodecContext* codec_ctx, AVFrame* frame, int stream_idx = 0);
|
||||
std::pair<const AVCodec*, AVCodecContext*> create_codec_context(int fps, int bitrate, int width, int height, int duration_sec);
|
||||
#if LIBAVFORMAT_VERSION_INT < ((61 << 16) | (0 << 8) | 0)
|
||||
static int write_packet_cb(void* opaque, uint8_t* buf, int buf_size);
|
||||
#else
|
||||
static int write_packet_cb(void* opaque, const uint8_t* buf, int buf_size);
|
||||
#endif
|
||||
static int read_packet_cb(void* opaque, uint8_t* buf, int buf_size);
|
||||
static int64_t seek_cb(void* opaque, int64_t offset, int whence);
|
||||
static double get_dvbs2_rate(double symbol_rate, DATVModSettings::DATVModulation modulation, DATVModSettings::DATVCodeRate code_rate);
|
||||
|
||||
@ -286,30 +286,23 @@ bool HackRFOutput::handleMessage(const Message& message)
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (DeviceHackRFShared::MsgSynchronizeFrequency::match(message))
|
||||
else if (DeviceHackRFShared::MsgSynchronizeSampleRate::match(message))
|
||||
{
|
||||
DeviceHackRFShared::MsgSynchronizeFrequency& freqMsg = (DeviceHackRFShared::MsgSynchronizeFrequency&) message;
|
||||
qint64 centerFrequency = DeviceSampleSink::calculateCenterFrequency(
|
||||
freqMsg.getFrequency(),
|
||||
0,
|
||||
m_settings.m_log2Interp,
|
||||
(DeviceSampleSink::fcPos_t) m_settings.m_fcPos,
|
||||
m_settings.m_devSampleRate);
|
||||
qDebug("HackRFOutput::handleMessage: MsgSynchronizeFrequency: centerFrequency: %lld Hz", centerFrequency);
|
||||
DeviceHackRFShared::MsgSynchronizeSampleRate& cmd = (DeviceHackRFShared::MsgSynchronizeSampleRate&) message;
|
||||
qDebug() << "HackRFOutput::handleMessage: MsgSynchronizeSampleRate: " << cmd.getDeviceSampleRate();
|
||||
|
||||
HackRFOutputSettings settings = m_settings;
|
||||
settings.m_centerFrequency = centerFrequency;
|
||||
settings.m_devSampleRate = cmd.getDeviceSampleRate();
|
||||
|
||||
MsgConfigureHackRF* message = MsgConfigureHackRF::create(settings, QList<QString>{"devSampleRate"}, false);
|
||||
m_inputMessageQueue.push(message);
|
||||
|
||||
if (m_guiMessageQueue)
|
||||
{
|
||||
MsgConfigureHackRF* messageToGUI = MsgConfigureHackRF::create(settings, QList<QString>{"centerFrequency"}, false);
|
||||
MsgConfigureHackRF* messageToGUI = MsgConfigureHackRF::create(settings, QList<QString>{"devSampleRate"}, false);
|
||||
m_guiMessageQueue->push(messageToGUI);
|
||||
}
|
||||
|
||||
m_settings.m_centerFrequency = settings.m_centerFrequency;
|
||||
int sampleRate = m_settings.m_devSampleRate/(1<<m_settings.m_log2Interp);
|
||||
DSPSignalNotification *notif = new DSPSignalNotification(sampleRate, m_settings.m_centerFrequency);
|
||||
m_deviceAPI->getDeviceEngineInputMessageQueue()->push(notif);
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
@ -394,6 +387,13 @@ bool HackRFOutput::applySettings(const HackRFOutputSettings& settings, const QLi
|
||||
settings.m_devSampleRate);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_deviceAPI->getSourceBuddies().size() > 0)
|
||||
{
|
||||
DeviceAPI *buddy = m_deviceAPI->getSourceBuddies()[0];
|
||||
DeviceHackRFShared::MsgSynchronizeSampleRate *sampleRateMsg = DeviceHackRFShared::MsgSynchronizeSampleRate::create(settings.m_devSampleRate);
|
||||
buddy->getSamplingDeviceInputMessageQueue()->push(sampleRateMsg);
|
||||
}
|
||||
}
|
||||
|
||||
if (settingsKeys.contains("log2Interp") || force)
|
||||
@ -405,13 +405,13 @@ bool HackRFOutput::applySettings(const HackRFOutputSettings& settings, const QLi
|
||||
}
|
||||
}
|
||||
|
||||
if (settingsKeys.contains("centerFrequency") ||
|
||||
if (m_running &&(settingsKeys.contains("centerFrequency") ||
|
||||
settingsKeys.contains("devSampleRate") ||
|
||||
settingsKeys.contains("log2Interp") ||
|
||||
settingsKeys.contains("fcPos") ||
|
||||
settingsKeys.contains("transverterMode") ||
|
||||
settingsKeys.contains("transverterDeltaFrequency") ||
|
||||
settingsKeys.contains("LOppmTenths") || force)
|
||||
settingsKeys.contains("LOppmTenths") || force))
|
||||
{
|
||||
qint64 deviceCenterFrequency = DeviceSampleSink::calculateDeviceCenterFrequency(
|
||||
settings.m_centerFrequency,
|
||||
@ -422,13 +422,6 @@ bool HackRFOutput::applySettings(const HackRFOutputSettings& settings, const QLi
|
||||
settings.m_transverterMode);
|
||||
setDeviceCenterFrequency(deviceCenterFrequency, settings.m_LOppmTenths);
|
||||
|
||||
if (m_deviceAPI->getSourceBuddies().size() > 0)
|
||||
{
|
||||
DeviceAPI *buddy = m_deviceAPI->getSourceBuddies()[0];
|
||||
DeviceHackRFShared::MsgSynchronizeFrequency *freqMsg = DeviceHackRFShared::MsgSynchronizeFrequency::create(deviceCenterFrequency);
|
||||
buddy->getSamplingDeviceInputMessageQueue()->push(freqMsg);
|
||||
}
|
||||
|
||||
forwardChange = true;
|
||||
}
|
||||
|
||||
|
||||
@ -200,10 +200,10 @@
|
||||
<string>Local Oscillator ppm correction</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>-300</number>
|
||||
<number>-1000</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>300</number>
|
||||
<number>1000</number>
|
||||
</property>
|
||||
<property name="pageStep">
|
||||
<number>1</number>
|
||||
@ -546,17 +546,17 @@
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>ButtonSwitch</class>
|
||||
<extends>QToolButton</extends>
|
||||
<header>gui/buttonswitch.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>ValueDial</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>gui/valuedial.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>ButtonSwitch</class>
|
||||
<extends>QToolButton</extends>
|
||||
<header>gui/buttonswitch.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>TransverterButton</class>
|
||||
<extends>QPushButton</extends>
|
||||
|
||||
@ -72,27 +72,34 @@ void HackRFOutputThread::run()
|
||||
m_running = true;
|
||||
m_startWaiter.wakeAll();
|
||||
|
||||
|
||||
if (hackrf_is_streaming(m_dev) == HACKRF_TRUE)
|
||||
{
|
||||
qDebug("HackRFInputThread::run: HackRF is streaming already");
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug("HackRFInputThread::run: HackRF is not streaming");
|
||||
|
||||
rc = (hackrf_error) hackrf_start_tx(m_dev, tx_callback, this);
|
||||
qDebug("HackRFOutputThread::run: HackRF is streaming already");
|
||||
rc = (hackrf_error) hackrf_stop_tx(m_dev);
|
||||
|
||||
if (rc == HACKRF_SUCCESS)
|
||||
{
|
||||
qDebug("HackRFOutputThread::run: started HackRF Tx");
|
||||
qDebug("HackRFOutputThread::run: stopped HackRF Tx");
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug("HackRFOutputThread::run: failed to start HackRF Tx: %s", hackrf_error_name(rc));
|
||||
qDebug("HackRFOutputThread::run: failed to stop HackRF Tx: %s", hackrf_error_name(rc));
|
||||
}
|
||||
}
|
||||
|
||||
usleep(200000);
|
||||
|
||||
rc = (hackrf_error) hackrf_start_tx(m_dev, tx_callback, this);
|
||||
|
||||
if (rc == HACKRF_SUCCESS)
|
||||
{
|
||||
qDebug("HackRFOutputThread::run: started HackRF Tx");
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug("HackRFOutputThread::run: failed to start HackRF Tx: %s", hackrf_error_name(rc));
|
||||
}
|
||||
|
||||
while ((m_running) && (hackrf_is_streaming(m_dev) == HACKRF_TRUE))
|
||||
{
|
||||
usleep(200000);
|
||||
|
||||
@ -38,7 +38,7 @@ This is the center frequency of transmission in kHz.
|
||||
|
||||
<h3>4: Local Oscillator correction</h3>
|
||||
|
||||
Use this slider to adjust LO correction in ppm. It can be varied from -10.0 to 10.0 in 0.1 steps and is applied in software.
|
||||
Use this slider to adjust LO correction in ppm. It can be varied from -100.0 to 100.0 in 0.1 steps and is applied in software.
|
||||
|
||||
<h3>5: Rx filter bandwidth</h3>
|
||||
|
||||
|
||||
@ -152,9 +152,6 @@ bool HackRFInput::start()
|
||||
return false;
|
||||
}
|
||||
|
||||
// applySettings needs to called before thread is started,
|
||||
// otherwise HackRF will not start correctly
|
||||
applySettings(m_settings, QList<QString>(), true);
|
||||
|
||||
m_hackRFThread = new HackRFInputThread(m_dev, &m_sampleFifo);
|
||||
|
||||
@ -164,6 +161,7 @@ bool HackRFInput::start()
|
||||
m_hackRFThread->setIQOrder(m_settings.m_iqOrder);
|
||||
m_hackRFThread->startWork();
|
||||
m_running = true;
|
||||
applySettings(m_settings, QList<QString>(), true);
|
||||
|
||||
mutexLocker.unlock();
|
||||
|
||||
@ -301,32 +299,23 @@ bool HackRFInput::handleMessage(const Message& message)
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (DeviceHackRFShared::MsgSynchronizeFrequency::match(message))
|
||||
else if (DeviceHackRFShared::MsgSynchronizeSampleRate::match(message))
|
||||
{
|
||||
DeviceHackRFShared::MsgSynchronizeFrequency& freqMsg = (DeviceHackRFShared::MsgSynchronizeFrequency&) message;
|
||||
qint64 centerFrequency = DeviceSampleSource::calculateCenterFrequency(
|
||||
freqMsg.getFrequency(),
|
||||
0,
|
||||
m_settings.m_log2Decim,
|
||||
(DeviceSampleSource::fcPos_t) m_settings.m_fcPos,
|
||||
m_settings.m_devSampleRate,
|
||||
DeviceSampleSource::FSHIFT_TXSYNC);
|
||||
qDebug("HackRFInput::handleMessage: MsgSynchronizeFrequency: centerFrequency: %lld Hz", centerFrequency);
|
||||
DeviceHackRFShared::MsgSynchronizeSampleRate& cmd = (DeviceHackRFShared::MsgSynchronizeSampleRate&) message;
|
||||
qDebug() << "HackRFInput::handleMessage: MsgSynchronizeSampleRate: " << cmd.getDeviceSampleRate();
|
||||
|
||||
HackRFInputSettings settings = m_settings;
|
||||
settings.m_centerFrequency = centerFrequency;
|
||||
settings.m_devSampleRate = cmd.getDeviceSampleRate();
|
||||
|
||||
MsgConfigureHackRF* message = MsgConfigureHackRF::create(settings, QList<QString>{"devSampleRate"}, false);
|
||||
m_inputMessageQueue.push(message);
|
||||
|
||||
if (m_guiMessageQueue)
|
||||
{
|
||||
QList<QString> settingsKeys({"log2Decim", "fcPos", "devSampleRate", "centerFrequency"});
|
||||
MsgConfigureHackRF* messageToGUI = MsgConfigureHackRF::create(settings, settingsKeys, false);
|
||||
MsgConfigureHackRF* messageToGUI = MsgConfigureHackRF::create(settings, QList<QString>{"devSampleRate"}, false);
|
||||
m_guiMessageQueue->push(messageToGUI);
|
||||
}
|
||||
|
||||
m_settings.m_centerFrequency = settings.m_centerFrequency;
|
||||
int sampleRate = m_settings.m_devSampleRate/(1<<m_settings.m_log2Decim);
|
||||
DSPSignalNotification *notif = new DSPSignalNotification(sampleRate, m_settings.m_centerFrequency);
|
||||
m_deviceAPI->getDeviceEngineInputMessageQueue()->push(notif);
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
@ -388,6 +377,13 @@ bool HackRFInput::applySettings(const HackRFInputSettings& settings, const QList
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_deviceAPI->getSourceBuddies().size() > 0)
|
||||
{
|
||||
DeviceAPI *buddy = m_deviceAPI->getSourceBuddies()[0];
|
||||
DeviceHackRFShared::MsgSynchronizeSampleRate *sampleRateMsg = DeviceHackRFShared::MsgSynchronizeSampleRate::create(settings.m_devSampleRate);
|
||||
buddy->getSamplingDeviceInputMessageQueue()->push(sampleRateMsg);
|
||||
}
|
||||
}
|
||||
|
||||
if (settingsKeys.contains("log2Decim") || force)
|
||||
@ -522,7 +518,7 @@ bool HackRFInput::applySettings(const HackRFInputSettings& settings, const QList
|
||||
m_deviceAPI->configureCorrections(m_settings.m_dcBlock, m_settings.m_iqCorrection);
|
||||
}
|
||||
|
||||
if (setFrequency)
|
||||
if (m_running && setFrequency)
|
||||
{
|
||||
qint64 deviceCenterFrequency = DeviceSampleSource::calculateDeviceCenterFrequency(
|
||||
m_settings.m_centerFrequency,
|
||||
@ -535,13 +531,6 @@ bool HackRFInput::applySettings(const HackRFInputSettings& settings, const QList
|
||||
qDebug() << "HackRFInput::applySettings deviceCenterFrequency:" << deviceCenterFrequency;
|
||||
setDeviceCenterFrequency(deviceCenterFrequency, m_settings.m_LOppmTenths);
|
||||
|
||||
if (m_deviceAPI->getSinkBuddies().size() > 0) // forward to buddy if necessary
|
||||
{
|
||||
DeviceAPI *buddy = m_deviceAPI->getSinkBuddies()[0];
|
||||
DeviceHackRFShared::MsgSynchronizeFrequency *freqMsg = DeviceHackRFShared::MsgSynchronizeFrequency::create(deviceCenterFrequency);
|
||||
buddy->getSamplingDeviceInputMessageQueue()->push(freqMsg);
|
||||
}
|
||||
|
||||
forwardChange = true;
|
||||
}
|
||||
|
||||
|
||||
@ -191,10 +191,10 @@
|
||||
<string>Local Oscillator ppm correction</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>-300</number>
|
||||
<number>-1000</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>300</number>
|
||||
<number>1000</number>
|
||||
</property>
|
||||
<property name="pageStep">
|
||||
<number>1</number>
|
||||
@ -667,17 +667,17 @@
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>ButtonSwitch</class>
|
||||
<extends>QToolButton</extends>
|
||||
<header>gui/buttonswitch.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>ValueDial</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>gui/valuedial.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>ButtonSwitch</class>
|
||||
<extends>QToolButton</extends>
|
||||
<header>gui/buttonswitch.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>TransverterButton</class>
|
||||
<extends>QPushButton</extends>
|
||||
|
||||
@ -83,23 +83,31 @@ void HackRFInputThread::run()
|
||||
if (hackrf_is_streaming(m_dev) == HACKRF_TRUE)
|
||||
{
|
||||
qDebug("HackRFInputThread::run: HackRF is streaming already");
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug("HackRFInputThread::run: HackRF is not streaming");
|
||||
|
||||
rc = (hackrf_error) hackrf_start_rx(m_dev, rx_callback, this);
|
||||
rc = (hackrf_error) hackrf_stop_rx(m_dev);
|
||||
|
||||
if (rc == HACKRF_SUCCESS)
|
||||
{
|
||||
qDebug("HackRFInputThread::run: started HackRF Rx");
|
||||
qDebug("HackRFInputThread::run: stopped HackRF Rx");
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug("HackRFInputThread::run: failed to start HackRF Rx: %s", hackrf_error_name(rc));
|
||||
qDebug("HackRFInputThread::run: failed to stop HackRF Rx: %s", hackrf_error_name(rc));
|
||||
}
|
||||
}
|
||||
|
||||
usleep(200000);
|
||||
|
||||
rc = (hackrf_error) hackrf_start_rx(m_dev, rx_callback, this);
|
||||
|
||||
if (rc == HACKRF_SUCCESS)
|
||||
{
|
||||
qDebug("HackRFInputThread::run: started HackRF Rx");
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug("HackRFInputThread::run: failed to start HackRF Rx: %s", hackrf_error_name(rc));
|
||||
}
|
||||
|
||||
while ((m_running) && (hackrf_is_streaming(m_dev) == HACKRF_TRUE))
|
||||
{
|
||||
usleep(200000);
|
||||
|
||||
@ -38,7 +38,7 @@ In baseband sample rate input mode (6A) this is the device to host sample rate i
|
||||
|
||||
<h3>2: Local Oscillator correction</h3>
|
||||
|
||||
Use this slider to adjust LO correction in ppm. It can be varied from -10.0 to 10.0 in 0.1 steps and is applied in software.
|
||||
Use this slider to adjust LO correction in ppm. It can be varied from -100.0 to 100.0 in 0.1 steps and is applied in software.
|
||||
|
||||
<h3>3: Auto correction options</h3>
|
||||
|
||||
|
||||
@ -2948,6 +2948,10 @@ margin-bottom: 20px;
|
||||
"type" : "number",
|
||||
"format" : "float"
|
||||
},
|
||||
"deEmphasis" : {
|
||||
"type" : "integer",
|
||||
"description" : "De-emphasis time constant (us)\n * 0 - 50us (Europe, Australia)\n * 1 - 75us (US, Japan)\n"
|
||||
},
|
||||
"volume" : {
|
||||
"type" : "number",
|
||||
"format" : "float"
|
||||
@ -2956,6 +2960,9 @@ margin-bottom: 20px;
|
||||
"type" : "number",
|
||||
"format" : "float"
|
||||
},
|
||||
"audioMute" : {
|
||||
"type" : "integer"
|
||||
},
|
||||
"audioStereo" : {
|
||||
"type" : "integer"
|
||||
},
|
||||
@ -6386,6 +6393,19 @@ margin-bottom: 20px;
|
||||
"type" : "integer",
|
||||
"description" : "Verify OSD decoded message against a list of validated callsigns\n * 0 - Disable\n * 1 - Enable\n"
|
||||
},
|
||||
"enablePSKReporter" : {
|
||||
"type" : "integer",
|
||||
"description" : "Enable reporting of decoded messages to PSK Reporter server\n * 0 - Disable\n * 1 - Enable\n"
|
||||
},
|
||||
"pskReporterCallsign" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"pskReporterLocator" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"pskReporterSoftware" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"rgbColor" : {
|
||||
"type" : "integer"
|
||||
},
|
||||
@ -59734,7 +59754,7 @@ except ApiException as e:
|
||||
</div>
|
||||
<div id="generator">
|
||||
<div class="content">
|
||||
Generated 2025-12-31T21:12:50.336+01:00
|
||||
Generated 2026-01-04T00:29:36.688+01:00
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -10,12 +10,20 @@ BFMDemodSettings:
|
||||
afBandwidth:
|
||||
type: number
|
||||
format: float
|
||||
deEmphasis:
|
||||
type: integer
|
||||
description: >
|
||||
De-emphasis time constant (us)
|
||||
* 0 - 50us (Europe, Australia)
|
||||
* 1 - 75us (US, Japan)
|
||||
volume:
|
||||
type: number
|
||||
format: float
|
||||
squelch:
|
||||
type: number
|
||||
format: float
|
||||
audioMute:
|
||||
type: integer
|
||||
audioStereo:
|
||||
type: integer
|
||||
lsbStereo:
|
||||
|
||||
@ -70,6 +70,18 @@ FT8DemodSettings:
|
||||
Verify OSD decoded message against a list of validated callsigns
|
||||
* 0 - Disable
|
||||
* 1 - Enable
|
||||
enablePSKReporter:
|
||||
type: integer
|
||||
description: >
|
||||
Enable reporting of decoded messages to PSK Reporter server
|
||||
* 0 - Disable
|
||||
* 1 - Enable
|
||||
pskReporterCallsign:
|
||||
type: string
|
||||
pskReporterLocator:
|
||||
type: string
|
||||
pskReporterSoftware:
|
||||
type: string
|
||||
rgbColor:
|
||||
type: integer
|
||||
title:
|
||||
|
||||
@ -44,7 +44,9 @@ struct SDRBASE_API FT8Message
|
||||
class SDRBASE_API MsgReportFT8Messages : public Message {
|
||||
MESSAGE_CLASS_DECLARATION
|
||||
public:
|
||||
const QList<FT8Message>& getFT8Messages() const { return m_ft8Messages; }
|
||||
QList<FT8Message>& getFT8Messages() { return m_ft8Messages; }
|
||||
qint64 getBaseFrequency() const { return m_baseFrequency; }
|
||||
void setBaseFrequency(qint64 baseFrequency) { m_baseFrequency = baseFrequency; }
|
||||
|
||||
static MsgReportFT8Messages* create() {
|
||||
|
||||
@ -10,12 +10,20 @@ BFMDemodSettings:
|
||||
afBandwidth:
|
||||
type: number
|
||||
format: float
|
||||
deEmphasis:
|
||||
type: integer
|
||||
description: >
|
||||
De-emphasis time constant (us)
|
||||
* 0 - 50us (Europe, Australia)
|
||||
* 1 - 75us (US, Japan)
|
||||
volume:
|
||||
type: number
|
||||
format: float
|
||||
squelch:
|
||||
type: number
|
||||
format: float
|
||||
audioMute:
|
||||
type: integer
|
||||
audioStereo:
|
||||
type: integer
|
||||
lsbStereo:
|
||||
|
||||
@ -70,6 +70,18 @@ FT8DemodSettings:
|
||||
Verify OSD decoded message against a list of validated callsigns
|
||||
* 0 - Disable
|
||||
* 1 - Enable
|
||||
enablePSKReporter:
|
||||
type: integer
|
||||
description: >
|
||||
Enable reporting of decoded messages to PSK Reporter server
|
||||
* 0 - Disable
|
||||
* 1 - Enable
|
||||
pskReporterCallsign:
|
||||
type: string
|
||||
pskReporterLocator:
|
||||
type: string
|
||||
pskReporterSoftware:
|
||||
type: string
|
||||
rgbColor:
|
||||
type: integer
|
||||
title:
|
||||
|
||||
@ -2948,6 +2948,10 @@ margin-bottom: 20px;
|
||||
"type" : "number",
|
||||
"format" : "float"
|
||||
},
|
||||
"deEmphasis" : {
|
||||
"type" : "integer",
|
||||
"description" : "De-emphasis time constant (us)\n * 0 - 50us (Europe, Australia)\n * 1 - 75us (US, Japan)\n"
|
||||
},
|
||||
"volume" : {
|
||||
"type" : "number",
|
||||
"format" : "float"
|
||||
@ -2956,6 +2960,9 @@ margin-bottom: 20px;
|
||||
"type" : "number",
|
||||
"format" : "float"
|
||||
},
|
||||
"audioMute" : {
|
||||
"type" : "integer"
|
||||
},
|
||||
"audioStereo" : {
|
||||
"type" : "integer"
|
||||
},
|
||||
@ -6386,6 +6393,19 @@ margin-bottom: 20px;
|
||||
"type" : "integer",
|
||||
"description" : "Verify OSD decoded message against a list of validated callsigns\n * 0 - Disable\n * 1 - Enable\n"
|
||||
},
|
||||
"enablePSKReporter" : {
|
||||
"type" : "integer",
|
||||
"description" : "Enable reporting of decoded messages to PSK Reporter server\n * 0 - Disable\n * 1 - Enable\n"
|
||||
},
|
||||
"pskReporterCallsign" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"pskReporterLocator" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"pskReporterSoftware" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"rgbColor" : {
|
||||
"type" : "integer"
|
||||
},
|
||||
@ -59734,7 +59754,7 @@ except ApiException as e:
|
||||
</div>
|
||||
<div id="generator">
|
||||
<div class="content">
|
||||
Generated 2025-12-31T21:12:50.336+01:00
|
||||
Generated 2026-01-04T00:29:36.688+01:00
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -34,10 +34,14 @@ SWGBFMDemodSettings::SWGBFMDemodSettings() {
|
||||
m_rf_bandwidth_isSet = false;
|
||||
af_bandwidth = 0.0f;
|
||||
m_af_bandwidth_isSet = false;
|
||||
de_emphasis = 0;
|
||||
m_de_emphasis_isSet = false;
|
||||
volume = 0.0f;
|
||||
m_volume_isSet = false;
|
||||
squelch = 0.0f;
|
||||
m_squelch_isSet = false;
|
||||
audio_mute = 0;
|
||||
m_audio_mute_isSet = false;
|
||||
audio_stereo = 0;
|
||||
m_audio_stereo_isSet = false;
|
||||
lsb_stereo = 0;
|
||||
@ -84,10 +88,14 @@ SWGBFMDemodSettings::init() {
|
||||
m_rf_bandwidth_isSet = false;
|
||||
af_bandwidth = 0.0f;
|
||||
m_af_bandwidth_isSet = false;
|
||||
de_emphasis = 0;
|
||||
m_de_emphasis_isSet = false;
|
||||
volume = 0.0f;
|
||||
m_volume_isSet = false;
|
||||
squelch = 0.0f;
|
||||
m_squelch_isSet = false;
|
||||
audio_mute = 0;
|
||||
m_audio_mute_isSet = false;
|
||||
audio_stereo = 0;
|
||||
m_audio_stereo_isSet = false;
|
||||
lsb_stereo = 0;
|
||||
@ -134,6 +142,8 @@ SWGBFMDemodSettings::cleanup() {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if(title != nullptr) {
|
||||
delete title;
|
||||
}
|
||||
@ -176,10 +186,14 @@ SWGBFMDemodSettings::fromJsonObject(QJsonObject &pJson) {
|
||||
|
||||
::SWGSDRangel::setValue(&af_bandwidth, pJson["afBandwidth"], "float", "");
|
||||
|
||||
::SWGSDRangel::setValue(&de_emphasis, pJson["deEmphasis"], "qint32", "");
|
||||
|
||||
::SWGSDRangel::setValue(&volume, pJson["volume"], "float", "");
|
||||
|
||||
::SWGSDRangel::setValue(&squelch, pJson["squelch"], "float", "");
|
||||
|
||||
::SWGSDRangel::setValue(&audio_mute, pJson["audioMute"], "qint32", "");
|
||||
|
||||
::SWGSDRangel::setValue(&audio_stereo, pJson["audioStereo"], "qint32", "");
|
||||
|
||||
::SWGSDRangel::setValue(&lsb_stereo, pJson["lsbStereo"], "qint32", "");
|
||||
@ -237,12 +251,18 @@ SWGBFMDemodSettings::asJsonObject() {
|
||||
if(m_af_bandwidth_isSet){
|
||||
obj->insert("afBandwidth", QJsonValue(af_bandwidth));
|
||||
}
|
||||
if(m_de_emphasis_isSet){
|
||||
obj->insert("deEmphasis", QJsonValue(de_emphasis));
|
||||
}
|
||||
if(m_volume_isSet){
|
||||
obj->insert("volume", QJsonValue(volume));
|
||||
}
|
||||
if(m_squelch_isSet){
|
||||
obj->insert("squelch", QJsonValue(squelch));
|
||||
}
|
||||
if(m_audio_mute_isSet){
|
||||
obj->insert("audioMute", QJsonValue(audio_mute));
|
||||
}
|
||||
if(m_audio_stereo_isSet){
|
||||
obj->insert("audioStereo", QJsonValue(audio_stereo));
|
||||
}
|
||||
@ -325,6 +345,16 @@ SWGBFMDemodSettings::setAfBandwidth(float af_bandwidth) {
|
||||
this->m_af_bandwidth_isSet = true;
|
||||
}
|
||||
|
||||
qint32
|
||||
SWGBFMDemodSettings::getDeEmphasis() {
|
||||
return de_emphasis;
|
||||
}
|
||||
void
|
||||
SWGBFMDemodSettings::setDeEmphasis(qint32 de_emphasis) {
|
||||
this->de_emphasis = de_emphasis;
|
||||
this->m_de_emphasis_isSet = true;
|
||||
}
|
||||
|
||||
float
|
||||
SWGBFMDemodSettings::getVolume() {
|
||||
return volume;
|
||||
@ -345,6 +375,16 @@ SWGBFMDemodSettings::setSquelch(float squelch) {
|
||||
this->m_squelch_isSet = true;
|
||||
}
|
||||
|
||||
qint32
|
||||
SWGBFMDemodSettings::getAudioMute() {
|
||||
return audio_mute;
|
||||
}
|
||||
void
|
||||
SWGBFMDemodSettings::setAudioMute(qint32 audio_mute) {
|
||||
this->audio_mute = audio_mute;
|
||||
this->m_audio_mute_isSet = true;
|
||||
}
|
||||
|
||||
qint32
|
||||
SWGBFMDemodSettings::getAudioStereo() {
|
||||
return audio_stereo;
|
||||
@ -519,12 +559,18 @@ SWGBFMDemodSettings::isSet(){
|
||||
if(m_af_bandwidth_isSet){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(m_de_emphasis_isSet){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(m_volume_isSet){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(m_squelch_isSet){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(m_audio_mute_isSet){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(m_audio_stereo_isSet){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
|
||||
@ -54,12 +54,18 @@ public:
|
||||
float getAfBandwidth();
|
||||
void setAfBandwidth(float af_bandwidth);
|
||||
|
||||
qint32 getDeEmphasis();
|
||||
void setDeEmphasis(qint32 de_emphasis);
|
||||
|
||||
float getVolume();
|
||||
void setVolume(float volume);
|
||||
|
||||
float getSquelch();
|
||||
void setSquelch(float squelch);
|
||||
|
||||
qint32 getAudioMute();
|
||||
void setAudioMute(qint32 audio_mute);
|
||||
|
||||
qint32 getAudioStereo();
|
||||
void setAudioStereo(qint32 audio_stereo);
|
||||
|
||||
@ -121,12 +127,18 @@ private:
|
||||
float af_bandwidth;
|
||||
bool m_af_bandwidth_isSet;
|
||||
|
||||
qint32 de_emphasis;
|
||||
bool m_de_emphasis_isSet;
|
||||
|
||||
float volume;
|
||||
bool m_volume_isSet;
|
||||
|
||||
float squelch;
|
||||
bool m_squelch_isSet;
|
||||
|
||||
qint32 audio_mute;
|
||||
bool m_audio_mute_isSet;
|
||||
|
||||
qint32 audio_stereo;
|
||||
bool m_audio_stereo_isSet;
|
||||
|
||||
|
||||
@ -60,6 +60,14 @@ SWGFT8DemodSettings::SWGFT8DemodSettings() {
|
||||
m_osd_ldpc_threshold_isSet = false;
|
||||
verify_osd = 0;
|
||||
m_verify_osd_isSet = false;
|
||||
enable_psk_reporter = 0;
|
||||
m_enable_psk_reporter_isSet = false;
|
||||
psk_reporter_callsign = nullptr;
|
||||
m_psk_reporter_callsign_isSet = false;
|
||||
psk_reporter_locator = nullptr;
|
||||
m_psk_reporter_locator_isSet = false;
|
||||
psk_reporter_software = nullptr;
|
||||
m_psk_reporter_software_isSet = false;
|
||||
rgb_color = 0;
|
||||
m_rgb_color_isSet = false;
|
||||
title = nullptr;
|
||||
@ -122,6 +130,14 @@ SWGFT8DemodSettings::init() {
|
||||
m_osd_ldpc_threshold_isSet = false;
|
||||
verify_osd = 0;
|
||||
m_verify_osd_isSet = false;
|
||||
enable_psk_reporter = 0;
|
||||
m_enable_psk_reporter_isSet = false;
|
||||
psk_reporter_callsign = new QString("");
|
||||
m_psk_reporter_callsign_isSet = false;
|
||||
psk_reporter_locator = new QString("");
|
||||
m_psk_reporter_locator_isSet = false;
|
||||
psk_reporter_software = new QString("");
|
||||
m_psk_reporter_software_isSet = false;
|
||||
rgb_color = 0;
|
||||
m_rgb_color_isSet = false;
|
||||
title = new QString("");
|
||||
@ -165,6 +181,16 @@ SWGFT8DemodSettings::cleanup() {
|
||||
|
||||
|
||||
|
||||
if(psk_reporter_callsign != nullptr) {
|
||||
delete psk_reporter_callsign;
|
||||
}
|
||||
if(psk_reporter_locator != nullptr) {
|
||||
delete psk_reporter_locator;
|
||||
}
|
||||
if(psk_reporter_software != nullptr) {
|
||||
delete psk_reporter_software;
|
||||
}
|
||||
|
||||
if(title != nullptr) {
|
||||
delete title;
|
||||
}
|
||||
@ -230,6 +256,14 @@ SWGFT8DemodSettings::fromJsonObject(QJsonObject &pJson) {
|
||||
|
||||
::SWGSDRangel::setValue(&verify_osd, pJson["verifyOSD"], "qint32", "");
|
||||
|
||||
::SWGSDRangel::setValue(&enable_psk_reporter, pJson["enablePSKReporter"], "qint32", "");
|
||||
|
||||
::SWGSDRangel::setValue(&psk_reporter_callsign, pJson["pskReporterCallsign"], "QString", "QString");
|
||||
|
||||
::SWGSDRangel::setValue(&psk_reporter_locator, pJson["pskReporterLocator"], "QString", "QString");
|
||||
|
||||
::SWGSDRangel::setValue(&psk_reporter_software, pJson["pskReporterSoftware"], "QString", "QString");
|
||||
|
||||
::SWGSDRangel::setValue(&rgb_color, pJson["rgbColor"], "qint32", "");
|
||||
|
||||
::SWGSDRangel::setValue(&title, pJson["title"], "QString", "QString");
|
||||
@ -316,6 +350,18 @@ SWGFT8DemodSettings::asJsonObject() {
|
||||
if(m_verify_osd_isSet){
|
||||
obj->insert("verifyOSD", QJsonValue(verify_osd));
|
||||
}
|
||||
if(m_enable_psk_reporter_isSet){
|
||||
obj->insert("enablePSKReporter", QJsonValue(enable_psk_reporter));
|
||||
}
|
||||
if(psk_reporter_callsign != nullptr && *psk_reporter_callsign != QString("")){
|
||||
toJsonValue(QString("pskReporterCallsign"), psk_reporter_callsign, obj, QString("QString"));
|
||||
}
|
||||
if(psk_reporter_locator != nullptr && *psk_reporter_locator != QString("")){
|
||||
toJsonValue(QString("pskReporterLocator"), psk_reporter_locator, obj, QString("QString"));
|
||||
}
|
||||
if(psk_reporter_software != nullptr && *psk_reporter_software != QString("")){
|
||||
toJsonValue(QString("pskReporterSoftware"), psk_reporter_software, obj, QString("QString"));
|
||||
}
|
||||
if(m_rgb_color_isSet){
|
||||
obj->insert("rgbColor", QJsonValue(rgb_color));
|
||||
}
|
||||
@ -513,6 +559,46 @@ SWGFT8DemodSettings::setVerifyOsd(qint32 verify_osd) {
|
||||
this->m_verify_osd_isSet = true;
|
||||
}
|
||||
|
||||
qint32
|
||||
SWGFT8DemodSettings::getEnablePskReporter() {
|
||||
return enable_psk_reporter;
|
||||
}
|
||||
void
|
||||
SWGFT8DemodSettings::setEnablePskReporter(qint32 enable_psk_reporter) {
|
||||
this->enable_psk_reporter = enable_psk_reporter;
|
||||
this->m_enable_psk_reporter_isSet = true;
|
||||
}
|
||||
|
||||
QString*
|
||||
SWGFT8DemodSettings::getPskReporterCallsign() {
|
||||
return psk_reporter_callsign;
|
||||
}
|
||||
void
|
||||
SWGFT8DemodSettings::setPskReporterCallsign(QString* psk_reporter_callsign) {
|
||||
this->psk_reporter_callsign = psk_reporter_callsign;
|
||||
this->m_psk_reporter_callsign_isSet = true;
|
||||
}
|
||||
|
||||
QString*
|
||||
SWGFT8DemodSettings::getPskReporterLocator() {
|
||||
return psk_reporter_locator;
|
||||
}
|
||||
void
|
||||
SWGFT8DemodSettings::setPskReporterLocator(QString* psk_reporter_locator) {
|
||||
this->psk_reporter_locator = psk_reporter_locator;
|
||||
this->m_psk_reporter_locator_isSet = true;
|
||||
}
|
||||
|
||||
QString*
|
||||
SWGFT8DemodSettings::getPskReporterSoftware() {
|
||||
return psk_reporter_software;
|
||||
}
|
||||
void
|
||||
SWGFT8DemodSettings::setPskReporterSoftware(QString* psk_reporter_software) {
|
||||
this->psk_reporter_software = psk_reporter_software;
|
||||
this->m_psk_reporter_software_isSet = true;
|
||||
}
|
||||
|
||||
qint32
|
||||
SWGFT8DemodSettings::getRgbColor() {
|
||||
return rgb_color;
|
||||
@ -676,6 +762,18 @@ SWGFT8DemodSettings::isSet(){
|
||||
if(m_verify_osd_isSet){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(m_enable_psk_reporter_isSet){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(psk_reporter_callsign && *psk_reporter_callsign != QString("")){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(psk_reporter_locator && *psk_reporter_locator != QString("")){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(psk_reporter_software && *psk_reporter_software != QString("")){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(m_rgb_color_isSet){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
|
||||
@ -93,6 +93,18 @@ public:
|
||||
qint32 getVerifyOsd();
|
||||
void setVerifyOsd(qint32 verify_osd);
|
||||
|
||||
qint32 getEnablePskReporter();
|
||||
void setEnablePskReporter(qint32 enable_psk_reporter);
|
||||
|
||||
QString* getPskReporterCallsign();
|
||||
void setPskReporterCallsign(QString* psk_reporter_callsign);
|
||||
|
||||
QString* getPskReporterLocator();
|
||||
void setPskReporterLocator(QString* psk_reporter_locator);
|
||||
|
||||
QString* getPskReporterSoftware();
|
||||
void setPskReporterSoftware(QString* psk_reporter_software);
|
||||
|
||||
qint32 getRgbColor();
|
||||
void setRgbColor(qint32 rgb_color);
|
||||
|
||||
@ -178,6 +190,18 @@ private:
|
||||
qint32 verify_osd;
|
||||
bool m_verify_osd_isSet;
|
||||
|
||||
qint32 enable_psk_reporter;
|
||||
bool m_enable_psk_reporter_isSet;
|
||||
|
||||
QString* psk_reporter_callsign;
|
||||
bool m_psk_reporter_callsign_isSet;
|
||||
|
||||
QString* psk_reporter_locator;
|
||||
bool m_psk_reporter_locator_isSet;
|
||||
|
||||
QString* psk_reporter_software;
|
||||
bool m_psk_reporter_software_isSet;
|
||||
|
||||
qint32 rgb_color;
|
||||
bool m_rgb_color_isSet;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user