mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-11-26 01:39:05 -05:00
Merge CSV code in to a single file.
This commit is contained in:
parent
0141639b7a
commit
9f2cb0c29c
@ -42,7 +42,6 @@ if(NOT SERVER_MODE)
|
||||
adsbdemoddisplaydialog.ui
|
||||
adsbdemodnotificationdialog.cpp
|
||||
adsbdemodnotificationdialog.ui
|
||||
csv.cpp
|
||||
airlinelogos.qrc
|
||||
flags.qrc
|
||||
map.qrc
|
||||
@ -56,7 +55,6 @@ if(NOT SERVER_MODE)
|
||||
adsbdemodnotificationdialog.h
|
||||
ourairports.h
|
||||
osndb.h
|
||||
csv.h
|
||||
)
|
||||
|
||||
set(TARGET_NAME demodadsb)
|
||||
|
@ -2127,9 +2127,9 @@ ADSBDemodGUI::ADSBDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseb
|
||||
if (m_airportInfo != nullptr)
|
||||
AirportInformation::readFrequenciesDB(getAirportFrequenciesDBFilename(), m_airportInfo);
|
||||
// Read registration prefix to country map
|
||||
m_prefixMap = csvHash(":/flags/regprefixmap.csv");
|
||||
m_prefixMap = CSV::hash(":/flags/regprefixmap.csv");
|
||||
// Read operator air force to military map
|
||||
m_militaryMap = csvHash(":/flags/militarymap.csv");
|
||||
m_militaryMap = CSV::hash(":/flags/militarymap.csv");
|
||||
|
||||
// Get station position
|
||||
Real stationLatitude = MainCore::instance()->getSettings().getLatitude();
|
||||
@ -2548,30 +2548,14 @@ void ADSBDemodGUI::on_logOpen_clicked()
|
||||
if (file.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
{
|
||||
QTextStream in(&file);
|
||||
QString header = in.readLine();
|
||||
QStringList colNames = header.split(",");
|
||||
int dateCol = colNames.indexOf("Date");
|
||||
int timeCol = colNames.indexOf("Time");
|
||||
int dataCol = colNames.indexOf("Data");
|
||||
int correlationCol = colNames.indexOf("Correlation");
|
||||
if (dateCol == -1)
|
||||
{
|
||||
QMessageBox::critical(this, "ADS-B", QString(".csv file doesn't contain a column named 'Date'"));
|
||||
}
|
||||
else if (timeCol == -1)
|
||||
{
|
||||
QMessageBox::critical(this, "ADS-B", QString(".csv file doesn't contain a column named 'Time'"));
|
||||
}
|
||||
else if (dataCol == -1)
|
||||
{
|
||||
QMessageBox::critical(this, "ADS-B", QString(".csv file doesn't contain a column named 'Data'"));
|
||||
}
|
||||
else if (correlationCol == -1)
|
||||
{
|
||||
QMessageBox::critical(this, "ADS-B", QString(".csv file doesn't contain a column named 'Correlation'"));
|
||||
}
|
||||
else
|
||||
QString error;
|
||||
QHash<QString, int> colIndexes = CSV::readHeader(in, {"Data", "Correlation"}, error);
|
||||
if (error.isEmpty())
|
||||
{
|
||||
int dataCol = colIndexes.value("Data");
|
||||
int correlationCol = colIndexes.value("Correlation");
|
||||
int maxCol = std::max(dataCol, correlationCol);
|
||||
|
||||
QMessageBox dialog(this);
|
||||
dialog.setText("Reading ADS-B data");
|
||||
dialog.addButton(QMessageBox::Cancel);
|
||||
@ -2579,15 +2563,11 @@ void ADSBDemodGUI::on_logOpen_clicked()
|
||||
QApplication::processEvents();
|
||||
int count = 0;
|
||||
bool cancelled = false;
|
||||
while (!in.atEnd() && !cancelled)
|
||||
QStringList cols;
|
||||
while (!cancelled && CSV::readRow(in, &cols))
|
||||
{
|
||||
QString row = in.readLine();
|
||||
QStringList cols = row.split(",");
|
||||
if (cols.size() >= dataCol)
|
||||
if (cols.size() > maxCol)
|
||||
{
|
||||
//QDate date = QDate::fromString(cols[dateCol]);
|
||||
//QTime time = QTime::fromString(cols[timeCol]);
|
||||
//QDateTime dateTime(date, time);
|
||||
QDateTime dateTime = QDateTime::currentDateTime(); // So they aren't removed immediately as too old
|
||||
QByteArray bytes = QByteArray::fromHex(cols[dataCol].toLatin1());
|
||||
float correlation = cols[correlationCol].toFloat();
|
||||
@ -2604,6 +2584,10 @@ void ADSBDemodGUI::on_logOpen_clicked()
|
||||
}
|
||||
dialog.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::critical(this, "ADS-B", error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1,69 +0,0 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2020 Jon Beniston, M7RCE //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation as version 3 of the License, or //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// This program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License V3 for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "csv.h"
|
||||
|
||||
#include <QString>
|
||||
#include <QFile>
|
||||
#include <QByteArray>
|
||||
#include <QHash>
|
||||
#include <QList>
|
||||
#include <QDebug>
|
||||
|
||||
// Create a hash map from a CSV file with two columns
|
||||
QHash<QString, QString> *csvHash(const QString& filename, int reserve)
|
||||
{
|
||||
int cnt = 0;
|
||||
QHash<QString, QString> *map = nullptr;
|
||||
|
||||
qDebug() << "csvHash: " << filename;
|
||||
|
||||
QFile file(filename);
|
||||
if (file.open(QIODevice::ReadOnly))
|
||||
{
|
||||
// Read header
|
||||
if (!file.atEnd())
|
||||
{
|
||||
QByteArray row = file.readLine().trimmed();
|
||||
if (row.split(',').size() == 2)
|
||||
{
|
||||
map = new QHash<QString, QString>();
|
||||
if (reserve > 0)
|
||||
map->reserve(reserve);
|
||||
// Read data
|
||||
while (!file.atEnd())
|
||||
{
|
||||
row = file.readLine().trimmed();
|
||||
QList<QByteArray> cols = row.split(',');
|
||||
map->insert(QString(cols[0]), QString(cols[1]));
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
else
|
||||
qDebug() << "csvHash: Unexpected header";
|
||||
}
|
||||
else
|
||||
qDebug() << "csvHash: Empty file";
|
||||
file.close();
|
||||
}
|
||||
else
|
||||
qDebug() << "csvHash: Failed to open " << filename;
|
||||
|
||||
qDebug() << "csvHash: " << filename << ": read " << cnt << " entries";
|
||||
|
||||
return map;
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2020 Jon Beniston, M7RCE //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation as version 3 of the License, or //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// This program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License V3 for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef INCLUDE_CSV_H
|
||||
#define INCLUDE_CSV_H
|
||||
|
||||
#include <QString>
|
||||
#include <QHash>
|
||||
|
||||
// Extract string from CSV line, updating pp to next column
|
||||
static inline char *csvNext(char **pp, char delimiter=',')
|
||||
{
|
||||
char *p = *pp;
|
||||
|
||||
if (p[0] == '\0')
|
||||
return nullptr;
|
||||
|
||||
char *start = p;
|
||||
|
||||
while ((*p != delimiter) && (*p != '\n'))
|
||||
p++;
|
||||
*p++ = '\0';
|
||||
*pp = p;
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
QHash<QString, QString> *csvHash(const QString& filename, int reserve=0);
|
||||
|
||||
#endif /* INCLUDE_CSV_H */
|
@ -28,7 +28,7 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "csv.h"
|
||||
#include "util/csv.h"
|
||||
|
||||
#define OSNDB_URL "https://opensky-network.org/datasets/metadata/aircraftDatabase.csv"
|
||||
|
||||
|
@ -28,7 +28,7 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "csv.h"
|
||||
#include "util/csv.h"
|
||||
#include "adsbdemodsettings.h"
|
||||
|
||||
#define AIRPORTS_URL "https://ourairports.com/data/airports.csv"
|
||||
|
@ -173,7 +173,7 @@ Click to specify the name of the .csv file which received ADS-B frames are logge
|
||||
|
||||
<h3>Read Data from .csv File</h3>
|
||||
|
||||
Click to specify a previously written ADS-B .csv log file, which is read and used to updated the ADS-B data table and map.
|
||||
Click to specify a previously written ADS-B .csv log file, which is read and used to update the ADS-B data table and map.
|
||||
|
||||
<h3>14: Refresh list of devices</h3>
|
||||
|
||||
|
@ -179,6 +179,25 @@ bool AISDemod::handleMessage(const Message& cmd)
|
||||
}
|
||||
}
|
||||
|
||||
// Write to log file
|
||||
if (m_logFile.isOpen())
|
||||
{
|
||||
AISMessage *ais;
|
||||
|
||||
// Decode the message
|
||||
ais = AISMessage::decode(report.getMessage());
|
||||
|
||||
m_logStream << report.getDateTime().date().toString() << ","
|
||||
<< report.getDateTime().time().toString() << ","
|
||||
<< report.getMessage().toHex() << ","
|
||||
<< QString("%1").arg(ais->m_mmsi, 9, 10, QChar('0')) << ","
|
||||
<< ais->getType() << ","
|
||||
<< "\"" << ais->toString() << "\"" << ","
|
||||
<< "\"" << ais->toNMEA() << "\"" << "\n";
|
||||
|
||||
delete ais;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (MainCore::MsgChannelDemodQuery::match(cmd))
|
||||
@ -202,6 +221,8 @@ ScopeVis *AISDemod::getScopeSink()
|
||||
void AISDemod::applySettings(const AISDemodSettings& settings, bool force)
|
||||
{
|
||||
qDebug() << "AISDemod::applySettings:"
|
||||
<< " m_logEnabled: " << settings.m_logEnabled
|
||||
<< " m_logFilename: " << settings.m_logFilename
|
||||
<< " m_streamIndex: " << settings.m_streamIndex
|
||||
<< " m_useReverseAPI: " << settings.m_useReverseAPI
|
||||
<< " m_reverseAPIAddress: " << settings.m_reverseAPIAddress
|
||||
@ -236,6 +257,12 @@ void AISDemod::applySettings(const AISDemodSettings& settings, bool force)
|
||||
if ((settings.m_udpFormat != m_settings.m_udpFormat) || force) {
|
||||
reverseAPIKeys.append("udpFormat");
|
||||
}
|
||||
if ((settings.m_logFilename != m_settings.m_logFilename) || force) {
|
||||
reverseAPIKeys.append("logFilename");
|
||||
}
|
||||
if ((settings.m_logEnabled != m_settings.m_logEnabled) || force) {
|
||||
reverseAPIKeys.append("logEnabled");
|
||||
}
|
||||
if (m_settings.m_streamIndex != settings.m_streamIndex)
|
||||
{
|
||||
if (m_deviceAPI->getSampleMIMO()) // change of stream is possible for MIMO devices only
|
||||
@ -262,6 +289,36 @@ void AISDemod::applySettings(const AISDemodSettings& settings, bool force)
|
||||
webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
|
||||
}
|
||||
|
||||
if ((settings.m_logEnabled != m_settings.m_logEnabled)
|
||||
|| (settings.m_logFilename != m_settings.m_logFilename)
|
||||
|| force)
|
||||
{
|
||||
if (m_logFile.isOpen())
|
||||
{
|
||||
m_logStream.flush();
|
||||
m_logFile.close();
|
||||
}
|
||||
if (settings.m_logEnabled && !settings.m_logFilename.isEmpty())
|
||||
{
|
||||
m_logFile.setFileName(settings.m_logFilename);
|
||||
if (m_logFile.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text))
|
||||
{
|
||||
qDebug() << "AISDemod::applySettings - Logging to: " << settings.m_logFilename;
|
||||
bool newFile = m_logFile.size() == 0;
|
||||
m_logStream.setDevice(&m_logFile);
|
||||
if (newFile)
|
||||
{
|
||||
// Write header
|
||||
m_logStream << "Date,Time,Data,MMSI,Type,Message,NMEA\n";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "AISDemod::applySettings - Unable to open log file: " << settings.m_logFilename;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_settings = settings;
|
||||
}
|
||||
|
||||
@ -371,6 +428,12 @@ void AISDemod::webapiUpdateChannelSettings(
|
||||
if (channelSettingsKeys.contains("udpFormat")) {
|
||||
settings.m_udpFormat = (AISDemodSettings::UDPFormat)response.getAisDemodSettings()->getUdpFormat();
|
||||
}
|
||||
if (channelSettingsKeys.contains("logFilename")) {
|
||||
settings.m_logFilename = *response.getAisDemodSettings()->getLogFilename();
|
||||
}
|
||||
if (channelSettingsKeys.contains("logEnabled")) {
|
||||
settings.m_logEnabled = response.getAisDemodSettings()->getLogEnabled();
|
||||
}
|
||||
if (channelSettingsKeys.contains("rgbColor")) {
|
||||
settings.m_rgbColor = response.getAisDemodSettings()->getRgbColor();
|
||||
}
|
||||
@ -407,6 +470,8 @@ void AISDemod::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& resp
|
||||
response.getAisDemodSettings()->setUdpAddress(new QString(settings.m_udpAddress));
|
||||
response.getAisDemodSettings()->setUdpPort(settings.m_udpPort);
|
||||
response.getAisDemodSettings()->setUdpFormat((int)settings.m_udpFormat);
|
||||
response.getAisDemodSettings()->setLogFilename(new QString(settings.m_logFilename));
|
||||
response.getAisDemodSettings()->setLogEnabled(settings.m_logEnabled);
|
||||
|
||||
response.getAisDemodSettings()->setRgbColor(settings.m_rgbColor);
|
||||
if (response.getAisDemodSettings()->getTitle()) {
|
||||
@ -494,6 +559,12 @@ void AISDemod::webapiFormatChannelSettings(
|
||||
if (channelSettingsKeys.contains("udpFormat") || force) {
|
||||
swgAISDemodSettings->setUdpPort((int)settings.m_udpFormat);
|
||||
}
|
||||
if (channelSettingsKeys.contains("logFilename") || force) {
|
||||
swgAISDemodSettings->setLogFilename(new QString(settings.m_logFilename));
|
||||
}
|
||||
if (channelSettingsKeys.contains("logEnabled") || force) {
|
||||
swgAISDemodSettings->setLogEnabled(settings.m_logEnabled);
|
||||
}
|
||||
if (channelSettingsKeys.contains("rgbColor") || force) {
|
||||
swgAISDemodSettings->setRgbColor(settings.m_rgbColor);
|
||||
}
|
||||
|
@ -25,6 +25,8 @@
|
||||
#include <QUdpSocket>
|
||||
#include <QThread>
|
||||
#include <QDateTime>
|
||||
#include <QFile>
|
||||
#include <QTextStream>
|
||||
|
||||
#include "dsp/basebandsamplesink.h"
|
||||
#include "channel/channelapi.h"
|
||||
@ -160,6 +162,8 @@ private:
|
||||
int m_basebandSampleRate; //!< stored from device message used when starting baseband sink
|
||||
qint64 m_centerFrequency;
|
||||
QUdpSocket m_udpSocket;
|
||||
QFile m_logFile;
|
||||
QTextStream m_logStream;
|
||||
|
||||
QNetworkAccessManager *m_networkManager;
|
||||
QNetworkRequest m_networkRequest;
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <QAction>
|
||||
#include <QRegExp>
|
||||
#include <QClipboard>
|
||||
#include <QFileDialog>
|
||||
|
||||
#include "aisdemodgui.h"
|
||||
|
||||
@ -36,6 +37,7 @@
|
||||
#include "plugin/pluginapi.h"
|
||||
#include "util/simpleserializer.h"
|
||||
#include "util/ais.h"
|
||||
#include "util/csv.h"
|
||||
#include "util/db.h"
|
||||
#include "gui/basicchannelsettingsdialog.h"
|
||||
#include "gui/devicestreamselectiondialog.h"
|
||||
@ -49,8 +51,6 @@
|
||||
#include "aisdemod.h"
|
||||
#include "aisdemodsink.h"
|
||||
|
||||
#include "SWGMapItem.h"
|
||||
|
||||
void AISDemodGUI::resizeTable()
|
||||
{
|
||||
// Fill table with a row of dummy data that will size the columns nicely
|
||||
@ -150,12 +150,12 @@ bool AISDemodGUI::deserialize(const QByteArray& data)
|
||||
}
|
||||
|
||||
// Add row to table
|
||||
void AISDemodGUI::messageReceived(const AISDemod::MsgMessage& message)
|
||||
void AISDemodGUI::messageReceived(const QByteArray& message, const QDateTime& dateTime)
|
||||
{
|
||||
AISMessage *ais;
|
||||
|
||||
// Decode the message
|
||||
ais = AISMessage::decode(message.getMessage());
|
||||
ais = AISMessage::decode(message);
|
||||
|
||||
// Add to messages table
|
||||
ui->messages->setSortingEnabled(false);
|
||||
@ -176,8 +176,8 @@ void AISDemodGUI::messageReceived(const AISDemod::MsgMessage& message)
|
||||
ui->messages->setItem(row, MESSAGE_COL_DATA, dataItem);
|
||||
ui->messages->setItem(row, MESSAGE_COL_NMEA, nmeaItem);
|
||||
ui->messages->setItem(row, MESSAGE_COL_HEX, hexItem);
|
||||
dateItem->setText(message.getDateTime().date().toString());
|
||||
timeItem->setText(message.getDateTime().time().toString());
|
||||
dateItem->setText(dateTime.date().toString());
|
||||
timeItem->setText(dateTime.time().toString());
|
||||
mmsiItem->setText(QString("%1").arg(ais->m_mmsi, 9, 10, QChar('0')));
|
||||
typeItem->setText(ais->getType());
|
||||
dataItem->setText(ais->toString());
|
||||
@ -186,6 +186,8 @@ void AISDemodGUI::messageReceived(const AISDemod::MsgMessage& message)
|
||||
ui->messages->setSortingEnabled(true);
|
||||
ui->messages->scrollToItem(dateItem); // Will only scroll if not hidden
|
||||
filterRow(row);
|
||||
|
||||
delete ais;
|
||||
}
|
||||
|
||||
bool AISDemodGUI::handleMessage(const Message& message)
|
||||
@ -203,7 +205,7 @@ bool AISDemodGUI::handleMessage(const Message& message)
|
||||
else if (AISDemod::MsgMessage::match(message))
|
||||
{
|
||||
AISDemod::MsgMessage& report = (AISDemod::MsgMessage&) message;
|
||||
messageReceived(report);
|
||||
messageReceived(report.getMessage(), report.getDateTime());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -579,6 +581,9 @@ void AISDemodGUI::displaySettings()
|
||||
ui->channel1->setCurrentIndex(m_settings.m_scopeCh1);
|
||||
ui->channel2->setCurrentIndex(m_settings.m_scopeCh2);
|
||||
|
||||
ui->logFilename->setToolTip(QString(".csv log filename: %1").arg(m_settings.m_logFilename));
|
||||
ui->logEnable->setChecked(m_settings.m_logEnabled);
|
||||
|
||||
// Order and size columns
|
||||
QHeaderView *header = ui->messages->horizontalHeader();
|
||||
for (int i = 0; i < AISDEMOD_MESSAGE_COLUMNS; i++)
|
||||
@ -633,3 +638,108 @@ void AISDemodGUI::tick()
|
||||
|
||||
m_tickCount++;
|
||||
}
|
||||
|
||||
void AISDemodGUI::on_logEnable_clicked(bool checked)
|
||||
{
|
||||
m_settings.m_logEnabled = checked;
|
||||
applySettings();
|
||||
}
|
||||
|
||||
void AISDemodGUI::on_logFilename_clicked()
|
||||
{
|
||||
// Get filename to save to
|
||||
QFileDialog fileDialog(nullptr, "Select file to log received frames to", "", "*.csv");
|
||||
fileDialog.setAcceptMode(QFileDialog::AcceptSave);
|
||||
if (fileDialog.exec())
|
||||
{
|
||||
QStringList fileNames = fileDialog.selectedFiles();
|
||||
if (fileNames.size() > 0)
|
||||
{
|
||||
m_settings.m_logFilename = fileNames[0];
|
||||
ui->logFilename->setToolTip(QString(".csv log filename: %1").arg(m_settings.m_logFilename));
|
||||
applySettings();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Read .csv log and process as received frames
|
||||
void AISDemodGUI::on_logOpen_clicked()
|
||||
{
|
||||
QFileDialog fileDialog(nullptr, "Select .csv log file to read", "", "*.csv");
|
||||
if (fileDialog.exec())
|
||||
{
|
||||
QStringList fileNames = fileDialog.selectedFiles();
|
||||
if (fileNames.size() > 0)
|
||||
{
|
||||
QFile file(fileNames[0]);
|
||||
if (file.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
{
|
||||
QTextStream in(&file);
|
||||
QString error;
|
||||
QHash<QString, int> colIndexes = CSV::readHeader(in, {"Date", "Time", "Data"}, error);
|
||||
if (error.isEmpty())
|
||||
{
|
||||
int dateCol = colIndexes.value("Date");
|
||||
int timeCol = colIndexes.value("Time");
|
||||
int dataCol = colIndexes.value("Data");
|
||||
int maxCol = std::max({dateCol, timeCol, dataCol});
|
||||
|
||||
QMessageBox dialog(this);
|
||||
dialog.setText("Reading messages");
|
||||
dialog.addButton(QMessageBox::Cancel);
|
||||
dialog.show();
|
||||
QApplication::processEvents();
|
||||
int count = 0;
|
||||
bool cancelled = false;
|
||||
QStringList cols;
|
||||
|
||||
MessagePipes& messagePipes = MainCore::instance()->getMessagePipes();
|
||||
QList<MessageQueue*> *aisMessageQueues = messagePipes.getMessageQueues(m_aisDemod, "ais");
|
||||
|
||||
while (!cancelled && CSV::readRow(in, &cols))
|
||||
{
|
||||
if (cols.size() > maxCol)
|
||||
{
|
||||
QDate date = QDate::fromString(cols[dateCol]);
|
||||
QTime time = QTime::fromString(cols[timeCol]);
|
||||
QDateTime dateTime(date, time);
|
||||
QByteArray bytes = QByteArray::fromHex(cols[dataCol].toLatin1());
|
||||
|
||||
// Add to table
|
||||
messageReceived(bytes, dateTime);
|
||||
|
||||
// Forward to AIS feature
|
||||
if (aisMessageQueues)
|
||||
{
|
||||
QList<MessageQueue*>::iterator it = aisMessageQueues->begin();
|
||||
for (; it != aisMessageQueues->end(); ++it)
|
||||
{
|
||||
MainCore::MsgPacket *msg = MainCore::MsgPacket::create(m_aisDemod, bytes, dateTime);
|
||||
(*it)->push(msg);
|
||||
}
|
||||
}
|
||||
|
||||
if (count % 1000 == 0)
|
||||
{
|
||||
QApplication::processEvents();
|
||||
if (dialog.clickedButton()) {
|
||||
cancelled = true;
|
||||
}
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
dialog.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::critical(this, "AIS Demod", error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::critical(this, "AIS Demod", QString("Failed to open file %1").arg(fileNames[0]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -85,7 +85,7 @@ private:
|
||||
void applySettings(bool force = false);
|
||||
void displaySettings();
|
||||
void displayStreamIndex();
|
||||
void messageReceived(const AISDemod::MsgMessage& message);
|
||||
void messageReceived(const QByteArray& message, const QDateTime& dateTime);
|
||||
bool handleMessage(const Message& message);
|
||||
|
||||
void leaveEvent(QEvent*);
|
||||
@ -118,6 +118,9 @@ private slots:
|
||||
void on_channel1_currentIndexChanged(int index);
|
||||
void on_channel2_currentIndexChanged(int index);
|
||||
void on_messages_cellDoubleClicked(int row, int column);
|
||||
void on_logEnable_clicked(bool checked=false);
|
||||
void on_logFilename_clicked();
|
||||
void on_logOpen_clicked();
|
||||
void filterRow(int row);
|
||||
void filter();
|
||||
void messages_sectionMoved(int logicalIndex, int oldVisualIndex, int newVisualIndex);
|
||||
|
@ -560,6 +560,60 @@
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="ButtonSwitch" name="logEnable">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>24</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Start/stop logging of received messages to .csv file</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../sdrgui/resources/res.qrc">
|
||||
<normaloff>:/record_off.png</normaloff>:/record_off.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="logFilename">
|
||||
<property name="toolTip">
|
||||
<string>Set log .csv filename</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../sdrgui/resources/res.qrc">
|
||||
<normaloff>:/save.png</normaloff>:/save.png</iconset>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="logOpen">
|
||||
<property name="toolTip">
|
||||
<string>Read data from .csv log file</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../sdrgui/resources/res.qrc">
|
||||
<normaloff>:/load.png</normaloff>:/load.png</iconset>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="clearTable">
|
||||
<property name="toolTip">
|
||||
@ -878,6 +932,11 @@
|
||||
<header>gui/levelmeter.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>ButtonSwitch</class>
|
||||
<extends>QToolButton</extends>
|
||||
<header>gui/buttonswitch.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>GLScope</class>
|
||||
<extends>QWidget</extends>
|
||||
@ -893,6 +952,7 @@
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="../../../sdrgui/resources/res.qrc"/>
|
||||
<include location="../demodadsb/icons.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
@ -44,6 +44,8 @@ void AISDemodSettings::resetToDefaults()
|
||||
m_udpFormat = Binary;
|
||||
m_scopeCh1 = 5;
|
||||
m_scopeCh2 = 6;
|
||||
m_logFilename = "ais_log.csv";
|
||||
m_logEnabled = false;
|
||||
m_rgbColor = QColor(102, 0, 0).rgb();
|
||||
m_title = "AIS Demodulator";
|
||||
m_streamIndex = 0;
|
||||
@ -88,6 +90,9 @@ QByteArray AISDemodSettings::serialize() const
|
||||
s.writeU32(20, m_reverseAPIChannelIndex);
|
||||
s.writeBlob(21, m_scopeGUI->serialize());
|
||||
|
||||
s.writeString(22, m_logFilename);
|
||||
s.writeBool(23, m_logEnabled);
|
||||
|
||||
for (int i = 0; i < AISDEMOD_MESSAGE_COLUMNS; i++)
|
||||
s.writeS32(100 + i, m_messageColumnIndexes[i]);
|
||||
for (int i = 0; i < AISDEMOD_MESSAGE_COLUMNS; i++)
|
||||
@ -154,6 +159,9 @@ bool AISDemodSettings::deserialize(const QByteArray& data)
|
||||
m_scopeGUI->deserialize(bytetmp);
|
||||
}
|
||||
|
||||
d.readString(22, &m_logFilename, "ais_log.csv");
|
||||
d.readBool(23, &m_logEnabled, false);
|
||||
|
||||
for (int i = 0; i < AISDEMOD_MESSAGE_COLUMNS; i++)
|
||||
d.readS32(100 + i, &m_messageColumnIndexes[i], i);
|
||||
for (int i = 0; i < AISDEMOD_MESSAGE_COLUMNS; i++)
|
||||
|
@ -47,6 +47,9 @@ struct AISDemodSettings
|
||||
int m_scopeCh1;
|
||||
int m_scopeCh2;
|
||||
|
||||
QString m_logFilename;
|
||||
bool m_logEnabled;
|
||||
|
||||
quint32 m_rgbColor;
|
||||
QString m_title;
|
||||
Serializable *m_channelMarker;
|
||||
|
@ -68,6 +68,18 @@ UDP port number to forward received messages to.
|
||||
|
||||
The format the messages are forwared via UDP in. This can be either binary (which is useful for SDRangel's PERTester feature) or NMEA (which is useful for 3rd party applications such as OpenCPN).
|
||||
|
||||
<h3>13: Start/stop Logging Messages to .csv File</h3>
|
||||
|
||||
When checked, writes all received AIS messages to a .csv file.
|
||||
|
||||
<h3>14: .csv Log Filename</h3>
|
||||
|
||||
Click to specify the name of the .csv file which received AIS messages are logged to.
|
||||
|
||||
<h3>15: Read Data from .csv File</h3>
|
||||
|
||||
Click to specify a previously written AIS .csv log file, which is read and used to update the table.
|
||||
|
||||
<h3>Received Messages Table</h3>
|
||||
|
||||
The received messages table displays information about each AIS message received. Only messages with valid CRCs are displayed.
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "dsp/dspcommands.h"
|
||||
#include "device/deviceapi.h"
|
||||
#include "feature/feature.h"
|
||||
#include "util/ax25.h"
|
||||
#include "util/db.h"
|
||||
#include "maincore.h"
|
||||
|
||||
@ -176,6 +177,32 @@ bool PacketDemod::handleMessage(const Message& cmd)
|
||||
QHostAddress(m_settings.m_udpAddress), m_settings.m_udpPort);
|
||||
}
|
||||
|
||||
// Write to log file
|
||||
if (m_logFile.isOpen())
|
||||
{
|
||||
AX25Packet ax25;
|
||||
|
||||
if (ax25.decode(report.getPacket()))
|
||||
{
|
||||
m_logStream << report.getDateTime().date().toString() << ","
|
||||
<< report.getDateTime().time().toString() << ","
|
||||
<< report.getPacket().toHex() << ","
|
||||
<< "\"" << ax25.m_from << "\","
|
||||
<< "\"" << ax25.m_to << "\","
|
||||
<< "\"" << ax25.m_via << "\","
|
||||
<< ax25.m_type << ","
|
||||
<< ax25.m_pid << ","
|
||||
<< "\"" << ax25.m_dataASCII << "\","
|
||||
<< "\"" << ax25.m_dataHex << "\"\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
m_logStream << report.getDateTime().date().toString() << ","
|
||||
<< report.getDateTime().time().toString() << ","
|
||||
<< report.getPacket().toHex() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (MainCore::MsgChannelDemodQuery::match(cmd))
|
||||
@ -194,6 +221,8 @@ bool PacketDemod::handleMessage(const Message& cmd)
|
||||
void PacketDemod::applySettings(const PacketDemodSettings& settings, bool force)
|
||||
{
|
||||
qDebug() << "PacketDemod::applySettings:"
|
||||
<< " m_logEnabled: " << settings.m_logEnabled
|
||||
<< " m_logFilename: " << settings.m_logFilename
|
||||
<< " m_streamIndex: " << settings.m_streamIndex
|
||||
<< " m_useReverseAPI: " << settings.m_useReverseAPI
|
||||
<< " m_reverseAPIAddress: " << settings.m_reverseAPIAddress
|
||||
@ -222,6 +251,12 @@ void PacketDemod::applySettings(const PacketDemodSettings& settings, bool force)
|
||||
if ((settings.m_udpPort != m_settings.m_udpPort) || force) {
|
||||
reverseAPIKeys.append("udpPort");
|
||||
}
|
||||
if ((settings.m_logFilename != m_settings.m_logFilename) || force) {
|
||||
reverseAPIKeys.append("logFilename");
|
||||
}
|
||||
if ((settings.m_logEnabled != m_settings.m_logEnabled) || force) {
|
||||
reverseAPIKeys.append("logEnabled");
|
||||
}
|
||||
if (m_settings.m_streamIndex != settings.m_streamIndex)
|
||||
{
|
||||
if (m_deviceAPI->getSampleMIMO()) // change of stream is possible for MIMO devices only
|
||||
@ -248,6 +283,36 @@ void PacketDemod::applySettings(const PacketDemodSettings& settings, bool force)
|
||||
webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
|
||||
}
|
||||
|
||||
if ((settings.m_logEnabled != m_settings.m_logEnabled)
|
||||
|| (settings.m_logFilename != m_settings.m_logFilename)
|
||||
|| force)
|
||||
{
|
||||
if (m_logFile.isOpen())
|
||||
{
|
||||
m_logStream.flush();
|
||||
m_logFile.close();
|
||||
}
|
||||
if (settings.m_logEnabled && !settings.m_logFilename.isEmpty())
|
||||
{
|
||||
m_logFile.setFileName(settings.m_logFilename);
|
||||
if (m_logFile.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text))
|
||||
{
|
||||
qDebug() << "PacketDemod::applySettings - Logging to: " << settings.m_logFilename;
|
||||
bool newFile = m_logFile.size() == 0;
|
||||
m_logStream.setDevice(&m_logFile);
|
||||
if (newFile)
|
||||
{
|
||||
// Write header
|
||||
m_logStream << "Date,Time,Data,From,To,Via,Type,PID,Data ASCII,Data Hex\n";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "PacketDemod::applySettings - Unable to open log file: " << settings.m_logFilename;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_settings = settings;
|
||||
}
|
||||
|
||||
@ -351,6 +416,12 @@ void PacketDemod::webapiUpdateChannelSettings(
|
||||
if (channelSettingsKeys.contains("udpPort")) {
|
||||
settings.m_udpPort = response.getPacketDemodSettings()->getUdpPort();
|
||||
}
|
||||
if (channelSettingsKeys.contains("logFilename")) {
|
||||
settings.m_logFilename = *response.getAdsbDemodSettings()->getLogFilename();
|
||||
}
|
||||
if (channelSettingsKeys.contains("logEnabled")) {
|
||||
settings.m_logEnabled = response.getAdsbDemodSettings()->getLogEnabled();
|
||||
}
|
||||
if (channelSettingsKeys.contains("rgbColor")) {
|
||||
settings.m_rgbColor = response.getPacketDemodSettings()->getRgbColor();
|
||||
}
|
||||
@ -385,6 +456,8 @@ void PacketDemod::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& r
|
||||
response.getPacketDemodSettings()->setUdpEnabled(settings.m_udpEnabled);
|
||||
response.getPacketDemodSettings()->setUdpAddress(new QString(settings.m_udpAddress));
|
||||
response.getPacketDemodSettings()->setUdpPort(settings.m_udpPort);
|
||||
response.getPacketDemodSettings()->setLogFilename(new QString(settings.m_logFilename));
|
||||
response.getPacketDemodSettings()->setLogEnabled(settings.m_logEnabled);
|
||||
|
||||
response.getPacketDemodSettings()->setRgbColor(settings.m_rgbColor);
|
||||
if (response.getPacketDemodSettings()->getTitle()) {
|
||||
@ -466,6 +539,12 @@ void PacketDemod::webapiFormatChannelSettings(
|
||||
if (channelSettingsKeys.contains("udpPort") || force) {
|
||||
swgPacketDemodSettings->setUdpPort(settings.m_udpPort);
|
||||
}
|
||||
if (channelSettingsKeys.contains("logFilename") || force) {
|
||||
swgPacketDemodSettings->setLogFilename(new QString(settings.m_logFilename));
|
||||
}
|
||||
if (channelSettingsKeys.contains("logEnabled") || force) {
|
||||
swgPacketDemodSettings->setLogEnabled(settings.m_logEnabled);
|
||||
}
|
||||
if (channelSettingsKeys.contains("rgbColor") || force) {
|
||||
swgPacketDemodSettings->setRgbColor(settings.m_rgbColor);
|
||||
}
|
||||
|
@ -24,6 +24,8 @@
|
||||
#include <QNetworkRequest>
|
||||
#include <QUdpSocket>
|
||||
#include <QThread>
|
||||
#include <QFile>
|
||||
#include <QTextStream>
|
||||
|
||||
#include "dsp/basebandsamplesink.h"
|
||||
#include "channel/channelapi.h"
|
||||
@ -133,6 +135,8 @@ private:
|
||||
int m_basebandSampleRate; //!< stored from device message used when starting baseband sink
|
||||
qint64 m_centerFrequency;
|
||||
QUdpSocket m_udpSocket;
|
||||
QFile m_logFile;
|
||||
QTextStream m_logStream;
|
||||
|
||||
QNetworkAccessManager *m_networkManager;
|
||||
QNetworkRequest m_networkRequest;
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <QMessageBox>
|
||||
#include <QAction>
|
||||
#include <QRegExp>
|
||||
#include <QFileDialog>
|
||||
|
||||
#include "packetdemodgui.h"
|
||||
#include "util/ax25.h"
|
||||
@ -34,6 +35,7 @@
|
||||
#include "ui_packetdemodgui.h"
|
||||
#include "plugin/pluginapi.h"
|
||||
#include "util/simpleserializer.h"
|
||||
#include "util/csv.h"
|
||||
#include "util/db.h"
|
||||
#include "util/morse.h"
|
||||
#include "util/units.h"
|
||||
@ -521,6 +523,9 @@ void PacketDemodGUI::displaySettings()
|
||||
ui->udpAddress->setText(m_settings.m_udpAddress);
|
||||
ui->udpPort->setText(QString::number(m_settings.m_udpPort));
|
||||
|
||||
ui->logFilename->setToolTip(QString(".csv log filename: %1").arg(m_settings.m_logFilename));
|
||||
ui->logEnable->setChecked(m_settings.m_logEnabled);
|
||||
|
||||
// Order and size columns
|
||||
QHeaderView *header = ui->packets->horizontalHeader();
|
||||
for (int i = 0; i < PACKETDEMOD_COLUMNS; i++)
|
||||
@ -576,3 +581,90 @@ void PacketDemodGUI::tick()
|
||||
|
||||
m_tickCount++;
|
||||
}
|
||||
|
||||
void PacketDemodGUI::on_logEnable_clicked(bool checked)
|
||||
{
|
||||
m_settings.m_logEnabled = checked;
|
||||
applySettings();
|
||||
}
|
||||
|
||||
void PacketDemodGUI::on_logFilename_clicked()
|
||||
{
|
||||
// Get filename to save to
|
||||
QFileDialog fileDialog(nullptr, "Select file to log received frames to", "", "*.csv");
|
||||
fileDialog.setAcceptMode(QFileDialog::AcceptSave);
|
||||
if (fileDialog.exec())
|
||||
{
|
||||
QStringList fileNames = fileDialog.selectedFiles();
|
||||
if (fileNames.size() > 0)
|
||||
{
|
||||
m_settings.m_logFilename = fileNames[0];
|
||||
ui->logFilename->setToolTip(QString(".csv log filename: %1").arg(m_settings.m_logFilename));
|
||||
applySettings();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Read .csv log and process as received frames
|
||||
void PacketDemodGUI::on_logOpen_clicked()
|
||||
{
|
||||
QFileDialog fileDialog(nullptr, "Select .csv log file to read", "", "*.csv");
|
||||
if (fileDialog.exec())
|
||||
{
|
||||
QStringList fileNames = fileDialog.selectedFiles();
|
||||
if (fileNames.size() > 0)
|
||||
{
|
||||
QFile file(fileNames[0]);
|
||||
if (file.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
{
|
||||
QTextStream in(&file);
|
||||
QString error;
|
||||
QHash<QString, int> colIndexes = CSV::readHeader(in, {"Date", "Time", "Data"}, error);
|
||||
if (error.isEmpty())
|
||||
{
|
||||
int dateCol = colIndexes.value("Date");
|
||||
int timeCol = colIndexes.value("Time");
|
||||
int dataCol = colIndexes.value("Data");
|
||||
int maxCol = std::max({dateCol, timeCol, dataCol});
|
||||
|
||||
QMessageBox dialog(this);
|
||||
dialog.setText("Reading packet data");
|
||||
dialog.addButton(QMessageBox::Cancel);
|
||||
dialog.show();
|
||||
QApplication::processEvents();
|
||||
int count = 0;
|
||||
bool cancelled = false;
|
||||
QStringList cols;
|
||||
while (!cancelled && CSV::readRow(in, &cols))
|
||||
{
|
||||
if (cols.size() > maxCol)
|
||||
{
|
||||
QDate date = QDate::fromString(cols[dateCol]);
|
||||
QTime time = QTime::fromString(cols[timeCol]);
|
||||
QDateTime dateTime(date, time);
|
||||
QByteArray bytes = QByteArray::fromHex(cols[dataCol].toLatin1());
|
||||
packetReceived(bytes);
|
||||
if (count % 1000 == 0)
|
||||
{
|
||||
QApplication::processEvents();
|
||||
if (dialog.clickedButton()) {
|
||||
cancelled = true;
|
||||
}
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
dialog.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::critical(this, "Packet Demod", error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::critical(this, "Packet Demod", QString("Failed to open file %1").arg(fileNames[0]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -105,6 +105,9 @@ private slots:
|
||||
void on_udpEnabled_clicked(bool checked);
|
||||
void on_udpAddress_editingFinished();
|
||||
void on_udpPort_editingFinished();
|
||||
void on_logEnable_clicked(bool checked=false);
|
||||
void on_logFilename_clicked();
|
||||
void on_logOpen_clicked();
|
||||
void filterRow(int row);
|
||||
void filter();
|
||||
void packets_sectionMoved(int logicalIndex, int oldVisualIndex, int newVisualIndex);
|
||||
|
@ -43,7 +43,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>390</width>
|
||||
<height>131</height>
|
||||
<height>151</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
@ -522,7 +522,7 @@
|
||||
<string>Check to display only packets with PID set to No L3 (f0). This is typically used for APRS and BBS packets.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>PID No L3</string>
|
||||
<string>No L3</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -539,6 +539,60 @@
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="ButtonSwitch" name="logEnable">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>24</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Start/stop logging of received packets to .csv file</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../sdrgui/resources/res.qrc">
|
||||
<normaloff>:/record_off.png</normaloff>:/record_off.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="logFilename">
|
||||
<property name="toolTip">
|
||||
<string>Set log .csv filename</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../sdrgui/resources/res.qrc">
|
||||
<normaloff>:/save.png</normaloff>:/save.png</iconset>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="logOpen">
|
||||
<property name="toolTip">
|
||||
<string>Read data from .csv log file</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../sdrgui/resources/res.qrc">
|
||||
<normaloff>:/load.png</normaloff>:/load.png</iconset>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="clearTable">
|
||||
<property name="toolTip">
|
||||
@ -561,7 +615,7 @@
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>140</y>
|
||||
<y>170</y>
|
||||
<width>391</width>
|
||||
<height>261</height>
|
||||
</rect>
|
||||
@ -679,6 +733,11 @@
|
||||
<header>gui/levelmeter.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>ButtonSwitch</class>
|
||||
<extends>QToolButton</extends>
|
||||
<header>gui/buttonswitch.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>packets</tabstop>
|
||||
|
@ -41,6 +41,8 @@ void PacketDemodSettings::resetToDefaults()
|
||||
m_udpEnabled = false;
|
||||
m_udpAddress = "127.0.0.1";
|
||||
m_udpPort = 9999;
|
||||
m_logFilename = "packet_log.csv";
|
||||
m_logEnabled = false;
|
||||
|
||||
m_rgbColor = QColor(0, 105, 2).rgb();
|
||||
m_title = "Packet Demodulator";
|
||||
@ -85,6 +87,9 @@ QByteArray PacketDemodSettings::serialize() const
|
||||
s.writeString(23, m_udpAddress);
|
||||
s.writeU32(24, m_udpPort);
|
||||
|
||||
s.writeString(25, m_logFilename);
|
||||
s.writeBool(26, m_logEnabled);
|
||||
|
||||
for (int i = 0; i < PACKETDEMOD_COLUMNS; i++)
|
||||
s.writeS32(100 + i, m_columnIndexes[i]);
|
||||
for (int i = 0; i < PACKETDEMOD_COLUMNS; i++)
|
||||
@ -149,6 +154,9 @@ bool PacketDemodSettings::deserialize(const QByteArray& data)
|
||||
m_udpPort = 9999;
|
||||
}
|
||||
|
||||
d.readString(25, &m_logFilename, "pager_log.csv");
|
||||
d.readBool(26, &m_logEnabled, false);
|
||||
|
||||
for (int i = 0; i < PACKETDEMOD_COLUMNS; i++)
|
||||
d.readS32(100 + i, &m_columnIndexes[i], i);
|
||||
for (int i = 0; i < PACKETDEMOD_COLUMNS; i++)
|
||||
|
@ -50,6 +50,9 @@ struct PacketDemodSettings
|
||||
uint16_t m_reverseAPIDeviceIndex;
|
||||
uint16_t m_reverseAPIChannelIndex;
|
||||
|
||||
QString m_logFilename;
|
||||
bool m_logEnabled;
|
||||
|
||||
int m_columnIndexes[PACKETDEMOD_COLUMNS];//!< How the columns are ordered in the table
|
||||
int m_columnSizes[PACKETDEMOD_COLUMNS]; //!< Size of the columns in the table
|
||||
|
||||
|
@ -62,6 +62,18 @@ IP address of the host to forward received packets to via UDP.
|
||||
|
||||
UDP port number to forward received packets to.
|
||||
|
||||
<h3>12: Start/stop Logging Packets to .csv File</h3>
|
||||
|
||||
When checked, writes all received packets to a .csv file.
|
||||
|
||||
<h3>13: .csv Log Filename</h3>
|
||||
|
||||
Click to specify the name of the .csv file which received packets are logged to.
|
||||
|
||||
<h3>14: Read Data from .csv File</h3>
|
||||
|
||||
Click to specify a previously written .csv log file, which is read and used to update the table.
|
||||
|
||||
<h3>Received Packets Table</h3>
|
||||
|
||||
The received packets table displays the contents of the packets that have been received. Only packets with valid CRCs are displayed.
|
||||
|
@ -155,6 +155,19 @@ bool PagerDemod::handleMessage(const Message& cmd)
|
||||
QHostAddress(m_settings.m_udpAddress), m_settings.m_udpPort);
|
||||
}
|
||||
|
||||
// Write to log file
|
||||
if (m_logFile.isOpen())
|
||||
{
|
||||
m_logStream << report.getDateTime().date().toString() << ","
|
||||
<< report.getDateTime().time().toString() << ","
|
||||
<< QString("%1").arg(report.getAddress(), 7, 10, QChar('0')) << ","
|
||||
<< QString::number(report.getFunctionBits()) << ","
|
||||
<< "\"" << report.getAlphaMessage() << "\","
|
||||
<< report.getNumericMessage() << ","
|
||||
<< QString::number(report.getEvenParityErrors()) << ","
|
||||
<< QString::number(report.getBCHParityErrors()) << "\n";
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (MainCore::MsgChannelDemodQuery::match(cmd))
|
||||
@ -178,6 +191,8 @@ ScopeVis *PagerDemod::getScopeSink()
|
||||
void PagerDemod::applySettings(const PagerDemodSettings& settings, bool force)
|
||||
{
|
||||
qDebug() << "PagerDemod::applySettings:"
|
||||
<< " m_logEnabled: " << settings.m_logEnabled
|
||||
<< " m_logFilename: " << settings.m_logFilename
|
||||
<< " m_streamIndex: " << settings.m_streamIndex
|
||||
<< " m_useReverseAPI: " << settings.m_useReverseAPI
|
||||
<< " m_reverseAPIAddress: " << settings.m_reverseAPIAddress
|
||||
@ -209,6 +224,12 @@ void PagerDemod::applySettings(const PagerDemodSettings& settings, bool force)
|
||||
if ((settings.m_udpPort != m_settings.m_udpPort) || force) {
|
||||
reverseAPIKeys.append("udpPort");
|
||||
}
|
||||
if ((settings.m_logFilename != m_settings.m_logFilename) || force) {
|
||||
reverseAPIKeys.append("logFilename");
|
||||
}
|
||||
if ((settings.m_logEnabled != m_settings.m_logEnabled) || force) {
|
||||
reverseAPIKeys.append("logEnabled");
|
||||
}
|
||||
if (m_settings.m_streamIndex != settings.m_streamIndex)
|
||||
{
|
||||
if (m_deviceAPI->getSampleMIMO()) // change of stream is possible for MIMO devices only
|
||||
@ -235,6 +256,36 @@ void PagerDemod::applySettings(const PagerDemodSettings& settings, bool force)
|
||||
webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
|
||||
}
|
||||
|
||||
if ((settings.m_logEnabled != m_settings.m_logEnabled)
|
||||
|| (settings.m_logFilename != m_settings.m_logFilename)
|
||||
|| force)
|
||||
{
|
||||
if (m_logFile.isOpen())
|
||||
{
|
||||
m_logStream.flush();
|
||||
m_logFile.close();
|
||||
}
|
||||
if (settings.m_logEnabled && !settings.m_logFilename.isEmpty())
|
||||
{
|
||||
m_logFile.setFileName(settings.m_logFilename);
|
||||
if (m_logFile.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text))
|
||||
{
|
||||
qDebug() << "PagerDemod::applySettings - Logging to: " << settings.m_logFilename;
|
||||
bool newFile = m_logFile.size() == 0;
|
||||
m_logStream.setDevice(&m_logFile);
|
||||
if (newFile)
|
||||
{
|
||||
// Write header
|
||||
m_logStream << "Date,Time,Address,Function Bits,Alpha,Numeric,Even Parity Errors,BCH Parity Errors\n";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "PagerDemod::applySettings - Unable to open log file: " << settings.m_logFilename;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_settings = settings;
|
||||
}
|
||||
|
||||
@ -341,6 +392,12 @@ void PagerDemod::webapiUpdateChannelSettings(
|
||||
if (channelSettingsKeys.contains("udpPort")) {
|
||||
settings.m_udpPort = response.getPagerDemodSettings()->getUdpPort();
|
||||
}
|
||||
if (channelSettingsKeys.contains("logFilename")) {
|
||||
settings.m_logFilename = *response.getAdsbDemodSettings()->getLogFilename();
|
||||
}
|
||||
if (channelSettingsKeys.contains("logEnabled")) {
|
||||
settings.m_logEnabled = response.getAdsbDemodSettings()->getLogEnabled();
|
||||
}
|
||||
if (channelSettingsKeys.contains("rgbColor")) {
|
||||
settings.m_rgbColor = response.getPagerDemodSettings()->getRgbColor();
|
||||
}
|
||||
@ -376,6 +433,8 @@ void PagerDemod::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& re
|
||||
response.getPagerDemodSettings()->setUdpEnabled(settings.m_udpEnabled);
|
||||
response.getPagerDemodSettings()->setUdpAddress(new QString(settings.m_udpAddress));
|
||||
response.getPagerDemodSettings()->setUdpPort(settings.m_udpPort);
|
||||
response.getPagerDemodSettings()->setLogFilename(new QString(settings.m_logFilename));
|
||||
response.getPagerDemodSettings()->setLogEnabled(settings.m_logEnabled);
|
||||
|
||||
response.getPagerDemodSettings()->setRgbColor(settings.m_rgbColor);
|
||||
if (response.getPagerDemodSettings()->getTitle()) {
|
||||
@ -460,6 +519,12 @@ void PagerDemod::webapiFormatChannelSettings(
|
||||
if (channelSettingsKeys.contains("udpPort") || force) {
|
||||
swgPagerDemodSettings->setUdpPort(settings.m_udpPort);
|
||||
}
|
||||
if (channelSettingsKeys.contains("logFilename") || force) {
|
||||
swgPagerDemodSettings->setLogFilename(new QString(settings.m_logFilename));
|
||||
}
|
||||
if (channelSettingsKeys.contains("logEnabled") || force) {
|
||||
swgPagerDemodSettings->setLogEnabled(settings.m_logEnabled);
|
||||
}
|
||||
if (channelSettingsKeys.contains("rgbColor") || force) {
|
||||
swgPagerDemodSettings->setRgbColor(settings.m_rgbColor);
|
||||
}
|
||||
|
@ -25,6 +25,8 @@
|
||||
#include <QUdpSocket>
|
||||
#include <QThread>
|
||||
#include <QDateTime>
|
||||
#include <QFile>
|
||||
#include <QTextStream>
|
||||
|
||||
#include "dsp/basebandsamplesink.h"
|
||||
#include "channel/channelapi.h"
|
||||
@ -175,6 +177,8 @@ private:
|
||||
int m_basebandSampleRate; //!< stored from device message used when starting baseband sink
|
||||
qint64 m_centerFrequency;
|
||||
QUdpSocket m_udpSocket;
|
||||
QFile m_logFile;
|
||||
QTextStream m_logStream;
|
||||
|
||||
QNetworkAccessManager *m_networkManager;
|
||||
QNetworkRequest m_networkRequest;
|
||||
|
@ -23,6 +23,8 @@
|
||||
#include <QAction>
|
||||
#include <QRegExp>
|
||||
#include <QClipboard>
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include "pagerdemodgui.h"
|
||||
|
||||
@ -33,6 +35,7 @@
|
||||
#include "plugin/pluginapi.h"
|
||||
#include "util/simpleserializer.h"
|
||||
#include "util/db.h"
|
||||
#include "util/csv.h"
|
||||
#include "gui/basicchannelsettingsdialog.h"
|
||||
#include "gui/devicestreamselectiondialog.h"
|
||||
#include "dsp/dspengine.h"
|
||||
@ -144,7 +147,9 @@ bool PagerDemodGUI::deserialize(const QByteArray& data)
|
||||
}
|
||||
|
||||
// Add row to table
|
||||
void PagerDemodGUI::messageReceived(const PagerDemod::MsgPagerMessage& message)
|
||||
void PagerDemodGUI::messageReceived(const QDateTime dateTime, int address, int functionBits,
|
||||
const QString &numericMessage, const QString &alphaMessage,
|
||||
int evenParityErrors, int bchParityErrors)
|
||||
{
|
||||
// Add to messages table
|
||||
ui->messages->setSortingEnabled(false);
|
||||
@ -169,43 +174,43 @@ void PagerDemodGUI::messageReceived(const PagerDemod::MsgPagerMessage& message)
|
||||
ui->messages->setItem(row, MESSAGE_COL_NUMERIC, numericItem);
|
||||
ui->messages->setItem(row, MESSAGE_COL_EVEN_PE, evenPEItem);
|
||||
ui->messages->setItem(row, MESSAGE_COL_BCH_PE, bchPEItem);
|
||||
dateItem->setText(message.getDateTime().date().toString());
|
||||
timeItem->setText(message.getDateTime().time().toString());
|
||||
addressItem->setText(QString("%1").arg(message.getAddress(), 7, 10, QChar('0')));
|
||||
dateItem->setText(dateTime.date().toString());
|
||||
timeItem->setText(dateTime.time().toString());
|
||||
addressItem->setText(QString("%1").arg(address, 7, 10, QChar('0')));
|
||||
// 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 (message.getFunctionBits() == 0) {
|
||||
messageItem->setText(message.getNumericMessage());
|
||||
if (functionBits == 0) {
|
||||
messageItem->setText(numericMessage);
|
||||
} else {
|
||||
messageItem->setText(message.getAlphaMessage());
|
||||
messageItem->setText(alphaMessage);
|
||||
}
|
||||
}
|
||||
else if (m_settings.m_decode == PagerDemodSettings::Inverted)
|
||||
{
|
||||
// Encoding is based on function bits, but inverted from standard
|
||||
if (message.getFunctionBits() == 3) {
|
||||
messageItem->setText(message.getNumericMessage());
|
||||
if (functionBits == 3) {
|
||||
messageItem->setText(numericMessage);
|
||||
} else {
|
||||
messageItem->setText(message.getAlphaMessage());
|
||||
messageItem->setText(alphaMessage);
|
||||
}
|
||||
}
|
||||
else if (m_settings.m_decode == PagerDemodSettings::Numeric)
|
||||
{
|
||||
// Always display as numeric
|
||||
messageItem->setText(message.getNumericMessage());
|
||||
messageItem->setText(numericMessage);
|
||||
}
|
||||
else if (m_settings.m_decode == PagerDemodSettings::Alphanumeric)
|
||||
{
|
||||
// Always display as alphanumeric
|
||||
messageItem->setText(message.getAlphaMessage());
|
||||
messageItem->setText(alphaMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Guess at what the encoding is
|
||||
QString numeric = message.getNumericMessage();
|
||||
QString alpha = message.getAlphaMessage();
|
||||
QString numeric = numericMessage;
|
||||
QString alpha = alphaMessage;
|
||||
bool done = false;
|
||||
if (!done)
|
||||
{
|
||||
@ -233,11 +238,11 @@ void PagerDemodGUI::messageReceived(const PagerDemod::MsgPagerMessage& message)
|
||||
messageItem->setText(alpha);
|
||||
}
|
||||
}
|
||||
functionItem->setText(QString("%1").arg(message.getFunctionBits()));
|
||||
alphaItem->setText(message.getAlphaMessage());
|
||||
numericItem->setText(message.getNumericMessage());
|
||||
evenPEItem->setText(QString("%1").arg(message.getEvenParityErrors()));
|
||||
bchPEItem->setText(QString("%1").arg(message.getBCHParityErrors()));
|
||||
functionItem->setText(QString("%1").arg(functionBits));
|
||||
alphaItem->setText(alphaMessage);
|
||||
numericItem->setText(numericMessage);
|
||||
evenPEItem->setText(QString("%1").arg(evenParityErrors));
|
||||
bchPEItem->setText(QString("%1").arg(bchParityErrors));
|
||||
ui->messages->setSortingEnabled(true);
|
||||
ui->messages->scrollToItem(dateItem); // Will only scroll if not hidden
|
||||
filterRow(row);
|
||||
@ -258,7 +263,9 @@ bool PagerDemodGUI::handleMessage(const Message& message)
|
||||
else if (PagerDemod::MsgPagerMessage::match(message))
|
||||
{
|
||||
PagerDemod::MsgPagerMessage& report = (PagerDemod::MsgPagerMessage&) message;
|
||||
messageReceived(report);
|
||||
messageReceived(report.getDateTime(), report.getAddress(), report.getFunctionBits(),
|
||||
report.getNumericMessage(), report.getAlphaMessage(),
|
||||
report.getEvenParityErrors(), report.getBCHParityErrors());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -606,6 +613,9 @@ void PagerDemodGUI::displaySettings()
|
||||
ui->channel1->setCurrentIndex(m_settings.m_scopeCh1);
|
||||
ui->channel2->setCurrentIndex(m_settings.m_scopeCh2);
|
||||
|
||||
ui->logFilename->setToolTip(QString(".csv log filename: %1").arg(m_settings.m_logFilename));
|
||||
ui->logEnable->setChecked(m_settings.m_logEnabled);
|
||||
|
||||
// Order and size columns
|
||||
QHeaderView *header = ui->messages->horizontalHeader();
|
||||
for (int i = 0; i < PAGERDEMOD_MESSAGE_COLUMNS; i++)
|
||||
@ -669,3 +679,104 @@ void PagerDemodGUI::on_charset_clicked()
|
||||
applySettings();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PagerDemodGUI::on_logEnable_clicked(bool checked)
|
||||
{
|
||||
m_settings.m_logEnabled = checked;
|
||||
applySettings();
|
||||
}
|
||||
|
||||
void PagerDemodGUI::on_logFilename_clicked()
|
||||
{
|
||||
// Get filename to save to
|
||||
QFileDialog fileDialog(nullptr, "Select file to log received messages to", "", "*.csv");
|
||||
fileDialog.setAcceptMode(QFileDialog::AcceptSave);
|
||||
if (fileDialog.exec())
|
||||
{
|
||||
QStringList fileNames = fileDialog.selectedFiles();
|
||||
if (fileNames.size() > 0)
|
||||
{
|
||||
m_settings.m_logFilename = fileNames[0];
|
||||
ui->logFilename->setToolTip(QString(".csv log filename: %1").arg(m_settings.m_logFilename));
|
||||
applySettings();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Read .csv log and process as received messages
|
||||
void PagerDemodGUI::on_logOpen_clicked()
|
||||
{
|
||||
QFileDialog fileDialog(nullptr, "Select .csv log file to read", "", "*.csv");
|
||||
if (fileDialog.exec())
|
||||
{
|
||||
QStringList fileNames = fileDialog.selectedFiles();
|
||||
if (fileNames.size() > 0)
|
||||
{
|
||||
QFile file(fileNames[0]);
|
||||
if (file.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
{
|
||||
QTextStream in(&file);
|
||||
QString error;
|
||||
QHash<QString, int> colIndexes = CSV::readHeader(in, {"Date", "Time", "Address", "Function Bits", "Alpha", "Numeric", "Even Parity Errors", "BCH Parity Errors"}, error);
|
||||
if (error.isEmpty())
|
||||
{
|
||||
int dateCol = colIndexes.value("Date");
|
||||
int timeCol = colIndexes.value("Time");
|
||||
int addressCol = colIndexes.value("Address");
|
||||
int functionCol = colIndexes.value("Function Bits");
|
||||
int alphaCol = colIndexes.value("Alpha");
|
||||
int numericCol = colIndexes.value("Numeric");
|
||||
int evenCol = colIndexes.value("Even Parity Errors");
|
||||
int bchCol = colIndexes.value("BCH Parity Errors");
|
||||
int maxCol = std::max({dateCol, timeCol, addressCol, functionCol, alphaCol, numericCol, evenCol, bchCol});
|
||||
|
||||
QMessageBox dialog(this);
|
||||
dialog.setText("Reading messages");
|
||||
dialog.addButton(QMessageBox::Cancel);
|
||||
dialog.show();
|
||||
QApplication::processEvents();
|
||||
int count = 0;
|
||||
bool cancelled = false;
|
||||
|
||||
QStringList cols;
|
||||
while (!cancelled && CSV::readRow(in, &cols))
|
||||
{
|
||||
if (cols.size() > maxCol)
|
||||
{
|
||||
QDate date = QDate::fromString(cols[dateCol]);
|
||||
QTime time = QTime::fromString(cols[timeCol]);
|
||||
QDateTime dateTime(date, time);
|
||||
int address = cols[addressCol].toInt();
|
||||
int functionBits = cols[functionCol].toInt();
|
||||
int evenErrors = cols[evenCol].toInt();
|
||||
int bchErrors = cols[bchCol].toInt();
|
||||
|
||||
messageReceived(dateTime, address, functionBits,
|
||||
cols[numericCol], cols[alphaCol],
|
||||
evenErrors, bchErrors);
|
||||
|
||||
if (count % 1000 == 0)
|
||||
{
|
||||
QApplication::processEvents();
|
||||
if (dialog.clickedButton()) {
|
||||
cancelled = true;
|
||||
}
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
dialog.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::critical(this, "Pager Demod", error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::critical(this, "Pager Demod", QString("Failed to open file %1").arg(fileNames[0]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -78,7 +78,9 @@ private:
|
||||
void applySettings(bool force = false);
|
||||
void displaySettings();
|
||||
void displayStreamIndex();
|
||||
void messageReceived(const PagerDemod::MsgPagerMessage& message);
|
||||
void messageReceived(const QDateTime dateTime, int address, int functionBits,
|
||||
const QString &numericMessage, const QString &alphaMessage,
|
||||
int evenParityErrors, int bchParityErrors);
|
||||
bool handleMessage(const Message& message);
|
||||
|
||||
void leaveEvent(QEvent*);
|
||||
@ -113,6 +115,9 @@ private slots:
|
||||
void on_udpPort_editingFinished();
|
||||
void on_channel1_currentIndexChanged(int index);
|
||||
void on_channel2_currentIndexChanged(int index);
|
||||
void on_logEnable_clicked(bool checked=false);
|
||||
void on_logFilename_clicked();
|
||||
void on_logOpen_clicked();
|
||||
void filterRow(int row);
|
||||
void filter();
|
||||
void messages_sectionMoved(int logicalIndex, int oldVisualIndex, int newVisualIndex);
|
||||
|
@ -627,6 +627,60 @@
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="ButtonSwitch" name="logEnable">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>24</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Start/stop logging of received messages to .csv file</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../sdrgui/resources/res.qrc">
|
||||
<normaloff>:/record_off.png</normaloff>:/record_off.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="logFilename">
|
||||
<property name="toolTip">
|
||||
<string>Set log .csv filename</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../sdrgui/resources/res.qrc">
|
||||
<normaloff>:/save.png</normaloff>:/save.png</iconset>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="logOpen">
|
||||
<property name="toolTip">
|
||||
<string>Read data from .csv log file</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../sdrgui/resources/res.qrc">
|
||||
<normaloff>:/load.png</normaloff>:/load.png</iconset>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="clearTable">
|
||||
<property name="toolTip">
|
||||
@ -979,6 +1033,11 @@
|
||||
<header>gui/levelmeter.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>ButtonSwitch</class>
|
||||
<extends>QToolButton</extends>
|
||||
<header>gui/buttonswitch.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>GLScope</class>
|
||||
<extends>QWidget</extends>
|
||||
|
@ -44,6 +44,8 @@ void PagerDemodSettings::resetToDefaults()
|
||||
m_udpPort = 9999;
|
||||
m_scopeCh1 = 4;
|
||||
m_scopeCh2 = 9;
|
||||
m_logFilename = "pager_log.csv";
|
||||
m_logEnabled = false;
|
||||
m_rgbColor = QColor(200, 191, 231).rgb();
|
||||
m_title = "Pager Demodulator";
|
||||
m_streamIndex = 0;
|
||||
@ -92,6 +94,9 @@ QByteArray PagerDemodSettings::serialize() const
|
||||
s.writeBlob(23, serializeIntList(m_sevenbit));
|
||||
s.writeBlob(24, serializeIntList(m_unicode));
|
||||
|
||||
s.writeString(25, m_logFilename);
|
||||
s.writeBool(26, m_logEnabled);
|
||||
|
||||
for (int i = 0; i < PAGERDEMOD_MESSAGE_COLUMNS; i++) {
|
||||
s.writeS32(100 + i, m_messageColumnIndexes[i]);
|
||||
}
|
||||
@ -166,6 +171,9 @@ bool PagerDemodSettings::deserialize(const QByteArray& data)
|
||||
d.readBlob(24, &blob);
|
||||
deserializeIntList(blob, m_unicode);
|
||||
|
||||
d.readString(25, &m_logFilename, "pager_log.csv");
|
||||
d.readBool(26, &m_logEnabled, false);
|
||||
|
||||
for (int i = 0; i < PAGERDEMOD_MESSAGE_COLUMNS; i++) {
|
||||
d.readS32(100 + i, &m_messageColumnIndexes[i], i);
|
||||
}
|
||||
|
@ -64,6 +64,9 @@ struct PagerDemodSettings
|
||||
QList<qint32> m_sevenbit;
|
||||
QList<qint32> m_unicode;
|
||||
|
||||
QString m_logFilename;
|
||||
bool m_logEnabled;
|
||||
|
||||
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
|
||||
|
||||
|
@ -84,6 +84,18 @@ IP address of the host to forward received messages to via UDP.
|
||||
|
||||
UDP port number to forward received messages to.
|
||||
|
||||
<h3>15: Start/stop Logging Messages to .csv File</h3>
|
||||
|
||||
When checked, writes all received messages to a .csv file.
|
||||
|
||||
<h3>16: .csv Log Filename</h3>
|
||||
|
||||
Click to specify the name of the .csv file which received messages are logged to.
|
||||
|
||||
<h3>17: Read Data from .csv File</h3>
|
||||
|
||||
Click to specify a previously written .csv log file, which is read and used to update the table.
|
||||
|
||||
<h3>Received Messages Table</h3>
|
||||
|
||||
The received messages table displays each pager message received.
|
||||
|
@ -30,7 +30,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "util/units.h"
|
||||
#include "../demodadsb/csv.h"
|
||||
#include "util/csv.h"
|
||||
|
||||
#define OURAIRPORTS_NAVAIDS_URL "https://ourairports.com/data/navaids.csv"
|
||||
|
||||
|
@ -26,7 +26,7 @@
|
||||
|
||||
#include "util/units.h"
|
||||
#include "util/maidenhead.h"
|
||||
#include "../../channelrx/demodadsb/csv.h"
|
||||
#include "util/csv.h"
|
||||
|
||||
#define IARU_BEACONS_URL "https://iaru-r1-c5-beacons.org/wp-content/uploads/beacons.csv"
|
||||
|
||||
|
@ -25,7 +25,7 @@
|
||||
#include <QDebug>
|
||||
|
||||
// Create a hash map from a CSV file with two columns
|
||||
QHash<QString, QString> *csvHash(const QString& filename, int reserve)
|
||||
QHash<QString, QString> *CSV::hash(const QString& filename, int reserve)
|
||||
{
|
||||
int cnt = 0;
|
||||
QHash<QString, QString> *map = nullptr;
|
||||
@ -67,3 +67,100 @@ QHash<QString, QString> *csvHash(const QString& filename, int reserve)
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
// Read a row from a CSV file (handling quotes)
|
||||
// https://stackoverflow.com/questions/27318631/parsing-through-a-csv-file-in-qt
|
||||
bool CSV::readRow(QTextStream &in, QStringList *row)
|
||||
{
|
||||
static const int delta[][5] = {
|
||||
// , " \n ? eof
|
||||
{ 1, 2, -1, 0, -1 }, // 0: parsing (store char)
|
||||
{ 1, 2, -1, 0, -1 }, // 1: parsing (store column)
|
||||
{ 3, 4, 3, 3, -2 }, // 2: quote entered (no-op)
|
||||
{ 3, 4, 3, 3, -2 }, // 3: parsing inside quotes (store char)
|
||||
{ 1, 3, -1, 0, -1 }, // 4: quote exited (no-op)
|
||||
// -1: end of row, store column, success
|
||||
// -2: eof inside quotes
|
||||
};
|
||||
|
||||
row->clear();
|
||||
|
||||
if (in.atEnd())
|
||||
return false;
|
||||
|
||||
int state = 0, t;
|
||||
char ch;
|
||||
QString cell;
|
||||
|
||||
while (state >= 0)
|
||||
{
|
||||
if (in.atEnd())
|
||||
{
|
||||
t = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
in >> ch;
|
||||
if (ch == ',') {
|
||||
t = 0;
|
||||
} else if (ch == '\"') {
|
||||
t = 1;
|
||||
} else if (ch == '\n') {
|
||||
t = 2;
|
||||
} else {
|
||||
t = 3;
|
||||
}
|
||||
}
|
||||
|
||||
state = delta[state][t];
|
||||
|
||||
switch (state) {
|
||||
case 0:
|
||||
case 3:
|
||||
cell += ch;
|
||||
break;
|
||||
case -1:
|
||||
case 1:
|
||||
row->append(cell);
|
||||
cell = "";
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (state == -2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Read header row from CSV file and return a hash mapping names to column numbers
|
||||
// Returns error if header row can't be read, or if all of requiredColumns aren't found
|
||||
QHash<QString, int> CSV::readHeader(QTextStream &in, QStringList requiredColumns, QString &error)
|
||||
{
|
||||
QHash<QString, int> colNumbers;
|
||||
QStringList row;
|
||||
|
||||
// Read column names
|
||||
if (CSV::readRow(in, &row))
|
||||
{
|
||||
// Create hash mapping column names to indices
|
||||
for (int i = 0; i < row.size(); i++) {
|
||||
colNumbers.insert(row[i], i);
|
||||
}
|
||||
// Check all required columns exist
|
||||
for (const auto col : requiredColumns)
|
||||
{
|
||||
if (!colNumbers.contains(col)) {
|
||||
error = QString("Missing column %1").arg(col);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
error = "Failed to read header row";
|
||||
}
|
||||
|
||||
return colNumbers;
|
||||
}
|
||||
|
@ -20,9 +20,12 @@
|
||||
|
||||
#include <QString>
|
||||
#include <QHash>
|
||||
#include <QTextStream>
|
||||
|
||||
// Extract string from CSV line, updating pp to next column
|
||||
static inline char *csvNext(char **pp)
|
||||
#include "export.h"
|
||||
|
||||
// Extract string from CSV line, updating pp to next column (This doesn't handle , inside quotes)
|
||||
static inline char *csvNext(char **pp, char delimiter=',')
|
||||
{
|
||||
char *p = *pp;
|
||||
|
||||
@ -31,7 +34,7 @@ static inline char *csvNext(char **pp)
|
||||
|
||||
char *start = p;
|
||||
|
||||
while ((*p != ',') && (*p != '\n'))
|
||||
while ((*p != delimiter) && (*p != '\n'))
|
||||
p++;
|
||||
*p++ = '\0';
|
||||
*pp = p;
|
||||
@ -39,6 +42,13 @@ static inline char *csvNext(char **pp)
|
||||
return start;
|
||||
}
|
||||
|
||||
QHash<QString, QString> *csvHash(const QString& filename, int reserve=0);
|
||||
struct SDRBASE_API CSV {
|
||||
|
||||
static QHash<QString, QString> *hash(const QString& filename, int reserve=0);
|
||||
|
||||
static bool readRow(QTextStream &in, QStringList *row);
|
||||
static QHash<QString, int> readHeader(QTextStream &in, QStringList requiredColumns, QString &error);
|
||||
|
||||
};
|
||||
|
||||
#endif /* INCLUDE_CSV_H */
|
||||
|
@ -25,6 +25,10 @@ AISDemodSettings:
|
||||
udpFormat:
|
||||
description: "0 for binary, 1 for NMEA"
|
||||
type: integer
|
||||
logFilename:
|
||||
type: string
|
||||
logEnabled:
|
||||
type: integer
|
||||
rgbColor:
|
||||
type: integer
|
||||
title:
|
||||
|
@ -24,6 +24,10 @@ PacketDemodSettings:
|
||||
udpPort:
|
||||
description: "UDP port to forward received packets to"
|
||||
type: integer
|
||||
logFilename:
|
||||
type: string
|
||||
logEnabled:
|
||||
type: integer
|
||||
rgbColor:
|
||||
type: integer
|
||||
title:
|
||||
|
@ -28,6 +28,10 @@ PagerDemodSettings:
|
||||
udpFormat:
|
||||
description: "0 for binary, 1 for NMEA"
|
||||
type: integer
|
||||
logFilename:
|
||||
type: string
|
||||
logEnabled:
|
||||
type: integer
|
||||
rgbColor:
|
||||
type: integer
|
||||
title:
|
||||
|
@ -44,6 +44,10 @@ SWGAISDemodSettings::SWGAISDemodSettings() {
|
||||
m_udp_port_isSet = false;
|
||||
udp_format = 0;
|
||||
m_udp_format_isSet = false;
|
||||
log_filename = nullptr;
|
||||
m_log_filename_isSet = false;
|
||||
log_enabled = 0;
|
||||
m_log_enabled_isSet = false;
|
||||
rgb_color = 0;
|
||||
m_rgb_color_isSet = false;
|
||||
title = nullptr;
|
||||
@ -84,6 +88,10 @@ SWGAISDemodSettings::init() {
|
||||
m_udp_port_isSet = false;
|
||||
udp_format = 0;
|
||||
m_udp_format_isSet = false;
|
||||
log_filename = new QString("");
|
||||
m_log_filename_isSet = false;
|
||||
log_enabled = 0;
|
||||
m_log_enabled_isSet = false;
|
||||
rgb_color = 0;
|
||||
m_rgb_color_isSet = false;
|
||||
title = new QString("");
|
||||
@ -114,6 +122,10 @@ SWGAISDemodSettings::cleanup() {
|
||||
}
|
||||
|
||||
|
||||
if(log_filename != nullptr) {
|
||||
delete log_filename;
|
||||
}
|
||||
|
||||
|
||||
if(title != nullptr) {
|
||||
delete title;
|
||||
@ -155,6 +167,10 @@ SWGAISDemodSettings::fromJsonObject(QJsonObject &pJson) {
|
||||
|
||||
::SWGSDRangel::setValue(&udp_format, pJson["udpFormat"], "qint32", "");
|
||||
|
||||
::SWGSDRangel::setValue(&log_filename, pJson["logFilename"], "QString", "QString");
|
||||
|
||||
::SWGSDRangel::setValue(&log_enabled, pJson["logEnabled"], "qint32", "");
|
||||
|
||||
::SWGSDRangel::setValue(&rgb_color, pJson["rgbColor"], "qint32", "");
|
||||
|
||||
::SWGSDRangel::setValue(&title, pJson["title"], "QString", "QString");
|
||||
@ -211,6 +227,12 @@ SWGAISDemodSettings::asJsonObject() {
|
||||
if(m_udp_format_isSet){
|
||||
obj->insert("udpFormat", QJsonValue(udp_format));
|
||||
}
|
||||
if(log_filename != nullptr && *log_filename != QString("")){
|
||||
toJsonValue(QString("logFilename"), log_filename, obj, QString("QString"));
|
||||
}
|
||||
if(m_log_enabled_isSet){
|
||||
obj->insert("logEnabled", QJsonValue(log_enabled));
|
||||
}
|
||||
if(m_rgb_color_isSet){
|
||||
obj->insert("rgbColor", QJsonValue(rgb_color));
|
||||
}
|
||||
@ -319,6 +341,26 @@ SWGAISDemodSettings::setUdpFormat(qint32 udp_format) {
|
||||
this->m_udp_format_isSet = true;
|
||||
}
|
||||
|
||||
QString*
|
||||
SWGAISDemodSettings::getLogFilename() {
|
||||
return log_filename;
|
||||
}
|
||||
void
|
||||
SWGAISDemodSettings::setLogFilename(QString* log_filename) {
|
||||
this->log_filename = log_filename;
|
||||
this->m_log_filename_isSet = true;
|
||||
}
|
||||
|
||||
qint32
|
||||
SWGAISDemodSettings::getLogEnabled() {
|
||||
return log_enabled;
|
||||
}
|
||||
void
|
||||
SWGAISDemodSettings::setLogEnabled(qint32 log_enabled) {
|
||||
this->log_enabled = log_enabled;
|
||||
this->m_log_enabled_isSet = true;
|
||||
}
|
||||
|
||||
qint32
|
||||
SWGAISDemodSettings::getRgbColor() {
|
||||
return rgb_color;
|
||||
@ -428,6 +470,12 @@ SWGAISDemodSettings::isSet(){
|
||||
if(m_udp_format_isSet){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(log_filename && *log_filename != QString("")){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(m_log_enabled_isSet){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(m_rgb_color_isSet){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
|
@ -66,6 +66,12 @@ public:
|
||||
qint32 getUdpFormat();
|
||||
void setUdpFormat(qint32 udp_format);
|
||||
|
||||
QString* getLogFilename();
|
||||
void setLogFilename(QString* log_filename);
|
||||
|
||||
qint32 getLogEnabled();
|
||||
void setLogEnabled(qint32 log_enabled);
|
||||
|
||||
qint32 getRgbColor();
|
||||
void setRgbColor(qint32 rgb_color);
|
||||
|
||||
@ -118,6 +124,12 @@ private:
|
||||
qint32 udp_format;
|
||||
bool m_udp_format_isSet;
|
||||
|
||||
QString* log_filename;
|
||||
bool m_log_filename_isSet;
|
||||
|
||||
qint32 log_enabled;
|
||||
bool m_log_enabled_isSet;
|
||||
|
||||
qint32 rgb_color;
|
||||
bool m_rgb_color_isSet;
|
||||
|
||||
|
@ -42,6 +42,10 @@ SWGPacketDemodSettings::SWGPacketDemodSettings() {
|
||||
m_udp_address_isSet = false;
|
||||
udp_port = 0;
|
||||
m_udp_port_isSet = false;
|
||||
log_filename = nullptr;
|
||||
m_log_filename_isSet = false;
|
||||
log_enabled = 0;
|
||||
m_log_enabled_isSet = false;
|
||||
rgb_color = 0;
|
||||
m_rgb_color_isSet = false;
|
||||
title = nullptr;
|
||||
@ -80,6 +84,10 @@ SWGPacketDemodSettings::init() {
|
||||
m_udp_address_isSet = false;
|
||||
udp_port = 0;
|
||||
m_udp_port_isSet = false;
|
||||
log_filename = new QString("");
|
||||
m_log_filename_isSet = false;
|
||||
log_enabled = 0;
|
||||
m_log_enabled_isSet = false;
|
||||
rgb_color = 0;
|
||||
m_rgb_color_isSet = false;
|
||||
title = new QString("");
|
||||
@ -111,6 +119,10 @@ SWGPacketDemodSettings::cleanup() {
|
||||
delete udp_address;
|
||||
}
|
||||
|
||||
if(log_filename != nullptr) {
|
||||
delete log_filename;
|
||||
}
|
||||
|
||||
|
||||
if(title != nullptr) {
|
||||
delete title;
|
||||
@ -150,6 +162,10 @@ SWGPacketDemodSettings::fromJsonObject(QJsonObject &pJson) {
|
||||
|
||||
::SWGSDRangel::setValue(&udp_port, pJson["udpPort"], "qint32", "");
|
||||
|
||||
::SWGSDRangel::setValue(&log_filename, pJson["logFilename"], "QString", "QString");
|
||||
|
||||
::SWGSDRangel::setValue(&log_enabled, pJson["logEnabled"], "qint32", "");
|
||||
|
||||
::SWGSDRangel::setValue(&rgb_color, pJson["rgbColor"], "qint32", "");
|
||||
|
||||
::SWGSDRangel::setValue(&title, pJson["title"], "QString", "QString");
|
||||
@ -203,6 +219,12 @@ SWGPacketDemodSettings::asJsonObject() {
|
||||
if(m_udp_port_isSet){
|
||||
obj->insert("udpPort", QJsonValue(udp_port));
|
||||
}
|
||||
if(log_filename != nullptr && *log_filename != QString("")){
|
||||
toJsonValue(QString("logFilename"), log_filename, obj, QString("QString"));
|
||||
}
|
||||
if(m_log_enabled_isSet){
|
||||
obj->insert("logEnabled", QJsonValue(log_enabled));
|
||||
}
|
||||
if(m_rgb_color_isSet){
|
||||
obj->insert("rgbColor", QJsonValue(rgb_color));
|
||||
}
|
||||
@ -301,6 +323,26 @@ SWGPacketDemodSettings::setUdpPort(qint32 udp_port) {
|
||||
this->m_udp_port_isSet = true;
|
||||
}
|
||||
|
||||
QString*
|
||||
SWGPacketDemodSettings::getLogFilename() {
|
||||
return log_filename;
|
||||
}
|
||||
void
|
||||
SWGPacketDemodSettings::setLogFilename(QString* log_filename) {
|
||||
this->log_filename = log_filename;
|
||||
this->m_log_filename_isSet = true;
|
||||
}
|
||||
|
||||
qint32
|
||||
SWGPacketDemodSettings::getLogEnabled() {
|
||||
return log_enabled;
|
||||
}
|
||||
void
|
||||
SWGPacketDemodSettings::setLogEnabled(qint32 log_enabled) {
|
||||
this->log_enabled = log_enabled;
|
||||
this->m_log_enabled_isSet = true;
|
||||
}
|
||||
|
||||
qint32
|
||||
SWGPacketDemodSettings::getRgbColor() {
|
||||
return rgb_color;
|
||||
@ -407,6 +449,12 @@ SWGPacketDemodSettings::isSet(){
|
||||
if(m_udp_port_isSet){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(log_filename && *log_filename != QString("")){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(m_log_enabled_isSet){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(m_rgb_color_isSet){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
|
@ -63,6 +63,12 @@ public:
|
||||
qint32 getUdpPort();
|
||||
void setUdpPort(qint32 udp_port);
|
||||
|
||||
QString* getLogFilename();
|
||||
void setLogFilename(QString* log_filename);
|
||||
|
||||
qint32 getLogEnabled();
|
||||
void setLogEnabled(qint32 log_enabled);
|
||||
|
||||
qint32 getRgbColor();
|
||||
void setRgbColor(qint32 rgb_color);
|
||||
|
||||
@ -112,6 +118,12 @@ private:
|
||||
qint32 udp_port;
|
||||
bool m_udp_port_isSet;
|
||||
|
||||
QString* log_filename;
|
||||
bool m_log_filename_isSet;
|
||||
|
||||
qint32 log_enabled;
|
||||
bool m_log_enabled_isSet;
|
||||
|
||||
qint32 rgb_color;
|
||||
bool m_rgb_color_isSet;
|
||||
|
||||
|
@ -46,6 +46,10 @@ SWGPagerDemodSettings::SWGPagerDemodSettings() {
|
||||
m_udp_port_isSet = false;
|
||||
udp_format = 0;
|
||||
m_udp_format_isSet = false;
|
||||
log_filename = nullptr;
|
||||
m_log_filename_isSet = false;
|
||||
log_enabled = 0;
|
||||
m_log_enabled_isSet = false;
|
||||
rgb_color = 0;
|
||||
m_rgb_color_isSet = false;
|
||||
title = nullptr;
|
||||
@ -88,6 +92,10 @@ SWGPagerDemodSettings::init() {
|
||||
m_udp_port_isSet = false;
|
||||
udp_format = 0;
|
||||
m_udp_format_isSet = false;
|
||||
log_filename = new QString("");
|
||||
m_log_filename_isSet = false;
|
||||
log_enabled = 0;
|
||||
m_log_enabled_isSet = false;
|
||||
rgb_color = 0;
|
||||
m_rgb_color_isSet = false;
|
||||
title = new QString("");
|
||||
@ -119,6 +127,10 @@ SWGPagerDemodSettings::cleanup() {
|
||||
}
|
||||
|
||||
|
||||
if(log_filename != nullptr) {
|
||||
delete log_filename;
|
||||
}
|
||||
|
||||
|
||||
if(title != nullptr) {
|
||||
delete title;
|
||||
@ -162,6 +174,10 @@ SWGPagerDemodSettings::fromJsonObject(QJsonObject &pJson) {
|
||||
|
||||
::SWGSDRangel::setValue(&udp_format, pJson["udpFormat"], "qint32", "");
|
||||
|
||||
::SWGSDRangel::setValue(&log_filename, pJson["logFilename"], "QString", "QString");
|
||||
|
||||
::SWGSDRangel::setValue(&log_enabled, pJson["logEnabled"], "qint32", "");
|
||||
|
||||
::SWGSDRangel::setValue(&rgb_color, pJson["rgbColor"], "qint32", "");
|
||||
|
||||
::SWGSDRangel::setValue(&title, pJson["title"], "QString", "QString");
|
||||
@ -221,6 +237,12 @@ SWGPagerDemodSettings::asJsonObject() {
|
||||
if(m_udp_format_isSet){
|
||||
obj->insert("udpFormat", QJsonValue(udp_format));
|
||||
}
|
||||
if(log_filename != nullptr && *log_filename != QString("")){
|
||||
toJsonValue(QString("logFilename"), log_filename, obj, QString("QString"));
|
||||
}
|
||||
if(m_log_enabled_isSet){
|
||||
obj->insert("logEnabled", QJsonValue(log_enabled));
|
||||
}
|
||||
if(m_rgb_color_isSet){
|
||||
obj->insert("rgbColor", QJsonValue(rgb_color));
|
||||
}
|
||||
@ -339,6 +361,26 @@ SWGPagerDemodSettings::setUdpFormat(qint32 udp_format) {
|
||||
this->m_udp_format_isSet = true;
|
||||
}
|
||||
|
||||
QString*
|
||||
SWGPagerDemodSettings::getLogFilename() {
|
||||
return log_filename;
|
||||
}
|
||||
void
|
||||
SWGPagerDemodSettings::setLogFilename(QString* log_filename) {
|
||||
this->log_filename = log_filename;
|
||||
this->m_log_filename_isSet = true;
|
||||
}
|
||||
|
||||
qint32
|
||||
SWGPagerDemodSettings::getLogEnabled() {
|
||||
return log_enabled;
|
||||
}
|
||||
void
|
||||
SWGPagerDemodSettings::setLogEnabled(qint32 log_enabled) {
|
||||
this->log_enabled = log_enabled;
|
||||
this->m_log_enabled_isSet = true;
|
||||
}
|
||||
|
||||
qint32
|
||||
SWGPagerDemodSettings::getRgbColor() {
|
||||
return rgb_color;
|
||||
@ -451,6 +493,12 @@ SWGPagerDemodSettings::isSet(){
|
||||
if(m_udp_format_isSet){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(log_filename && *log_filename != QString("")){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(m_log_enabled_isSet){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(m_rgb_color_isSet){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
|
@ -69,6 +69,12 @@ public:
|
||||
qint32 getUdpFormat();
|
||||
void setUdpFormat(qint32 udp_format);
|
||||
|
||||
QString* getLogFilename();
|
||||
void setLogFilename(QString* log_filename);
|
||||
|
||||
qint32 getLogEnabled();
|
||||
void setLogEnabled(qint32 log_enabled);
|
||||
|
||||
qint32 getRgbColor();
|
||||
void setRgbColor(qint32 rgb_color);
|
||||
|
||||
@ -124,6 +130,12 @@ private:
|
||||
qint32 udp_format;
|
||||
bool m_udp_format_isSet;
|
||||
|
||||
QString* log_filename;
|
||||
bool m_log_filename_isSet;
|
||||
|
||||
qint32 log_enabled;
|
||||
bool m_log_enabled_isSet;
|
||||
|
||||
qint32 rgb_color;
|
||||
bool m_rgb_color_isSet;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user