mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-12-23 01:55:48 -05:00
Merge pull request #2057 from srcejon/freq_scanner
Support VOR Localizer on Qt6. Add Add Channels dialog to SID. Add JJY to Radio Clock
This commit is contained in:
commit
a6c1dc56c4
BIN
doc/img/SID_plugin_addchannels.png
Normal file
BIN
doc/img/SID_plugin_addchannels.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 19 KiB |
Binary file not shown.
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
@ -289,13 +289,26 @@ int ChannelPower::webapiSettingsPutPatch(
|
||||
ChannelPowerSettings settings = m_settings;
|
||||
webapiUpdateChannelSettings(settings, channelSettingsKeys, response);
|
||||
|
||||
MsgConfigureChannelPower *msg = MsgConfigureChannelPower::create(settings, channelSettingsKeys, force);
|
||||
// Ensure inputFrequencyOffset and frequency are consistent
|
||||
QStringList settingsKeys = channelSettingsKeys;
|
||||
if (settingsKeys.contains("frequency") && !settingsKeys.contains("inputFrequencyOffset"))
|
||||
{
|
||||
settings.m_inputFrequencyOffset = settings.m_frequency - m_centerFrequency;
|
||||
settingsKeys.append("inputFrequencyOffset");
|
||||
}
|
||||
else if (settingsKeys.contains("inputFrequencyOffset") && !settingsKeys.contains("frequency"))
|
||||
{
|
||||
settings.m_frequency = m_centerFrequency + settings.m_inputFrequencyOffset;
|
||||
settingsKeys.append("frequency");
|
||||
}
|
||||
|
||||
MsgConfigureChannelPower *msg = MsgConfigureChannelPower::create(settings, settingsKeys, force);
|
||||
m_inputMessageQueue.push(msg);
|
||||
|
||||
qDebug("ChannelPower::webapiSettingsPutPatch: forward to GUI: %p", m_guiMessageQueue);
|
||||
if (m_guiMessageQueue) // forward to GUI if any
|
||||
{
|
||||
MsgConfigureChannelPower *msgToGUI = MsgConfigureChannelPower::create(settings, channelSettingsKeys, force);
|
||||
MsgConfigureChannelPower *msgToGUI = MsgConfigureChannelPower::create(settings, settingsKeys, force);
|
||||
m_guiMessageQueue->push(msgToGUI);
|
||||
}
|
||||
|
||||
@ -312,6 +325,12 @@ void ChannelPower::webapiUpdateChannelSettings(
|
||||
if (channelSettingsKeys.contains("inputFrequencyOffset")) {
|
||||
settings.m_inputFrequencyOffset = response.getChannelPowerSettings()->getInputFrequencyOffset();
|
||||
}
|
||||
if (channelSettingsKeys.contains("frequencyMode")) {
|
||||
settings.m_frequencyMode = (ChannelPowerSettings::FrequencyMode) response.getChannelPowerSettings()->getFrequencyMode();
|
||||
}
|
||||
if (channelSettingsKeys.contains("frequency")) {
|
||||
settings.m_frequency = response.getChannelPowerSettings()->getFrequency();
|
||||
}
|
||||
if (channelSettingsKeys.contains("rfBandwidth")) {
|
||||
settings.m_rfBandwidth = response.getChannelPowerSettings()->getRfBandwidth();
|
||||
}
|
||||
@ -356,6 +375,8 @@ void ChannelPower::webapiUpdateChannelSettings(
|
||||
void ChannelPower::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& response, const ChannelPowerSettings& settings)
|
||||
{
|
||||
response.getChannelPowerSettings()->setInputFrequencyOffset(settings.m_inputFrequencyOffset);
|
||||
response.getChannelPowerSettings()->setFrequencyMode(settings.m_frequencyMode);
|
||||
response.getChannelPowerSettings()->setFrequency(settings.m_frequency);
|
||||
response.getChannelPowerSettings()->setRfBandwidth(settings.m_rfBandwidth);
|
||||
response.getChannelPowerSettings()->setPulseThreshold(settings.m_pulseThreshold);
|
||||
response.getChannelPowerSettings()->setAveragePeriodUs(settings.m_averagePeriodUS);
|
||||
@ -469,6 +490,12 @@ void ChannelPower::webapiFormatChannelSettings(
|
||||
if (channelSettingsKeys.contains("inputFrequencyOffset") || force) {
|
||||
swgChannelPowerSettings->setInputFrequencyOffset(settings.m_inputFrequencyOffset);
|
||||
}
|
||||
if (channelSettingsKeys.contains("frequencyMode") || force) {
|
||||
swgChannelPowerSettings->setFrequencyMode(settings.m_frequencyMode);
|
||||
}
|
||||
if (channelSettingsKeys.contains("inputFrequency") || force) {
|
||||
swgChannelPowerSettings->setFrequency(settings.m_frequency);
|
||||
}
|
||||
if (channelSettingsKeys.contains("rfBandwidth") || force) {
|
||||
swgChannelPowerSettings->setRfBandwidth(settings.m_rfBandwidth);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
<h1>Channel Power Plugin</h1>
|
||||
<h1>Channel Power Plugin</h1>
|
||||
|
||||
<h2>Introduction</h2>
|
||||
|
||||
@ -10,38 +10,48 @@ The top and bottom bars of the channel window are described [here](../../../sdrg
|
||||
|
||||
![Channel power plugin GUI](../../../doc/img/ChannelPower_plugin_settings.png)
|
||||
|
||||
<h3>1: Frequency shift from center frequency of reception</h3>
|
||||
<h3>1: Channel frequency entry mode</h3>
|
||||
|
||||
Use the wheels to adjust the channel center frequency as a shift in Hz from the center frequency of reception. Left click on a digit sets the cursor position at this digit. Right click on a digit sets all digits on the right to zero. This effectively floors value at the digit position. Wheels are moved with the mousewheel while pointing at the wheel or by selecting the wheel with the left mouse click and using the keyboard arrows. Pressing shift simultaneously moves digit by 5 and pressing control moves it by 2.
|
||||
Select from one of the following modes to determine how the channel center frequency is calculated:
|
||||
|
||||
<h3>2: BW - Channel Bandwidth</h3>
|
||||
* Δf - Specify an offset in Hz from device center frequency.
|
||||
* f - Specific a frequency in Hz.
|
||||
|
||||
<h3>2: Channel Frequency</h3>
|
||||
|
||||
Specifies channel center frequency according to frequency entry mode (1):
|
||||
|
||||
* Δf - Offset in Hz from device center frequency.
|
||||
* f - Absolute frequency in Hz.
|
||||
|
||||
<h3>3: BW - Channel Bandwidth</h3>
|
||||
|
||||
Bandwidth in Hz of the channel for which power is to be measured.
|
||||
|
||||
<h3>3: Tavg - Average Time</h3>
|
||||
<h3>4: Tavg - Average Time</h3>
|
||||
|
||||
Time period overwhich the channel power is averaged. Values range from 10us to 10s in powers of 10. The available values depend upon the sample rate.
|
||||
|
||||
<h3>4: THp - Pulse Threshold</h3>
|
||||
<h3>5: THp - Pulse Threshold</h3>
|
||||
|
||||
The pulse threshold sets the power in dB for which the channel power needs to exceed, in order to be included in the pulse average power measurement.
|
||||
|
||||
<h3>5: Avg - Average Power</h3>
|
||||
<h3>6: Avg - Average Power</h3>
|
||||
|
||||
Displays the most recent average power measurement in dB.
|
||||
|
||||
<h3>6: Max - Max Peak Power</h3>
|
||||
<h3>7: Max - Max Peak Power</h3>
|
||||
|
||||
Displays the maximum instantaneous peak power measurement in dB.
|
||||
|
||||
<h3>7: Min - Min Peak Power</h3>
|
||||
<h3>8: Min - Min Peak Power</h3>
|
||||
|
||||
Displays the minimum instantaneous peak power measurement in dB.
|
||||
|
||||
<h3>8: Pulse - Pulse Average Power</h3>
|
||||
<h3>9: Pulse - Pulse Average Power</h3>
|
||||
|
||||
Displays the most recent pulse average power measurement in dB.
|
||||
|
||||
<h3>9: Clear Data</h3>
|
||||
<h3>10: Clear Data</h3>
|
||||
|
||||
Clears current measurements (min and max values are reset).
|
||||
|
@ -431,7 +431,6 @@ Item {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
onClicked: (mouse) => {
|
||||
console.log("AIRPORT CLICKED ************************* ");
|
||||
if (mouse.button === Qt.RightButton) {
|
||||
showRangeItem.visible = !rangeGroup.groupVisible
|
||||
hideRangeItem.visible = rangeGroup.groupVisible
|
||||
@ -508,7 +507,6 @@ Item {
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: (mouse) => {
|
||||
console.log("AIRPORT 2 CLICKED ************************* ");
|
||||
if (showFreq) {
|
||||
var freqIdx = Math.floor((mouse.y-5)/((height-10)/airportDataRows))
|
||||
if (freqIdx == 0) {
|
||||
|
@ -233,9 +233,15 @@ void RadioClock::applySettings(const RadioClockSettings& settings, bool force)
|
||||
|
||||
QList<QString> reverseAPIKeys;
|
||||
|
||||
if ((settings.m_frequencyMode != m_settings.m_frequencyMode) || force) {
|
||||
reverseAPIKeys.append("frequencyMode");
|
||||
}
|
||||
if ((settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) || force) {
|
||||
reverseAPIKeys.append("inputFrequencyOffset");
|
||||
}
|
||||
if ((settings.m_frequency != m_settings.m_frequency) || force) {
|
||||
reverseAPIKeys.append("frequency");
|
||||
}
|
||||
if ((settings.m_rfBandwidth != m_settings.m_rfBandwidth) || force) {
|
||||
reverseAPIKeys.append("rfBandwidth");
|
||||
}
|
||||
@ -331,6 +337,13 @@ int RadioClock::webapiSettingsPutPatch(
|
||||
RadioClockSettings settings = m_settings;
|
||||
webapiUpdateChannelSettings(settings, channelSettingsKeys, response);
|
||||
|
||||
// Ensure inputFrequencyOffset and frequency are consistent
|
||||
if (channelSettingsKeys.contains("frequency") && !channelSettingsKeys.contains("inputFrequencyOffset")) {
|
||||
settings.m_inputFrequencyOffset = settings.m_frequency - m_centerFrequency;
|
||||
} else if (channelSettingsKeys.contains("inputFrequencyOffset") && !channelSettingsKeys.contains("frequency")) {
|
||||
settings.m_frequency = m_centerFrequency + settings.m_inputFrequencyOffset;
|
||||
}
|
||||
|
||||
MsgConfigureRadioClock *msg = MsgConfigureRadioClock::create(settings, force);
|
||||
m_inputMessageQueue.push(msg);
|
||||
|
||||
@ -351,9 +364,15 @@ void RadioClock::webapiUpdateChannelSettings(
|
||||
const QStringList& channelSettingsKeys,
|
||||
SWGSDRangel::SWGChannelSettings& response)
|
||||
{
|
||||
if (channelSettingsKeys.contains("frequencyMode")) {
|
||||
settings.m_frequencyMode = (RadioClockSettings::FrequencyMode) response.getRadioClockSettings()->getFrequencyMode();
|
||||
}
|
||||
if (channelSettingsKeys.contains("inputFrequencyOffset")) {
|
||||
settings.m_inputFrequencyOffset = response.getRadioClockSettings()->getInputFrequencyOffset();
|
||||
}
|
||||
if (channelSettingsKeys.contains("frequency")) {
|
||||
settings.m_frequency = response.getRadioClockSettings()->getFrequency();
|
||||
}
|
||||
if (channelSettingsKeys.contains("rfBandwidth")) {
|
||||
settings.m_rfBandwidth = response.getRadioClockSettings()->getRfBandwidth();
|
||||
}
|
||||
@ -403,7 +422,9 @@ void RadioClock::webapiUpdateChannelSettings(
|
||||
|
||||
void RadioClock::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& response, const RadioClockSettings& settings)
|
||||
{
|
||||
response.getRadioClockSettings()->setFrequencyMode((int)settings.m_frequencyMode);
|
||||
response.getRadioClockSettings()->setInputFrequencyOffset(settings.m_inputFrequencyOffset);
|
||||
response.getRadioClockSettings()->setFrequency(settings.m_frequency);
|
||||
response.getRadioClockSettings()->setRfBandwidth(settings.m_rfBandwidth);
|
||||
response.getRadioClockSettings()->setThreshold(settings.m_threshold);
|
||||
response.getRadioClockSettings()->setModulation((int)settings.m_modulation);
|
||||
@ -536,9 +557,15 @@ void RadioClock::webapiFormatChannelSettings(
|
||||
|
||||
// transfer data that has been modified. When force is on transfer all data except reverse API data
|
||||
|
||||
if (channelSettingsKeys.contains("frequencyMode") || force) {
|
||||
swgRadioClockSettings->setFrequencyMode(settings.m_frequencyMode);
|
||||
}
|
||||
if (channelSettingsKeys.contains("inputFrequencyOffset") || force) {
|
||||
swgRadioClockSettings->setInputFrequencyOffset(settings.m_inputFrequencyOffset);
|
||||
}
|
||||
if (channelSettingsKeys.contains("frequency") || force) {
|
||||
swgRadioClockSettings->setFrequency(settings.m_frequency);
|
||||
}
|
||||
if (channelSettingsKeys.contains("rfBandwidth") || force) {
|
||||
swgRadioClockSettings->setRfBandwidth(settings.m_rfBandwidth);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2020-2023 Jon Beniston, M7RCE <jon@beniston.com> //
|
||||
// Copyright (C) 2020-2024 Jon Beniston, M7RCE <jon@beniston.com> //
|
||||
// Copyright (C) 2020-2022 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
@ -139,8 +139,7 @@ bool RadioClockGUI::handleMessage(const Message& message)
|
||||
const DSPSignalNotification& notif = (const DSPSignalNotification&) message;
|
||||
m_deviceCenterFrequency = notif.getCenterFrequency();
|
||||
m_basebandSampleRate = notif.getSampleRate();
|
||||
ui->deltaFrequency->setValueRange(false, 7, -m_basebandSampleRate/2, m_basebandSampleRate/2);
|
||||
ui->deltaFrequencyLabel->setToolTip(tr("Range %1 %L2 Hz").arg(QChar(0xB1)).arg(m_basebandSampleRate/2));
|
||||
calcOffset();
|
||||
updateAbsoluteCenterFrequency();
|
||||
return true;
|
||||
}
|
||||
@ -148,6 +147,23 @@ bool RadioClockGUI::handleMessage(const Message& message)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Calculate input frequency offset, when device center frequency changes
|
||||
void RadioClockGUI::calcOffset()
|
||||
{
|
||||
if (m_settings.m_frequencyMode == RadioClockSettings::Offset)
|
||||
{
|
||||
ui->deltaFrequency->setValueRange(false, 7, -m_basebandSampleRate/2, m_basebandSampleRate/2);
|
||||
}
|
||||
else
|
||||
{
|
||||
qint64 offset = m_settings.m_frequency - m_deviceCenterFrequency;
|
||||
m_channelMarker.setCenterFrequency(offset);
|
||||
m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency();
|
||||
updateAbsoluteCenterFrequency();
|
||||
applySettings();
|
||||
}
|
||||
}
|
||||
|
||||
void RadioClockGUI::handleInputMessages()
|
||||
{
|
||||
Message* message;
|
||||
@ -163,8 +179,22 @@ void RadioClockGUI::handleInputMessages()
|
||||
|
||||
void RadioClockGUI::channelMarkerChangedByCursor()
|
||||
{
|
||||
ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency());
|
||||
m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency();
|
||||
m_settings.m_frequency = m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset;
|
||||
|
||||
qint64 value = 0;
|
||||
|
||||
if (m_settings.m_frequencyMode == RadioClockSettings::Offset) {
|
||||
value = m_settings.m_inputFrequencyOffset;
|
||||
} else if (m_settings.m_frequencyMode == RadioClockSettings::Absolute) {
|
||||
value = m_settings.m_frequency;
|
||||
}
|
||||
|
||||
ui->deltaFrequency->blockSignals(true);
|
||||
ui->deltaFrequency->setValue(value);
|
||||
ui->deltaFrequency->blockSignals(false);
|
||||
|
||||
updateAbsoluteCenterFrequency();
|
||||
applySettings();
|
||||
}
|
||||
|
||||
@ -173,9 +203,46 @@ void RadioClockGUI::channelMarkerHighlightedByCursor()
|
||||
setHighlighted(m_channelMarker.getHighlighted());
|
||||
}
|
||||
|
||||
void RadioClockGUI::on_frequencyMode_currentIndexChanged(int index)
|
||||
{
|
||||
m_settings.m_frequencyMode = (RadioClockSettings::FrequencyMode) index;
|
||||
ui->deltaFrequency->blockSignals(true);
|
||||
|
||||
if (m_settings.m_frequencyMode == RadioClockSettings::Offset)
|
||||
{
|
||||
ui->deltaFrequency->setValueRange(false, 7, -9999999, 9999999);
|
||||
ui->deltaFrequency->setValue(m_settings.m_inputFrequencyOffset);
|
||||
ui->deltaUnits->setText("Hz");
|
||||
}
|
||||
else if (m_settings.m_frequencyMode == RadioClockSettings::Absolute)
|
||||
{
|
||||
ui->deltaFrequency->setValueRange(true, 11, 0, 99999999999, 0);
|
||||
ui->deltaFrequency->setValue(m_settings.m_frequency);
|
||||
ui->deltaUnits->setText("Hz");
|
||||
}
|
||||
|
||||
ui->deltaFrequency->blockSignals(false);
|
||||
|
||||
updateAbsoluteCenterFrequency();
|
||||
applySettings();
|
||||
}
|
||||
|
||||
void RadioClockGUI::on_deltaFrequency_changed(qint64 value)
|
||||
{
|
||||
m_channelMarker.setCenterFrequency(value);
|
||||
qint64 offset = 0;
|
||||
|
||||
if (m_settings.m_frequencyMode == RadioClockSettings::Offset)
|
||||
{
|
||||
offset = value;
|
||||
m_settings.m_frequency = m_deviceCenterFrequency + offset;
|
||||
}
|
||||
else if (m_settings.m_frequencyMode == RadioClockSettings::Absolute)
|
||||
{
|
||||
m_settings.m_frequency = value;
|
||||
offset = m_settings.m_frequency - m_deviceCenterFrequency;
|
||||
}
|
||||
|
||||
m_channelMarker.setCenterFrequency(offset);
|
||||
m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency();
|
||||
updateAbsoluteCenterFrequency();
|
||||
applySettings();
|
||||
@ -300,7 +367,6 @@ RadioClockGUI::RadioClockGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Bas
|
||||
|
||||
ui->status->setText("Looking for minute marker");
|
||||
|
||||
ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03)));
|
||||
ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold));
|
||||
ui->deltaFrequency->setValueRange(false, 7, -9999999, 9999999);
|
||||
ui->channelPowerMeter->setColorTheme(LevelMeterSignalDB::ColorGreenAndBlue);
|
||||
@ -368,7 +434,8 @@ void RadioClockGUI::displaySettings()
|
||||
|
||||
blockApplySettings(true);
|
||||
|
||||
ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency());
|
||||
ui->frequencyMode->setCurrentIndex((int) m_settings.m_frequencyMode);
|
||||
on_frequencyMode_currentIndexChanged((int) m_settings.m_frequencyMode);
|
||||
|
||||
ui->rfBWText->setText(QString("%1 Hz").arg((int)m_settings.m_rfBandwidth));
|
||||
ui->rfBW->setValue(m_settings.m_rfBandwidth);
|
||||
@ -420,6 +487,7 @@ void RadioClockGUI::tick()
|
||||
|
||||
void RadioClockGUI::makeUIConnections()
|
||||
{
|
||||
QObject::connect(ui->frequencyMode, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &RadioClockGUI::on_frequencyMode_currentIndexChanged);
|
||||
QObject::connect(ui->deltaFrequency, &ValueDialZ::changed, this, &RadioClockGUI::on_deltaFrequency_changed);
|
||||
QObject::connect(ui->rfBW, &QSlider::valueChanged, this, &RadioClockGUI::on_rfBW_valueChanged);
|
||||
QObject::connect(ui->threshold, &QDial::valueChanged, this, &RadioClockGUI::on_threshold_valueChanged);
|
||||
@ -430,4 +498,11 @@ void RadioClockGUI::makeUIConnections()
|
||||
void RadioClockGUI::updateAbsoluteCenterFrequency()
|
||||
{
|
||||
setStatusFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset);
|
||||
if ( (m_basebandSampleRate > 1)
|
||||
&& ( (m_settings.m_inputFrequencyOffset >= m_basebandSampleRate / 2)
|
||||
|| (m_settings.m_inputFrequencyOffset < -m_basebandSampleRate / 2))) {
|
||||
setStatusText("Frequency out of band");
|
||||
} else {
|
||||
setStatusText("");
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2020-2022 Jon Beniston, M7RCE <jon@beniston.com> //
|
||||
// Copyright (C) 2020-2024 Jon Beniston, M7RCE <jon@beniston.com> //
|
||||
// Copyright (C) 2020, 2022 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
@ -93,6 +93,7 @@ private:
|
||||
bool handleMessage(const Message& message);
|
||||
void makeUIConnections();
|
||||
void updateAbsoluteCenterFrequency();
|
||||
void calcOffset();
|
||||
|
||||
void displayDateTime();
|
||||
|
||||
@ -100,6 +101,7 @@ private:
|
||||
void enterEvent(EnterEventType*);
|
||||
|
||||
private slots:
|
||||
void on_frequencyMode_currentIndexChanged(int index);
|
||||
void on_deltaFrequency_changed(qint64 value);
|
||||
void on_rfBW_valueChanged(int index);
|
||||
void on_threshold_valueChanged(int value);
|
||||
|
@ -74,16 +74,32 @@
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="deltaFrequencyLabel">
|
||||
<widget class="QComboBox" name="frequencyMode">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>16</width>
|
||||
<width>40</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Df</string>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Select frequency entry mode.</string>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Δf</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>f</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
@ -370,6 +386,11 @@
|
||||
<string>WWVB</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>JJY</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
|
@ -2,7 +2,7 @@
|
||||
// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
|
||||
// written by Christian Daniel //
|
||||
// Copyright (C) 2015-2020, 2022 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
|
||||
// Copyright (C) 2021 Jon Beniston, M7RCE <jon@beniston.com> //
|
||||
// Copyright (C) 2021-2024 Jon Beniston, M7RCE <jon@beniston.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 //
|
||||
@ -35,7 +35,9 @@ RadioClockSettings::RadioClockSettings() :
|
||||
|
||||
void RadioClockSettings::resetToDefaults()
|
||||
{
|
||||
m_frequencyMode = Offset;
|
||||
m_inputFrequencyOffset = 0;
|
||||
m_frequency = 0;
|
||||
m_rfBandwidth = 50.0f;
|
||||
m_threshold = 5;
|
||||
m_modulation = MSF;
|
||||
@ -58,9 +60,11 @@ QByteArray RadioClockSettings::serialize() const
|
||||
|
||||
s.writeS32(1, m_inputFrequencyOffset);
|
||||
s.writeFloat(2, m_rfBandwidth);
|
||||
s.writeS64(3, m_frequency);
|
||||
s.writeFloat(4, m_threshold);
|
||||
s.writeS32(5, (int)m_modulation);
|
||||
s.writeS32(6, (int)m_timezone);
|
||||
s.writeS32(7, (int)m_frequencyMode);
|
||||
s.writeU32(12, m_rgbColor);
|
||||
s.writeString(13, m_title);
|
||||
|
||||
@ -108,9 +112,11 @@ bool RadioClockSettings::deserialize(const QByteArray& data)
|
||||
|
||||
d.readS32(1, &m_inputFrequencyOffset, 0);
|
||||
d.readFloat(2, &m_rfBandwidth, 50.0f);
|
||||
d.readS64(3, &m_frequency, 0);
|
||||
d.readFloat(4, &m_threshold, 30);
|
||||
d.readS32(5, (int *)&m_modulation, DCF77);
|
||||
d.readS32(6, (int *)&m_timezone, BROADCAST);
|
||||
d.readS32(7, (int *)&m_frequencyMode, Offset);
|
||||
d.readU32(12, &m_rgbColor, QColor(102, 0, 0).rgb());
|
||||
d.readString(13, &m_title, "Radio Clock");
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
|
||||
// written by Christian Daniel //
|
||||
// Copyright (C) 2015-2019, 2021-2022 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
|
||||
// Copyright (C) 2021 Jon Beniston, M7RCE <jon@beniston.com> //
|
||||
// Copyright (C) 2021-2024 Jon Beniston, M7RCE <jon@beniston.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 //
|
||||
@ -30,14 +30,20 @@ class Serializable;
|
||||
|
||||
struct RadioClockSettings
|
||||
{
|
||||
enum FrequencyMode {
|
||||
Offset,
|
||||
Absolute
|
||||
} m_frequencyMode;
|
||||
qint32 m_inputFrequencyOffset;
|
||||
qint64 m_frequency;
|
||||
Real m_rfBandwidth;
|
||||
Real m_threshold; //!< For MSF and DCF in dB
|
||||
enum Modulation {
|
||||
MSF,
|
||||
DCF77,
|
||||
TDF,
|
||||
WWVB
|
||||
WWVB,
|
||||
JJY
|
||||
} m_modulation;
|
||||
enum DisplayTZ {
|
||||
BROADCAST,
|
||||
|
@ -1,6 +1,6 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2021-2022 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
|
||||
// Copyright (C) 2021 Jon Beniston, M7RCE <jon@beniston.com> //
|
||||
// Copyright (C) 2021-2024 Jon Beniston, M7RCE <jon@beniston.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 //
|
||||
@ -794,6 +794,158 @@ void RadioClockSink::wwvb()
|
||||
m_prevData = m_data;
|
||||
}
|
||||
|
||||
// Japan JJY 40kHz
|
||||
// https://en.wikipedia.org/wiki/JJY
|
||||
void RadioClockSink::jjy()
|
||||
{
|
||||
// JJY reduces carrier by -10dB
|
||||
// Full power, then reduced power, which is the opposite of WWVB
|
||||
// 0.8s full power is is zero bit, 0.5s full power is one bit
|
||||
// 0.2s full power is a marker. Seven markers per minute (0, 9, 19, 29, 39, 49, and 59s) and for leap second
|
||||
m_threshold = m_thresholdMovingAverage.asDouble() * m_linearThreshold; // xdB below average
|
||||
m_data = m_magsq > m_threshold;
|
||||
|
||||
// Look for minute marker - two consequtive markers
|
||||
if ((m_data == 1) && (m_prevData == 0))
|
||||
{
|
||||
if ( (m_highCount <= RadioClockSettings::RADIOCLOCK_CHANNEL_SAMPLE_RATE * 0.3)
|
||||
&& (m_lowCount >= RadioClockSettings::RADIOCLOCK_CHANNEL_SAMPLE_RATE * 0.7)
|
||||
)
|
||||
{
|
||||
if (m_gotMarker && !m_gotMinuteMarker)
|
||||
{
|
||||
qDebug() << "RadioClockSink::jjy - Minute marker: (low " << m_lowCount << " high " << m_highCount << ") prev period " << m_periodCount;
|
||||
m_gotMinuteMarker = true;
|
||||
m_second = 1;
|
||||
m_secondMarkers = 1;
|
||||
if (getMessageQueueToChannel()) {
|
||||
getMessageQueueToChannel()->push(RadioClock::MsgStatus::create("Got minute marker"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "RadioClockSink::jjy - Marker: (low " << m_lowCount << " high " << m_highCount << ") prev period " << m_periodCount << " second " << m_second;
|
||||
}
|
||||
m_gotMarker = true;
|
||||
m_periodCount = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_gotMarker = false;
|
||||
}
|
||||
m_highCount = 0;
|
||||
}
|
||||
else if ((m_data == 0) && (m_prevData == 1))
|
||||
{
|
||||
m_lowCount = 0;
|
||||
}
|
||||
else if (m_data == 1)
|
||||
{
|
||||
m_highCount++;
|
||||
}
|
||||
else if (m_data == 0)
|
||||
{
|
||||
m_lowCount++;
|
||||
}
|
||||
|
||||
m_sample = false;
|
||||
if (m_gotMinuteMarker)
|
||||
{
|
||||
m_periodCount++;
|
||||
if (m_periodCount == 100)
|
||||
{
|
||||
// Check we get second marker
|
||||
m_secondMarkers += m_data == 1;
|
||||
// If we see too many 0s instead of 1s, assume we've lost the signal
|
||||
if ((m_second > 10) && (m_secondMarkers / m_second < 0.7))
|
||||
{
|
||||
qDebug() << "RadioClockSink::jjy - Lost lock: " << m_secondMarkers << m_second;
|
||||
m_gotMinuteMarker = false;
|
||||
if (getMessageQueueToChannel()) {
|
||||
getMessageQueueToChannel()->push(RadioClock::MsgStatus::create("Looking for minute marker"));
|
||||
}
|
||||
}
|
||||
m_sample = true;
|
||||
}
|
||||
else if (m_periodCount == 650)
|
||||
{
|
||||
// Get data bit A for timecode
|
||||
m_timeCode[m_second] = !m_data; // No carrier = 1, carrier = 0
|
||||
m_sample = true;
|
||||
}
|
||||
else if (m_periodCount == 950)
|
||||
{
|
||||
if (m_second == 59)
|
||||
{
|
||||
// Check markers are decoded as 1s
|
||||
const QList<int> markerBits = {9, 19, 29, 39, 49, 59};
|
||||
int missingMarkers = 0;
|
||||
for (int i = 0; i < markerBits.size(); i++)
|
||||
{
|
||||
if (m_timeCode[markerBits[i]] != 1)
|
||||
{
|
||||
missingMarkers++;
|
||||
qDebug() << "RadioClockSink::jjy - Missing marker at bit " << markerBits[i];
|
||||
}
|
||||
}
|
||||
if (missingMarkers >= 3)
|
||||
{
|
||||
m_gotMinuteMarker = false;
|
||||
qDebug() << "RadioClockSink::jjy - Lost lock: Missing markers: " << missingMarkers;
|
||||
if (getMessageQueueToChannel()) {
|
||||
getMessageQueueToChannel()->push(RadioClock::MsgStatus::create("Looking for minute marker"));
|
||||
}
|
||||
}
|
||||
|
||||
// Check 0s where expected
|
||||
const QList<int> zeroBits = {4, 10, 11, 14, 20, 21, 24, 34, 35, 44, 55, 56, 57, 58};
|
||||
for (int i = 0; i < zeroBits.size(); i++)
|
||||
{
|
||||
if (m_timeCode[zeroBits[i]] != 0) {
|
||||
qDebug() << "RadioClockSink::jjy - Unexpected 1 at bit " << zeroBits[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Decode timecode to time and date
|
||||
int minute = bcdMSB(1, 8, 4);
|
||||
int hour = bcdMSB(12, 18, 14);
|
||||
int dayOfYear = bcdMSB(22, 33, 24, 29);
|
||||
int year = 2000 + bcdMSB(41, 48);
|
||||
|
||||
// Japan doesn't have daylight savings
|
||||
m_dst = RadioClockSettings::NOT_IN_EFFECT;
|
||||
|
||||
// Time is UTC
|
||||
QDate date(year, 1, 1);
|
||||
date = date.addDays(dayOfYear - 1);
|
||||
m_dateTime = QDateTime(date, QTime(hour, minute), Qt::OffsetFromUTC, 0);
|
||||
if (getMessageQueueToChannel()) {
|
||||
getMessageQueueToChannel()->push(RadioClock::MsgStatus::create("OK"));
|
||||
}
|
||||
|
||||
m_second = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_second++;
|
||||
m_dateTime = m_dateTime.addSecs(1);
|
||||
}
|
||||
|
||||
if (getMessageQueueToChannel())
|
||||
{
|
||||
RadioClock::MsgDateTime *msg = RadioClock::MsgDateTime::create(m_dateTime, m_dst);
|
||||
getMessageQueueToChannel()->push(msg);
|
||||
}
|
||||
}
|
||||
else if (m_periodCount == 1000)
|
||||
{
|
||||
m_periodCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
m_prevData = m_data;
|
||||
}
|
||||
|
||||
void RadioClockSink::processOneSample(Complex &ci)
|
||||
{
|
||||
// Calculate average and peak levels for level meter
|
||||
@ -817,6 +969,8 @@ void RadioClockSink::processOneSample(Complex &ci)
|
||||
tdf(ci);
|
||||
} else if (m_settings.m_modulation == RadioClockSettings::WWVB) {
|
||||
wwvb();
|
||||
} else if (m_settings.m_modulation == RadioClockSettings::JJY) {
|
||||
jjy();
|
||||
} else {
|
||||
msf60();
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2019-2021 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
|
||||
// Copyright (C) 2020-2021 Jon Beniston, M7RCE <jon@beniston.com> //
|
||||
// Copyright (C) 2020-2024 Jon Beniston, M7RCE <jon@beniston.com> //
|
||||
// Copyright (C) 2020 Kacper Michajłow <kasper93@gmail.com> //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
@ -160,6 +160,7 @@ private:
|
||||
void tdf(Complex &ci);
|
||||
void msf60();
|
||||
void wwvb();
|
||||
void jjy();
|
||||
};
|
||||
|
||||
#endif // INCLUDE_RADIOCLOCKSINK_H
|
||||
|
@ -1,4 +1,4 @@
|
||||
<h1>Radio clock plugin</h1>
|
||||
<h1>Radio Clock Plugin</h1>
|
||||
|
||||
<h2>Introduction</h2>
|
||||
|
||||
@ -8,6 +8,7 @@ This plugin can be used to receive the time and date as broadcast on Low Frequen
|
||||
* [DCF77](https://en.wikipedia.org/wiki/DCF77) - Germany - 77.5kHz
|
||||
* [TDF](https://en.wikipedia.org/wiki/TDF_time_signal) - France - 162kHz
|
||||
* [WWVB](https://en.wikipedia.org/wiki/WWVB) - USA - 60kHz
|
||||
* [JJY](https://en.wikipedia.org/wiki/JJY) - Japan - 40kHz
|
||||
|
||||
If you'd like other transmitters to be supported, please upload a .sdriq file to SDRangel's [github issue tracker](https://github.com/f4exb/sdrangel/issues).
|
||||
|
||||
@ -21,29 +22,39 @@ The top and bottom bars of the channel window are described [here](../../../sdrg
|
||||
|
||||
![Radio clock plugin GUI](../../../doc/img/RadioClock_plugin.png)
|
||||
|
||||
<h3>1: Frequency shift from center frequency of reception</h3>
|
||||
<h3>1: Channel frequency entry mode</h3>
|
||||
|
||||
Use the wheels to adjust the frequency shift in Hz from the center frequency of reception. Left click on a digit sets the cursor position at this digit. Right click on a digit sets all digits on the right to zero. This effectively floors value at the digit position. Wheels are moved with the mousewheel while pointing at the wheel or by selecting the wheel with the left mouse click and using the keyboard arrows. Pressing shift simultaneously moves digit by 5 and pressing control moves it by 2.
|
||||
Select from one of the following modes to determine how the channel center frequency is calculated:
|
||||
|
||||
<h3>2: Channel power</h3>
|
||||
* Δf - Specify an offset in Hz from device center frequency.
|
||||
* f - Specific a frequency in Hz.
|
||||
|
||||
<h3>2: Channel Frequency</h3>
|
||||
|
||||
Specifies channel center frequency according to frequency entry mode (1):
|
||||
|
||||
* Δf - Offset in Hz from device center frequency.
|
||||
* f - Absolute frequency in Hz.
|
||||
|
||||
<h3>3: Channel power</h3>
|
||||
|
||||
Average total power in dB relative to a +/- 1.0 amplitude signal received in the pass band.
|
||||
|
||||
<h3>3: Level meter in dB</h3>
|
||||
<h3>4: 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>4: BW - RF Bandwidth</h3>
|
||||
<h3>5: BW - RF Bandwidth</h3>
|
||||
|
||||
This specifies the bandwidth of a LPF that is applied to the input signal to limit the RF bandwidth.
|
||||
|
||||
<h3>5: TH - Threshold</h3>
|
||||
<h3>6: TH - Threshold</h3>
|
||||
|
||||
For MSF, DCF77 and WWVB, specifies the threshold in dB below the average carrier power level that determines a binary 0 or 1.
|
||||
For MSF, DCF77, WWVB and JJY, specifies the threshold in dB below the average carrier power level that determines a binary 0 or 1.
|
||||
|
||||
<h3>6: Modulation</h3>
|
||||
<h3>7: Modulation</h3>
|
||||
|
||||
Specifies the modulation and timecode encoding used:
|
||||
|
||||
@ -51,8 +62,9 @@ Specifies the modulation and timecode encoding used:
|
||||
* DCF77 - OOK (On-off keying)
|
||||
* TDF - PM (Phase modulation)
|
||||
* WWVB - OOK (On-off keying)
|
||||
* JJY - OOK (On-off keying)
|
||||
|
||||
<h3>7: Display Time Zone</h3>
|
||||
<h3>8: Display Time Zone</h3>
|
||||
|
||||
Specifies the time zone used to display the received time. This can be:
|
||||
|
||||
@ -60,15 +72,15 @@ Specifies the time zone used to display the received time. This can be:
|
||||
* Local - the time is converted to the local time (as determined by your operating system's time zone).
|
||||
* UTC - the time is converted to Coordinated Universal Time.
|
||||
|
||||
<h3>8: Date</h3>
|
||||
<h3>9: Date</h3>
|
||||
|
||||
Displays the decoded date.
|
||||
|
||||
<h3>9: Time</h3>
|
||||
<h3>10: Time</h3>
|
||||
|
||||
Displays the decoded time, adjusted for the time zone set by (7).
|
||||
Displays the decoded time, adjusted for the time zone set by (8).
|
||||
|
||||
<h3>10: Status</h3>
|
||||
<h3>11: Status</h3>
|
||||
|
||||
Displays the demodulator status. This can be:
|
||||
|
||||
@ -81,7 +93,7 @@ The date and time fields are only valid when the status indicates OK.
|
||||
|
||||
If while in the OK state several second markers are not detected, the status will return to Looking for minute marker.
|
||||
|
||||
<h3>11: Daylight Savings</h3>
|
||||
<h3>12: Daylight Savings</h3>
|
||||
|
||||
Displays the daylight savings state:
|
||||
|
||||
@ -90,7 +102,7 @@ Displays the daylight savings state:
|
||||
* Starting
|
||||
* Ending
|
||||
|
||||
For MSF, DCF77 and TDF, starting/ending is indicated one hour before the change. For WWVB it is set for the whole day.
|
||||
For MSF, DCF77 and TDF, starting/ending is indicated one hour before the change. For WWVB it is set for the whole day. Japan does not use daylight savings.
|
||||
|
||||
<h3>Waveforms</h3>
|
||||
|
||||
|
@ -27,12 +27,15 @@ if(NOT SERVER_MODE)
|
||||
sidgui.ui
|
||||
sidsettingsdialog.cpp
|
||||
sidsettingsdialog.ui
|
||||
sidaddchannelsdialog.cpp
|
||||
sidaddchannelsdialog.ui
|
||||
icons.qrc
|
||||
)
|
||||
set(sid_HEADERS
|
||||
${sid_HEADERS}
|
||||
sidgui.h
|
||||
sidsettingsdialog.h
|
||||
sidaddchannelsdialog.h
|
||||
)
|
||||
|
||||
set(TARGET_NAME featuresid)
|
||||
|
@ -119,7 +119,17 @@ When checked, all data is displayed on a single combined chart.
|
||||
Check to display a legend on the chart. When unchecked the legend will be hidden. You can click on items in the legend to temporarily hide and then show the corresponding series on the chart.
|
||||
The position of the legend can be set in the Settings Dialog.
|
||||
|
||||
<h3>16: Open Settings Dialog</h3>
|
||||
<h3>16: Add Channels</h3>
|
||||
|
||||
Click to open the Add Channels Dialog. This allows you to easily add the Channel Power channels for each VLF transmitter on each RX device.
|
||||
This dialog shows a table with one row for each VLF Transmitter, and a column for each RX device.
|
||||
When OK is pressed, a corresponding Channel Power channel will be created for every cell that is checked.
|
||||
|
||||
For example, in the image below, Channel Power channels will be added for the GDQ transmitter on both devices R0 and R1, with one for FTA on device R0 only.
|
||||
|
||||
![SID Add Channels dialog](../../../doc/img/SID_plugin_addchannels.png)
|
||||
|
||||
<h3>17: Open Settings Dialog</h3>
|
||||
|
||||
Click to open the Settings Dialog. The settings dialog allows a user to:
|
||||
|
||||
@ -134,7 +144,7 @@ Click to open the Settings Dialog. The settings dialog allows a user to:
|
||||
|
||||
![SID settings dialog](../../../doc/img/SID_plugin_settings_dialog.png)
|
||||
|
||||
<h3>17: Display SDO/SOHO Imagery</h3>
|
||||
<h3>18: Display SDO/SOHO Imagery</h3>
|
||||
|
||||
When checked, displays imagary from NASA's SDO (Solar Dynamic Observatory) and ESA/NASA's SOHO (Solar and Heliospheric Observatory) satellites.
|
||||
|
||||
@ -142,11 +152,11 @@ SDOs images the Sun in a variety of UV and EUV wavelengths. SOHO shows images of
|
||||
|
||||
Solar flares are particularly visible in the AIA 131 Å images.
|
||||
|
||||
<h3>18: Image or Video Selection</h3>
|
||||
<h3>19: Image or Video Selection</h3>
|
||||
|
||||
Selects whether to display images (unchecked) or video (checked).
|
||||
|
||||
<h3>19: Image/Wavelength Selection</h3>
|
||||
<h3>20: Image/Wavelength Selection</h3>
|
||||
|
||||
Selects which image / wavelength to view.
|
||||
|
||||
@ -172,63 +182,63 @@ Selects which image / wavelength to view.
|
||||
|
||||
* LASCO (Large Angle Spectrometric Coronagraph) shows solar corona. C2 shows corona up to 8.4Mkm. C3 shows corona up to 23Mkm.
|
||||
|
||||
<h3>20: Show GOES 16, 18 and SDO</h3>
|
||||
<h3>21: Show GOES 16, 18 and SDO</h3>
|
||||
|
||||
When checked, opens a [Satellite Tracker](../../feature/satellitetracker/readme.md) feature and sets it to display data for the GOES 16, GOES 18 and SDO satellites.
|
||||
The position and tracks of the satellites will then be visible on a [Map](../../feature/map/readme.md) feature.
|
||||
|
||||
<h3>21: Autoscale X</h3>
|
||||
<h3>22: Autoscale X</h3>
|
||||
|
||||
When clicked, the chart X-axis is automatically scaled so that all power data is visible. When right-clicked, autoscaling of the X-axis will occur whenever new data is added to the chart.
|
||||
|
||||
<h3>22: Autoscale Y</h3>
|
||||
<h3>23: Autoscale Y</h3>
|
||||
|
||||
When clicked, the chart Y-axis is automatically scaled so that all power data is visible. When right-clicked, autoscaling of the Y-axis will occur whenever new data is added to the chart.
|
||||
|
||||
<h3>23: Set X-axis to Today</h3>
|
||||
<h3>24: Set X-axis to Today</h3>
|
||||
|
||||
When clicked, the X-axis is set to show today, from midnight to midnight.
|
||||
|
||||
When right-clicked, the X-axis is set to show sunrise to sunset. This uses latitude and longitude from Preferences > My position.
|
||||
|
||||
<h3>24: Set X-axis to -1 day</h3>
|
||||
<h3>25: Set X-axis to -1 day</h3>
|
||||
|
||||
When clicked, the X-axis is set 1 day earlier than the current setting, at the same time.
|
||||
|
||||
<h3>25: Set X-axis to +1 day</h3>
|
||||
<h3>26: Set X-axis to +1 day</h3>
|
||||
|
||||
When clicked, the X-axis is set 1 day later than the current setting, at the same time.
|
||||
|
||||
<h3>26: Start Time</h3>
|
||||
<h3>27: Start Time</h3>
|
||||
|
||||
Displays/sets the current start time of the chart (X-axis minimum). It's possible to scroll through hours/days/months by clicking on the relevant segment and using the mouse scroll wheel.
|
||||
|
||||
<h3>27: End Time</h3>
|
||||
<h3>28: End Time</h3>
|
||||
|
||||
Displays/sets the current end time of the chart (X-axis maximum). It's possible to scroll through hours/days/months by clicking on the relevant segment and using the mouse scroll wheel.
|
||||
|
||||
<h3>28: Min</h3>
|
||||
<h3>29: Min</h3>
|
||||
|
||||
Displays/sets the minimum Y-axis value.
|
||||
|
||||
<h3>29: Max</h3>
|
||||
<h3>30: Max</h3>
|
||||
|
||||
Displays/sets the maximum Y-axis value.
|
||||
|
||||
<h3>30: Now</h3>
|
||||
<h3>31: Now</h3>
|
||||
|
||||
When checked, the latest SDO imagery is displayed. When unchecked, you can enter a date and time for which imagery should be displayed.
|
||||
|
||||
<h3>31: Date Time</h3>
|
||||
<h3>32: Date Time</h3>
|
||||
|
||||
Specifies the date and time for which SDO imagery should be displayed. Images are updated every 15 minutes. The date and time can also be set by clicking on the chart.
|
||||
|
||||
<h3>32: Map</h3>
|
||||
<h3>33: Map</h3>
|
||||
|
||||
Select a Map to link to the SID feature. When a time is selected on the SID charts, the [Map](../../feature/map/readme.md) feature will have it's time set accordingly.
|
||||
This allows you, for example, to see the corresponding impact on MUF/foF2 displayed on the 3D map.
|
||||
|
||||
<h3>33: Show Paths on Map</h3>
|
||||
<h3>34: Show Paths on Map</h3>
|
||||
|
||||
When clicked, shows the great circle paths between transmitters and receivers on a [Map](../../feature/map/readme.md).
|
||||
|
||||
|
156
plugins/feature/sid/sidaddchannelsdialog.cpp
Normal file
156
plugins/feature/sid/sidaddchannelsdialog.cpp
Normal file
@ -0,0 +1,156 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2024 Jon Beniston, M7RCE //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation as version 3 of the License, or //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// This program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License V3 for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <QTableWidgetItem>
|
||||
#include <QDebug>
|
||||
|
||||
#include "util/vlftransmitters.h"
|
||||
#include "channel/channelwebapiutils.h"
|
||||
#include "device/deviceapi.h"
|
||||
#include "device/deviceset.h"
|
||||
#include "dsp/dspdevicesourceengine.h"
|
||||
#include "maincore.h"
|
||||
|
||||
#include "sidaddchannelsdialog.h"
|
||||
|
||||
SIDAddChannelsDialog::SIDAddChannelsDialog(SIDSettings *settings, QWidget* parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::SIDAddChannelsDialog),
|
||||
m_settings(settings)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
MainCore *mainCore = MainCore::instance();
|
||||
std::vector<DeviceSet*>& deviceSets = mainCore->getDeviceSets();
|
||||
|
||||
ui->channels->setColumnCount(deviceSets.size() + 2);
|
||||
|
||||
// Create column header
|
||||
ui->channels->setHorizontalHeaderItem(COL_TX_NAME, new QTableWidgetItem("Callsign"));
|
||||
ui->channels->setHorizontalHeaderItem(COL_TX_FREQUENCY, new QTableWidgetItem("Frequency (Hz)"));
|
||||
for (unsigned int i = 0; i < deviceSets.size(); i++)
|
||||
{
|
||||
if (deviceSets[i]->m_deviceSourceEngine || deviceSets[i]->m_deviceMIMOEngine)
|
||||
{
|
||||
QTableWidgetItem *item = new QTableWidgetItem(mainCore->getDeviceSetId(deviceSets[i]));
|
||||
|
||||
ui->channels->setHorizontalHeaderItem(COL_DEVICE + i, item);
|
||||
}
|
||||
}
|
||||
|
||||
// Add row for each transmitter, with checkbox for each device
|
||||
for (int j = 0; j < VLFTransmitters::m_transmitters.size(); j++)
|
||||
{
|
||||
int row = ui->channels->rowCount();
|
||||
ui->channels->setRowCount(row+1);
|
||||
|
||||
ui->channels->setItem(row, COL_TX_NAME, new QTableWidgetItem(VLFTransmitters::m_transmitters[j].m_callsign));
|
||||
ui->channels->setItem(row, COL_TX_FREQUENCY, new QTableWidgetItem(QString::number(VLFTransmitters::m_transmitters[j].m_frequency)));
|
||||
|
||||
for (unsigned int i = 0; i < deviceSets.size(); i++)
|
||||
{
|
||||
if (deviceSets[i]->m_deviceSourceEngine || deviceSets[i]->m_deviceMIMOEngine)
|
||||
{
|
||||
QTableWidgetItem *enableItem = new QTableWidgetItem();
|
||||
enableItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
|
||||
enableItem->setCheckState(Qt::Unchecked);
|
||||
ui->channels->setItem(row, COL_DEVICE + i, enableItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ui->channels->resizeColumnsToContents();
|
||||
}
|
||||
|
||||
SIDAddChannelsDialog::~SIDAddChannelsDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void SIDAddChannelsDialog::accept()
|
||||
{
|
||||
if (ui->channels->columnCount() > 2)
|
||||
{
|
||||
MainCore *mainCore = MainCore::instance();
|
||||
connect(mainCore, &MainCore::channelAdded, this, &SIDAddChannelsDialog::channelAdded);
|
||||
|
||||
m_count = m_settings->m_channelSettings.size();
|
||||
m_row = 0;
|
||||
m_col = COL_DEVICE;
|
||||
addNextChannel();
|
||||
}
|
||||
else
|
||||
{
|
||||
QDialog::accept();
|
||||
}
|
||||
}
|
||||
|
||||
void SIDAddChannelsDialog::addNextChannel()
|
||||
{
|
||||
if (m_row < ui->channels->rowCount())
|
||||
{
|
||||
QString id = ui->channels->horizontalHeaderItem(m_col)->text();
|
||||
unsigned int deviceSetIndex;
|
||||
|
||||
if (ui->channels->item(m_row, m_col)->checkState() == Qt::Checked)
|
||||
{
|
||||
MainCore::getDeviceSetIndexFromId(id, deviceSetIndex);
|
||||
ChannelWebAPIUtils::addChannel(deviceSetIndex, "sdrangel.channel.channelpower", 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
nextChannel(); // can recursively call this method
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QDialog::accept();
|
||||
}
|
||||
}
|
||||
|
||||
void SIDAddChannelsDialog::nextChannel()
|
||||
{
|
||||
m_col++;
|
||||
if (m_col >= ui->channels->columnCount())
|
||||
{
|
||||
m_col = COL_DEVICE;
|
||||
m_row++;
|
||||
}
|
||||
|
||||
addNextChannel();
|
||||
}
|
||||
|
||||
void SIDAddChannelsDialog::channelAdded(int deviceSetIndex, ChannelAPI *channel)
|
||||
{
|
||||
(void) deviceSetIndex;
|
||||
|
||||
const VLFTransmitters::Transmitter *transmitter = VLFTransmitters::m_callsignHash.value(ui->channels->item(m_row, COL_TX_NAME)->text());
|
||||
|
||||
ChannelWebAPIUtils::patchChannelSetting(channel, "title", transmitter->m_callsign);
|
||||
ChannelWebAPIUtils::patchChannelSetting(channel, "frequency", transmitter->m_frequency);
|
||||
ChannelWebAPIUtils::patchChannelSetting(channel, "frequencyMode", 1);
|
||||
ChannelWebAPIUtils::patchChannelSetting(channel, "rfBandwidth", 300);
|
||||
ChannelWebAPIUtils::patchChannelSetting(channel, "averagePeriodUS", 10000000);
|
||||
|
||||
// Update setings if they are created by SIDGUI before this slot is called
|
||||
if (m_count < m_settings->m_channelSettings.size()) {
|
||||
m_settings->m_channelSettings[m_count].m_label = transmitter->m_callsign;
|
||||
}
|
||||
|
||||
m_count++;
|
||||
nextChannel();
|
||||
}
|
58
plugins/feature/sid/sidaddchannelsdialog.h
Normal file
58
plugins/feature/sid/sidaddchannelsdialog.h
Normal file
@ -0,0 +1,58 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2024 Jon Beniston, M7RCE //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation as version 3 of the License, or //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// This program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License V3 for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef INCLUDE_SIDADDCHANNELSDIALOG_H
|
||||
#define INCLUDE_SIDADDCHANNELSDIALOG_H
|
||||
|
||||
#include "ui_sidaddchannelsdialog.h"
|
||||
|
||||
#include "sidsettings.h"
|
||||
|
||||
class SIDAddChannelsDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit SIDAddChannelsDialog(SIDSettings *settings, QWidget* parent = 0);
|
||||
~SIDAddChannelsDialog();
|
||||
|
||||
private:
|
||||
|
||||
private slots:
|
||||
void accept();
|
||||
|
||||
void channelAdded(int deviceSetIndex, ChannelAPI *channel);
|
||||
|
||||
private:
|
||||
Ui::SIDAddChannelsDialog* ui;
|
||||
|
||||
enum Column {
|
||||
COL_TX_NAME,
|
||||
COL_TX_FREQUENCY,
|
||||
COL_DEVICE
|
||||
};
|
||||
|
||||
SIDSettings *m_settings;
|
||||
|
||||
int m_row; // Row and column in table, when adding channels
|
||||
int m_col;
|
||||
int m_count; // How many channels we've added
|
||||
|
||||
void addNextChannel();
|
||||
void nextChannel();
|
||||
};
|
||||
|
||||
#endif // INCLUDE_SIDADDCHANNELSDIALOG_H
|
92
plugins/feature/sid/sidaddchannelsdialog.ui
Normal file
92
plugins/feature/sid/sidaddchannelsdialog.ui
Normal file
@ -0,0 +1,92 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>SIDAddChannelsDialog</class>
|
||||
<widget class="QDialog" name="SIDAddChannelsDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>441</width>
|
||||
<height>463</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Liberation Sans</family>
|
||||
<pointsize>9</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Add channels</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Select devices and VLF transmitters to add channels for</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_2">
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QTableWidget" name="channels">
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::NoSelection</enum>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
<attribute name="verticalHeaderStretchLastSection">
|
||||
<bool>true</bool>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>SIDAddChannelsDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>257</x>
|
||||
<y>31</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>SIDAddChannelsDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>325</x>
|
||||
<y>31</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
@ -39,6 +39,7 @@
|
||||
#include "sid.h"
|
||||
#include "sidgui.h"
|
||||
#include "sidsettingsdialog.h"
|
||||
#include "sidaddchannelsdialog.h"
|
||||
|
||||
#include "SWGMapItem.h"
|
||||
|
||||
@ -1482,6 +1483,16 @@ void SIDGUI::on_deleteAll_clicked()
|
||||
getData();
|
||||
}
|
||||
|
||||
void SIDGUI::on_addChannels_clicked()
|
||||
{
|
||||
SIDAddChannelsDialog dialog(&m_settings);
|
||||
|
||||
new DialogPositioner(&dialog, true);
|
||||
|
||||
dialog.exec();
|
||||
}
|
||||
|
||||
|
||||
void SIDGUI::on_settings_clicked()
|
||||
{
|
||||
SIDSettingsDialog dialog(&m_settings);
|
||||
@ -1493,6 +1504,8 @@ void SIDGUI::on_settings_clicked()
|
||||
&SIDGUI::removeChannels
|
||||
);
|
||||
|
||||
new DialogPositioner(&dialog, true);
|
||||
|
||||
if (dialog.exec() == QDialog::Accepted)
|
||||
{
|
||||
setAutosaveTimer();
|
||||
@ -1587,6 +1600,7 @@ void SIDGUI::makeUIConnections()
|
||||
QObject::connect(ui->saveData, &QToolButton::clicked, this, &SIDGUI::on_saveData_clicked);
|
||||
QObject::connect(ui->loadData, &QToolButton::clicked, this, &SIDGUI::on_loadData_clicked);
|
||||
QObject::connect(ui->saveChartImage, &QToolButton::clicked, this, &SIDGUI::on_saveChartImage_clicked);
|
||||
QObject::connect(ui->addChannels, &QToolButton::clicked, this, &SIDGUI::on_addChannels_clicked);
|
||||
QObject::connect(ui->settings, &QToolButton::clicked, this, &SIDGUI::on_settings_clicked);
|
||||
}
|
||||
|
||||
|
@ -284,6 +284,7 @@ private slots:
|
||||
void updateStatus();
|
||||
void autosave();
|
||||
void on_settings_clicked();
|
||||
void on_addChannels_clicked();
|
||||
void xRayDataUpdated(const QList<GOESXRay::XRayData>& data, bool primary);
|
||||
void protonDataUpdated(const QList<GOESXRay::ProtonData>& data, bool primary);
|
||||
void grbDataUpdated(const QList<GRB::Data>& data);
|
||||
|
@ -327,6 +327,20 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="addChannels">
|
||||
<property name="toolTip">
|
||||
<string>Add channels</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../sdrgui/resources/res.qrc">
|
||||
<normaloff>:/channels_add.png</normaloff>:/channels_add.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="settings">
|
||||
<property name="toolTip">
|
||||
|
@ -1,7 +1,9 @@
|
||||
<RCC>
|
||||
<qresource prefix="/demodvor/">
|
||||
<file>map/map.qml</file>
|
||||
<file>map/map_6.qml</file>
|
||||
<file>map/MapStation.qml</file>
|
||||
<file>map/ModifiedMapView.qml</file>
|
||||
<file>map/antenna.png</file>
|
||||
<file>map/VOR.png</file>
|
||||
<file>map/VOR-DME.png</file>
|
||||
|
178
plugins/feature/vorlocalizer/map/ModifiedMapView.qml
Normal file
178
plugins/feature/vorlocalizer/map/ModifiedMapView.qml
Normal file
@ -0,0 +1,178 @@
|
||||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
import QtQuick
|
||||
import QtLocation as QL
|
||||
import QtPositioning as QP
|
||||
import Qt.labs.animation
|
||||
/*!
|
||||
\qmltype MapView
|
||||
\inqmlmodule QtLocation
|
||||
\brief An interactive map viewer component.
|
||||
|
||||
MapView wraps a Map and adds the typical interactive features:
|
||||
changing the zoom level, panning and tilting the map.
|
||||
|
||||
The implementation is a QML assembly of smaller building blocks that are
|
||||
available separately. In case you want to make changes in your own version
|
||||
of this component, you can copy the QML, which is installed into the
|
||||
\c qml/QtLocation module directory, and modify it as needed.
|
||||
|
||||
\sa Map
|
||||
*/
|
||||
Item {
|
||||
/*!
|
||||
\qmlproperty Map MapView::map
|
||||
|
||||
This property provides access to the underlying Map instance.
|
||||
*/
|
||||
property alias map: map
|
||||
|
||||
/*!
|
||||
\qmlproperty real minimumZoomLevel
|
||||
|
||||
The minimum zoom level according to the size of the view.
|
||||
|
||||
\sa Map::minimumZoomLevel
|
||||
*/
|
||||
property real minimumZoomLevel: map.minimumZoomLevel
|
||||
|
||||
/*!
|
||||
\qmlproperty real maximumZoomLevel
|
||||
|
||||
The maximum valid zoom level for the map.
|
||||
|
||||
\sa Map::maximumZoomLevel
|
||||
*/
|
||||
property real maximumZoomLevel: map.maximumZoomLevel
|
||||
|
||||
// --------------------------------
|
||||
// implementation
|
||||
id: root
|
||||
Component.onCompleted: map.resetPinchMinMax()
|
||||
|
||||
QL.Map {
|
||||
id: map
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
tilt: tiltHandler.persistentTranslation.y / -5
|
||||
property bool pinchAdjustingZoom: false
|
||||
|
||||
BoundaryRule on zoomLevel {
|
||||
id: br
|
||||
minimum: map.minimumZoomLevel
|
||||
maximum: map.maximumZoomLevel
|
||||
}
|
||||
|
||||
onZoomLevelChanged: {
|
||||
br.returnToBounds();
|
||||
if (!pinchAdjustingZoom) resetPinchMinMax()
|
||||
}
|
||||
|
||||
function resetPinchMinMax() {
|
||||
pinch.persistentScale = 1
|
||||
pinch.scaleAxis.minimum = Math.pow(2, root.minimumZoomLevel - map.zoomLevel + 1)
|
||||
pinch.scaleAxis.maximum = Math.pow(2, root.maximumZoomLevel - map.zoomLevel - 1)
|
||||
}
|
||||
|
||||
PinchHandler {
|
||||
id: pinch
|
||||
target: null
|
||||
property real rawBearing: 0
|
||||
property QP.geoCoordinate startCentroid
|
||||
onActiveChanged: if (active) {
|
||||
flickAnimation.stop()
|
||||
pinch.startCentroid = map.toCoordinate(pinch.centroid.position, false)
|
||||
} else {
|
||||
flickAnimation.restart(centroid.velocity)
|
||||
map.resetPinchMinMax()
|
||||
}
|
||||
onScaleChanged: (delta) => {
|
||||
map.pinchAdjustingZoom = true
|
||||
map.zoomLevel += Math.log2(delta)
|
||||
map.alignCoordinateToPoint(pinch.startCentroid, pinch.centroid.position)
|
||||
map.pinchAdjustingZoom = false
|
||||
}
|
||||
onRotationChanged: (delta) => {
|
||||
pinch.rawBearing -= delta
|
||||
// snap to 0° if we're close enough
|
||||
map.bearing = (Math.abs(pinch.rawBearing) < 5) ? 0 : pinch.rawBearing
|
||||
map.alignCoordinateToPoint(pinch.startCentroid, pinch.centroid.position)
|
||||
}
|
||||
grabPermissions: PointerHandler.TakeOverForbidden
|
||||
}
|
||||
WheelHandler {
|
||||
id: wheel
|
||||
// workaround for QTBUG-87646 / QTBUG-112394 / QTBUG-112432:
|
||||
// Magic Mouse pretends to be a trackpad but doesn't work with PinchHandler
|
||||
// and we don't yet distinguish mice and trackpads on Wayland either
|
||||
acceptedDevices: Qt.platform.pluginName === "cocoa" || Qt.platform.pluginName === "wayland"
|
||||
? PointerDevice.Mouse | PointerDevice.TouchPad
|
||||
: PointerDevice.Mouse
|
||||
onWheel: (event) => {
|
||||
const loc = map.toCoordinate(wheel.point.position)
|
||||
switch (event.modifiers) {
|
||||
case Qt.NoModifier:
|
||||
// jonb - Changed to make more like Qt5
|
||||
//map.zoomLevel += event.angleDelta.y / 120
|
||||
map.zoomLevel += event.angleDelta.y / 1000
|
||||
break
|
||||
case Qt.ShiftModifier:
|
||||
map.bearing += event.angleDelta.y / 15
|
||||
break
|
||||
case Qt.ControlModifier:
|
||||
map.tilt += event.angleDelta.y / 15
|
||||
break
|
||||
}
|
||||
map.alignCoordinateToPoint(loc, wheel.point.position)
|
||||
}
|
||||
}
|
||||
DragHandler {
|
||||
id: drag
|
||||
signal flickStarted // for autotests only
|
||||
signal flickEnded
|
||||
target: null
|
||||
onTranslationChanged: (delta) => map.pan(-delta.x, -delta.y)
|
||||
onActiveChanged: if (active) {
|
||||
flickAnimation.stop()
|
||||
} else {
|
||||
flickAnimation.restart(centroid.velocity)
|
||||
}
|
||||
}
|
||||
|
||||
property vector3d animDest
|
||||
onAnimDestChanged: if (flickAnimation.running) {
|
||||
const delta = Qt.vector2d(animDest.x - flickAnimation.animDestLast.x, animDest.y - flickAnimation.animDestLast.y)
|
||||
map.pan(-delta.x, -delta.y)
|
||||
flickAnimation.animDestLast = animDest
|
||||
}
|
||||
|
||||
Vector3dAnimation on animDest {
|
||||
id: flickAnimation
|
||||
property vector3d animDestLast
|
||||
from: Qt.vector3d(0, 0, 0)
|
||||
duration: 500
|
||||
easing.type: Easing.OutQuad
|
||||
onStarted: drag.flickStarted()
|
||||
onStopped: drag.flickEnded()
|
||||
|
||||
function restart(vel) {
|
||||
stop()
|
||||
map.animDest = Qt.vector3d(0, 0, 0)
|
||||
animDestLast = Qt.vector3d(0, 0, 0)
|
||||
to = Qt.vector3d(vel.x / duration * 100, vel.y / duration * 100, 0)
|
||||
start()
|
||||
}
|
||||
}
|
||||
|
||||
DragHandler {
|
||||
id: tiltHandler
|
||||
minimumPointCount: 2
|
||||
maximumPointCount: 2
|
||||
target: null
|
||||
xAxis.enabled: false
|
||||
grabPermissions: PointerHandler.TakeOverForbidden
|
||||
onActiveChanged: if (active) flickAnimation.stop()
|
||||
}
|
||||
}
|
||||
}
|
156
plugins/feature/vorlocalizer/map/map_6.qml
Normal file
156
plugins/feature/vorlocalizer/map/map_6.qml
Normal file
@ -0,0 +1,156 @@
|
||||
import QtQuick 2.14
|
||||
import QtQuick.Window 2.14
|
||||
import QtLocation 6.5
|
||||
import QtPositioning 6.5
|
||||
|
||||
Item {
|
||||
id: qmlMap
|
||||
property int vorZoomLevel: 11
|
||||
property string mapProvider: "osm"
|
||||
property variant mapPtr
|
||||
property string requestedMapType
|
||||
property variant guiPtr
|
||||
|
||||
function createMap(pluginParameters, requestedMap, gui) {
|
||||
requestedMapType = requestedMap
|
||||
guiPtr = gui
|
||||
|
||||
var paramString = ""
|
||||
for (var prop in pluginParameters) {
|
||||
var parameter = 'PluginParameter { name: "' + prop + '"; value: "' + pluginParameters[prop] + '"}'
|
||||
paramString = paramString + parameter
|
||||
}
|
||||
var pluginString = 'import QtLocation 6.5; Plugin{ name:"' + mapProvider + '"; ' + paramString + '}'
|
||||
var plugin = Qt.createQmlObject (pluginString, qmlMap)
|
||||
|
||||
if (mapPtr) {
|
||||
// Objects aren't destroyed immediately, so don't call findChild("map")
|
||||
mapPtr.destroy()
|
||||
mapPtr = null
|
||||
}
|
||||
mapPtr = actualMapComponent.createObject(page)
|
||||
mapPtr.map.plugin = plugin
|
||||
mapPtr.map.forceActiveFocus()
|
||||
return mapPtr
|
||||
}
|
||||
|
||||
Item {
|
||||
id: page
|
||||
anchors.fill: parent
|
||||
}
|
||||
|
||||
Component {
|
||||
id: actualMapComponent
|
||||
|
||||
ModifiedMapView {
|
||||
id: mapView
|
||||
objectName: "mapView"
|
||||
anchors.fill: parent
|
||||
map.center: QtPositioning.coordinate(51.5, 0.125) // London
|
||||
map.zoomLevel: 10
|
||||
map.objectName: "map"
|
||||
// not in 6
|
||||
//gesture.enabled: true
|
||||
//gesture.acceptedGestures: MapGestureArea.PinchGesture | MapGestureArea.PanGesture
|
||||
|
||||
MapItemView {
|
||||
model: vorModel
|
||||
delegate: vorRadialComponent
|
||||
parent: mapView.map
|
||||
}
|
||||
|
||||
MapStation {
|
||||
id: station
|
||||
objectName: "station"
|
||||
stationName: "Home"
|
||||
}
|
||||
|
||||
MapItemView {
|
||||
model: vorModel
|
||||
delegate: vorComponent
|
||||
parent: mapView.map
|
||||
}
|
||||
|
||||
map.onZoomLevelChanged: {
|
||||
if (map.zoomLevel > 11) {
|
||||
station.zoomLevel = map.zoomLevel
|
||||
vorZoomLevel = map.zoomLevel
|
||||
} else {
|
||||
station.zoomLevel = 11
|
||||
vorZoomLevel = 11
|
||||
}
|
||||
}
|
||||
|
||||
map.onSupportedMapTypesChanged : {
|
||||
for (var i = 0; i < map.supportedMapTypes.length; i++) {
|
||||
if (requestedMapType == map.supportedMapTypes[i].name) {
|
||||
map.activeMapType = map.supportedMapTypes[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: vorRadialComponent
|
||||
MapPolyline {
|
||||
line.width: 2
|
||||
line.color: 'gray'
|
||||
path: vorRadial
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: vorComponent
|
||||
MapQuickItem {
|
||||
id: vor
|
||||
anchorPoint.x: image.width/2
|
||||
anchorPoint.y: bubble.height/2
|
||||
coordinate: position
|
||||
zoomLevel: vorZoomLevel
|
||||
|
||||
sourceItem: Grid {
|
||||
columns: 1
|
||||
Grid {
|
||||
horizontalItemAlignment: Grid.AlignHCenter
|
||||
verticalItemAlignment: Grid.AlignVCenter
|
||||
columnSpacing: 5
|
||||
layer.enabled: true
|
||||
layer.smooth: true
|
||||
Image {
|
||||
id: image
|
||||
source: vorImage
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onDoubleClicked: (mouse) => {
|
||||
selected = !selected
|
||||
}
|
||||
}
|
||||
}
|
||||
Rectangle {
|
||||
id: bubble
|
||||
color: bubbleColour
|
||||
border.width: 1
|
||||
width: text.width + 5
|
||||
height: text.height + 5
|
||||
radius: 5
|
||||
Text {
|
||||
id: text
|
||||
anchors.centerIn: parent
|
||||
text: vorData
|
||||
}
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onDoubleClicked: (mouse) => {
|
||||
selected = !selected
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1041,6 +1041,11 @@ void VORLocalizerGUI::applyMapSettings()
|
||||
m_azEl.setLocation(stationLatitude, stationLongitude, stationAltitude);
|
||||
|
||||
QQuickItem *item = ui->map->rootObject();
|
||||
if (!item)
|
||||
{
|
||||
qCritical("VORLocalizerGUI::applyMapSettings: Map not found. Are all required Qt plugins installed?");
|
||||
return;
|
||||
}
|
||||
|
||||
QObject *object = item->findChild<QObject*>("map");
|
||||
QGeoCoordinate coords;
|
||||
@ -1146,7 +1151,11 @@ VORLocalizerGUI::VORLocalizerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISe
|
||||
ui->map->setAttribute(Qt::WA_AcceptTouchEvents, true);
|
||||
|
||||
ui->map->rootContext()->setContextProperty("vorModel", &m_vorModel);
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
|
||||
ui->map->setSource(QUrl(QStringLiteral("qrc:/demodvor/map/map.qml")));
|
||||
#else
|
||||
ui->map->setSource(QUrl(QStringLiteral("qrc:/demodvor/map/map_6.qml")));
|
||||
#endif
|
||||
|
||||
m_muteIcon.addPixmap(QPixmap("://sound_off.png"), QIcon::Normal, QIcon::On);
|
||||
m_muteIcon.addPixmap(QPixmap("://sound_on.png"), QIcon::Normal, QIcon::Off);
|
||||
|
@ -1,5 +1,5 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2020-2023 Jon Beniston, M7RCE <jon@beniston.com> //
|
||||
// Copyright (C) 2020-2024 Jon Beniston, M7RCE <jon@beniston.com> //
|
||||
// Copyright (C) 2020, 2022 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
@ -267,6 +267,23 @@ bool ChannelWebAPIUtils::getChannelSettings(unsigned int deviceIndex, unsigned i
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ChannelWebAPIUtils::getChannelSettings(ChannelAPI *channel, SWGSDRangel::SWGChannelSettings &channelSettingsResponse)
|
||||
{
|
||||
QString errorResponse;
|
||||
int httpRC;
|
||||
|
||||
httpRC = channel->webapiSettingsGet(channelSettingsResponse, errorResponse);
|
||||
|
||||
if (httpRC/100 != 2)
|
||||
{
|
||||
qWarning("ChannelWebAPIUtils::getChannelSettings: get channel settings error %d: %s",
|
||||
httpRC, qPrintable(errorResponse));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ChannelWebAPIUtils::getChannelReport(unsigned int deviceIndex, unsigned int channelIndex, SWGSDRangel::SWGChannelReport &channelReport)
|
||||
{
|
||||
QString errorResponse;
|
||||
@ -1485,22 +1502,19 @@ bool ChannelWebAPIUtils::patchFeatureSetting(unsigned int featureSetIndex, unsig
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool ChannelWebAPIUtils::patchChannelSetting(unsigned int deviceSetIndex, unsigned int channelIndex, const QString &setting, double value)
|
||||
bool ChannelWebAPIUtils::patchChannelSetting(ChannelAPI *channel, const QString &setting, const QVariant& value)
|
||||
{
|
||||
SWGSDRangel::SWGChannelSettings channelSettingsResponse;
|
||||
QString errorResponse;
|
||||
int httpRC;
|
||||
ChannelAPI *channel;
|
||||
|
||||
if (getChannelSettings(deviceSetIndex, channelIndex, channelSettingsResponse, channel))
|
||||
if (getChannelSettings(channel, channelSettingsResponse))
|
||||
{
|
||||
// Patch settings
|
||||
QJsonObject *jsonObj = channelSettingsResponse.asJsonObject();
|
||||
double oldValue;
|
||||
if (WebAPIUtils::getSubObjectDouble(*jsonObj, setting, oldValue))
|
||||
if (WebAPIUtils::hasSubObject(*jsonObj, setting))
|
||||
{
|
||||
WebAPIUtils::setSubObjectDouble(*jsonObj, setting, value);
|
||||
WebAPIUtils::setSubObject(*jsonObj, setting, value);
|
||||
QStringList channelSettingsKeys;
|
||||
channelSettingsKeys.append(setting);
|
||||
channelSettingsResponse.init();
|
||||
@ -1511,19 +1525,19 @@ bool ChannelWebAPIUtils::patchChannelSetting(unsigned int deviceSetIndex, unsign
|
||||
|
||||
if (httpRC/100 == 2)
|
||||
{
|
||||
qDebug("ChannelWebAPIUtils::patchChannelSetting: set feature setting %s to %f OK", qPrintable(setting), value);
|
||||
qDebug("ChannelWebAPIUtils::patchChannelSetting: set feature setting %s to %s OK", qPrintable(setting), qPrintable(value.toString()));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
qWarning("ChannelWebAPIUtils::patchChannelSetting: set feature setting %s to %f error %d: %s",
|
||||
qPrintable(setting), value, httpRC, qPrintable(*errorResponse2.getMessage()));
|
||||
qWarning("ChannelWebAPIUtils::patchChannelSetting: set feature setting %s to %s error %d: %s",
|
||||
qPrintable(setting), qPrintable(value.toString()), httpRC, qPrintable(*errorResponse2.getMessage()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
qWarning("ChannelWebAPIUtils::patchChannelSetting: no key %s in feature settings", qPrintable(setting));
|
||||
qWarning("ChannelWebAPIUtils::patchChannelSetting: no key %s in channel settings", qPrintable(setting));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -1533,6 +1547,39 @@ bool ChannelWebAPIUtils::patchChannelSetting(unsigned int deviceSetIndex, unsign
|
||||
}
|
||||
}
|
||||
|
||||
bool ChannelWebAPIUtils::patchChannelSetting(unsigned int deviceSetIndex, unsigned int channelIndex, const QString &setting, const QString& value)
|
||||
{
|
||||
ChannelAPI *channel = MainCore::instance()->getChannel(deviceSetIndex, channelIndex);
|
||||
|
||||
if (channel) {
|
||||
return patchChannelSetting(channel, setting, value);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ChannelWebAPIUtils::patchChannelSetting(unsigned int deviceSetIndex, unsigned int channelIndex, const QString &setting, int value)
|
||||
{
|
||||
ChannelAPI *channel = MainCore::instance()->getChannel(deviceSetIndex, channelIndex);
|
||||
|
||||
if (channel) {
|
||||
return patchChannelSetting(channel, setting, value);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ChannelWebAPIUtils::patchChannelSetting(unsigned int deviceSetIndex, unsigned int channelIndex, const QString &setting, double value)
|
||||
{
|
||||
ChannelAPI *channel = MainCore::instance()->getChannel(deviceSetIndex, channelIndex);
|
||||
|
||||
if (channel) {
|
||||
return patchChannelSetting(channel, setting, value);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ChannelWebAPIUtils::patchChannelSetting(unsigned int deviceSetIndex, unsigned int channelIndex, const QString &setting, const QJsonArray& value)
|
||||
{
|
||||
SWGSDRangel::SWGChannelSettings channelSettingsResponse;
|
||||
@ -1835,3 +1882,30 @@ bool ChannelWebAPIUtils::getChannelReportValue(unsigned int deviceIndex, unsigne
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ChannelWebAPIUtils::addChannel(unsigned int deviceSetIndex, const QString& uri, int direction)
|
||||
{
|
||||
MainCore *mainCore = MainCore::instance();
|
||||
PluginAPI::ChannelRegistrations *channelRegistrations = mainCore->getPluginManager()->getRxChannelRegistrations();
|
||||
int nbRegistrations = channelRegistrations->size();
|
||||
int index = 0;
|
||||
|
||||
for (; index < nbRegistrations; index++)
|
||||
{
|
||||
if (channelRegistrations->at(index).m_channelIdURI == uri) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (index < nbRegistrations)
|
||||
{
|
||||
MainCore::MsgAddChannel *msg = MainCore::MsgAddChannel::create(deviceSetIndex, index, direction);
|
||||
mainCore->getMainMessageQueue()->push(msg);
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
qWarning() << "ChannelWebAPIUtils::addChannel:" << uri << "plugin not available";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
|
||||
// written by Christian Daniel //
|
||||
// Copyright (C) 2015-2020 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
|
||||
// Copyright (C) 2020-2023 Jon Beniston, M7RCE <jon@beniston.com> //
|
||||
// Copyright (C) 2020-2024 Jon Beniston, M7RCE <jon@beniston.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 //
|
||||
@ -79,6 +79,9 @@ public:
|
||||
static bool patchFeatureSetting(unsigned int featureSetIndex, unsigned int featureIndex, const QString &setting, const QString &value);
|
||||
static bool patchFeatureSetting(unsigned int featureSetIndex, unsigned int featureIndex, const QString &setting, double value);
|
||||
static bool patchFeatureSetting(unsigned int featureSetIndex, unsigned int featureIndex, const QString &setting, const QJsonArray& value);
|
||||
static bool patchChannelSetting(ChannelAPI *channel, const QString &setting, const QVariant &value);
|
||||
static bool patchChannelSetting(unsigned int deviceSetIndex, unsigned int channeIndex, const QString &setting, const QString &value);
|
||||
static bool patchChannelSetting(unsigned int deviceSetIndex, unsigned int channeIndex, const QString &setting, int value);
|
||||
static bool patchChannelSetting(unsigned int deviceSetIndex, unsigned int channeIndex, const QString &setting, double value);
|
||||
static bool patchChannelSetting(unsigned int deviceSetIndex, unsigned int channeIndex, const QString &setting, const QJsonArray& value);
|
||||
static bool getFeatureSetting(unsigned int featureSetIndex, unsigned int featureIndex, const QString &setting, int &value);
|
||||
@ -98,7 +101,9 @@ public:
|
||||
static bool getFeatureSettings(unsigned int featureSetIndex, unsigned int featureIndex, SWGSDRangel::SWGFeatureSettings &featureSettingsResponse, Feature *&feature);
|
||||
static bool getFeatureReport(unsigned int featureSetIndex, unsigned int featureIndex, SWGSDRangel::SWGFeatureReport &featureReport);
|
||||
static bool getChannelSettings(unsigned int deviceIndex, unsigned int channelIndex, SWGSDRangel::SWGChannelSettings &channelSettingsResponse, ChannelAPI *&channel);
|
||||
static bool getChannelSettings(ChannelAPI *channel, SWGSDRangel::SWGChannelSettings &channelSettingsResponse);
|
||||
static bool getChannelReport(unsigned int deviceIndex, unsigned int channelIndex, SWGSDRangel::SWGChannelReport &channelReport);
|
||||
static bool addChannel(unsigned int deviceSetIndex, const QString& uri, int direction);
|
||||
protected:
|
||||
static QString getDeviceHardwareId(unsigned int deviceIndex);
|
||||
};
|
||||
|
@ -3819,6 +3819,15 @@ margin-bottom: 20px;
|
||||
"type" : "integer",
|
||||
"format" : "int64"
|
||||
},
|
||||
"frequencyMode" : {
|
||||
"type" : "integer",
|
||||
"description" : "(0 for Offset, 1 for Absolute)"
|
||||
},
|
||||
"frequency" : {
|
||||
"type" : "integer",
|
||||
"format" : "int64",
|
||||
"description" : "Channel center frequency"
|
||||
},
|
||||
"rfBandwidth" : {
|
||||
"type" : "number",
|
||||
"format" : "float"
|
||||
@ -12692,6 +12701,15 @@ margin-bottom: 20px;
|
||||
"format" : "int64",
|
||||
"description" : "channel center frequency shift from baseband center in Hz"
|
||||
},
|
||||
"frequencyMode" : {
|
||||
"type" : "integer",
|
||||
"description" : "(0 for Offset, 1 for Absolute)"
|
||||
},
|
||||
"frequency" : {
|
||||
"type" : "integer",
|
||||
"format" : "int64",
|
||||
"description" : "Channel center frequency"
|
||||
},
|
||||
"rfBandwidth" : {
|
||||
"type" : "number",
|
||||
"format" : "float",
|
||||
@ -12703,7 +12721,7 @@ margin-bottom: 20px;
|
||||
},
|
||||
"modulation" : {
|
||||
"type" : "integer",
|
||||
"description" : "0 - MSF, 1 - DCF77, 2 - TDF, 3 - WWVB"
|
||||
"description" : "0 - MSF, 1 - DCF77, 2 - TDF, 3 - WWVB, 4 - JJY"
|
||||
},
|
||||
"timezone" : {
|
||||
"type" : "integer",
|
||||
@ -58934,7 +58952,7 @@ except ApiException as e:
|
||||
</div>
|
||||
<div id="generator">
|
||||
<div class="content">
|
||||
Generated 2024-04-04T16:23:36.765+02:00
|
||||
Generated 2024-04-07T17:52:28.367+02:00
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -4,6 +4,13 @@ ChannelPowerSettings:
|
||||
inputFrequencyOffset:
|
||||
type: integer
|
||||
format: int64
|
||||
frequencyMode:
|
||||
description: (0 for Offset, 1 for Absolute)
|
||||
type: integer
|
||||
frequency:
|
||||
description: Channel center frequency
|
||||
type: integer
|
||||
format: int64
|
||||
rfBandwidth:
|
||||
type: number
|
||||
format: float
|
||||
|
@ -5,6 +5,13 @@ RadioClockSettings:
|
||||
description: channel center frequency shift from baseband center in Hz
|
||||
type: integer
|
||||
format: int64
|
||||
frequencyMode:
|
||||
description: (0 for Offset, 1 for Absolute)
|
||||
type: integer
|
||||
frequency:
|
||||
description: Channel center frequency
|
||||
type: integer
|
||||
format: int64
|
||||
rfBandwidth:
|
||||
description: channel RF bandwidth in Hz
|
||||
type: number
|
||||
@ -13,7 +20,7 @@ RadioClockSettings:
|
||||
type: number
|
||||
format: float
|
||||
modulation:
|
||||
description: 0 - MSF, 1 - DCF77, 2 - TDF, 3 - WWVB
|
||||
description: 0 - MSF, 1 - DCF77, 2 - TDF, 3 - WWVB, 4 - JJY
|
||||
type: integer
|
||||
timezone:
|
||||
description: 0 - Broadcast, 1 - Local, 2 - UTC
|
||||
|
@ -584,6 +584,54 @@ bool WebAPIUtils::getSubObjectIntList(const QJsonObject &json, const QString &ke
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WebAPIUtils::hasSubObject(const QJsonObject &json, const QString &key)
|
||||
{
|
||||
for (QJsonObject::const_iterator it = json.begin(); it != json.end(); it++)
|
||||
{
|
||||
QJsonValue jsonValue = it.value();
|
||||
|
||||
if (jsonValue.isObject())
|
||||
{
|
||||
QJsonObject subObject = jsonValue.toObject();
|
||||
|
||||
if (subObject.contains(key)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set value withing nested JSON object
|
||||
bool WebAPIUtils::setSubObject(QJsonObject &json, const QString &key, const QVariant &value)
|
||||
{
|
||||
for (QJsonObject::iterator it = json.begin(); it != json.end(); it++)
|
||||
{
|
||||
QJsonValue jsonValue = it.value();
|
||||
|
||||
if (jsonValue.isObject())
|
||||
{
|
||||
QJsonObject subObject = jsonValue.toObject();
|
||||
|
||||
if (subObject.contains(key))
|
||||
{
|
||||
if (subObject[key].isString()) {
|
||||
subObject[key] = value.toString();
|
||||
} else if (subObject[key].isDouble()) {
|
||||
subObject[key] = value.toDouble();
|
||||
} else {
|
||||
qDebug() << "WebAPIUtils::setSubObject: Unsupported type";
|
||||
}
|
||||
it.value() = subObject;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// look for value in key=value
|
||||
bool WebAPIUtils::extractValue(const QJsonObject &json, const QString &key, QJsonValue &value)
|
||||
{
|
||||
|
@ -54,6 +54,8 @@ public:
|
||||
static bool getSubObjectString(const QJsonObject &json, const QString &key, QString &value);
|
||||
static bool setSubObjectString(QJsonObject &json, const QString &key, const QString &value);
|
||||
static bool getSubObjectIntList(const QJsonObject &json, const QString &key, const QString &subKey, QList<int> &values);
|
||||
static bool setSubObject(QJsonObject &json, const QString &key, const QVariant &value);
|
||||
static bool hasSubObject(const QJsonObject &json, const QString &key);
|
||||
static bool extractValue(const QJsonObject &json, const QString &key, QJsonValue &value);
|
||||
static bool extractArray(const QJsonObject &json, const QString &key, QJsonArray &value);
|
||||
static bool extractObject(const QJsonObject &json, const QString &key, QJsonObject &value);
|
||||
|
@ -4,6 +4,13 @@ ChannelPowerSettings:
|
||||
inputFrequencyOffset:
|
||||
type: integer
|
||||
format: int64
|
||||
frequencyMode:
|
||||
description: (0 for Offset, 1 for Absolute)
|
||||
type: integer
|
||||
frequency:
|
||||
description: Channel center frequency
|
||||
type: integer
|
||||
format: int64
|
||||
rfBandwidth:
|
||||
type: number
|
||||
format: float
|
||||
|
@ -5,6 +5,13 @@ RadioClockSettings:
|
||||
description: channel center frequency shift from baseband center in Hz
|
||||
type: integer
|
||||
format: int64
|
||||
frequencyMode:
|
||||
description: (0 for Offset, 1 for Absolute)
|
||||
type: integer
|
||||
frequency:
|
||||
description: Channel center frequency
|
||||
type: integer
|
||||
format: int64
|
||||
rfBandwidth:
|
||||
description: channel RF bandwidth in Hz
|
||||
type: number
|
||||
@ -13,7 +20,7 @@ RadioClockSettings:
|
||||
type: number
|
||||
format: float
|
||||
modulation:
|
||||
description: 0 - MSF, 1 - DCF77, 2 - TDF, 3 - WWVB
|
||||
description: 0 - MSF, 1 - DCF77, 2 - TDF, 3 - WWVB, 4 - JJY
|
||||
type: integer
|
||||
timezone:
|
||||
description: 0 - Broadcast, 1 - Local, 2 - UTC
|
||||
|
@ -3819,6 +3819,15 @@ margin-bottom: 20px;
|
||||
"type" : "integer",
|
||||
"format" : "int64"
|
||||
},
|
||||
"frequencyMode" : {
|
||||
"type" : "integer",
|
||||
"description" : "(0 for Offset, 1 for Absolute)"
|
||||
},
|
||||
"frequency" : {
|
||||
"type" : "integer",
|
||||
"format" : "int64",
|
||||
"description" : "Channel center frequency"
|
||||
},
|
||||
"rfBandwidth" : {
|
||||
"type" : "number",
|
||||
"format" : "float"
|
||||
@ -12692,6 +12701,15 @@ margin-bottom: 20px;
|
||||
"format" : "int64",
|
||||
"description" : "channel center frequency shift from baseband center in Hz"
|
||||
},
|
||||
"frequencyMode" : {
|
||||
"type" : "integer",
|
||||
"description" : "(0 for Offset, 1 for Absolute)"
|
||||
},
|
||||
"frequency" : {
|
||||
"type" : "integer",
|
||||
"format" : "int64",
|
||||
"description" : "Channel center frequency"
|
||||
},
|
||||
"rfBandwidth" : {
|
||||
"type" : "number",
|
||||
"format" : "float",
|
||||
@ -12703,7 +12721,7 @@ margin-bottom: 20px;
|
||||
},
|
||||
"modulation" : {
|
||||
"type" : "integer",
|
||||
"description" : "0 - MSF, 1 - DCF77, 2 - TDF, 3 - WWVB"
|
||||
"description" : "0 - MSF, 1 - DCF77, 2 - TDF, 3 - WWVB, 4 - JJY"
|
||||
},
|
||||
"timezone" : {
|
||||
"type" : "integer",
|
||||
@ -58934,7 +58952,7 @@ except ApiException as e:
|
||||
</div>
|
||||
<div id="generator">
|
||||
<div class="content">
|
||||
Generated 2024-04-04T16:23:36.765+02:00
|
||||
Generated 2024-04-07T17:52:28.367+02:00
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -30,6 +30,10 @@ SWGChannelPowerSettings::SWGChannelPowerSettings(QString* json) {
|
||||
SWGChannelPowerSettings::SWGChannelPowerSettings() {
|
||||
input_frequency_offset = 0L;
|
||||
m_input_frequency_offset_isSet = false;
|
||||
frequency_mode = 0;
|
||||
m_frequency_mode_isSet = false;
|
||||
frequency = 0L;
|
||||
m_frequency_isSet = false;
|
||||
rf_bandwidth = 0.0f;
|
||||
m_rf_bandwidth_isSet = false;
|
||||
pulse_threshold = 0.0f;
|
||||
@ -66,6 +70,10 @@ void
|
||||
SWGChannelPowerSettings::init() {
|
||||
input_frequency_offset = 0L;
|
||||
m_input_frequency_offset_isSet = false;
|
||||
frequency_mode = 0;
|
||||
m_frequency_mode_isSet = false;
|
||||
frequency = 0L;
|
||||
m_frequency_isSet = false;
|
||||
rf_bandwidth = 0.0f;
|
||||
m_rf_bandwidth_isSet = false;
|
||||
pulse_threshold = 0.0f;
|
||||
@ -101,6 +109,8 @@ SWGChannelPowerSettings::cleanup() {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if(title != nullptr) {
|
||||
delete title;
|
||||
}
|
||||
@ -133,6 +143,10 @@ void
|
||||
SWGChannelPowerSettings::fromJsonObject(QJsonObject &pJson) {
|
||||
::SWGSDRangel::setValue(&input_frequency_offset, pJson["inputFrequencyOffset"], "qint64", "");
|
||||
|
||||
::SWGSDRangel::setValue(&frequency_mode, pJson["frequencyMode"], "qint32", "");
|
||||
|
||||
::SWGSDRangel::setValue(&frequency, pJson["frequency"], "qint64", "");
|
||||
|
||||
::SWGSDRangel::setValue(&rf_bandwidth, pJson["rfBandwidth"], "float", "");
|
||||
|
||||
::SWGSDRangel::setValue(&pulse_threshold, pJson["pulseThreshold"], "float", "");
|
||||
@ -178,6 +192,12 @@ SWGChannelPowerSettings::asJsonObject() {
|
||||
if(m_input_frequency_offset_isSet){
|
||||
obj->insert("inputFrequencyOffset", QJsonValue(input_frequency_offset));
|
||||
}
|
||||
if(m_frequency_mode_isSet){
|
||||
obj->insert("frequencyMode", QJsonValue(frequency_mode));
|
||||
}
|
||||
if(m_frequency_isSet){
|
||||
obj->insert("frequency", QJsonValue(frequency));
|
||||
}
|
||||
if(m_rf_bandwidth_isSet){
|
||||
obj->insert("rfBandwidth", QJsonValue(rf_bandwidth));
|
||||
}
|
||||
@ -231,6 +251,26 @@ SWGChannelPowerSettings::setInputFrequencyOffset(qint64 input_frequency_offset)
|
||||
this->m_input_frequency_offset_isSet = true;
|
||||
}
|
||||
|
||||
qint32
|
||||
SWGChannelPowerSettings::getFrequencyMode() {
|
||||
return frequency_mode;
|
||||
}
|
||||
void
|
||||
SWGChannelPowerSettings::setFrequencyMode(qint32 frequency_mode) {
|
||||
this->frequency_mode = frequency_mode;
|
||||
this->m_frequency_mode_isSet = true;
|
||||
}
|
||||
|
||||
qint64
|
||||
SWGChannelPowerSettings::getFrequency() {
|
||||
return frequency;
|
||||
}
|
||||
void
|
||||
SWGChannelPowerSettings::setFrequency(qint64 frequency) {
|
||||
this->frequency = frequency;
|
||||
this->m_frequency_isSet = true;
|
||||
}
|
||||
|
||||
float
|
||||
SWGChannelPowerSettings::getRfBandwidth() {
|
||||
return rf_bandwidth;
|
||||
@ -369,6 +409,12 @@ SWGChannelPowerSettings::isSet(){
|
||||
if(m_input_frequency_offset_isSet){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(m_frequency_mode_isSet){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(m_frequency_isSet){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(m_rf_bandwidth_isSet){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
|
@ -47,6 +47,12 @@ public:
|
||||
qint64 getInputFrequencyOffset();
|
||||
void setInputFrequencyOffset(qint64 input_frequency_offset);
|
||||
|
||||
qint32 getFrequencyMode();
|
||||
void setFrequencyMode(qint32 frequency_mode);
|
||||
|
||||
qint64 getFrequency();
|
||||
void setFrequency(qint64 frequency);
|
||||
|
||||
float getRfBandwidth();
|
||||
void setRfBandwidth(float rf_bandwidth);
|
||||
|
||||
@ -93,6 +99,12 @@ private:
|
||||
qint64 input_frequency_offset;
|
||||
bool m_input_frequency_offset_isSet;
|
||||
|
||||
qint32 frequency_mode;
|
||||
bool m_frequency_mode_isSet;
|
||||
|
||||
qint64 frequency;
|
||||
bool m_frequency_isSet;
|
||||
|
||||
float rf_bandwidth;
|
||||
bool m_rf_bandwidth_isSet;
|
||||
|
||||
|
@ -30,6 +30,10 @@ SWGRadioClockSettings::SWGRadioClockSettings(QString* json) {
|
||||
SWGRadioClockSettings::SWGRadioClockSettings() {
|
||||
input_frequency_offset = 0L;
|
||||
m_input_frequency_offset_isSet = false;
|
||||
frequency_mode = 0;
|
||||
m_frequency_mode_isSet = false;
|
||||
frequency = 0L;
|
||||
m_frequency_isSet = false;
|
||||
rf_bandwidth = 0.0f;
|
||||
m_rf_bandwidth_isSet = false;
|
||||
threshold = 0.0f;
|
||||
@ -70,6 +74,10 @@ void
|
||||
SWGRadioClockSettings::init() {
|
||||
input_frequency_offset = 0L;
|
||||
m_input_frequency_offset_isSet = false;
|
||||
frequency_mode = 0;
|
||||
m_frequency_mode_isSet = false;
|
||||
frequency = 0L;
|
||||
m_frequency_isSet = false;
|
||||
rf_bandwidth = 0.0f;
|
||||
m_rf_bandwidth_isSet = false;
|
||||
threshold = 0.0f;
|
||||
@ -110,6 +118,8 @@ SWGRadioClockSettings::cleanup() {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if(title != nullptr) {
|
||||
delete title;
|
||||
}
|
||||
@ -145,6 +155,10 @@ void
|
||||
SWGRadioClockSettings::fromJsonObject(QJsonObject &pJson) {
|
||||
::SWGSDRangel::setValue(&input_frequency_offset, pJson["inputFrequencyOffset"], "qint64", "");
|
||||
|
||||
::SWGSDRangel::setValue(&frequency_mode, pJson["frequencyMode"], "qint32", "");
|
||||
|
||||
::SWGSDRangel::setValue(&frequency, pJson["frequency"], "qint64", "");
|
||||
|
||||
::SWGSDRangel::setValue(&rf_bandwidth, pJson["rfBandwidth"], "float", "");
|
||||
|
||||
::SWGSDRangel::setValue(&threshold, pJson["threshold"], "float", "");
|
||||
@ -194,6 +208,12 @@ SWGRadioClockSettings::asJsonObject() {
|
||||
if(m_input_frequency_offset_isSet){
|
||||
obj->insert("inputFrequencyOffset", QJsonValue(input_frequency_offset));
|
||||
}
|
||||
if(m_frequency_mode_isSet){
|
||||
obj->insert("frequencyMode", QJsonValue(frequency_mode));
|
||||
}
|
||||
if(m_frequency_isSet){
|
||||
obj->insert("frequency", QJsonValue(frequency));
|
||||
}
|
||||
if(m_rf_bandwidth_isSet){
|
||||
obj->insert("rfBandwidth", QJsonValue(rf_bandwidth));
|
||||
}
|
||||
@ -253,6 +273,26 @@ SWGRadioClockSettings::setInputFrequencyOffset(qint64 input_frequency_offset) {
|
||||
this->m_input_frequency_offset_isSet = true;
|
||||
}
|
||||
|
||||
qint32
|
||||
SWGRadioClockSettings::getFrequencyMode() {
|
||||
return frequency_mode;
|
||||
}
|
||||
void
|
||||
SWGRadioClockSettings::setFrequencyMode(qint32 frequency_mode) {
|
||||
this->frequency_mode = frequency_mode;
|
||||
this->m_frequency_mode_isSet = true;
|
||||
}
|
||||
|
||||
qint64
|
||||
SWGRadioClockSettings::getFrequency() {
|
||||
return frequency;
|
||||
}
|
||||
void
|
||||
SWGRadioClockSettings::setFrequency(qint64 frequency) {
|
||||
this->frequency = frequency;
|
||||
this->m_frequency_isSet = true;
|
||||
}
|
||||
|
||||
float
|
||||
SWGRadioClockSettings::getRfBandwidth() {
|
||||
return rf_bandwidth;
|
||||
@ -411,6 +451,12 @@ SWGRadioClockSettings::isSet(){
|
||||
if(m_input_frequency_offset_isSet){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(m_frequency_mode_isSet){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(m_frequency_isSet){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(m_rf_bandwidth_isSet){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
|
@ -48,6 +48,12 @@ public:
|
||||
qint64 getInputFrequencyOffset();
|
||||
void setInputFrequencyOffset(qint64 input_frequency_offset);
|
||||
|
||||
qint32 getFrequencyMode();
|
||||
void setFrequencyMode(qint32 frequency_mode);
|
||||
|
||||
qint64 getFrequency();
|
||||
void setFrequency(qint64 frequency);
|
||||
|
||||
float getRfBandwidth();
|
||||
void setRfBandwidth(float rf_bandwidth);
|
||||
|
||||
@ -100,6 +106,12 @@ private:
|
||||
qint64 input_frequency_offset;
|
||||
bool m_input_frequency_offset_isSet;
|
||||
|
||||
qint32 frequency_mode;
|
||||
bool m_frequency_mode_isSet;
|
||||
|
||||
qint64 frequency;
|
||||
bool m_frequency_isSet;
|
||||
|
||||
float rf_bandwidth;
|
||||
bool m_rf_bandwidth_isSet;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user