mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-12-23 01:55:48 -05:00
Add pager notifications.
Add option to ignore duplicates. Support plotting pager messages on the map.
This commit is contained in:
parent
f24600b909
commit
4455ac0c55
@ -29,16 +29,25 @@ if(NOT SERVER_MODE)
|
|||||||
pagerdemodgui.ui
|
pagerdemodgui.ui
|
||||||
pagerdemodcharsetdialog.cpp
|
pagerdemodcharsetdialog.cpp
|
||||||
pagerdemodcharsetdialog.ui
|
pagerdemodcharsetdialog.ui
|
||||||
|
pagerdemodnotificationdialog.cpp
|
||||||
|
pagerdemodnotificationdialog.ui
|
||||||
|
pagerdemodfilterdialog.cpp
|
||||||
|
pagerdemodfilterdialog.ui
|
||||||
|
pagerdemodicons.qrc
|
||||||
)
|
)
|
||||||
set(demodpager_HEADERS
|
set(demodpager_HEADERS
|
||||||
${demodpager_HEADERS}
|
${demodpager_HEADERS}
|
||||||
pagerdemodgui.h
|
pagerdemodgui.h
|
||||||
pagerdemodcharsetdialog.h
|
pagerdemodcharsetdialog.h
|
||||||
|
pagerdemodnotificationdialog.h
|
||||||
)
|
)
|
||||||
|
|
||||||
set(TARGET_NAME ${PLUGINS_PREFIX}demodpager)
|
set(TARGET_NAME ${PLUGINS_PREFIX}demodpager)
|
||||||
set(TARGET_LIB "Qt::Widgets")
|
set(TARGET_LIB "Qt::Widgets")
|
||||||
set(TARGET_LIB_GUI "sdrgui")
|
set(TARGET_LIB_GUI "sdrgui")
|
||||||
|
if(Qt${QT_DEFAULT_MAJOR_VERSION}TextToSpeech_FOUND)
|
||||||
|
list(APPEND TARGET_LIB_GUI Qt::TextToSpeech)
|
||||||
|
endif()
|
||||||
set(INSTALL_FOLDER ${INSTALL_PLUGINS_DIR})
|
set(INSTALL_FOLDER ${INSTALL_PLUGINS_DIR})
|
||||||
else()
|
else()
|
||||||
set(TARGET_NAME ${PLUGINSSRV_PREFIX}demodpagersrv)
|
set(TARGET_NAME ${PLUGINSSRV_PREFIX}demodpagersrv)
|
||||||
|
BIN
plugins/channelrx/demodpager/icons/filterduplicate.png
Normal file
BIN
plugins/channelrx/demodpager/icons/filterduplicate.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.2 KiB |
@ -31,6 +31,7 @@
|
|||||||
#include "dsp/dspcommands.h"
|
#include "dsp/dspcommands.h"
|
||||||
#include "device/deviceapi.h"
|
#include "device/deviceapi.h"
|
||||||
#include "util/db.h"
|
#include "util/db.h"
|
||||||
|
#include "util/csv.h"
|
||||||
#include "maincore.h"
|
#include "maincore.h"
|
||||||
|
|
||||||
MESSAGE_CLASS_DEFINITION(PagerDemod::MsgConfigurePagerDemod, Message)
|
MESSAGE_CLASS_DEFINITION(PagerDemod::MsgConfigurePagerDemod, Message)
|
||||||
@ -141,7 +142,7 @@ bool PagerDemod::handleMessage(const Message& cmd)
|
|||||||
{
|
{
|
||||||
if (MsgConfigurePagerDemod::match(cmd))
|
if (MsgConfigurePagerDemod::match(cmd))
|
||||||
{
|
{
|
||||||
MsgConfigurePagerDemod& cfg = (MsgConfigurePagerDemod&) cmd;
|
const MsgConfigurePagerDemod& cfg = (const MsgConfigurePagerDemod&) cmd;
|
||||||
qDebug() << "PagerDemod::handleMessage: MsgConfigurePagerDemod";
|
qDebug() << "PagerDemod::handleMessage: MsgConfigurePagerDemod";
|
||||||
applySettings(cfg.getSettings(), cfg.getForce());
|
applySettings(cfg.getSettings(), cfg.getForce());
|
||||||
|
|
||||||
@ -149,7 +150,7 @@ bool PagerDemod::handleMessage(const Message& cmd)
|
|||||||
}
|
}
|
||||||
else if (DSPSignalNotification::match(cmd))
|
else if (DSPSignalNotification::match(cmd))
|
||||||
{
|
{
|
||||||
DSPSignalNotification& notif = (DSPSignalNotification&) cmd;
|
const DSPSignalNotification& notif = (const DSPSignalNotification&) cmd;
|
||||||
m_basebandSampleRate = notif.getSampleRate();
|
m_basebandSampleRate = notif.getSampleRate();
|
||||||
m_centerFrequency = notif.getCenterFrequency();
|
m_centerFrequency = notif.getCenterFrequency();
|
||||||
// Forward to the sink
|
// Forward to the sink
|
||||||
@ -166,7 +167,7 @@ bool PagerDemod::handleMessage(const Message& cmd)
|
|||||||
else if (MsgPagerMessage::match(cmd))
|
else if (MsgPagerMessage::match(cmd))
|
||||||
{
|
{
|
||||||
// Forward to GUI
|
// Forward to GUI
|
||||||
MsgPagerMessage& report = (MsgPagerMessage&)cmd;
|
const MsgPagerMessage& report = (const MsgPagerMessage&)cmd;
|
||||||
if (getMessageQueueToGUI())
|
if (getMessageQueueToGUI())
|
||||||
{
|
{
|
||||||
MsgPagerMessage *msg = new MsgPagerMessage(report);
|
MsgPagerMessage *msg = new MsgPagerMessage(report);
|
||||||
@ -200,7 +201,7 @@ bool PagerDemod::handleMessage(const Message& cmd)
|
|||||||
<< report.getDateTime().time().toString() << ","
|
<< report.getDateTime().time().toString() << ","
|
||||||
<< QString("%1").arg(report.getAddress(), 7, 10, QChar('0')) << ","
|
<< QString("%1").arg(report.getAddress(), 7, 10, QChar('0')) << ","
|
||||||
<< QString::number(report.getFunctionBits()) << ","
|
<< QString::number(report.getFunctionBits()) << ","
|
||||||
<< "\"" << report.getAlphaMessage() << "\","
|
<< CSV::escape(report.getAlphaMessage()) << ","
|
||||||
<< report.getNumericMessage() << ","
|
<< report.getNumericMessage() << ","
|
||||||
<< QString::number(report.getEvenParityErrors()) << ","
|
<< QString::number(report.getEvenParityErrors()) << ","
|
||||||
<< QString::number(report.getBCHParityErrors()) << "\n";
|
<< QString::number(report.getBCHParityErrors()) << "\n";
|
||||||
|
@ -131,7 +131,7 @@ bool PagerDemodBaseband::handleMessage(const Message& cmd)
|
|||||||
if (MsgConfigurePagerDemodBaseband::match(cmd))
|
if (MsgConfigurePagerDemodBaseband::match(cmd))
|
||||||
{
|
{
|
||||||
QMutexLocker mutexLocker(&m_mutex);
|
QMutexLocker mutexLocker(&m_mutex);
|
||||||
MsgConfigurePagerDemodBaseband& cfg = (MsgConfigurePagerDemodBaseband&) cmd;
|
const MsgConfigurePagerDemodBaseband& cfg = (const MsgConfigurePagerDemodBaseband&) cmd;
|
||||||
qDebug() << "PagerDemodBaseband::handleMessage: MsgConfigurePagerDemodBaseband";
|
qDebug() << "PagerDemodBaseband::handleMessage: MsgConfigurePagerDemodBaseband";
|
||||||
|
|
||||||
applySettings(cfg.getSettings(), cfg.getForce());
|
applySettings(cfg.getSettings(), cfg.getForce());
|
||||||
@ -141,7 +141,7 @@ bool PagerDemodBaseband::handleMessage(const Message& cmd)
|
|||||||
else if (DSPSignalNotification::match(cmd))
|
else if (DSPSignalNotification::match(cmd))
|
||||||
{
|
{
|
||||||
QMutexLocker mutexLocker(&m_mutex);
|
QMutexLocker mutexLocker(&m_mutex);
|
||||||
DSPSignalNotification& notif = (DSPSignalNotification&) cmd;
|
const DSPSignalNotification& notif = (const DSPSignalNotification&) cmd;
|
||||||
qDebug() << "PagerDemodBaseband::handleMessage: DSPSignalNotification: basebandSampleRate: " << notif.getSampleRate();
|
qDebug() << "PagerDemodBaseband::handleMessage: DSPSignalNotification: basebandSampleRate: " << notif.getSampleRate();
|
||||||
setBasebandSampleRate(notif.getSampleRate());
|
setBasebandSampleRate(notif.getSampleRate());
|
||||||
m_sampleFifo.setSize(SampleSinkFifo::getSizePolicy(notif.getSampleRate()));
|
m_sampleFifo.setSize(SampleSinkFifo::getSizePolicy(notif.getSampleRate()));
|
||||||
|
46
plugins/channelrx/demodpager/pagerdemodfilterdialog.cpp
Normal file
46
plugins/channelrx/demodpager/pagerdemodfilterdialog.cpp
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright (C) 2021 Jon Beniston, M7RCE //
|
||||||
|
// //
|
||||||
|
// This program is free software; you can redistribute it and/or modify //
|
||||||
|
// it under the terms of the GNU General Public License as published by //
|
||||||
|
// the Free Software Foundation as version 3 of the License, or //
|
||||||
|
// (at your option) any later version. //
|
||||||
|
// //
|
||||||
|
// This program is distributed in the hope that it will be useful, //
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||||
|
// GNU General Public License V3 for more details. //
|
||||||
|
// //
|
||||||
|
// You should have received a copy of the GNU General Public License //
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QCheckBox>
|
||||||
|
|
||||||
|
#include "pagerdemodfilterdialog.h"
|
||||||
|
|
||||||
|
PagerDemodFilterDialog::PagerDemodFilterDialog(PagerDemodSettings *settings,
|
||||||
|
QWidget* parent) :
|
||||||
|
QDialog(parent),
|
||||||
|
ui(new Ui::PagerDemodFilterDialog),
|
||||||
|
m_settings(settings)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
ui->matchLastOnly->setChecked(m_settings->m_duplicateMatchLastOnly);
|
||||||
|
ui->matchMessageOnly->setChecked(m_settings->m_duplicateMatchMessageOnly);
|
||||||
|
}
|
||||||
|
|
||||||
|
PagerDemodFilterDialog::~PagerDemodFilterDialog()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PagerDemodFilterDialog::accept()
|
||||||
|
{
|
||||||
|
m_settings->m_duplicateMatchLastOnly = ui->matchLastOnly->isChecked();
|
||||||
|
m_settings->m_duplicateMatchMessageOnly = ui->matchMessageOnly->isChecked();
|
||||||
|
|
||||||
|
QDialog::accept();
|
||||||
|
}
|
41
plugins/channelrx/demodpager/pagerdemodfilterdialog.h
Normal file
41
plugins/channelrx/demodpager/pagerdemodfilterdialog.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright (C) 2021 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_PAGERDEMODFILTERDIALOG_H
|
||||||
|
#define INCLUDE_PAGERDEMODFILTERDIALOG_H
|
||||||
|
|
||||||
|
|
||||||
|
#include "ui_pagerdemodfilterdialog.h"
|
||||||
|
#include "pagerdemodsettings.h"
|
||||||
|
|
||||||
|
|
||||||
|
class PagerDemodFilterDialog : public QDialog {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit PagerDemodFilterDialog(PagerDemodSettings* settings, QWidget* parent = 0);
|
||||||
|
~PagerDemodFilterDialog();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void accept() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::PagerDemodFilterDialog* ui;
|
||||||
|
PagerDemodSettings *m_settings;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // INCLUDE_PAGERDEMODFILTERDIALOG_H
|
118
plugins/channelrx/demodpager/pagerdemodfilterdialog.ui
Normal file
118
plugins/channelrx/demodpager/pagerdemodfilterdialog.ui
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>PagerDemodFilterDialog</class>
|
||||||
|
<widget class="QDialog" name="PagerDemodFilterDialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>396</width>
|
||||||
|
<height>167</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Liberation Sans</family>
|
||||||
|
<pointsize>9</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="contextMenuPolicy">
|
||||||
|
<enum>Qt::ContextMenuPolicy::PreventContextMenu</enum>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Duplicate Filtering</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Duplicate Filtering</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QFormLayout" name="formLayout">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="matchMessageOnlyLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Match message only</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QCheckBox" name="matchMessageOnly">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Whether both the address and message must match or only the message to be considered a duplicate</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="matchLastOnlyLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Match last message only</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QCheckBox" name="matchLastOnly">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Whether to match with only the last message or any message in the table</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Orientation::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources>
|
||||||
|
<include location="../../../sdrgui/resources/res.qrc"/>
|
||||||
|
</resources>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>PagerDemodFilterDialog</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>248</x>
|
||||||
|
<y>254</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>157</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>rejected()</signal>
|
||||||
|
<receiver>PagerDemodFilterDialog</receiver>
|
||||||
|
<slot>reject()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>316</x>
|
||||||
|
<y>260</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>286</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
@ -16,8 +16,6 @@
|
|||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||||
///////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#include <limits>
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <QDockWidget>
|
#include <QDockWidget>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
@ -26,6 +24,7 @@
|
|||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QScrollBar>
|
#include <QScrollBar>
|
||||||
|
#include <QProcess>
|
||||||
|
|
||||||
#include "pagerdemodgui.h"
|
#include "pagerdemodgui.h"
|
||||||
|
|
||||||
@ -36,6 +35,8 @@
|
|||||||
#include "plugin/pluginapi.h"
|
#include "plugin/pluginapi.h"
|
||||||
#include "util/db.h"
|
#include "util/db.h"
|
||||||
#include "util/csv.h"
|
#include "util/csv.h"
|
||||||
|
#include "util/units.h"
|
||||||
|
#include "gui/crightclickenabler.h"
|
||||||
#include "gui/basicchannelsettingsdialog.h"
|
#include "gui/basicchannelsettingsdialog.h"
|
||||||
#include "dsp/dspengine.h"
|
#include "dsp/dspengine.h"
|
||||||
#include "gui/dialogpositioner.h"
|
#include "gui/dialogpositioner.h"
|
||||||
@ -43,6 +44,10 @@
|
|||||||
|
|
||||||
#include "pagerdemod.h"
|
#include "pagerdemod.h"
|
||||||
#include "pagerdemodcharsetdialog.h"
|
#include "pagerdemodcharsetdialog.h"
|
||||||
|
#include "pagerdemodnotificationdialog.h"
|
||||||
|
#include "pagerdemodfilterdialog.h"
|
||||||
|
|
||||||
|
#include "SWGMapItem.h"
|
||||||
|
|
||||||
void PagerDemodGUI::resizeTable()
|
void PagerDemodGUI::resizeTable()
|
||||||
{
|
{
|
||||||
@ -50,7 +55,7 @@ void PagerDemodGUI::resizeTable()
|
|||||||
// Trailing spaces are for sort arrow
|
// Trailing spaces are for sort arrow
|
||||||
int row = ui->messages->rowCount();
|
int row = ui->messages->rowCount();
|
||||||
ui->messages->setRowCount(row + 1);
|
ui->messages->setRowCount(row + 1);
|
||||||
ui->messages->setItem(row, MESSAGE_COL_DATE, new QTableWidgetItem("Fri Apr 15 2016-"));
|
ui->messages->setItem(row, MESSAGE_COL_DATE, new QTableWidgetItem("Fri Apr 15 2016--"));
|
||||||
ui->messages->setItem(row, MESSAGE_COL_TIME, new QTableWidgetItem("10:17:00"));
|
ui->messages->setItem(row, MESSAGE_COL_TIME, new QTableWidgetItem("10:17:00"));
|
||||||
ui->messages->setItem(row, MESSAGE_COL_ADDRESS, new QTableWidgetItem("1000000"));
|
ui->messages->setItem(row, MESSAGE_COL_ADDRESS, new QTableWidgetItem("1000000"));
|
||||||
ui->messages->setItem(row, MESSAGE_COL_MESSAGE, new QTableWidgetItem("ABCEDGHIJKLMNOPQRSTUVWXYZABCEDGHIJKLMNOPQRSTUVWXYZ"));
|
ui->messages->setItem(row, MESSAGE_COL_MESSAGE, new QTableWidgetItem("ABCEDGHIJKLMNOPQRSTUVWXYZABCEDGHIJKLMNOPQRSTUVWXYZ"));
|
||||||
@ -144,11 +149,101 @@ bool PagerDemodGUI::deserialize(const QByteArray& data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString PagerDemodGUI::selectMessage(int functionBits, const QString &numericMessage, const QString &alphaMessage) const
|
||||||
|
{
|
||||||
|
QString message;
|
||||||
|
|
||||||
|
// Standard way of choosing numeric or alpha decode isn't followed widely
|
||||||
|
if (m_settings.m_decode == PagerDemodSettings::Standard)
|
||||||
|
{
|
||||||
|
// Encoding is based on function bits
|
||||||
|
if (functionBits == 0) {
|
||||||
|
message = numericMessage;
|
||||||
|
} else {
|
||||||
|
message = alphaMessage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (m_settings.m_decode == PagerDemodSettings::Inverted)
|
||||||
|
{
|
||||||
|
// Encoding is based on function bits, but inverted from standard
|
||||||
|
if (functionBits == 3) {
|
||||||
|
message = numericMessage;
|
||||||
|
} else {
|
||||||
|
message = alphaMessage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (m_settings.m_decode == PagerDemodSettings::Numeric)
|
||||||
|
{
|
||||||
|
// Always display as numeric
|
||||||
|
message = numericMessage;
|
||||||
|
}
|
||||||
|
else if (m_settings.m_decode == PagerDemodSettings::Alphanumeric)
|
||||||
|
{
|
||||||
|
// Always display as alphanumeric
|
||||||
|
message = alphaMessage;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Guess at what the encoding is
|
||||||
|
QString numeric = numericMessage;
|
||||||
|
QString alpha = alphaMessage;
|
||||||
|
bool done = false;
|
||||||
|
if (!done)
|
||||||
|
{
|
||||||
|
// If alpha contains control characters, possibly numeric
|
||||||
|
for (int i = 0; i < alpha.size(); i++)
|
||||||
|
{
|
||||||
|
if (iscntrl(alpha[i].toLatin1()) && !isspace(alpha[i].toLatin1()))
|
||||||
|
{
|
||||||
|
message = numeric;
|
||||||
|
done = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!done) {
|
||||||
|
// Possibly not likely to get only longer than 15 digits
|
||||||
|
if (numeric.size() > 15)
|
||||||
|
{
|
||||||
|
done = true;
|
||||||
|
message = alpha;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!done) {
|
||||||
|
// Default to alpha
|
||||||
|
message = alpha;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return message;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// Add row to table
|
// Add row to table
|
||||||
void PagerDemodGUI::messageReceived(const QDateTime dateTime, int address, int functionBits,
|
void PagerDemodGUI::messageReceived(const QDateTime dateTime, int address, int functionBits,
|
||||||
const QString &numericMessage, const QString &alphaMessage,
|
const QString &numericMessage, const QString &alphaMessage,
|
||||||
int evenParityErrors, int bchParityErrors)
|
int evenParityErrors, int bchParityErrors)
|
||||||
{
|
{
|
||||||
|
QString message = selectMessage(functionBits, numericMessage, alphaMessage);
|
||||||
|
QString addressString = QString("%1").arg(address, 7, 10, QChar('0'));
|
||||||
|
|
||||||
|
// Should we ignore the message if it is a duplicate?
|
||||||
|
if (m_settings.m_filterDuplicates && (ui->messages->rowCount() > 0))
|
||||||
|
{
|
||||||
|
int startRow = m_settings.m_duplicateMatchLastOnly ? ui->messages->rowCount() - 1 : 0;
|
||||||
|
for (int row = startRow; row < ui->messages->rowCount(); row++)
|
||||||
|
{
|
||||||
|
QString prevAddress = ui->messages->item(row, MESSAGE_COL_ADDRESS)->text();
|
||||||
|
QString prevMessage = ui->messages->item(row, MESSAGE_COL_MESSAGE)->text();
|
||||||
|
|
||||||
|
if ((message == prevMessage) && (m_settings.m_duplicateMatchMessageOnly || (addressString == prevAddress)))
|
||||||
|
{
|
||||||
|
// Ignore this message
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Is scroll bar at bottom
|
// Is scroll bar at bottom
|
||||||
QScrollBar *sb = ui->messages->verticalScrollBar();
|
QScrollBar *sb = ui->messages->verticalScrollBar();
|
||||||
bool scrollToBottom = sb->value() == sb->maximum();
|
bool scrollToBottom = sb->value() == sb->maximum();
|
||||||
@ -178,68 +273,8 @@ void PagerDemodGUI::messageReceived(const QDateTime dateTime, int address, int f
|
|||||||
ui->messages->setItem(row, MESSAGE_COL_BCH_PE, bchPEItem);
|
ui->messages->setItem(row, MESSAGE_COL_BCH_PE, bchPEItem);
|
||||||
dateItem->setText(dateTime.date().toString());
|
dateItem->setText(dateTime.date().toString());
|
||||||
timeItem->setText(dateTime.time().toString());
|
timeItem->setText(dateTime.time().toString());
|
||||||
addressItem->setText(QString("%1").arg(address, 7, 10, QChar('0')));
|
addressItem->setText(addressString);
|
||||||
// Standard way of choosing numeric or alpha decode isn't followed widely
|
messageItem->setText(message);
|
||||||
if (m_settings.m_decode == PagerDemodSettings::Standard)
|
|
||||||
{
|
|
||||||
// Encoding is based on function bits
|
|
||||||
if (functionBits == 0) {
|
|
||||||
messageItem->setText(numericMessage);
|
|
||||||
} else {
|
|
||||||
messageItem->setText(alphaMessage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (m_settings.m_decode == PagerDemodSettings::Inverted)
|
|
||||||
{
|
|
||||||
// Encoding is based on function bits, but inverted from standard
|
|
||||||
if (functionBits == 3) {
|
|
||||||
messageItem->setText(numericMessage);
|
|
||||||
} else {
|
|
||||||
messageItem->setText(alphaMessage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (m_settings.m_decode == PagerDemodSettings::Numeric)
|
|
||||||
{
|
|
||||||
// Always display as numeric
|
|
||||||
messageItem->setText(numericMessage);
|
|
||||||
}
|
|
||||||
else if (m_settings.m_decode == PagerDemodSettings::Alphanumeric)
|
|
||||||
{
|
|
||||||
// Always display as alphanumeric
|
|
||||||
messageItem->setText(alphaMessage);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Guess at what the encoding is
|
|
||||||
QString numeric = numericMessage;
|
|
||||||
QString alpha = alphaMessage;
|
|
||||||
bool done = false;
|
|
||||||
if (!done)
|
|
||||||
{
|
|
||||||
// If alpha contains control characters, possibly numeric
|
|
||||||
for (int i = 0; i < alpha.size(); i++)
|
|
||||||
{
|
|
||||||
if (iscntrl(alpha[i].toLatin1()) && !isspace(alpha[i].toLatin1()))
|
|
||||||
{
|
|
||||||
messageItem->setText(numeric);
|
|
||||||
done = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!done) {
|
|
||||||
// Possibly not likely to get only longer than 15 digits
|
|
||||||
if (numeric.size() > 15)
|
|
||||||
{
|
|
||||||
done = true;
|
|
||||||
messageItem->setText(alpha);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!done) {
|
|
||||||
// Default to alpha
|
|
||||||
messageItem->setText(alpha);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
functionItem->setText(QString("%1").arg(functionBits));
|
functionItem->setText(QString("%1").arg(functionBits));
|
||||||
alphaItem->setText(alphaMessage);
|
alphaItem->setText(alphaMessage);
|
||||||
numericItem->setText(numericMessage);
|
numericItem->setText(numericMessage);
|
||||||
@ -250,6 +285,7 @@ void PagerDemodGUI::messageReceived(const QDateTime dateTime, int address, int f
|
|||||||
if (scrollToBottom) {
|
if (scrollToBottom) {
|
||||||
ui->messages->scrollToBottom();
|
ui->messages->scrollToBottom();
|
||||||
}
|
}
|
||||||
|
checkNotification(row);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PagerDemodGUI::handleMessage(const Message& message)
|
bool PagerDemodGUI::handleMessage(const Message& message)
|
||||||
@ -257,7 +293,7 @@ bool PagerDemodGUI::handleMessage(const Message& message)
|
|||||||
if (PagerDemod::MsgConfigurePagerDemod::match(message))
|
if (PagerDemod::MsgConfigurePagerDemod::match(message))
|
||||||
{
|
{
|
||||||
qDebug("PagerDemodGUI::handleMessage: PagerDemod::MsgConfigurePagerDemod");
|
qDebug("PagerDemodGUI::handleMessage: PagerDemod::MsgConfigurePagerDemod");
|
||||||
const PagerDemod::MsgConfigurePagerDemod& cfg = (PagerDemod::MsgConfigurePagerDemod&) message;
|
const PagerDemod::MsgConfigurePagerDemod& cfg = (const PagerDemod::MsgConfigurePagerDemod&) message;
|
||||||
m_settings = cfg.getSettings();
|
m_settings = cfg.getSettings();
|
||||||
blockApplySettings(true);
|
blockApplySettings(true);
|
||||||
ui->scopeGUI->updateSettings();
|
ui->scopeGUI->updateSettings();
|
||||||
@ -268,7 +304,7 @@ bool PagerDemodGUI::handleMessage(const Message& message)
|
|||||||
}
|
}
|
||||||
else if (PagerDemod::MsgPagerMessage::match(message))
|
else if (PagerDemod::MsgPagerMessage::match(message))
|
||||||
{
|
{
|
||||||
PagerDemod::MsgPagerMessage& report = (PagerDemod::MsgPagerMessage&) message;
|
const PagerDemod::MsgPagerMessage& report = (const PagerDemod::MsgPagerMessage&) message;
|
||||||
messageReceived(report.getDateTime(), report.getAddress(), report.getFunctionBits(),
|
messageReceived(report.getDateTime(), report.getAddress(), report.getFunctionBits(),
|
||||||
report.getNumericMessage(), report.getAlphaMessage(),
|
report.getNumericMessage(), report.getAlphaMessage(),
|
||||||
report.getEvenParityErrors(), report.getBCHParityErrors());
|
report.getEvenParityErrors(), report.getBCHParityErrors());
|
||||||
@ -276,7 +312,7 @@ bool PagerDemodGUI::handleMessage(const Message& message)
|
|||||||
}
|
}
|
||||||
else if (DSPSignalNotification::match(message))
|
else if (DSPSignalNotification::match(message))
|
||||||
{
|
{
|
||||||
DSPSignalNotification& notif = (DSPSignalNotification&) message;
|
const DSPSignalNotification& notif = (const DSPSignalNotification&) message;
|
||||||
m_deviceCenterFrequency = notif.getCenterFrequency();
|
m_deviceCenterFrequency = notif.getCenterFrequency();
|
||||||
m_basebandSampleRate = notif.getSampleRate();
|
m_basebandSampleRate = notif.getSampleRate();
|
||||||
ui->deltaFrequency->setValueRange(false, 7, -m_basebandSampleRate/2, m_basebandSampleRate/2);
|
ui->deltaFrequency->setValueRange(false, 7, -m_basebandSampleRate/2, m_basebandSampleRate/2);
|
||||||
@ -479,7 +515,8 @@ PagerDemodGUI::PagerDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Bas
|
|||||||
m_deviceCenterFrequency(0),
|
m_deviceCenterFrequency(0),
|
||||||
m_basebandSampleRate(1),
|
m_basebandSampleRate(1),
|
||||||
m_doApplySettings(true),
|
m_doApplySettings(true),
|
||||||
m_tickCount(0)
|
m_tickCount(0),
|
||||||
|
m_speech(nullptr)
|
||||||
{
|
{
|
||||||
setAttribute(Qt::WA_DeleteOnClose, true);
|
setAttribute(Qt::WA_DeleteOnClose, true);
|
||||||
m_helpURL = "plugins/channelrx/demodpager/readme.md";
|
m_helpURL = "plugins/channelrx/demodpager/readme.md";
|
||||||
@ -526,6 +563,9 @@ PagerDemodGUI::PagerDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Bas
|
|||||||
connect(&m_channelMarker, SIGNAL(highlightedByCursor()), this, SLOT(channelMarkerHighlightedByCursor()));
|
connect(&m_channelMarker, SIGNAL(highlightedByCursor()), this, SLOT(channelMarkerHighlightedByCursor()));
|
||||||
connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
|
connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
|
||||||
|
|
||||||
|
CRightClickEnabler *filterDuplicatesRightClickEnabler = new CRightClickEnabler(ui->filterDuplicates);
|
||||||
|
connect(filterDuplicatesRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(on_filterDuplicates_rightClicked(const QPoint &)));
|
||||||
|
|
||||||
// Resize the table using dummy data
|
// Resize the table using dummy data
|
||||||
resizeTable();
|
resizeTable();
|
||||||
// Allow user to reorder columns
|
// Allow user to reorder columns
|
||||||
@ -575,6 +615,7 @@ void PagerDemodGUI::customContextMenuRequested(QPoint pos)
|
|||||||
|
|
||||||
PagerDemodGUI::~PagerDemodGUI()
|
PagerDemodGUI::~PagerDemodGUI()
|
||||||
{
|
{
|
||||||
|
clearFromMap();
|
||||||
delete ui;
|
delete ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -638,6 +679,8 @@ void PagerDemodGUI::displaySettings()
|
|||||||
ui->logFilename->setToolTip(QString(".csv log filename: %1").arg(m_settings.m_logFilename));
|
ui->logFilename->setToolTip(QString(".csv log filename: %1").arg(m_settings.m_logFilename));
|
||||||
ui->logEnable->setChecked(m_settings.m_logEnabled);
|
ui->logEnable->setChecked(m_settings.m_logEnabled);
|
||||||
|
|
||||||
|
ui->filterDuplicates->setChecked(m_settings.m_filterDuplicates);
|
||||||
|
|
||||||
// Order and size columns
|
// Order and size columns
|
||||||
QHeaderView *header = ui->messages->horizontalHeader();
|
QHeaderView *header = ui->messages->horizontalHeader();
|
||||||
|
|
||||||
@ -656,6 +699,7 @@ void PagerDemodGUI::displaySettings()
|
|||||||
getRollupContents()->restoreState(m_rollupState);
|
getRollupContents()->restoreState(m_rollupState);
|
||||||
updateAbsoluteCenterFrequency();
|
updateAbsoluteCenterFrequency();
|
||||||
blockApplySettings(false);
|
blockApplySettings(false);
|
||||||
|
enableSpeechIfNeeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PagerDemodGUI::leaveEvent(QEvent* event)
|
void PagerDemodGUI::leaveEvent(QEvent* event)
|
||||||
@ -693,12 +737,39 @@ void PagerDemodGUI::tick()
|
|||||||
void PagerDemodGUI::on_charset_clicked()
|
void PagerDemodGUI::on_charset_clicked()
|
||||||
{
|
{
|
||||||
PagerDemodCharsetDialog dialog(&m_settings);
|
PagerDemodCharsetDialog dialog(&m_settings);
|
||||||
if (dialog.exec() == QDialog::Accepted)
|
new DialogPositioner(&dialog, true);
|
||||||
{
|
if (dialog.exec() == QDialog::Accepted) {
|
||||||
applySettings();
|
applySettings();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PagerDemodGUI::on_notifications_clicked()
|
||||||
|
{
|
||||||
|
PagerDemodNotificationDialog dialog(&m_settings);
|
||||||
|
new DialogPositioner(&dialog, true);
|
||||||
|
if (dialog.exec() == QDialog::Accepted)
|
||||||
|
{
|
||||||
|
enableSpeechIfNeeded();
|
||||||
|
applySettings();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PagerDemodGUI::on_filterDuplicates_clicked(bool checked)
|
||||||
|
{
|
||||||
|
m_settings.m_filterDuplicates = checked;
|
||||||
|
applySettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PagerDemodGUI::on_filterDuplicates_rightClicked(const QPoint &p)
|
||||||
|
{
|
||||||
|
(void) p;
|
||||||
|
|
||||||
|
PagerDemodFilterDialog dialog(&m_settings);
|
||||||
|
new DialogPositioner(&dialog, true);
|
||||||
|
if (dialog.exec() == QDialog::Accepted) {
|
||||||
|
applySettings();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void PagerDemodGUI::on_logEnable_clicked(bool checked)
|
void PagerDemodGUI::on_logEnable_clicked(bool checked)
|
||||||
{
|
{
|
||||||
@ -813,6 +884,8 @@ void PagerDemodGUI::makeUIConnections()
|
|||||||
QObject::connect(ui->udpEnabled, &QCheckBox::clicked, this, &PagerDemodGUI::on_udpEnabled_clicked);
|
QObject::connect(ui->udpEnabled, &QCheckBox::clicked, this, &PagerDemodGUI::on_udpEnabled_clicked);
|
||||||
QObject::connect(ui->udpAddress, &QLineEdit::editingFinished, this, &PagerDemodGUI::on_udpAddress_editingFinished);
|
QObject::connect(ui->udpAddress, &QLineEdit::editingFinished, this, &PagerDemodGUI::on_udpAddress_editingFinished);
|
||||||
QObject::connect(ui->udpPort, &QLineEdit::editingFinished, this, &PagerDemodGUI::on_udpPort_editingFinished);
|
QObject::connect(ui->udpPort, &QLineEdit::editingFinished, this, &PagerDemodGUI::on_udpPort_editingFinished);
|
||||||
|
QObject::connect(ui->notifications, &QToolButton::clicked, this, &PagerDemodGUI::on_notifications_clicked);
|
||||||
|
QObject::connect(ui->filterDuplicates, &ButtonSwitch::clicked, this, &PagerDemodGUI::on_filterDuplicates_clicked);
|
||||||
QObject::connect(ui->logEnable, &ButtonSwitch::clicked, this, &PagerDemodGUI::on_logEnable_clicked);
|
QObject::connect(ui->logEnable, &ButtonSwitch::clicked, this, &PagerDemodGUI::on_logEnable_clicked);
|
||||||
QObject::connect(ui->logFilename, &QToolButton::clicked, this, &PagerDemodGUI::on_logFilename_clicked);
|
QObject::connect(ui->logFilename, &QToolButton::clicked, this, &PagerDemodGUI::on_logFilename_clicked);
|
||||||
QObject::connect(ui->logOpen, &QToolButton::clicked, this, &PagerDemodGUI::on_logOpen_clicked);
|
QObject::connect(ui->logOpen, &QToolButton::clicked, this, &PagerDemodGUI::on_logOpen_clicked);
|
||||||
@ -824,3 +897,178 @@ void PagerDemodGUI::updateAbsoluteCenterFrequency()
|
|||||||
{
|
{
|
||||||
setStatusFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset);
|
setStatusFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialise text to speech engine
|
||||||
|
// This takes 10 seconds on some versions of Linux, so only do it, if user actually
|
||||||
|
// has speech notifications configured
|
||||||
|
void PagerDemodGUI::enableSpeechIfNeeded()
|
||||||
|
{
|
||||||
|
#ifdef QT_TEXTTOSPEECH_FOUND
|
||||||
|
if (m_speech) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (const auto& notification : m_settings.m_notificationSettings)
|
||||||
|
{
|
||||||
|
if (!notification->m_speech.isEmpty())
|
||||||
|
{
|
||||||
|
qDebug() << "PagerDemodGUI: Enabling text to speech";
|
||||||
|
m_speech = new QTextToSpeech(this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void PagerDemodGUI::checkNotification(int row)
|
||||||
|
{
|
||||||
|
QString address = ui->messages->item(row, MESSAGE_COL_ADDRESS)->text();
|
||||||
|
QString message = ui->messages->item(row, MESSAGE_COL_MESSAGE)->text();
|
||||||
|
|
||||||
|
for (int i = 0; i < m_settings.m_notificationSettings.size(); i++)
|
||||||
|
{
|
||||||
|
QString match;
|
||||||
|
switch (m_settings.m_notificationSettings[i]->m_matchColumn)
|
||||||
|
{
|
||||||
|
case MESSAGE_COL_ADDRESS:
|
||||||
|
match = address;
|
||||||
|
break;
|
||||||
|
case MESSAGE_COL_MESSAGE:
|
||||||
|
match = message;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!match.isEmpty())
|
||||||
|
{
|
||||||
|
if (m_settings.m_notificationSettings[i]->m_regularExpression.isValid())
|
||||||
|
{
|
||||||
|
QRegularExpressionMatch matchResult = m_settings.m_notificationSettings[i]->m_regularExpression.match(match);
|
||||||
|
if (matchResult.hasMatch())
|
||||||
|
{
|
||||||
|
if (m_settings.m_notificationSettings[i]->m_highlight) {
|
||||||
|
ui->messages->item(row, MESSAGE_COL_MESSAGE)->setTextColor(m_settings.m_notificationSettings[i]->m_highlightColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_settings.m_notificationSettings[i]->m_speech.isEmpty())
|
||||||
|
{
|
||||||
|
QString speech = subStrings(address, message, matchResult, m_settings.m_notificationSettings[i]->m_speech);
|
||||||
|
|
||||||
|
speechNotification(speech);
|
||||||
|
}
|
||||||
|
if (!m_settings.m_notificationSettings[i]->m_command.isEmpty())
|
||||||
|
{
|
||||||
|
QString command = subStrings(address, message, matchResult, m_settings.m_notificationSettings[i]->m_command);
|
||||||
|
|
||||||
|
commandNotification(command);
|
||||||
|
}
|
||||||
|
if (m_settings.m_notificationSettings[i]->m_plotOnMap)
|
||||||
|
{
|
||||||
|
float latitude;
|
||||||
|
float longitude;
|
||||||
|
|
||||||
|
if (Units::stringToLatitudeAndLongitude(message, latitude, longitude, false))
|
||||||
|
{
|
||||||
|
QDateTime dateTime;
|
||||||
|
|
||||||
|
dateTime.setDate(QDate::fromString(ui->messages->item(row, MESSAGE_COL_DATE)->text()));
|
||||||
|
dateTime.setTime(QTime::fromString(ui->messages->item(row, MESSAGE_COL_TIME)->text()));
|
||||||
|
|
||||||
|
sendToMap(address, message, latitude, longitude, dateTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString PagerDemodGUI::subStrings(const QString& address, const QString& message, const QRegularExpressionMatch& match, const QString &string) const
|
||||||
|
{
|
||||||
|
QString s = string;
|
||||||
|
s = s.replace("${address}", address);
|
||||||
|
s = s.replace("${message}", message);
|
||||||
|
for (int i = 0; i < match.capturedTexts().size(); i++)
|
||||||
|
{
|
||||||
|
QString escape = QString("${%1}").arg(i);
|
||||||
|
s = s.replace(escape, match.capturedTexts()[i]);
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PagerDemodGUI::speechNotification(const QString &speech)
|
||||||
|
{
|
||||||
|
#ifdef QT_TEXTTOSPEECH_FOUND
|
||||||
|
if (m_speech) {
|
||||||
|
m_speech->say(speech);
|
||||||
|
} else {
|
||||||
|
qWarning() << "PagerDemodGUI::speechNotification: Unable to say " << speech;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
qWarning() << "PagerDemodGUI::speechNotification: TextToSpeech not supported. Unable to say " << speech;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void PagerDemodGUI::commandNotification(const QString &command)
|
||||||
|
{
|
||||||
|
#if QT_CONFIG(process)
|
||||||
|
QStringList allArgs = QProcess::splitCommand(command);
|
||||||
|
|
||||||
|
if (allArgs.size() > 0)
|
||||||
|
{
|
||||||
|
QString program = allArgs[0];
|
||||||
|
allArgs.pop_front();
|
||||||
|
QProcess::startDetached(program, allArgs);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
qWarning() << "PagerDemodGUI::commandNotification: QProcess not supported. Can't run: " << command;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void PagerDemodGUI::sendToMap(const QString& address, const QString& message, float latitude, float longitude, QDateTime dateTime)
|
||||||
|
{
|
||||||
|
QList<ObjectPipe*> mapPipes;
|
||||||
|
MainCore::instance()->getMessagePipes().getMessagePipes(m_pagerDemod, "mapitems", mapPipes);
|
||||||
|
|
||||||
|
for (const auto& pipe : mapPipes)
|
||||||
|
{
|
||||||
|
MessageQueue *messageQueue = qobject_cast<MessageQueue*>(pipe->m_element);
|
||||||
|
SWGSDRangel::SWGMapItem *swgMapItem = new SWGSDRangel::SWGMapItem();
|
||||||
|
swgMapItem->setName(new QString(address));
|
||||||
|
swgMapItem->setLatitude(latitude);
|
||||||
|
swgMapItem->setLongitude(longitude);
|
||||||
|
swgMapItem->setAltitude(0);
|
||||||
|
swgMapItem->setAltitudeReference(1); // CLAMP_TO_GROUND
|
||||||
|
swgMapItem->setFixedPosition(false);
|
||||||
|
swgMapItem->setPositionDateTime(new QString(dateTime.toString(Qt::ISODateWithMs)));
|
||||||
|
|
||||||
|
swgMapItem->setImageRotation(0);
|
||||||
|
swgMapItem->setText(new QString(message));
|
||||||
|
swgMapItem->setImage(new QString(QString("pager.png")));
|
||||||
|
|
||||||
|
MainCore::MsgMapItem *msg = MainCore::MsgMapItem::create(m_pagerDemod, swgMapItem);
|
||||||
|
messageQueue->push(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_mapItems.insert(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear all items from map
|
||||||
|
void PagerDemodGUI::clearFromMap()
|
||||||
|
{
|
||||||
|
for (const auto& address : m_mapItems)
|
||||||
|
{
|
||||||
|
QList<ObjectPipe*> mapPipes;
|
||||||
|
MainCore::instance()->getMessagePipes().getMessagePipes(m_pagerDemod, "mapitems", mapPipes);
|
||||||
|
|
||||||
|
for (const auto& pipe : mapPipes)
|
||||||
|
{
|
||||||
|
MessageQueue *messageQueue = qobject_cast<MessageQueue*>(pipe->m_element);
|
||||||
|
SWGSDRangel::SWGMapItem *swgMapItem = new SWGSDRangel::SWGMapItem();
|
||||||
|
swgMapItem->setName(new QString(address));
|
||||||
|
swgMapItem->setImage(new QString(QString("")));
|
||||||
|
|
||||||
|
MainCore::MsgMapItem *msg = MainCore::MsgMapItem::create(m_pagerDemod, swgMapItem);
|
||||||
|
messageQueue->push(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_mapItems.clear();
|
||||||
|
}
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#define INCLUDE_PAGERDEMODGUI_H
|
#define INCLUDE_PAGERDEMODGUI_H
|
||||||
|
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
|
#include <QTextToSpeech>
|
||||||
|
|
||||||
#include "channel/channelgui.h"
|
#include "channel/channelgui.h"
|
||||||
#include "dsp/channelmarker.h"
|
#include "dsp/channelmarker.h"
|
||||||
@ -45,6 +46,18 @@ class PagerDemodGUI : public ChannelGUI {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
enum MessageCol {
|
||||||
|
MESSAGE_COL_DATE,
|
||||||
|
MESSAGE_COL_TIME,
|
||||||
|
MESSAGE_COL_ADDRESS,
|
||||||
|
MESSAGE_COL_MESSAGE,
|
||||||
|
MESSAGE_COL_FUNCTION,
|
||||||
|
MESSAGE_COL_ALPHA,
|
||||||
|
MESSAGE_COL_NUMERIC,
|
||||||
|
MESSAGE_COL_EVEN_PE,
|
||||||
|
MESSAGE_COL_BCH_PE
|
||||||
|
};
|
||||||
|
|
||||||
static PagerDemodGUI* create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel);
|
static PagerDemodGUI* create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel);
|
||||||
virtual void destroy();
|
virtual void destroy();
|
||||||
|
|
||||||
@ -86,12 +99,18 @@ private:
|
|||||||
|
|
||||||
QMenu *messagesMenu; // Column select context menu
|
QMenu *messagesMenu; // Column select context menu
|
||||||
|
|
||||||
|
#ifdef QT_TEXTTOSPEECH_FOUND
|
||||||
|
QTextToSpeech *m_speech;
|
||||||
|
#endif
|
||||||
|
QSet<QString> m_mapItems;
|
||||||
|
|
||||||
explicit PagerDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel, QWidget* parent = 0);
|
explicit PagerDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel, QWidget* parent = 0);
|
||||||
virtual ~PagerDemodGUI();
|
virtual ~PagerDemodGUI();
|
||||||
|
|
||||||
void blockApplySettings(bool block);
|
void blockApplySettings(bool block);
|
||||||
void applySettings(bool force = false);
|
void applySettings(bool force = false);
|
||||||
void displaySettings();
|
void displaySettings();
|
||||||
|
QString selectMessage(int functionBits, const QString &numericMessage, const QString &alphaMessage) const;
|
||||||
void messageReceived(const QDateTime dateTime, int address, int functionBits,
|
void messageReceived(const QDateTime dateTime, int address, int functionBits,
|
||||||
const QString &numericMessage, const QString &alphaMessage,
|
const QString &numericMessage, const QString &alphaMessage,
|
||||||
int evenParityErrors, int bchParityErrors);
|
int evenParityErrors, int bchParityErrors);
|
||||||
@ -105,17 +124,13 @@ private:
|
|||||||
void resizeTable();
|
void resizeTable();
|
||||||
QAction *createCheckableItem(QString& text, int idx, bool checked, const char *slot);
|
QAction *createCheckableItem(QString& text, int idx, bool checked, const char *slot);
|
||||||
|
|
||||||
enum MessageCol {
|
void enableSpeechIfNeeded();
|
||||||
MESSAGE_COL_DATE,
|
void checkNotification(int row);
|
||||||
MESSAGE_COL_TIME,
|
void speechNotification(const QString &speech);
|
||||||
MESSAGE_COL_ADDRESS,
|
void commandNotification(const QString &command);
|
||||||
MESSAGE_COL_MESSAGE,
|
QString subStrings(const QString& address, const QString& message, const QRegularExpressionMatch& match, const QString &string) const;
|
||||||
MESSAGE_COL_FUNCTION,
|
void sendToMap(const QString& address, const QString& message, float latitide, float longitude, QDateTime dateTime);
|
||||||
MESSAGE_COL_ALPHA,
|
void clearFromMap();
|
||||||
MESSAGE_COL_NUMERIC,
|
|
||||||
MESSAGE_COL_EVEN_PE,
|
|
||||||
MESSAGE_COL_BCH_PE
|
|
||||||
};
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void on_deltaFrequency_changed(qint64 value);
|
void on_deltaFrequency_changed(qint64 value);
|
||||||
@ -131,6 +146,9 @@ private slots:
|
|||||||
void on_udpPort_editingFinished();
|
void on_udpPort_editingFinished();
|
||||||
void on_channel1_currentIndexChanged(int index);
|
void on_channel1_currentIndexChanged(int index);
|
||||||
void on_channel2_currentIndexChanged(int index);
|
void on_channel2_currentIndexChanged(int index);
|
||||||
|
void on_notifications_clicked();
|
||||||
|
void on_filterDuplicates_clicked(bool checked=false);
|
||||||
|
void on_filterDuplicates_rightClicked(const QPoint &);
|
||||||
void on_logEnable_clicked(bool checked=false);
|
void on_logEnable_clicked(bool checked=false);
|
||||||
void on_logFilename_clicked();
|
void on_logFilename_clicked();
|
||||||
void on_logOpen_clicked();
|
void on_logOpen_clicked();
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
</font>
|
</font>
|
||||||
</property>
|
</property>
|
||||||
<property name="focusPolicy">
|
<property name="focusPolicy">
|
||||||
<enum>Qt::StrongFocus</enum>
|
<enum>Qt::FocusPolicy::StrongFocus</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>Pager Demodulator</string>
|
<string>Pager Demodulator</string>
|
||||||
@ -110,7 +110,7 @@
|
|||||||
<cursorShape>PointingHandCursor</cursorShape>
|
<cursorShape>PointingHandCursor</cursorShape>
|
||||||
</property>
|
</property>
|
||||||
<property name="focusPolicy">
|
<property name="focusPolicy">
|
||||||
<enum>Qt::StrongFocus</enum>
|
<enum>Qt::FocusPolicy::StrongFocus</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Demod shift frequency from center in Hz</string>
|
<string>Demod shift frequency from center in Hz</string>
|
||||||
@ -127,14 +127,14 @@
|
|||||||
<item>
|
<item>
|
||||||
<widget class="Line" name="line">
|
<widget class="Line" name="line">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Vertical</enum>
|
<enum>Qt::Orientation::Vertical</enum>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<spacer name="horizontalSpacer">
|
<spacer name="horizontalSpacer">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Orientation::Horizontal</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizeHint" stdset="0">
|
<property name="sizeHint" stdset="0">
|
||||||
<size>
|
<size>
|
||||||
@ -152,7 +152,7 @@
|
|||||||
<string>Channel power</string>
|
<string>Channel power</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="layoutDirection">
|
<property name="layoutDirection">
|
||||||
<enum>Qt::RightToLeft</enum>
|
<enum>Qt::LayoutDirection::RightToLeft</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>0.0</string>
|
<string>0.0</string>
|
||||||
@ -209,7 +209,7 @@
|
|||||||
<item>
|
<item>
|
||||||
<widget class="Line" name="line_5">
|
<widget class="Line" name="line_5">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Orientation::Horizontal</enum>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@ -252,7 +252,7 @@
|
|||||||
<number>100</number>
|
<number>100</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Orientation::Horizontal</enum>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@ -268,14 +268,14 @@
|
|||||||
<string>10.0k</string>
|
<string>10.0k</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="alignment">
|
<property name="alignment">
|
||||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="Line" name="line_2">
|
<widget class="Line" name="line_2">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Vertical</enum>
|
<enum>Qt::Orientation::Vertical</enum>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@ -316,7 +316,7 @@
|
|||||||
<number>24</number>
|
<number>24</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Orientation::Horizontal</enum>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@ -332,7 +332,7 @@
|
|||||||
<string>2.4k</string>
|
<string>2.4k</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="alignment">
|
<property name="alignment">
|
||||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@ -368,7 +368,7 @@
|
|||||||
<item>
|
<item>
|
||||||
<widget class="Line" name="line_10">
|
<widget class="Line" name="line_10">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Vertical</enum>
|
<enum>Qt::Orientation::Vertical</enum>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@ -413,7 +413,7 @@
|
|||||||
<item>
|
<item>
|
||||||
<widget class="Line" name="line_11">
|
<widget class="Line" name="line_11">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Vertical</enum>
|
<enum>Qt::Orientation::Vertical</enum>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@ -479,7 +479,7 @@
|
|||||||
<item>
|
<item>
|
||||||
<spacer name="horizontalSpacer_2">
|
<spacer name="horizontalSpacer_2">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Orientation::Horizontal</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizeHint" stdset="0">
|
<property name="sizeHint" stdset="0">
|
||||||
<size>
|
<size>
|
||||||
@ -494,22 +494,29 @@
|
|||||||
<item>
|
<item>
|
||||||
<widget class="Line" name="line_6">
|
<widget class="Line" name="line_6">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Orientation::Horizontal</enum>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="udpLayout">
|
<layout class="QHBoxLayout" name="udpLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="udpLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>UDP</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QCheckBox" name="udpEnabled">
|
<widget class="QCheckBox" name="udpEnabled">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Forward messages via UDP</string>
|
<string>Forward messages via UDP</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="layoutDirection">
|
<property name="layoutDirection">
|
||||||
<enum>Qt::RightToLeft</enum>
|
<enum>Qt::LayoutDirection::RightToLeft</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>UDP</string>
|
<string/>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@ -522,7 +529,7 @@
|
|||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="focusPolicy">
|
<property name="focusPolicy">
|
||||||
<enum>Qt::ClickFocus</enum>
|
<enum>Qt::FocusPolicy::ClickFocus</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Destination UDP address</string>
|
<string>Destination UDP address</string>
|
||||||
@ -541,7 +548,7 @@
|
|||||||
<string>:</string>
|
<string>:</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="alignment">
|
<property name="alignment">
|
||||||
<set>Qt::AlignCenter</set>
|
<set>Qt::AlignmentFlag::AlignCenter</set>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@ -560,7 +567,7 @@
|
|||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="focusPolicy">
|
<property name="focusPolicy">
|
||||||
<enum>Qt::ClickFocus</enum>
|
<enum>Qt::FocusPolicy::ClickFocus</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Destination UDP port</string>
|
<string>Destination UDP port</string>
|
||||||
@ -576,7 +583,7 @@
|
|||||||
<item>
|
<item>
|
||||||
<spacer name="horizontalSpacer_4">
|
<spacer name="horizontalSpacer_4">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Orientation::Horizontal</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizeHint" stdset="0">
|
<property name="sizeHint" stdset="0">
|
||||||
<size>
|
<size>
|
||||||
@ -591,7 +598,7 @@
|
|||||||
<item>
|
<item>
|
||||||
<widget class="Line" name="line_3">
|
<widget class="Line" name="line_3">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Orientation::Horizontal</enum>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@ -614,7 +621,7 @@
|
|||||||
<item>
|
<item>
|
||||||
<spacer name="horizontalSpacer_3">
|
<spacer name="horizontalSpacer_3">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Orientation::Horizontal</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizeHint" stdset="0">
|
<property name="sizeHint" stdset="0">
|
||||||
<size>
|
<size>
|
||||||
@ -624,6 +631,43 @@
|
|||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="ButtonSwitch" name="filterDuplicates">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>24</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Filter duplicate messages. Right click for options.</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="pagerdemodicons.qrc">
|
||||||
|
<normaloff>:/icons/filterduplicate.png</normaloff>:/icons/filterduplicate.png</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="notifications">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Open notifications dialog</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>...</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="../../../sdrgui/resources/res.qrc">
|
||||||
|
<normaloff>:/mono.png</normaloff>:/mono.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="ButtonSwitch" name="logEnable">
|
<widget class="ButtonSwitch" name="logEnable">
|
||||||
<property name="maximumSize">
|
<property name="maximumSize">
|
||||||
@ -736,7 +780,7 @@
|
|||||||
<string>Received messages</string>
|
<string>Received messages</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="editTriggers">
|
<property name="editTriggers">
|
||||||
<set>QAbstractItemView::NoEditTriggers</set>
|
<set>QAbstractItemView::EditTrigger::NoEditTriggers</set>
|
||||||
</property>
|
</property>
|
||||||
<column>
|
<column>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
@ -1056,6 +1100,7 @@
|
|||||||
</customwidgets>
|
</customwidgets>
|
||||||
<resources>
|
<resources>
|
||||||
<include location="../../../sdrgui/resources/res.qrc"/>
|
<include location="../../../sdrgui/resources/res.qrc"/>
|
||||||
|
<include location="pagerdemodicons.qrc"/>
|
||||||
</resources>
|
</resources>
|
||||||
<connections/>
|
<connections/>
|
||||||
</ui>
|
</ui>
|
||||||
|
5
plugins/channelrx/demodpager/pagerdemodicons.qrc
Normal file
5
plugins/channelrx/demodpager/pagerdemodicons.qrc
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<RCC>
|
||||||
|
<qresource prefix="/">
|
||||||
|
<file>icons/filterduplicate.png</file>
|
||||||
|
</qresource>
|
||||||
|
</RCC>
|
173
plugins/channelrx/demodpager/pagerdemodnotificationdialog.cpp
Normal file
173
plugins/channelrx/demodpager/pagerdemodnotificationdialog.cpp
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright (C) 2021 Jon Beniston, M7RCE //
|
||||||
|
// //
|
||||||
|
// This program is free software; you can redistribute it and/or modify //
|
||||||
|
// it under the terms of the GNU General Public License as published by //
|
||||||
|
// the Free Software Foundation as version 3 of the License, or //
|
||||||
|
// (at your option) any later version. //
|
||||||
|
// //
|
||||||
|
// This program is distributed in the hope that it will be useful, //
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||||
|
// GNU General Public License V3 for more details. //
|
||||||
|
// //
|
||||||
|
// You should have received a copy of the GNU General Public License //
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QComboBox>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QCheckBox>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
|
||||||
|
#include "gui/tablecolorchooser.h"
|
||||||
|
|
||||||
|
#include "pagerdemodnotificationdialog.h"
|
||||||
|
#include "pagerdemodgui.h"
|
||||||
|
|
||||||
|
// Map main table column numbers to combo box indices
|
||||||
|
std::vector<int> PagerDemodNotificationDialog::m_columnMap = {
|
||||||
|
PagerDemodGUI::MESSAGE_COL_ADDRESS, PagerDemodGUI::MESSAGE_COL_MESSAGE
|
||||||
|
};
|
||||||
|
|
||||||
|
PagerDemodNotificationDialog::PagerDemodNotificationDialog(PagerDemodSettings *settings,
|
||||||
|
QWidget* parent) :
|
||||||
|
QDialog(parent),
|
||||||
|
ui(new Ui::PagerDemodNotificationDialog),
|
||||||
|
m_settings(settings)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
resizeTable();
|
||||||
|
|
||||||
|
for (int i = 0; i < m_settings->m_notificationSettings.size(); i++) {
|
||||||
|
addRow(m_settings->m_notificationSettings[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PagerDemodNotificationDialog::~PagerDemodNotificationDialog()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
qDeleteAll(m_colorGUIs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PagerDemodNotificationDialog::accept()
|
||||||
|
{
|
||||||
|
qDeleteAll(m_settings->m_notificationSettings);
|
||||||
|
m_settings->m_notificationSettings.clear();
|
||||||
|
for (int i = 0; i < ui->table->rowCount(); i++)
|
||||||
|
{
|
||||||
|
PagerDemodSettings::NotificationSettings *notificationSettings = new PagerDemodSettings::NotificationSettings();
|
||||||
|
int idx = ((QComboBox *)ui->table->cellWidget(i, NOTIFICATION_COL_MATCH))->currentIndex();
|
||||||
|
notificationSettings->m_matchColumn = m_columnMap[idx];
|
||||||
|
notificationSettings->m_regExp = ui->table->item(i, NOTIFICATION_COL_REG_EXP)->data(Qt::DisplayRole).toString().trimmed();
|
||||||
|
notificationSettings->m_speech = ui->table->item(i, NOTIFICATION_COL_SPEECH)->data(Qt::DisplayRole).toString().trimmed();
|
||||||
|
notificationSettings->m_command = ui->table->item(i, NOTIFICATION_COL_COMMAND)->data(Qt::DisplayRole).toString().trimmed();
|
||||||
|
notificationSettings->m_highlight = !m_colorGUIs[i]->m_noColor;
|
||||||
|
notificationSettings->m_highlightColor = m_colorGUIs[i]->m_color;
|
||||||
|
notificationSettings->m_plotOnMap = ((QCheckBox *) ui->table->cellWidget(i, NOTIFICATION_COL_PLOT_ON_MAP))->isChecked();
|
||||||
|
notificationSettings->updateRegularExpression();
|
||||||
|
m_settings->m_notificationSettings.append(notificationSettings);
|
||||||
|
}
|
||||||
|
QDialog::accept();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PagerDemodNotificationDialog::resizeTable()
|
||||||
|
{
|
||||||
|
PagerDemodSettings::NotificationSettings dummy;
|
||||||
|
dummy.m_matchColumn = PagerDemodGUI::MESSAGE_COL_ADDRESS;
|
||||||
|
dummy.m_regExp = "1234567";
|
||||||
|
dummy.m_speech = "${message}";
|
||||||
|
dummy.m_command = "cmail.exe -to:user@host.com \"-subject: Paging ${address}\" \"-body: ${message}\"";
|
||||||
|
dummy.m_highlight = true;
|
||||||
|
dummy.m_plotOnMap = true;
|
||||||
|
addRow(&dummy);
|
||||||
|
ui->table->resizeColumnsToContents();
|
||||||
|
ui->table->selectRow(0);
|
||||||
|
on_remove_clicked();
|
||||||
|
ui->table->selectRow(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PagerDemodNotificationDialog::on_add_clicked()
|
||||||
|
{
|
||||||
|
addRow();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove selected row
|
||||||
|
void PagerDemodNotificationDialog::on_remove_clicked()
|
||||||
|
{
|
||||||
|
// Selection mode is single, so only a single row should be returned
|
||||||
|
QModelIndexList indexList = ui->table->selectionModel()->selectedRows();
|
||||||
|
if (!indexList.isEmpty())
|
||||||
|
{
|
||||||
|
int row = indexList.at(0).row();
|
||||||
|
ui->table->removeRow(row);
|
||||||
|
m_colorGUIs.removeAt(row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PagerDemodNotificationDialog::addRow(PagerDemodSettings::NotificationSettings *settings)
|
||||||
|
{
|
||||||
|
int row = ui->table->rowCount();
|
||||||
|
ui->table->setSortingEnabled(false);
|
||||||
|
ui->table->setRowCount(row + 1);
|
||||||
|
|
||||||
|
QComboBox *match = new QComboBox();
|
||||||
|
TableColorChooser *highlight;
|
||||||
|
if (settings) {
|
||||||
|
highlight = new TableColorChooser(ui->table, row, NOTIFICATION_COL_HIGHLIGHT, !settings->m_highlight, settings->m_highlightColor);
|
||||||
|
} else {
|
||||||
|
highlight = new TableColorChooser(ui->table, row, NOTIFICATION_COL_HIGHLIGHT, false, QColor(Qt::red).rgba());
|
||||||
|
}
|
||||||
|
m_colorGUIs.append(highlight);
|
||||||
|
QCheckBox *plotOnMap = new QCheckBox();
|
||||||
|
plotOnMap->setChecked(false);
|
||||||
|
QWidget *matchWidget = new QWidget();
|
||||||
|
QHBoxLayout *pLayout = new QHBoxLayout(matchWidget);
|
||||||
|
pLayout->addWidget(match);
|
||||||
|
pLayout->setAlignment(Qt::AlignCenter);
|
||||||
|
pLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
matchWidget->setLayout(pLayout);
|
||||||
|
|
||||||
|
match->addItem("Address");
|
||||||
|
match->addItem("Message");
|
||||||
|
|
||||||
|
QTableWidgetItem *regExpItem = new QTableWidgetItem();
|
||||||
|
QTableWidgetItem *speechItem = new QTableWidgetItem();
|
||||||
|
QTableWidgetItem *commandItem = new QTableWidgetItem();
|
||||||
|
|
||||||
|
if (settings != nullptr)
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < m_columnMap.size(); i++)
|
||||||
|
{
|
||||||
|
if (m_columnMap[i] == settings->m_matchColumn)
|
||||||
|
{
|
||||||
|
match->setCurrentIndex(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
regExpItem->setData(Qt::DisplayRole, settings->m_regExp);
|
||||||
|
speechItem->setData(Qt::DisplayRole, settings->m_speech);
|
||||||
|
commandItem->setData(Qt::DisplayRole, settings->m_command);
|
||||||
|
plotOnMap->setChecked(settings->m_plotOnMap);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
match->setCurrentIndex(0);
|
||||||
|
regExpItem->setData(Qt::DisplayRole, ".*");
|
||||||
|
speechItem->setData(Qt::DisplayRole, "${message}");
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
commandItem->setData(Qt::DisplayRole, "cmail.exe -to:user@host.com \"-subject: Paging ${address}\" \"-body: ${message}\"");
|
||||||
|
#else
|
||||||
|
commandItem->setData(Qt::DisplayRole, "sendmail -s \"Paging ${address}: ${message}\" user@host.com");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
ui->table->setCellWidget(row, NOTIFICATION_COL_MATCH, match);
|
||||||
|
ui->table->setItem(row, NOTIFICATION_COL_REG_EXP, regExpItem);
|
||||||
|
ui->table->setItem(row, NOTIFICATION_COL_SPEECH, speechItem);
|
||||||
|
ui->table->setItem(row, NOTIFICATION_COL_COMMAND, commandItem);
|
||||||
|
ui->table->setCellWidget(row, NOTIFICATION_COL_PLOT_ON_MAP, plotOnMap);
|
||||||
|
ui->table->setSortingEnabled(true);
|
||||||
|
}
|
61
plugins/channelrx/demodpager/pagerdemodnotificationdialog.h
Normal file
61
plugins/channelrx/demodpager/pagerdemodnotificationdialog.h
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright (C) 2021 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_PAGERDEMODNOTIFICATIONDIALOG_H
|
||||||
|
#define INCLUDE_PAGERDEMODNOTIFICATIONDIALOG_H
|
||||||
|
|
||||||
|
#include <QHash>
|
||||||
|
|
||||||
|
#include "ui_pagerdemodnotificationdialog.h"
|
||||||
|
#include "pagerdemodsettings.h"
|
||||||
|
|
||||||
|
class TableColorChooser;
|
||||||
|
|
||||||
|
class PagerDemodNotificationDialog : public QDialog {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit PagerDemodNotificationDialog(PagerDemodSettings* settings, QWidget* parent = 0);
|
||||||
|
~PagerDemodNotificationDialog();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void resizeTable();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void accept() override;
|
||||||
|
void on_add_clicked();
|
||||||
|
void on_remove_clicked();
|
||||||
|
void addRow(PagerDemodSettings::NotificationSettings *settings=nullptr);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::PagerDemodNotificationDialog* ui;
|
||||||
|
PagerDemodSettings *m_settings;
|
||||||
|
QList<TableColorChooser *> m_colorGUIs;
|
||||||
|
|
||||||
|
enum NotificationCol {
|
||||||
|
NOTIFICATION_COL_MATCH,
|
||||||
|
NOTIFICATION_COL_REG_EXP,
|
||||||
|
NOTIFICATION_COL_SPEECH,
|
||||||
|
NOTIFICATION_COL_COMMAND,
|
||||||
|
NOTIFICATION_COL_HIGHLIGHT,
|
||||||
|
NOTIFICATION_COL_PLOT_ON_MAP
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::vector<int> m_columnMap;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // INCLUDE_PagerDEMODNOTIFICATIONDIALOG_H
|
175
plugins/channelrx/demodpager/pagerdemodnotificationdialog.ui
Normal file
175
plugins/channelrx/demodpager/pagerdemodnotificationdialog.ui
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>PagerDemodNotificationDialog</class>
|
||||||
|
<widget class="QDialog" name="PagerDemodNotificationDialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>1100</width>
|
||||||
|
<height>400</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Liberation Sans</family>
|
||||||
|
<pointsize>9</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="contextMenuPolicy">
|
||||||
|
<enum>Qt::ContextMenuPolicy::PreventContextMenu</enum>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Notifications</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBox">
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="4" column="0">
|
||||||
|
<widget class="QTableWidget" name="table">
|
||||||
|
<property name="selectionMode">
|
||||||
|
<enum>QAbstractItemView::SelectionMode::SingleSelection</enum>
|
||||||
|
</property>
|
||||||
|
<property name="selectionBehavior">
|
||||||
|
<enum>QAbstractItemView::SelectionBehavior::SelectRows</enum>
|
||||||
|
</property>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>Match</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>ADS-B data to match</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>Reg Exp</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Regular expression to match with</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>Speech</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Speech for the computer to read when a match is made</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>Command</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Command/script to execute when a match is made</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>Highlight</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>Plot on Map</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="0">
|
||||||
|
<layout class="QHBoxLayout" name="buttonsHorizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="add">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Add device set control</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>+</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="remove">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Remove device set control</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>-</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="buttonsHorizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Orientation::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Orientation::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<tabstops>
|
||||||
|
<tabstop>table</tabstop>
|
||||||
|
<tabstop>add</tabstop>
|
||||||
|
<tabstop>remove</tabstop>
|
||||||
|
</tabstops>
|
||||||
|
<resources>
|
||||||
|
<include location="../../../sdrgui/resources/res.qrc"/>
|
||||||
|
</resources>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>PagerDemodNotificationDialog</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>248</x>
|
||||||
|
<y>254</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>157</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>rejected()</signal>
|
||||||
|
<receiver>PagerDemodNotificationDialog</receiver>
|
||||||
|
<slot>reject()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>316</x>
|
||||||
|
<y>260</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>286</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
@ -20,10 +20,12 @@
|
|||||||
|
|
||||||
#include <QColor>
|
#include <QColor>
|
||||||
#include <QDataStream>
|
#include <QDataStream>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
#include "util/simpleserializer.h"
|
#include "util/simpleserializer.h"
|
||||||
#include "settings/serializable.h"
|
#include "settings/serializable.h"
|
||||||
#include "pagerdemodsettings.h"
|
#include "pagerdemodsettings.h"
|
||||||
|
#include "pagerdemodgui.h"
|
||||||
|
|
||||||
PagerDemodSettings::PagerDemodSettings() :
|
PagerDemodSettings::PagerDemodSettings() :
|
||||||
m_channelMarker(nullptr),
|
m_channelMarker(nullptr),
|
||||||
@ -59,6 +61,9 @@ void PagerDemodSettings::resetToDefaults()
|
|||||||
m_reverse = false;
|
m_reverse = false;
|
||||||
m_workspaceIndex = 0;
|
m_workspaceIndex = 0;
|
||||||
m_hidden = false;
|
m_hidden = false;
|
||||||
|
m_filterDuplicates = false;
|
||||||
|
m_duplicateMatchMessageOnly = false;
|
||||||
|
m_duplicateMatchLastOnly = false;
|
||||||
|
|
||||||
for (int i = 0; i < PAGERDEMOD_MESSAGE_COLUMNS; i++)
|
for (int i = 0; i < PAGERDEMOD_MESSAGE_COLUMNS; i++)
|
||||||
{
|
{
|
||||||
@ -110,6 +115,11 @@ QByteArray PagerDemodSettings::serialize() const
|
|||||||
s.writeBlob(29, m_geometryBytes);
|
s.writeBlob(29, m_geometryBytes);
|
||||||
s.writeBool(30, m_hidden);
|
s.writeBool(30, m_hidden);
|
||||||
|
|
||||||
|
s.writeList(31, m_notificationSettings);
|
||||||
|
s.writeBool(32, m_filterDuplicates);
|
||||||
|
s.writeBool(33, m_duplicateMatchMessageOnly);
|
||||||
|
s.writeBool(34, m_duplicateMatchLastOnly);
|
||||||
|
|
||||||
for (int i = 0; i < PAGERDEMOD_MESSAGE_COLUMNS; i++) {
|
for (int i = 0; i < PAGERDEMOD_MESSAGE_COLUMNS; i++) {
|
||||||
s.writeS32(100 + i, m_messageColumnIndexes[i]);
|
s.writeS32(100 + i, m_messageColumnIndexes[i]);
|
||||||
}
|
}
|
||||||
@ -205,6 +215,12 @@ bool PagerDemodSettings::deserialize(const QByteArray& data)
|
|||||||
d.readBlob(29, &m_geometryBytes);
|
d.readBlob(29, &m_geometryBytes);
|
||||||
d.readBool(30, &m_hidden, false);
|
d.readBool(30, &m_hidden, false);
|
||||||
|
|
||||||
|
d.readList(31, &m_notificationSettings);
|
||||||
|
|
||||||
|
d.readBool(32, &m_filterDuplicates);
|
||||||
|
d.readBool(33, &m_duplicateMatchMessageOnly);
|
||||||
|
d.readBool(34, &m_duplicateMatchLastOnly);
|
||||||
|
|
||||||
for (int i = 0; i < PAGERDEMOD_MESSAGE_COLUMNS; i++) {
|
for (int i = 0; i < PAGERDEMOD_MESSAGE_COLUMNS; i++) {
|
||||||
d.readS32(100 + i, &m_messageColumnIndexes[i], i);
|
d.readS32(100 + i, &m_messageColumnIndexes[i], i);
|
||||||
}
|
}
|
||||||
@ -237,3 +253,80 @@ void PagerDemodSettings::deserializeIntList(const QByteArray& data, QList<qint32
|
|||||||
(*stream) >> ints;
|
(*stream) >> ints;
|
||||||
delete stream;
|
delete stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PagerDemodSettings::NotificationSettings::NotificationSettings() :
|
||||||
|
m_matchColumn(PagerDemodGUI::MESSAGE_COL_ADDRESS),
|
||||||
|
m_highlight(false),
|
||||||
|
m_highlightColor(Qt::red),
|
||||||
|
m_plotOnMap(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void PagerDemodSettings::NotificationSettings::updateRegularExpression()
|
||||||
|
{
|
||||||
|
m_regularExpression.setPattern(m_regExp);
|
||||||
|
m_regularExpression.optimize();
|
||||||
|
if (!m_regularExpression.isValid()) {
|
||||||
|
qDebug() << "PagerDemodSettings::NotificationSettings: Regular expression is not valid: " << m_regExp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray PagerDemodSettings::NotificationSettings::serialize() const
|
||||||
|
{
|
||||||
|
SimpleSerializer s(1);
|
||||||
|
|
||||||
|
s.writeS32(1, m_matchColumn);
|
||||||
|
s.writeString(2, m_regExp);
|
||||||
|
s.writeString(3, m_speech);
|
||||||
|
s.writeString(4, m_command);
|
||||||
|
s.writeBool(5, m_highlight);
|
||||||
|
s.writeS32(6, m_highlightColor);
|
||||||
|
s.writeBool(7, m_plotOnMap);
|
||||||
|
|
||||||
|
return s.final();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PagerDemodSettings::NotificationSettings::deserialize(const QByteArray& data)
|
||||||
|
{
|
||||||
|
SimpleDeserializer d(data);
|
||||||
|
|
||||||
|
if (!d.isValid()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d.getVersion() == 1)
|
||||||
|
{
|
||||||
|
QByteArray blob;
|
||||||
|
|
||||||
|
d.readS32(1, &m_matchColumn);
|
||||||
|
d.readString(2, &m_regExp);
|
||||||
|
d.readString(3, &m_speech);
|
||||||
|
d.readString(4, &m_command);
|
||||||
|
d.readBool(5, &m_highlight, false);
|
||||||
|
d.readS32(6, &m_highlightColor, QColor(Qt::red).rgba());
|
||||||
|
d.readBool(7, &m_plotOnMap, false);
|
||||||
|
|
||||||
|
updateRegularExpression();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QDataStream& operator<<(QDataStream& out, const PagerDemodSettings::NotificationSettings *settings)
|
||||||
|
{
|
||||||
|
out << settings->serialize();
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDataStream& operator>>(QDataStream& in, PagerDemodSettings::NotificationSettings*& settings)
|
||||||
|
{
|
||||||
|
settings = new PagerDemodSettings::NotificationSettings();
|
||||||
|
QByteArray data;
|
||||||
|
in >> data;
|
||||||
|
settings->deserialize(data);
|
||||||
|
return in;
|
||||||
|
}
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
|
||||||
#include "dsp/dsptypes.h"
|
#include "dsp/dsptypes.h"
|
||||||
|
|
||||||
@ -33,6 +34,23 @@ class Serializable;
|
|||||||
|
|
||||||
struct PagerDemodSettings
|
struct PagerDemodSettings
|
||||||
{
|
{
|
||||||
|
struct NotificationSettings {
|
||||||
|
int m_matchColumn;
|
||||||
|
QString m_regExp;
|
||||||
|
QString m_speech;
|
||||||
|
QString m_command;
|
||||||
|
bool m_highlight;
|
||||||
|
qint32 m_highlightColor;
|
||||||
|
bool m_plotOnMap;
|
||||||
|
|
||||||
|
QRegularExpression m_regularExpression;
|
||||||
|
|
||||||
|
NotificationSettings();
|
||||||
|
void updateRegularExpression();
|
||||||
|
QByteArray serialize() const;
|
||||||
|
bool deserialize(const QByteArray& data);
|
||||||
|
};
|
||||||
|
|
||||||
qint32 m_baud; //!< 512, 1200 or 2400
|
qint32 m_baud; //!< 512, 1200 or 2400
|
||||||
qint32 m_inputFrequencyOffset;
|
qint32 m_inputFrequencyOffset;
|
||||||
Real m_rfBandwidth;
|
Real m_rfBandwidth;
|
||||||
@ -73,6 +91,12 @@ struct PagerDemodSettings
|
|||||||
QByteArray m_geometryBytes;
|
QByteArray m_geometryBytes;
|
||||||
bool m_hidden;
|
bool m_hidden;
|
||||||
|
|
||||||
|
QList<NotificationSettings *> m_notificationSettings;
|
||||||
|
|
||||||
|
bool m_filterDuplicates;
|
||||||
|
bool m_duplicateMatchMessageOnly;
|
||||||
|
bool m_duplicateMatchLastOnly;
|
||||||
|
|
||||||
int m_messageColumnIndexes[PAGERDEMOD_MESSAGE_COLUMNS];//!< How the columns are ordered in the table
|
int m_messageColumnIndexes[PAGERDEMOD_MESSAGE_COLUMNS];//!< How the columns are ordered in the table
|
||||||
int m_messageColumnSizes[PAGERDEMOD_MESSAGE_COLUMNS]; //!< Size of the columns in the table
|
int m_messageColumnSizes[PAGERDEMOD_MESSAGE_COLUMNS]; //!< Size of the columns in the table
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<h1>Pager demodulator plugin</h1>
|
<h1>Pager demodulator plugin</h1>
|
||||||
|
|
||||||
<h2>Introduction</h2>
|
<h2>Introduction</h2>
|
||||||
|
|
||||||
@ -86,6 +86,36 @@ IP address of the host to forward received messages to via UDP.
|
|||||||
|
|
||||||
UDP port number to forward received messages to.
|
UDP port number to forward received messages to.
|
||||||
|
|
||||||
|
<h3>Filter Duplicates</h3>
|
||||||
|
|
||||||
|
Check to filter (discard) duplicate messages. Right click to show the Duplicate Filter options dialog:
|
||||||
|
|
||||||
|
- Match message only: When unchecked, compare address and message. When checked, compare only message, ignoring the address.
|
||||||
|
- Match last message only: When unchecked the message is compared against all messages in the table. When checked, the message is compared against the last received message only.
|
||||||
|
|
||||||
|
<h3>Open Notifications Dialog</h3>
|
||||||
|
|
||||||
|
When clicked, opens the Notifications Dialog, which allows speech notifications or programs/scripts to be run when messages matching user-defined rules are received.
|
||||||
|
|
||||||
|
By running a program such as [cmail](https://www.inveigle.net/cmail/download) on Windows or sendmail on Linux, e-mail notifications can be sent.
|
||||||
|
|
||||||
|
Messages can be highlighted in a user-defined colour.
|
||||||
|
|
||||||
|
By checking plot on map, if a message contains a position specified as latitude and longitude, the message can be displayed on the [Map](../../feature/map/readme.md) feature.
|
||||||
|
The format of the coordinates should follow https://en.wikipedia.org/wiki/ISO_6709, E.g: 50°40′46″N 95°48′26″W or -23.342,5.234
|
||||||
|
|
||||||
|
Here are a few examples:
|
||||||
|
|
||||||
|
![Notifications Dialog](../../../doc/img/PagerDemod_plugin_notifications.png)
|
||||||
|
|
||||||
|
In the Speech and Command strings, variables can be used to substitute data from the received message:
|
||||||
|
|
||||||
|
* ${address},
|
||||||
|
* ${message},
|
||||||
|
* ${1}, ${2}... are replaced with the string from the corresponding capture group in the regular expression.
|
||||||
|
|
||||||
|
To experiment with regular expressions, try [https://regexr.com/](https://regexr.com/).
|
||||||
|
|
||||||
<h3>15: Start/stop Logging Messages to .csv File</h3>
|
<h3>15: Start/stop Logging Messages to .csv File</h3>
|
||||||
|
|
||||||
When checked, writes all received messages to a .csv file.
|
When checked, writes all received messages to a .csv file.
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
<file>map/airport_small.png</file>
|
<file>map/airport_small.png</file>
|
||||||
<file>map/heliport.png</file>
|
<file>map/heliport.png</file>
|
||||||
<file>map/waypoint.png</file>
|
<file>map/waypoint.png</file>
|
||||||
|
<file>map/pager.png</file>
|
||||||
<file>map/map3d.html</file>
|
<file>map/map3d.html</file>
|
||||||
<file>data/transmitters.csv</file>
|
<file>data/transmitters.csv</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
|
BIN
plugins/feature/map/map/pager.png
Normal file
BIN
plugins/feature/map/map/pager.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.5 KiB |
@ -38,6 +38,7 @@ const QStringList MapSettings::m_pipeTypes = {
|
|||||||
QStringLiteral("FT8Demod"),
|
QStringLiteral("FT8Demod"),
|
||||||
QStringLiteral("HeatMap"),
|
QStringLiteral("HeatMap"),
|
||||||
QStringLiteral("ILSDemod"),
|
QStringLiteral("ILSDemod"),
|
||||||
|
QStringLiteral("PagerDemod"),
|
||||||
QStringLiteral("Radiosonde"),
|
QStringLiteral("Radiosonde"),
|
||||||
QStringLiteral("StarTracker"),
|
QStringLiteral("StarTracker"),
|
||||||
QStringLiteral("SatelliteTracker"),
|
QStringLiteral("SatelliteTracker"),
|
||||||
@ -55,6 +56,7 @@ const QStringList MapSettings::m_pipeURIs = {
|
|||||||
QStringLiteral("sdrangel.channel.ft8demod"),
|
QStringLiteral("sdrangel.channel.ft8demod"),
|
||||||
QStringLiteral("sdrangel.channel.heatmap"),
|
QStringLiteral("sdrangel.channel.heatmap"),
|
||||||
QStringLiteral("sdrangel.channel.ilsdemod"),
|
QStringLiteral("sdrangel.channel.ilsdemod"),
|
||||||
|
QStringLiteral("sdrangel.channel.pagerdemod"),
|
||||||
QStringLiteral("sdrangel.feature.radiosonde"),
|
QStringLiteral("sdrangel.feature.radiosonde"),
|
||||||
QStringLiteral("sdrangel.feature.startracker"),
|
QStringLiteral("sdrangel.feature.startracker"),
|
||||||
QStringLiteral("sdrangel.feature.satellitetracker"),
|
QStringLiteral("sdrangel.feature.satellitetracker"),
|
||||||
@ -96,6 +98,7 @@ MapSettings::MapSettings() :
|
|||||||
m_itemSettings.insert("StarTracker", new MapItemSettings("StarTracker", true, QColor(230, 230, 230), true, true, 3));
|
m_itemSettings.insert("StarTracker", new MapItemSettings("StarTracker", true, QColor(230, 230, 230), true, true, 3));
|
||||||
m_itemSettings.insert("SatelliteTracker", new MapItemSettings("SatelliteTracker", true, QColor(0, 0, 255), true, false, 0, modelMinPixelSize));
|
m_itemSettings.insert("SatelliteTracker", new MapItemSettings("SatelliteTracker", true, QColor(0, 0, 255), true, false, 0, modelMinPixelSize));
|
||||||
m_itemSettings.insert("Beacons", new MapItemSettings("Beacons", true, QColor(255, 0, 0), false, true, 8));
|
m_itemSettings.insert("Beacons", new MapItemSettings("Beacons", true, QColor(255, 0, 0), false, true, 8));
|
||||||
|
m_itemSettings.insert("PagerDemod", new MapItemSettings("PagerDemod", true, QColor(200, 191, 231), true, false, 11));
|
||||||
m_itemSettings.insert("Radiosonde", new MapItemSettings("Radiosonde", true, QColor(102, 0, 102), true, false, 11, modelMinPixelSize));
|
m_itemSettings.insert("Radiosonde", new MapItemSettings("Radiosonde", true, QColor(102, 0, 102), true, false, 11, modelMinPixelSize));
|
||||||
m_itemSettings.insert("Radio Time Transmitters", new MapItemSettings("Radio Time Transmitters", true, QColor(255, 0, 0), false, true, 8));
|
m_itemSettings.insert("Radio Time Transmitters", new MapItemSettings("Radio Time Transmitters", true, QColor(255, 0, 0), false, true, 8));
|
||||||
m_itemSettings.insert("Radar", new MapItemSettings("Radar", true, QColor(255, 0, 0), false, true, 8));
|
m_itemSettings.insert("Radar", new MapItemSettings("Radar", true, QColor(255, 0, 0), false, true, 8));
|
||||||
|
@ -16,7 +16,8 @@ On top of this, it can plot data from other plugins, such as:
|
|||||||
* Radials and estimated position from the VOR localizer feature,
|
* Radials and estimated position from the VOR localizer feature,
|
||||||
* ILS course line and glide path from the ILS Demodulator,
|
* ILS course line and glide path from the ILS Demodulator,
|
||||||
* DSC geographic call areas,
|
* DSC geographic call areas,
|
||||||
* SID paths.
|
* SID paths,
|
||||||
|
* Pager messages that contain coordinates.
|
||||||
|
|
||||||
As well as internet and built-in data sources:
|
As well as internet and built-in data sources:
|
||||||
|
|
||||||
@ -313,6 +314,7 @@ Mapbox: https://www.mapbox.com/ Cesium: https://www.cesium.com Bing: https://www
|
|||||||
|
|
||||||
Ionosonde data and MUF/coF2 contours from [KC2G](https://prop.kc2g.com/) with source data from [GIRO](https://giro.uml.edu/) and [NOAA NCEI](https://www.ngdc.noaa.gov/stp/iono/ionohome.html).
|
Ionosonde data and MUF/coF2 contours from [KC2G](https://prop.kc2g.com/) with source data from [GIRO](https://giro.uml.edu/) and [NOAA NCEI](https://www.ngdc.noaa.gov/stp/iono/ionohome.html).
|
||||||
|
|
||||||
|
|
||||||
Sea Marks are from OpenSeaMap: https://www.openseamap.org/
|
Sea Marks are from OpenSeaMap: https://www.openseamap.org/
|
||||||
|
|
||||||
Railways are from OpenRailwayMap: https://www.openrailwaymap.org/
|
Railways are from OpenRailwayMap: https://www.openrailwaymap.org/
|
||||||
@ -324,6 +326,7 @@ World icons created by turkkub from Flaticon: https://www.flaticon.com
|
|||||||
Layers and Boat icons created by Freepik from Flaticon: https://www.flaticon.com
|
Layers and Boat icons created by Freepik from Flaticon: https://www.flaticon.com
|
||||||
Railway icons created by Prosymbols Premium from Flaticon: https://www.flaticon.com
|
Railway icons created by Prosymbols Premium from Flaticon: https://www.flaticon.com
|
||||||
Satellite icons created by SyafriStudio from Flaticon: https://www.flaticon.com
|
Satellite icons created by SyafriStudio from Flaticon: https://www.flaticon.com
|
||||||
|
Pager icons created by xnimrodx from Flaticon: https://www.flaticon.com
|
||||||
|
|
||||||
3D models are by various artists under a variety of licenses. See: https://github.com/srcejon/sdrangel-3d-models
|
3D models are by various artists under a variety of licenses. See: https://github.com/srcejon/sdrangel-3d-models
|
||||||
|
|
||||||
|
@ -167,3 +167,11 @@ QHash<QString, int> CSV::readHeader(QTextStream &in, QStringList requiredColumns
|
|||||||
|
|
||||||
return colNumbers;
|
return colNumbers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString CSV::escape(const QString& string)
|
||||||
|
{
|
||||||
|
QString s = string;
|
||||||
|
s.replace('"', "\"\"");
|
||||||
|
s = QString("\"%1\"").arg(s);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
@ -52,6 +52,8 @@ struct SDRBASE_API CSV {
|
|||||||
static bool readRow(QTextStream &in, QStringList *row, char seperator=',');
|
static bool readRow(QTextStream &in, QStringList *row, char seperator=',');
|
||||||
static QHash<QString, int> readHeader(QTextStream &in, QStringList requiredColumns, QString &error, char seperator=',');
|
static QHash<QString, int> readHeader(QTextStream &in, QStringList requiredColumns, QString &error, char seperator=',');
|
||||||
|
|
||||||
|
static QString escape(const QString& string);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* INCLUDE_CSV_H */
|
#endif /* INCLUDE_CSV_H */
|
||||||
|
@ -269,11 +269,15 @@ public:
|
|||||||
// Try to convert a string to latitude and longitude. Returns false if not recognised format.
|
// Try to convert a string to latitude and longitude. Returns false if not recognised format.
|
||||||
// https://en.wikipedia.org/wiki/ISO_6709 specifies a standard syntax
|
// https://en.wikipedia.org/wiki/ISO_6709 specifies a standard syntax
|
||||||
// We support both decimal and DMS formats
|
// We support both decimal and DMS formats
|
||||||
static bool stringToLatitudeAndLongitude(const QString& string, float& latitude, float& longitude)
|
static bool stringToLatitudeAndLongitude(const QString& string, float& latitude, float& longitude, bool exact=true)
|
||||||
{
|
{
|
||||||
QRegularExpressionMatch match;
|
QRegularExpressionMatch match;
|
||||||
|
|
||||||
QRegularExpression decimal(QRegularExpression::anchoredPattern("(-?[0-9]+(\\.[0-9]+)?) *,? *(-?[0-9]+(\\.[0-9]+)?)"));
|
QString decimalPattern = "(-?[0-9]+(\\.[0-9]+)?) *,? *(-?[0-9]+(\\.[0-9]+)?)";
|
||||||
|
if (exact) {
|
||||||
|
decimalPattern = QRegularExpression::anchoredPattern(decimalPattern);
|
||||||
|
}
|
||||||
|
QRegularExpression decimal(decimalPattern);
|
||||||
match = decimal.match(string);
|
match = decimal.match(string);
|
||||||
if (match.hasMatch())
|
if (match.hasMatch())
|
||||||
{
|
{
|
||||||
@ -282,7 +286,11 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
QRegularExpression dms(QRegularExpression::anchoredPattern(QString("([0-9]+)[%1d]([0-9]+)['m]([0-9]+(\\.[0-9]+)?)[\"s]([NS]) *,? *([0-9]+)[%1d]([0-9]+)['m]([0-9]+(\\.[0-9]+)?)[\"s]([EW])").arg(QChar(0xb0))));
|
QString dmsPattern = QString("([0-9]+)[%1d]([0-9]+)['m]([0-9]+(\\.[0-9]+)?)[\"s]([NS]) *,? *([0-9]+)[%1d]([0-9]+)['m]([0-9]+(\\.[0-9]+)?)[\"s]([EW])").arg(QChar(0xb0));
|
||||||
|
if (exact) {
|
||||||
|
dmsPattern = QRegularExpression::anchoredPattern(dmsPattern);
|
||||||
|
}
|
||||||
|
QRegularExpression dms(dmsPattern);
|
||||||
match = dms.match(string);
|
match = dms.match(string);
|
||||||
if (match.hasMatch())
|
if (match.hasMatch())
|
||||||
{
|
{
|
||||||
@ -303,7 +311,11 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
QRegularExpression dms2(QRegularExpression::anchoredPattern(QString("([0-9]+)([NS])([0-9]{2})([0-9]{2}) *,?([0-9]+)([EW])([0-9]{2})([0-9]{2})")));
|
QString dms2Pattern = "([0-9]+)([NS])([0-9]{2})([0-9]{2}) *,?([0-9]+)([EW])([0-9]{2})([0-9]{2})";
|
||||||
|
if (exact) {
|
||||||
|
dms2Pattern = QRegularExpression::anchoredPattern(dms2Pattern);
|
||||||
|
}
|
||||||
|
QRegularExpression dms2(dms2Pattern);
|
||||||
match = dms2.match(string);
|
match = dms2.match(string);
|
||||||
if (match.hasMatch())
|
if (match.hasMatch())
|
||||||
{
|
{
|
||||||
@ -325,7 +337,11 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 512255.5900N 0024400.6105W as used on aviation charts
|
// 512255.5900N 0024400.6105W as used on aviation charts
|
||||||
QRegularExpression dms3(QRegularExpression::anchoredPattern(QString("(\\d{2})(\\d{2})((\\d{2})(\\.\\d+)?)([NS]) *,?(\\d{3})(\\d{2})((\\d{2})(\\.\\d+)?)([EW])")));
|
QString dms3Pattern = "(\\d{2})(\\d{2})((\\d{2})(\\.\\d+)?)([NS]) *,?(\\d{3})(\\d{2})((\\d{2})(\\.\\d+)?)([EW])";
|
||||||
|
if (exact) {
|
||||||
|
dms3Pattern = QRegularExpression::anchoredPattern(dms3Pattern);
|
||||||
|
}
|
||||||
|
QRegularExpression dms3(dms3Pattern);
|
||||||
match = dms3.match(string);
|
match = dms3.match(string);
|
||||||
if (match.hasMatch())
|
if (match.hasMatch())
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user