mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-11-22 08:04:49 -05:00
ADS-B Updates
Add support for writing/reading .csv log file containing received ADS-B frames for #1035. Fix some memory leaks.
This commit is contained in:
parent
71d2378b7e
commit
132244ef64
@ -176,8 +176,32 @@ void ADSBDemod::applySettings(const ADSBDemodSettings& settings, bool force)
|
||||
if ((settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) || force) {
|
||||
reverseAPIKeys.append("inputFrequencyOffset");
|
||||
}
|
||||
if ((settings.m_rgbColor != m_settings.m_rgbColor) || force) {
|
||||
reverseAPIKeys.append("rgbColor");
|
||||
if ((settings.m_rfBandwidth != m_settings.m_rfBandwidth) || force) {
|
||||
reverseAPIKeys.append("rfBandwidth");
|
||||
}
|
||||
if ((settings.m_correlationThreshold != m_settings.m_correlationThreshold) || force) {
|
||||
reverseAPIKeys.append("correlationThreshold");
|
||||
}
|
||||
if ((settings.m_samplesPerBit != m_settings.m_samplesPerBit) || force) {
|
||||
reverseAPIKeys.append("samplesPerBit");
|
||||
}
|
||||
if ((settings.m_removeTimeout != m_settings.m_removeTimeout) || force) {
|
||||
reverseAPIKeys.append("removeTimeout");
|
||||
}
|
||||
if ((settings.m_feedEnabled != m_settings.m_feedEnabled) || force) {
|
||||
reverseAPIKeys.append("beastEnabled");
|
||||
}
|
||||
if ((settings.m_feedHost != m_settings.m_feedHost) || force) {
|
||||
reverseAPIKeys.append("beastHost");
|
||||
}
|
||||
if ((settings.m_feedPort != m_settings.m_feedPort) || force) {
|
||||
reverseAPIKeys.append("beastPort");
|
||||
}
|
||||
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 ((settings.m_title != m_settings.m_title) || force) {
|
||||
reverseAPIKeys.append("title");
|
||||
@ -303,6 +327,12 @@ void ADSBDemod::webapiUpdateChannelSettings(
|
||||
if (channelSettingsKeys.contains("beastPort")) {
|
||||
settings.m_feedPort = response.getAdsbDemodSettings()->getBeastPort();
|
||||
}
|
||||
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.getAdsbDemodSettings()->getRgbColor();
|
||||
}
|
||||
@ -351,6 +381,8 @@ void ADSBDemod::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& res
|
||||
response.getAdsbDemodSettings()->setBeastHost(new QString(settings.m_feedHost));
|
||||
response.getAdsbDemodSettings()->setBeastPort(settings.m_feedPort);
|
||||
response.getAdsbDemodSettings()->setRgbColor(settings.m_rgbColor);
|
||||
response.getAdsbDemodSettings()->setLogFilename(new QString(settings.m_logFilename));
|
||||
response.getAdsbDemodSettings()->setLogEnabled(settings.m_logEnabled);
|
||||
|
||||
if (response.getAdsbDemodSettings()->getTitle()) {
|
||||
*response.getAdsbDemodSettings()->getTitle() = settings.m_title;
|
||||
@ -423,6 +455,12 @@ void ADSBDemod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, c
|
||||
if (channelSettingsKeys.contains("beastPort") || force) {
|
||||
swgADSBDemodSettings->setBeastPort(settings.m_feedPort);
|
||||
}
|
||||
if (channelSettingsKeys.contains("logFilename") || force) {
|
||||
swgADSBDemodSettings->setLogFilename(new QString(settings.m_logFilename));
|
||||
}
|
||||
if (channelSettingsKeys.contains("logEnabled") || force) {
|
||||
swgADSBDemodSettings->setLogEnabled(settings.m_logEnabled);
|
||||
}
|
||||
if (channelSettingsKeys.contains("rgbColor") || force) {
|
||||
swgADSBDemodSettings->setRgbColor(settings.m_rgbColor);
|
||||
}
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include <QMessageBox>
|
||||
#include <QDebug>
|
||||
#include <QProcess>
|
||||
#include <QFileDialog>
|
||||
|
||||
#include "SWGMapItem.h"
|
||||
|
||||
@ -1016,7 +1017,8 @@ void ADSBDemodGUI::handleADSB(
|
||||
aircraft->m_latitudeItem->setData(Qt::DisplayRole, aircraft->m_latitude);
|
||||
aircraft->m_longitude = longitude;
|
||||
aircraft->m_longitudeItem->setData(Qt::DisplayRole, aircraft->m_longitude);
|
||||
aircraft->m_coordinates.push_back(QVariant::fromValue(*new QGeoCoordinate(aircraft->m_latitude, aircraft->m_longitude, aircraft->m_altitude)));
|
||||
QGeoCoordinate coord(aircraft->m_latitude, aircraft->m_longitude, aircraft->m_altitude);
|
||||
aircraft->m_coordinates.push_back(QVariant::fromValue(coord));
|
||||
updatePosition(aircraft);
|
||||
}
|
||||
}
|
||||
@ -1070,7 +1072,8 @@ void ADSBDemodGUI::handleADSB(
|
||||
aircraft->m_latitudeItem->setData(Qt::DisplayRole, aircraft->m_latitude);
|
||||
aircraft->m_longitude = longitude;
|
||||
aircraft->m_longitudeItem->setData(Qt::DisplayRole, aircraft->m_longitude);
|
||||
aircraft->m_coordinates.push_back(QVariant::fromValue(*new QGeoCoordinate(aircraft->m_latitude, aircraft->m_longitude, aircraft->m_altitude)));
|
||||
QGeoCoordinate coord(aircraft->m_latitude, aircraft->m_longitude, aircraft->m_altitude);
|
||||
aircraft->m_coordinates.push_back(QVariant::fromValue(coord));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2172,13 +2175,15 @@ ADSBDemodGUI::ADSBDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseb
|
||||
ADSBDemodGUI::~ADSBDemodGUI()
|
||||
{
|
||||
delete ui;
|
||||
QHash<int,Aircraft *>::iterator i = m_aircraft.begin();
|
||||
while (i != m_aircraft.end())
|
||||
{
|
||||
Aircraft *a = i.value();
|
||||
delete a;
|
||||
++i;
|
||||
qDeleteAll(m_aircraft);
|
||||
if (m_airportInfo) {
|
||||
qDeleteAll(*m_airportInfo);
|
||||
}
|
||||
if (m_aircraftInfo) {
|
||||
qDeleteAll(*m_aircraftInfo);
|
||||
}
|
||||
qDeleteAll(m_airlineIcons);
|
||||
qDeleteAll(m_flagIcons);
|
||||
if (m_flightInformation)
|
||||
{
|
||||
disconnect(m_flightInformation, &FlightInformation::flightUpdated, this, &ADSBDemodGUI::flightInformationUpdated);
|
||||
@ -2242,6 +2247,9 @@ void ADSBDemodGUI::displaySettings()
|
||||
ui->allFlightPaths->setChecked(m_settings.m_allFlightPaths);
|
||||
m_aircraftModel.setAllFlightPaths(m_settings.m_allFlightPaths);
|
||||
|
||||
ui->logFilename->setToolTip(QString(".csv log filename: %1").arg(m_settings.m_logFilename));
|
||||
ui->logEnable->setChecked(m_settings.m_logEnabled);
|
||||
|
||||
displayStreamIndex();
|
||||
|
||||
QFont font(m_settings.m_tableFontName, m_settings.m_tableFontSize);
|
||||
@ -2503,3 +2511,104 @@ void ADSBDemodGUI::flightInformationUpdated(const FlightInformation::Flight& fli
|
||||
qDebug() << "ADSBDemodGUI::flightInformationUpdated - Flight not found in ADS-B table: " << flight.m_flightICAO;
|
||||
}
|
||||
}
|
||||
|
||||
void ADSBDemodGUI::on_logEnable_clicked(bool checked)
|
||||
{
|
||||
m_settings.m_logEnabled = checked;
|
||||
applySettings();
|
||||
}
|
||||
|
||||
void ADSBDemodGUI::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 ADSBDemodGUI::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 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
|
||||
{
|
||||
QMessageBox dialog(this);
|
||||
dialog.setText("Reading ADS-B data");
|
||||
dialog.addButton(QMessageBox::Cancel);
|
||||
dialog.show();
|
||||
QApplication::processEvents();
|
||||
int count = 0;
|
||||
bool cancelled = false;
|
||||
while (!in.atEnd() && !cancelled)
|
||||
{
|
||||
QString row = in.readLine();
|
||||
QStringList cols = row.split(",");
|
||||
if (cols.size() >= dataCol)
|
||||
{
|
||||
//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();
|
||||
handleADSB(bytes, dateTime, correlation, correlation);
|
||||
if (count % 1000 == 0)
|
||||
{
|
||||
QApplication::processEvents();
|
||||
if (dialog.clickedButton()) {
|
||||
cancelled = true;
|
||||
}
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
dialog.close();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::critical(this, "ADS-B", QString("Failed to open file %1").arg(fileNames[0]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -618,6 +618,9 @@ private slots:
|
||||
void on_device_currentIndexChanged(int index);
|
||||
void feedSelect();
|
||||
void on_displaySettings_clicked();
|
||||
void on_logEnable_clicked(bool checked=false);
|
||||
void on_logFilename_clicked();
|
||||
void on_logOpen_clicked();
|
||||
signals:
|
||||
void homePositionChanged();
|
||||
};
|
||||
|
@ -167,13 +167,6 @@
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="levelMeterLayout">
|
||||
<item>
|
||||
<widget class="Line" name="line_5">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="channelPowerMeterUnits">
|
||||
<property name="text">
|
||||
@ -210,13 +203,6 @@
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="rfBWLayout">
|
||||
<item>
|
||||
<widget class="Line" name="line_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="rfBWLabel">
|
||||
<property name="text">
|
||||
@ -634,6 +620,60 @@
|
||||
</property>
|
||||
</widget>
|
||||
</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 frames 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="QLabel" name="stats">
|
||||
<property name="toolTip">
|
||||
|
@ -72,6 +72,8 @@ void ADSBDemodSettings::resetToDefaults()
|
||||
m_columnIndexes[i] = i;
|
||||
m_columnSizes[i] = -1; // Autosize
|
||||
}
|
||||
m_logFilename = "adsb_log.csv";
|
||||
m_logEnabled = false;
|
||||
}
|
||||
|
||||
QByteArray ADSBDemodSettings::serialize() const
|
||||
@ -118,6 +120,9 @@ QByteArray ADSBDemodSettings::serialize() const
|
||||
s.writeBlob(34, serializeNotificationSettings(m_notificationSettings));
|
||||
s.writeString(35, m_apiKey);
|
||||
|
||||
s.writeString(36, m_logFilename);
|
||||
s.writeBool(37, m_logEnabled);
|
||||
|
||||
for (int i = 0; i < ADSBDEMOD_COLUMNS; i++)
|
||||
s.writeS32(100 + i, m_columnIndexes[i]);
|
||||
for (int i = 0; i < ADSBDEMOD_COLUMNS; i++)
|
||||
@ -203,6 +208,9 @@ bool ADSBDemodSettings::deserialize(const QByteArray& data)
|
||||
deserializeNotificationSettings(blob, m_notificationSettings);
|
||||
d.readString(35, &m_apiKey, "");
|
||||
|
||||
d.readString(36, &m_logFilename, "adsb_log.csv");
|
||||
d.readBool(37, &m_logEnabled, false);
|
||||
|
||||
for (int i = 0; i < ADSBDEMOD_COLUMNS; i++)
|
||||
d.readS32(100 + i, &m_columnIndexes[i], i);
|
||||
for (int i = 0; i < ADSBDEMOD_COLUMNS; i++)
|
||||
|
@ -130,6 +130,9 @@ struct ADSBDemodSettings
|
||||
QList<NotificationSettings *> m_notificationSettings;
|
||||
QString m_apiKey; //!< aviationstack.com API key
|
||||
|
||||
QString m_logFilename;
|
||||
bool m_logEnabled;
|
||||
|
||||
ADSBDemodSettings();
|
||||
void resetToDefaults();
|
||||
void setChannelMarker(Serializable *channelMarker) { m_channelMarker = channelMarker; }
|
||||
|
@ -122,6 +122,8 @@ void ADSBDemodWorker::applySettings(const ADSBDemodSettings& settings, bool forc
|
||||
<< " m_feedHost: " << settings.m_feedHost
|
||||
<< " m_feedPort: " << settings.m_feedPort
|
||||
<< " m_feedFormat: " << settings.m_feedFormat
|
||||
<< " m_logEnabled: " << settings.m_logEnabled
|
||||
<< " m_logFilename: " << settings.m_logFilename
|
||||
<< " force: " << force;
|
||||
|
||||
if ((settings.m_feedEnabled != m_settings.m_feedEnabled)
|
||||
@ -136,6 +138,36 @@ void ADSBDemodWorker::applySettings(const ADSBDemodSettings& settings, bool forc
|
||||
m_socket.connectToHost(settings.m_feedHost, settings.m_feedPort);
|
||||
}
|
||||
|
||||
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() << "ADSBDemodWorker::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,Correlation\n";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "ADSBDemodWorker::applySettings - Unable to open log file: " << settings.m_logFilename;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_settings = settings;
|
||||
}
|
||||
|
||||
@ -185,49 +217,57 @@ char *ADSBDemodWorker::escape(char *p, char c)
|
||||
|
||||
// Forward ADS-B data in Beast binary format to specified server
|
||||
// See: https://wiki.jetvision.de/wiki/Mode-S_Beast:Data_Output_Formats
|
||||
// Log to .csv file
|
||||
void ADSBDemodWorker::handleADSB(QByteArray data, const QDateTime dateTime, float correlation)
|
||||
{
|
||||
if (m_settings.m_feedFormat == ADSBDemodSettings::BeastBinary)
|
||||
if (m_logFile.isOpen())
|
||||
{
|
||||
char beastBinary[2+6*2+1*2+14*2];
|
||||
int length;
|
||||
char *p = beastBinary;
|
||||
qint64 timestamp;
|
||||
unsigned char signalStrength;
|
||||
|
||||
timestamp = dateTime.toMSecsSinceEpoch();
|
||||
|
||||
if (correlation > 255)
|
||||
signalStrength = 255;
|
||||
if (correlation < 1)
|
||||
signalStrength = 1;
|
||||
else
|
||||
signalStrength = (unsigned char)correlation;
|
||||
|
||||
*p++ = BEAST_ESC;
|
||||
*p++ = '3'; // Mode-S long
|
||||
|
||||
p = escape(p, timestamp >> 56); // Big-endian timestamp
|
||||
p = escape(p, timestamp >> 48);
|
||||
p = escape(p, timestamp >> 32);
|
||||
p = escape(p, timestamp >> 24);
|
||||
p = escape(p, timestamp >> 16);
|
||||
p = escape(p, timestamp >> 8);
|
||||
p = escape(p, timestamp);
|
||||
|
||||
p = escape(p, signalStrength); // Signal strength
|
||||
|
||||
for (int i = 0; i < data.length(); i++) // ADS-B data
|
||||
p = escape(p, data[i]);
|
||||
|
||||
length = p - beastBinary;
|
||||
|
||||
send(beastBinary, length);
|
||||
m_logStream << dateTime.date().toString() << "," << dateTime.time().toString() << "," << data.toHex() << "," << correlation << "\n";
|
||||
}
|
||||
else if (m_settings.m_feedFormat == ADSBDemodSettings::BeastHex)
|
||||
if (m_settings.m_feedEnabled)
|
||||
{
|
||||
QString beastHex = "*" + data.toHex() + ";\n";
|
||||
send(beastHex.toUtf8(), beastHex.size());
|
||||
if (m_settings.m_feedFormat == ADSBDemodSettings::BeastBinary)
|
||||
{
|
||||
char beastBinary[2+6*2+1*2+14*2];
|
||||
int length;
|
||||
char *p = beastBinary;
|
||||
qint64 timestamp;
|
||||
unsigned char signalStrength;
|
||||
|
||||
timestamp = dateTime.toMSecsSinceEpoch();
|
||||
|
||||
if (correlation > 255)
|
||||
signalStrength = 255;
|
||||
if (correlation < 1)
|
||||
signalStrength = 1;
|
||||
else
|
||||
signalStrength = (unsigned char)correlation;
|
||||
|
||||
*p++ = BEAST_ESC;
|
||||
*p++ = '3'; // Mode-S long
|
||||
|
||||
p = escape(p, timestamp >> 56); // Big-endian timestamp
|
||||
p = escape(p, timestamp >> 48);
|
||||
p = escape(p, timestamp >> 32);
|
||||
p = escape(p, timestamp >> 24);
|
||||
p = escape(p, timestamp >> 16);
|
||||
p = escape(p, timestamp >> 8);
|
||||
p = escape(p, timestamp);
|
||||
|
||||
p = escape(p, signalStrength); // Signal strength
|
||||
|
||||
for (int i = 0; i < data.length(); i++) // ADS-B data
|
||||
p = escape(p, data[i]);
|
||||
|
||||
length = p - beastBinary;
|
||||
|
||||
send(beastBinary, length);
|
||||
}
|
||||
else if (m_settings.m_feedFormat == ADSBDemodSettings::BeastHex)
|
||||
{
|
||||
QString beastHex = "*" + data.toHex() + ";\n";
|
||||
send(beastHex.toUtf8(), beastHex.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,8 @@
|
||||
#include <QObject>
|
||||
#include <QTimer>
|
||||
#include <QTcpSocket>
|
||||
#include <QFile>
|
||||
#include <QTextStream>
|
||||
|
||||
#include "util/message.h"
|
||||
#include "util/messagequeue.h"
|
||||
@ -71,6 +73,8 @@ private:
|
||||
QMutex m_mutex;
|
||||
QTimer m_heartbeatTimer;
|
||||
QTcpSocket m_socket;
|
||||
QFile m_logFile;
|
||||
QTextStream m_logStream;
|
||||
|
||||
bool handleMessage(const Message& cmd);
|
||||
void applySettings(const ADSBDemodSettings& settings, bool force = false);
|
||||
|
@ -51,6 +51,11 @@ struct AirportInformation {
|
||||
float m_elevation;
|
||||
QVector<FrequencyInformation *> m_frequencies;
|
||||
|
||||
AirportInformation::~AirportInformation()
|
||||
{
|
||||
qDeleteAll(m_frequencies);
|
||||
}
|
||||
|
||||
static QString trimQuotes(const QString s)
|
||||
{
|
||||
if (s.startsWith('\"') && s.endsWith('\"'))
|
||||
|
@ -163,6 +163,18 @@ the case for callsigns that end in two characters, as for these, some digits fro
|
||||
|
||||
To use this feature, an (aviationstack)[aviationstack.com] API Key must be entered in the Display Settings dialog (11). A free key giving 500 API calls per month is (available)[https://aviationstack.com/product].
|
||||
|
||||
<h3>Start/stop Logging ADS-B frames to .csv File</h3>
|
||||
|
||||
When checked, writes all received ADS-B frames to a .csv file.
|
||||
|
||||
<h3>.csv Log Filename</h3>
|
||||
|
||||
Click to specify the name of the .csv file which received ADS-B frames are logged to.
|
||||
|
||||
<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.
|
||||
|
||||
<h3>14: Refresh list of devices</h3>
|
||||
|
||||
Use this button to refresh the list of devices.
|
||||
|
@ -22,6 +22,10 @@ ADSBDemodSettings:
|
||||
type: string
|
||||
beastPort:
|
||||
type: integer
|
||||
logFilename:
|
||||
type: string
|
||||
logEnabled:
|
||||
type: integer
|
||||
rgbColor:
|
||||
type: integer
|
||||
title:
|
||||
|
@ -44,6 +44,10 @@ SWGADSBDemodSettings::SWGADSBDemodSettings() {
|
||||
m_beast_host_isSet = false;
|
||||
beast_port = 0;
|
||||
m_beast_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;
|
||||
@ -84,6 +88,10 @@ SWGADSBDemodSettings::init() {
|
||||
m_beast_host_isSet = false;
|
||||
beast_port = 0;
|
||||
m_beast_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("");
|
||||
@ -114,6 +122,10 @@ SWGADSBDemodSettings::cleanup() {
|
||||
delete beast_host;
|
||||
}
|
||||
|
||||
if(log_filename != nullptr) {
|
||||
delete log_filename;
|
||||
}
|
||||
|
||||
|
||||
if(title != nullptr) {
|
||||
delete title;
|
||||
@ -155,6 +167,10 @@ SWGADSBDemodSettings::fromJsonObject(QJsonObject &pJson) {
|
||||
|
||||
::SWGSDRangel::setValue(&beast_port, pJson["beastPort"], "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 @@ SWGADSBDemodSettings::asJsonObject() {
|
||||
if(m_beast_port_isSet){
|
||||
obj->insert("beastPort", QJsonValue(beast_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));
|
||||
}
|
||||
@ -319,6 +341,26 @@ SWGADSBDemodSettings::setBeastPort(qint32 beast_port) {
|
||||
this->m_beast_port_isSet = true;
|
||||
}
|
||||
|
||||
QString*
|
||||
SWGADSBDemodSettings::getLogFilename() {
|
||||
return log_filename;
|
||||
}
|
||||
void
|
||||
SWGADSBDemodSettings::setLogFilename(QString* log_filename) {
|
||||
this->log_filename = log_filename;
|
||||
this->m_log_filename_isSet = true;
|
||||
}
|
||||
|
||||
qint32
|
||||
SWGADSBDemodSettings::getLogEnabled() {
|
||||
return log_enabled;
|
||||
}
|
||||
void
|
||||
SWGADSBDemodSettings::setLogEnabled(qint32 log_enabled) {
|
||||
this->log_enabled = log_enabled;
|
||||
this->m_log_enabled_isSet = true;
|
||||
}
|
||||
|
||||
qint32
|
||||
SWGADSBDemodSettings::getRgbColor() {
|
||||
return rgb_color;
|
||||
@ -428,6 +470,12 @@ SWGADSBDemodSettings::isSet(){
|
||||
if(m_beast_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;
|
||||
}
|
||||
|
@ -66,6 +66,12 @@ public:
|
||||
qint32 getBeastPort();
|
||||
void setBeastPort(qint32 beast_port);
|
||||
|
||||
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 beast_port;
|
||||
bool m_beast_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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user