1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-12-23 10:05:46 -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:
Jon Beniston 2021-11-03 17:19:21 +00:00
parent 71d2378b7e
commit 132244ef64
13 changed files with 388 additions and 62 deletions

View File

@ -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);
}

View File

@ -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]));
}
}
}
}

View File

@ -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();
};

View File

@ -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">

View File

@ -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++)

View File

@ -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; }

View File

@ -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());
}
}
}

View File

@ -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);

View File

@ -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('\"'))

View File

@ -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.

View File

@ -22,6 +22,10 @@ ADSBDemodSettings:
type: string
beastPort:
type: integer
logFilename:
type: string
logEnabled:
type: integer
rgbColor:
type: integer
title:

View File

@ -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;
}

View File

@ -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;