diff --git a/companion/src/appdebugmessagehandler.cpp b/companion/src/appdebugmessagehandler.cpp index ab2ee3858..0a75d7949 100644 --- a/companion/src/appdebugmessagehandler.cpp +++ b/companion/src/appdebugmessagehandler.cpp @@ -20,6 +20,8 @@ #include "appdebugmessagehandler.h" +#include + AppDebugMessageHandler::AppDebugMessageHandler(QObject * parent) : QObject(parent), m_appDebugOutputLevel(APP_DBG_HANDLER_DEFAULT_LEVEL), @@ -55,6 +57,25 @@ void AppDebugMessageHandler::setShowFunctionDeclarations(bool showFunctionDeclar m_showFunctionDeclarations = showFunctionDeclarations; } +void AppDebugMessageHandler::addOutputDevice(QIODevice * device) +{ + if (device && !m_outputDevices.contains(device)) + m_outputDevices.append(device); +} + +void AppDebugMessageHandler::removeOutputDevice(QIODevice * device) +{ + if (device) { + // no QVector::removeAll() in Qt < 5.4 + int i = 0; + foreach (QIODevice * d, m_outputDevices) { + if (d == device) + m_outputDevices.remove(i); + ++i; + } + } +} + void AppDebugMessageHandler::installAppMessageHandler() { m_defaultHandler = qInstallMessageHandler(g_appDebugMessageHandler); @@ -98,7 +119,7 @@ void AppDebugMessageHandler::messageHandler(QtMsgType type, const QMessageLogCon qSetMessagePattern(msgPattern); - if (!m_defaultHandler || receivers(SIGNAL(messageOutput(quint8, const QString &)))) { + if (!m_defaultHandler || m_outputDevices.size() || receivers(SIGNAL(messageOutput(quint8, const QString &)))) { #if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)) msgPattern = qFormatLogMessage(type, context, msg); #else @@ -112,6 +133,14 @@ void AppDebugMessageHandler::messageHandler(QtMsgType type, const QMessageLogCon #endif emit messageOutput(lvl, msgPattern); + + foreach (QIODevice * d, m_outputDevices) { + if (d && d->isWritable() && (!d->property("level").isValid() || d->property("level").toInt() <= lvl)) { + d->write(qPrintable(msgPattern % "\n")); + if (QFileDevice * fd = qobject_cast(d)) + fd->flush(); + } + } } // if (QThread::currentThread() == qApp->thread()) // gui thread diff --git a/companion/src/appdebugmessagehandler.h b/companion/src/appdebugmessagehandler.h index 648090b16..7ea682899 100644 --- a/companion/src/appdebugmessagehandler.h +++ b/companion/src/appdebugmessagehandler.h @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -94,7 +95,7 @@ #else #define qInfo qDebug #endif - #define QtInfoMsg 4 + #define QtInfoMsg QtMsgType(4) #endif class AppDebugMessageHandler : public QObject @@ -110,6 +111,8 @@ class AppDebugMessageHandler : public QObject void setAppDebugOutputLevel(const quint8 & appDebugOutputLevel); void setShowSourcePath(bool showSourcePath); void setShowFunctionDeclarations(bool showFunctionDeclarations); + void addOutputDevice(QIODevice * device); + void removeOutputDevice(QIODevice * device); void installAppMessageHandler(); void messageHandler(QtMsgType type, const QMessageLogContext & context, const QString & msg); @@ -123,6 +126,7 @@ class AppDebugMessageHandler : public QObject QRegularExpression m_srcPathFilter; QRegularExpression m_functionFilter; quint8 m_appDebugOutputLevel; + QVector m_outputDevices; bool m_showSourcePath; bool m_showFunctionDeclarations; diff --git a/companion/src/apppreferencesdialog.cpp b/companion/src/apppreferencesdialog.cpp index c68d44332..1d8bf7b3b 100644 --- a/companion/src/apppreferencesdialog.cpp +++ b/companion/src/apppreferencesdialog.cpp @@ -41,6 +41,8 @@ AppPreferencesDialog::AppPreferencesDialog(QWidget * parent) : initSettings(); connect(ui->downloadVerCB, SIGNAL(currentIndexChanged(int)), this, SLOT(baseFirmwareChanged())); + connect(ui->opt_appDebugLog, &QCheckBox::toggled, this, &AppPreferencesDialog::toggleAppLogSettings); + connect(ui->opt_fwTraceLog, &QCheckBox::toggled, this, &AppPreferencesDialog::toggleAppLogSettings); connect(this, SIGNAL(accepted()), this, SLOT(writeValues())); #if !defined(JOYSTICKS) @@ -77,6 +79,10 @@ void AppPreferencesDialog::writeValues() g.embedSplashes(ui->splashincludeCB->currentIndex()); g.enableBackup(ui->backupEnable->isChecked()); + g.appDebugLog(ui->opt_appDebugLog->isChecked()); + g.fwTraceLog(ui->opt_fwTraceLog->isChecked()); + g.appLogsDir(ui->appLogsDir->text()); + if (ui->joystickChkB ->isChecked() && ui->joystickCB->isEnabled()) { g.jsSupport(ui->joystickChkB ->isChecked()); g.jsCtrl(ui->joystickCB ->currentIndex()); @@ -168,10 +174,15 @@ void AppPreferencesDialog::initSettings() } } else { - ui->backupEnable->setDisabled(true); + ui->backupEnable->setDisabled(true); } ui->splashincludeCB->setCurrentIndex(g.embedSplashes()); + ui->opt_appDebugLog->setChecked(g.appDebugLog()); + ui->opt_fwTraceLog->setChecked(g.fwTraceLog()); + ui->appLogsDir->setText(g.appLogsDir()); + toggleAppLogSettings(); + #if defined(JOYSTICKS) ui->joystickChkB->setChecked(g.jsSupport()); if (ui->joystickChkB->isChecked()) { @@ -286,6 +297,15 @@ void AppPreferencesDialog::on_ProfilebackupPathButton_clicked() } } + +void AppPreferencesDialog::on_btn_appLogsDir_clicked() +{ + QString fileName = QFileDialog::getExistingDirectory(this, tr("Select a folder for application logs"), ui->appLogsDir->text()); + if (!fileName.isEmpty()) { + ui->appLogsDir->setText(fileName); + } +} + void AppPreferencesDialog::on_ge_pathButton_clicked() { QString fileName = QFileDialog::getOpenFileName(this, tr("Select Google Earth executable"),ui->ge_lineedit->text()); @@ -458,6 +478,14 @@ void AppPreferencesDialog::firmwareOptionChanged(bool state) } } +void AppPreferencesDialog::toggleAppLogSettings() +{ + bool vis = (ui->opt_appDebugLog->isChecked() || ui->opt_fwTraceLog->isChecked()); + ui->appLogsDir->setVisible(vis); + ui->lbl_appLogsDir->setVisible(vis); + ui->btn_appLogsDir->setVisible(vis); +} + void AppPreferencesDialog::populateFirmwareOptions(const Firmware * firmware) { const Firmware * parent = firmware->getFirmwareBase(); @@ -539,4 +567,3 @@ void AppPreferencesDialog::shrink() { adjustSize(); } - diff --git a/companion/src/apppreferencesdialog.h b/companion/src/apppreferencesdialog.h index 19c67e6a1..82bb84a56 100644 --- a/companion/src/apppreferencesdialog.h +++ b/companion/src/apppreferencesdialog.h @@ -62,6 +62,7 @@ class AppPreferencesDialog : public QDialog void shrink(); void baseFirmwareChanged(); void firmwareOptionChanged(bool state); + void toggleAppLogSettings(); void writeValues(); void on_libraryPathButton_clicked(); @@ -74,6 +75,7 @@ class AppPreferencesDialog : public QDialog void on_sdPathButton_clicked(); void on_SplashSelect_clicked(); void on_clearImageButton_clicked(); + void on_btn_appLogsDir_clicked(); #if defined(JOYSTICKS) void on_joystickChkB_clicked(); diff --git a/companion/src/apppreferencesdialog.ui b/companion/src/apppreferencesdialog.ui index 9bd90b07d..b0978aab2 100644 --- a/companion/src/apppreferencesdialog.ui +++ b/companion/src/apppreferencesdialog.ui @@ -6,8 +6,8 @@ 0 0 - 623 - 537 + 703 + 534 @@ -26,9 +26,6 @@ true - - 6 - @@ -763,189 +760,454 @@ Mode 4: Application Settings - - - - - - 0 - 0 - + + + + + 6 - - Automatic Backup Folder - - - - - - - Automatic check for Companion updates - - - true - - - - - - - Show splash screen when Companion starts - - - true - - - - - - - - 40 - 0 - - - - - 50 - 16777215 - - - - 50 - - - 10 - - - - - - - Use OpenTX firmware nightly builds - - - false - - - - - - - - 350 - 0 - - - - false - - - - - - - - 0 - 0 - - - - - Only show user splash images - + + + + + + Use Companion nightly builds + + + false + + + + + + + Use firmware nightly builds + + + false + + + + + + + Automatic check for OpenTX firmware updates + + + true + + + + + + + Automatic check for Companion updates + + + true + + + + - - - Show user and companion splash images - + + + + 6 + + + + + + 40 + 0 + + + + 50 + + + 10 + + + + + + + + 0 + 0 + + + + most recently used files + + + + - + + + + + 0 + 0 + + + + Startup Settings + + + + + + + + 0 + 0 + + + + Google Earth Executable + + + + + + + + 0 + 0 + + + + Automatic Backup Folder + + + + + + + Qt::Horizontal + + + + + + + + 0 + 0 + + + + Remember + + + + + + + Show splash screen when Companion starts + + + true + + + + + + + + + false + + + + + + + + 0 + 0 + + + + Select Folder + + + + + + + + + + + true + + + false + + + + + + + + 0 + 0 + + + + Select Folder + + + + + + + + + + 0 + 0 + + + + Output Logs Folder + + + + + + + Qt::Horizontal + + + + + + + <html><head/><body><p>This option maintains the behaviour from older OpenTx versions where empty model slots are preserved when a model is deleted or moved. </p><p>When this option is de-selected, the other models may be re-arranged to fill the gap left by the removed model.</p></body></html> + + + Remove empty model slots when deleting models (only applies for radios w/out categories) + + + + + + + + + Use model wizard + + + btnGrp_newModelActions + + + + + + + Open model editor + + + btnGrp_newModelActions + + + + + + + Just create the model + + + btnGrp_newModelActions + + + + + + + + + + 0 + 0 + + + + Enable automatic backup before writing firmware + + + + + + + + 0 + 0 + + + + Debug Output Logging + + + + + + + Qt::Horizontal + + + + + + + + 0 + 0 + + + + + Only show user splash images + + + + + Show user and companion splash images + + + + + + + + Qt::Horizontal + + + + + + + + + true + + + + + + + + 0 + 0 + + + + Select Executable + + + + + + + + + + + true + + + false + + + + + + + Select Folder + + + + + + + + + + + <html><head/><body><p>Keep a log of all debugging messages generated by the desktop Companion/Simulator applications. An OpenTX developer may request this to help diagnose an issue.</p></body></html> + + + Application (Companion/Simulator) + + + + + + + <html><head/><body><p>Keep a log of all messages generated by the radio firmware when running in Simulator. This is the same information one would also see in the Simulator <span style=" font-style:italic;">Debug Output</span> window.</p></body></html> + + + Radio Firmware (in Simulator) + + + + + + + + + + 0 + 0 + + + + Splash Screen Library + + + + + + + + 0 + 0 + + + + User Splash Screens + + + + + + + + 0 + 0 + + + + Action on New Model + + + + + + + Qt::Horizontal + + + + - - - - Qt::Horizontal - - - - - - - - 0 - 0 - - - - Files to keep - - - - - - - Qt::Horizontal - - - - - - - Qt::Horizontal - - - - - - - Automatic check for OpenTX firmware updates - - - true - - - - - - - - 0 - 0 - - - - Select Folder - - - - - - - - 0 - 0 - - - - Splash Screen Library - - - - - - - - 0 - 0 - - - - Google Earth Executable - - - - + Qt::Vertical @@ -958,155 +1220,6 @@ Mode 4: - - - - - 0 - 0 - - - - Enable automatic backup before writing firmware - - - - - - - true - - - false - - - - - - - Qt::Horizontal - - - - - - - - 0 - 0 - - - - User Splash Screens - - - - - - - Use Companion nightly builds - - - false - - - - - - - - 350 - 0 - - - - true - - - - - - - - 0 - 0 - - - - Select Executable - - - - - - - - 0 - 0 - - - - Select Folder - - - - - - - - 0 - 0 - - - - Action on New Model - - - - - - - <html><head/><body><p>This option maintains the behaviour from older OpenTx versions where empty model slots are preserved when a model is deleted or moved. </p><p>When this option is de-selected, the other models may be re-arranged to fill the gap left by the removed model.</p></body></html> - - - Remove empty model slots when deleting models (only applies for radios w/out categories) - - - - - - - - - Use model wizard - - - btnGrp_newModelActions - - - - - - - Open model editor - - - btnGrp_newModelActions - - - - - - - Just create the model - - - btnGrp_newModelActions - - - - - @@ -1181,7 +1294,7 @@ Mode 4: - Simulator capture folder + Screenshot capture folder @@ -1363,18 +1476,7 @@ Mode 4: channelorderCB renameFirmware burnFirmware - ge_lineedit - ge_pathButton - historySize - showSplash - autoCheckFirmware - autoCheckCompanion - backupPath - backupPathButton - backupEnable splashincludeCB - libraryPath - libraryPathButton snapshotPath snapshotPathButton snapshotClipboardCKB diff --git a/companion/src/companion.cpp b/companion/src/companion.cpp index 7519ff054..864438fda 100644 --- a/companion/src/companion.cpp +++ b/companion/src/companion.cpp @@ -19,6 +19,9 @@ */ #include +#include +#include +#include #include #if defined(JOYSTICKS) || defined(SIMU_AUDIO) #include @@ -77,14 +80,21 @@ int main(int argc, char *argv[]) exit(0); } + QFile dbgLog; + if (AppDebugMessageHandler::instance() && g.appDebugLog() && !g.appLogsDir().isEmpty() && QDir().mkpath(g.appLogsDir())) { + QString fn = g.appLogsDir() % "/CompanionDebug_" % QDateTime::currentDateTime().toString("yy-MM-dd_HH-mm-ss") % ".log"; + dbgLog.setFileName(fn); + if (dbgLog.open(QIODevice::WriteOnly | QIODevice::Text)) { + AppDebugMessageHandler::instance()->addOutputDevice(&dbgLog); + } + } + #ifdef __APPLE__ app.setStyle(new MyProxyStyle); #endif Translations::installTranslators(); - // QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8")); - #if defined(JOYSTICKS) || defined(SIMU_AUDIO) uint32_t sdlFlags = 0; #ifdef JOYSTICKS @@ -139,5 +149,11 @@ int main(int argc, char *argv[]) #endif qDebug() << "COMPANION EXIT" << result; + + if (dbgLog.isOpen()) { + AppDebugMessageHandler::instance()->removeOutputDevice(&dbgLog); + dbgLog.close(); + } + return result; } diff --git a/companion/src/firmwares/er9x/er9xinterface.cpp b/companion/src/firmwares/er9x/er9xinterface.cpp index 8f04de3c6..e3ef6d424 100644 --- a/companion/src/firmwares/er9x/er9xinterface.cpp +++ b/companion/src/firmwares/er9x/er9xinterface.cpp @@ -82,7 +82,9 @@ inline void applyStickModeToModel(Er9xModelData & model, unsigned int mode) #if 0 unsigned long Er9xInterface::loadxml(RadioData &radioData, QDomDocument &doc) { - std::cout << "trying er9x xml import... "; + QDebug dbg = qDebug(); + dbg.setAutoInsertSpaces(false); + dbg << "trying er9x xml import... "; std::bitset errors; @@ -94,7 +96,7 @@ unsigned long Er9xInterface::loadxml(RadioData &radioData, QDomDocument &doc) } else { radioData.generalSettings=er9xGeneral; - std::cout << "version " << (unsigned int)er9xGeneral.myVers << " "; + dbg << "version " << (unsigned int)er9xGeneral.myVers << " "; } for (int i=0; i errors; if (size != Boards::getEEpromSize(Board::BOARD_STOCK)) { - std::cout << "wrong size\n"; + dbg << "wrong size"; errors.set(WRONG_SIZE); return errors.to_ulong(); } if (!efile->EeFsOpen((uint8_t *)eeprom, size, Board::BOARD_STOCK)) { - std::cout << "wrong file system\n"; + dbg << "wrong file system"; errors.set(WRONG_FILE_SYSTEM); return errors.to_ulong(); } @@ -132,16 +136,16 @@ unsigned long Er9xInterface::load(RadioData &radioData, const uint8_t *eeprom, i Er9xGeneral er9xGeneral; if (efile->readRlc1((uint8_t*)&er9xGeneral, 1) != 1) { - std::cout << "no\n"; + dbg << "no"; errors.set(UNKNOWN_ERROR); return errors.to_ulong(); } - std::cout << "version " << (unsigned int)er9xGeneral.myVers << " "; + dbg << "version " << (unsigned int)er9xGeneral.myVers << " "; switch(er9xGeneral.myVers) { case 3: - std::cout << "(old gruvin9x) "; + dbg << "(old gruvin9x) "; case 4: // case 5: case 6: @@ -151,14 +155,14 @@ unsigned long Er9xInterface::load(RadioData &radioData, const uint8_t *eeprom, i case 10: break; default: - std::cout << "not er9x\n"; + dbg << "not er9x"; errors.set(NOT_ER9X); return errors.to_ulong(); } efile->openRd(FILE_GENERAL); if (!efile->readRlc1((uint8_t*)&er9xGeneral, sizeof(Er9xGeneral))) { - std::cout << "ko\n"; + dbg << "ko"; errors.set(UNKNOWN_ERROR); return errors.to_ulong(); @@ -177,7 +181,7 @@ unsigned long Er9xInterface::load(RadioData &radioData, const uint8_t *eeprom, i } } - std::cout << "ok\n"; + dbg << "ok"; errors.set(ALL_OK); return errors.to_ulong(); } diff --git a/companion/src/firmwares/ersky9x/ersky9xinterface.cpp b/companion/src/firmwares/ersky9x/ersky9xinterface.cpp index 71e2555dc..0e7e87e01 100644 --- a/companion/src/firmwares/ersky9x/ersky9xinterface.cpp +++ b/companion/src/firmwares/ersky9x/ersky9xinterface.cpp @@ -116,7 +116,9 @@ inline void applyStickModeToModel(Ersky9xModelData_v11 & model, unsigned int mod #if 0 unsigned long Ersky9xInterface::loadxml(RadioData &radioData, QDomDocument &doc) { - std::cout << "trying ersky9x xml import... "; + QDebug dbg = qDebug(); + dbg.setAutoInsertSpaces(false); + dbg << "trying ersky9x xml import... "; std::bitset errors; @@ -128,25 +130,25 @@ unsigned long Ersky9xInterface::loadxml(RadioData &radioData, QDomDocument &doc) } else { radioData.generalSettings=ersky9xGeneral; - std::cout << "version " << (unsigned int)ersky9xGeneral.myVers << " "; + dbg << "version " << (unsigned int)ersky9xGeneral.myVers << " "; } for(int i=0; i(&doc, &radioData.models[i], i, radioData.generalSettings.stickMode+1)) { - std::cout << "ko\n"; + dbg << "ko"; errors.set(UNKNOWN_ERROR); return errors.to_ulong(); } } else { if (!loadModelDataXML(&doc, &radioData.models[i], i, radioData.generalSettings.stickMode+1)) { - std::cout << "ko\n"; + dbg << "ko"; errors.set(UNKNOWN_ERROR); return errors.to_ulong(); } } } - std::cout << "ok\n"; + dbg << "ok"; errors.set(ALL_OK); return errors.to_ulong(); } @@ -154,18 +156,20 @@ unsigned long Ersky9xInterface::loadxml(RadioData &radioData, QDomDocument &doc) unsigned long Ersky9xInterface::load(RadioData &radioData, const uint8_t *eeprom, int size) { - std::cout << "trying ersky9x import... "; + QDebug dbg = qDebug(); + dbg.setAutoInsertSpaces(false); + dbg << "trying ersky9x import... "; std::bitset errors; if (size != Boards::getEEpromSize(Board::BOARD_SKY9X)) { - std::cout << "wrong size\n"; + dbg << "wrong size"; errors.set(WRONG_SIZE); return errors.to_ulong(); } if (!efile->EeFsOpen((uint8_t *)eeprom, size, Board::BOARD_SKY9X)) { - std::cout << "wrong file system\n"; + dbg << "wrong file system"; errors.set(WRONG_FILE_SYSTEM); return errors.to_ulong(); } @@ -174,12 +178,12 @@ unsigned long Ersky9xInterface::load(RadioData &radioData, const uint8_t *eeprom Ersky9xGeneral ersky9xGeneral; if (efile->readRlc2((uint8_t*)&ersky9xGeneral, 1) != 1) { - std::cout << "no\n"; + dbg << "no"; errors.set(UNKNOWN_ERROR); return errors.to_ulong(); } - std::cout << "version " << (unsigned int)ersky9xGeneral.myVers << " "; + dbg << "version " << (unsigned int)ersky9xGeneral.myVers << " "; switch(ersky9xGeneral.myVers) { case 10: @@ -187,13 +191,13 @@ unsigned long Ersky9xInterface::load(RadioData &radioData, const uint8_t *eeprom case 11: break; default: - std::cout << "not ersky9x\n"; + dbg << "not ersky9x"; errors.set(NOT_ERSKY9X); return errors.to_ulong(); } efile->openRd(FILE_GENERAL); if (!efile->readRlc2((uint8_t*)&ersky9xGeneral, sizeof(Ersky9xGeneral))) { - std::cout << "ko\n"; + dbg << "ko"; errors.set(UNKNOWN_ERROR); return errors.to_ulong(); } @@ -225,7 +229,7 @@ unsigned long Ersky9xInterface::load(RadioData &radioData, const uint8_t *eeprom } } - std::cout << "ok\n"; + dbg << "ok"; errors.set(ALL_OK); return errors.to_ulong(); } diff --git a/companion/src/firmwares/opentx/opentxinterface.cpp b/companion/src/firmwares/opentx/opentxinterface.cpp index 67fff2d16..f55009699 100644 --- a/companion/src/firmwares/opentx/opentxinterface.cpp +++ b/companion/src/firmwares/opentx/opentxinterface.cpp @@ -107,7 +107,7 @@ bool OpenTxEepromInterface::loadRadioSettingsFromRLE(GeneralSettings & settings, return checkVariant(settings.version, settings.variant); } else { - std::cout << " error when loading general settings"; + qWarning() << " error when loading general settings"; return false; } } @@ -180,7 +180,9 @@ bool OpenTxEepromInterface::loadFromByteArray(T & dest, const QByteArray & data) unsigned long OpenTxEepromInterface::load(RadioData &radioData, const uint8_t * eeprom, int size) { - std::cout << "trying " << getName() << " import..."; + QDebug dbg = qDebug(); + dbg.setAutoInsertSpaces(false); + dbg << "trying " << getName() << " import..."; std::bitset errors; @@ -193,7 +195,7 @@ unsigned long OpenTxEepromInterface::load(RadioData &radioData, const uint8_t * } } if (notnull) { - std::cout << " wrong size (" << size << ")\n"; + dbg << " wrong size (" << size << ")"; errors.set(WRONG_SIZE); return errors.to_ulong(); } @@ -204,14 +206,14 @@ unsigned long OpenTxEepromInterface::load(RadioData &radioData, const uint8_t * } } else { - std::cout << " wrong size (" << size << "/" << Boards::getEEpromSize(board) << ")\n"; + dbg << " wrong size (" << size << "/" << Boards::getEEpromSize(board) << ")"; errors.set(WRONG_SIZE); return errors.to_ulong(); } } if (!efile->EeFsOpen((uint8_t *) eeprom, size, board)) { - std::cout << " wrong file system\n"; + dbg << " wrong file system"; errors.set(WRONG_FILE_SYSTEM); return errors.to_ulong(); } @@ -220,12 +222,12 @@ unsigned long OpenTxEepromInterface::load(RadioData &radioData, const uint8_t * uint8_t version; if (efile->readRlc2(&version, 1) != 1) { - std::cout << " no\n"; + dbg << " no"; errors.set(UNKNOWN_ERROR); return errors.to_ulong(); } - std::cout << " version " << (unsigned int) version; + dbg << " version " << (unsigned int) version; EepromLoadErrors version_error = checkVersion(version); if (version_error == OLD_VERSION) { @@ -234,24 +236,24 @@ unsigned long OpenTxEepromInterface::load(RadioData &radioData, const uint8_t * ShowEepromWarnings(NULL, QObject::tr("Warning"), errors.to_ulong()); } else if (version_error == NOT_OPENTX) { - std::cout << " not open9x\n"; + dbg << " not open9x"; errors.set(version_error); return errors.to_ulong(); } if (!loadRadioSettingsFromRLE(radioData.generalSettings, efile, version)) { - std::cout << " ko\n"; + dbg << " ko"; errors.set(UNKNOWN_ERROR); return errors.to_ulong(); } - std::cout << " variant " << radioData.generalSettings.variant; + dbg << " variant " << radioData.generalSettings.variant; if (getCurrentFirmware()->getCapability(Models) == 0) { radioData.models.resize(firmware->getCapability(Models)); } for (int i = 0; i < firmware->getCapability(Models); i++) { if (i < (int)radioData.models.size() && !loadModelFromRLE(radioData.models[i], efile, i, version, radioData.generalSettings.variant)) { - std::cout << " ko\n"; + dbg << " ko"; errors.set(UNKNOWN_ERROR); if (getCurrentFirmware()->getCapability(Models) == 0) { radioData.models.resize(i); @@ -259,7 +261,7 @@ unsigned long OpenTxEepromInterface::load(RadioData &radioData, const uint8_t * return errors.to_ulong(); } } - std::cout << " ok\n"; + dbg << " ok"; errors.set(ALL_OK); return errors.to_ulong(); } @@ -939,29 +941,29 @@ bool OpenTxEepromInterface::checkVariant(unsigned int version, unsigned int vari efile->openRd(i); int sz = efile->readRlc2(tmp, sizeof(tmp)); if (sz == 849) { - std::cout << " warning: M128 variant not set (but model size seems ok)"; + qWarning() << " warning: M128 variant not set (but model size seems ok)"; return true; } } } - std::cout << " wrong variant (" << variant << ")"; + qWarning() << " wrong variant (" << variant << ")"; return false; } else if (IS_TARANIS_X9E(board)) { if (variant != TARANIS_X9E_VARIANT) { - std::cout << " wrong variant (" << variant << ")"; + qWarning() << " wrong variant (" << variant << ")"; return false; } } else if (IS_TARANIS_X7(board)) { if (variant != TARANIS_X7_VARIANT) { - std::cout << " wrong variant (" << variant << ")"; + qWarning() << " wrong variant (" << variant << ")"; return false; } } else if (IS_TARANIS(board)) { if (variant != 0) { - std::cout << " wrong variant (" << variant << ")"; + qWarning() << " wrong variant (" << variant << ")"; return false; } } @@ -994,10 +996,12 @@ unsigned long OpenTxEepromInterface::loadBackup(RadioData &radioData, const uint { std::bitset errors; - std::cout << "trying " << getName() << " backup import..."; + QDebug dbg = qDebug(); + dbg.setAutoInsertSpaces(false); + dbg << "trying " << getName() << " backup import..."; if (esize < 8 || memcmp(eeprom, "o9x", 3) != 0) { - std::cout << " no\n"; + dbg << " no\n"; errors.set(WRONG_SIZE); return errors.to_ulong(); } @@ -1014,13 +1018,13 @@ unsigned long OpenTxEepromInterface::loadBackup(RadioData &radioData, const uint backupBoard = BOARD_GRUVIN9X; break; default: - std::cout << " unknown board\n"; + dbg << " unknown board"; errors.set(UNKNOWN_BOARD); return errors.to_ulong(); } if (backupBoard != board) { - std::cout << " not right board\n"; + dbg << " not right board"; errors.set(WRONG_BOARD); return errors.to_ulong(); } @@ -1030,7 +1034,7 @@ unsigned long OpenTxEepromInterface::loadBackup(RadioData &radioData, const uint uint16_t size = ((uint16_t) eeprom[7] << 8) + eeprom[6]; uint16_t variant = ((uint16_t) eeprom[9] << 8) + eeprom[8]; - std::cout << " version " << (unsigned int) version << " "; + dbg << " version " << (unsigned int) version << " "; EepromLoadErrors version_error = checkVersion(version); if (version_error == OLD_VERSION) { @@ -1038,31 +1042,31 @@ unsigned long OpenTxEepromInterface::loadBackup(RadioData &radioData, const uint errors.set(HAS_WARNINGS); } else if (version_error == NOT_OPENTX) { - std::cout << " not open9x\n"; + dbg << " not open9x"; errors.set(version_error); return errors.to_ulong(); } if (size > esize - 8) { - std::cout << " wrong size\n"; + dbg << " wrong size"; errors.set(WRONG_SIZE); return errors.to_ulong(); } if (bcktype == 'M') { if (!loadModelFromBackup(radioData.models[index], &eeprom[8], size, version, variant)) { - std::cout << " ko\n"; + dbg << " ko"; errors.set(UNKNOWN_ERROR); return errors.to_ulong(); } } else { - std::cout << " backup type not supported\n"; + dbg << " backup type not supported"; errors.set(BACKUP_NOT_SUPPORTED); return errors.to_ulong(); } - std::cout << " ok\n"; + dbg << " ok"; errors.set(ALL_OK); return errors.to_ulong(); } diff --git a/companion/src/simulation/debugoutput.cpp b/companion/src/simulation/debugoutput.cpp index c031084f0..006865bcc 100644 --- a/companion/src/simulation/debugoutput.cpp +++ b/companion/src/simulation/debugoutput.cpp @@ -94,8 +94,11 @@ DebugOutput::DebugOutput(QWidget * parent, SimulatorInterface *simulator): connect(ui->actionToggleFilter, &QAction::toggled, this, &DebugOutput::onFilterToggled); connect(ui->filterText, &QComboBox::currentTextChanged, this, &DebugOutput::onFilterTextChanged); - if (AppDebugMessageHandler::instance()) - connect(AppDebugMessageHandler::instance(), &AppDebugMessageHandler::messageOutput, this, &DebugOutput::onAppDebugMessage); + if (AppDebugMessageHandler::instance()) { + // send application Info/Warning/Error events to our data collector + m_dataBufferDevice->setProperty("level", 1); + AppDebugMessageHandler::instance()->addOutputDevice(m_dataBufferDevice); + } // send firmware TRACE events to our data collector m_simulator->addTracebackDevice(m_dataBufferDevice); @@ -103,10 +106,9 @@ DebugOutput::DebugOutput(QWidget * parent, SimulatorInterface *simulator): DebugOutput::~DebugOutput() { - if (AppDebugMessageHandler::instance()) - disconnect(AppDebugMessageHandler::instance(), 0, this, 0); - if (m_dataBufferDevice) { + if (AppDebugMessageHandler::instance()) + AppDebugMessageHandler::instance()->removeOutputDevice(m_dataBufferDevice); m_simulator->removeTracebackDevice(m_dataBufferDevice); disconnect(m_dataBufferDevice, 0, this, 0); disconnect(this, 0, m_dataBufferDevice, 0); @@ -201,13 +203,6 @@ void DebugOutput::onDataBufferOverflow(const qint64 len) } } -void DebugOutput::onAppDebugMessage(quint8 level, const QString & msg) -{ - if (level > 0 && m_dataBufferDevice) { - m_dataBufferDevice->write(qPrintable(msg % "\n")); - } -} - /* * UI handlers */ diff --git a/companion/src/simulation/debugoutput.h b/companion/src/simulation/debugoutput.h index b7a325b46..0e08e6c5b 100644 --- a/companion/src/simulation/debugoutput.h +++ b/companion/src/simulation/debugoutput.h @@ -72,7 +72,6 @@ class DebugOutput : public QWidget void restoreState(); void processBytesReceived(); void onDataBufferOverflow(const qint64 len); - void onAppDebugMessage(quint8 level, const QString & msg); void onFilterStateChanged(); void onFilterTextChanged(const QString &); void onFilterToggled(bool enable); diff --git a/companion/src/simulation/simulatormainwindow.cpp b/companion/src/simulation/simulatormainwindow.cpp index 9fe5e969e..949f0a2f7 100644 --- a/companion/src/simulation/simulatormainwindow.cpp +++ b/companion/src/simulation/simulatormainwindow.cpp @@ -33,6 +33,7 @@ #endif #include +#include #include #include @@ -69,6 +70,14 @@ SimulatorMainWindow::SimulatorMainWindow(QWidget *parent, const QString & firmwa return; } + if (g.fwTraceLog() && !g.appLogsDir().isEmpty() && QDir().mkpath(g.appLogsDir())) { + // send firmware TRACE events to log file + QString fn = g.appLogsDir() % "/FirmwareDebug_" % QDateTime::currentDateTime().toString("yy-MM-dd_HH-mm-ss") % ".log"; + m_simuLogFile.setFileName(fn); + if (m_simuLogFile.open(QIODevice::WriteOnly | QIODevice::Text)) + m_simulator->addTracebackDevice(&m_simuLogFile); + } + m_simulator->moveToThread(&simuThread); simuThread.start(); @@ -140,8 +149,6 @@ SimulatorMainWindow::SimulatorMainWindow(QWidget *parent, const QString & firmwa connect(ui->actionScreenshot, &QAction::triggered, m_simulatorWidget, &SimulatorWidget::captureScreenshot); connect(m_simulatorWidget, &SimulatorWidget::windowTitleChanged, this, &SimulatorMainWindow::setWindowTitle); } - - } SimulatorMainWindow::~SimulatorMainWindow() @@ -164,6 +171,10 @@ SimulatorMainWindow::~SimulatorMainWindow() if (m_simulator) { simuThread.quit(); simuThread.wait(); + if (m_simuLogFile.isOpen()) { + m_simulator->removeTracebackDevice(&m_simuLogFile); + m_simuLogFile.close(); + } delete m_simulator; } SimulatorLoader::unloadSimulator(m_simulatorId); diff --git a/companion/src/simulation/simulatormainwindow.h b/companion/src/simulation/simulatormainwindow.h index eb134a63f..e6e6be10f 100644 --- a/companion/src/simulation/simulatormainwindow.h +++ b/companion/src/simulation/simulatormainwindow.h @@ -24,6 +24,7 @@ #include "simulator.h" #include +#include #include #include @@ -99,6 +100,7 @@ class SimulatorMainWindow : public QMainWindow QDockWidget * m_outputsDockWidget; QThread simuThread; + QFile m_simuLogFile; QVector m_keymapHelp; QString m_simulatorId; QString m_exitStatusMsg; diff --git a/companion/src/simulator.cpp b/companion/src/simulator.cpp index 2f8d3f0f8..a75575143 100644 --- a/companion/src/simulator.cpp +++ b/companion/src/simulator.cpp @@ -19,6 +19,7 @@ */ #include +#include #include #include #include @@ -42,6 +43,7 @@ using namespace Simulator; +QFile simuDbgLog; int finish(int exitCode); void showMessage(const QString & message, enum QMessageBox::Icon icon = QMessageBox::NoIcon, bool useConsole = false) @@ -56,10 +58,9 @@ void showMessage(const QString & message, enum QMessageBox::Icon icon = QMessage } // use GUI QMessageBox msgBox; - QString escMsg(message); - escMsg.replace("<", "<"); - msgBox.setText("
" + escMsg + "
"); + msgBox.setText("
" + message.toHtmlEscaped() + "
"); msgBox.setIcon(icon); + msgBox.setWindowTitle(QApplication::translate("SimulatorMain", "OpenTx Simulator")); msgBox.exec(); } @@ -251,6 +252,14 @@ int main(int argc, char *argv[]) g.init(); // init settings before installing translations + if (AppDebugMessageHandler::instance() && g.appDebugLog() && !g.appLogsDir().isEmpty() && QDir().mkpath(g.appLogsDir())) { + QString fn = g.appLogsDir() % "/SimulatorDebug_" % QDateTime::currentDateTime().toString("yy-MM-dd_HH-mm-ss") % ".log"; + simuDbgLog.setFileName(fn); + if (simuDbgLog.open(QIODevice::WriteOnly | QIODevice::Text)) { + AppDebugMessageHandler::instance()->addOutputDevice(&simuDbgLog); + } + } + Translations::installTranslators(); #if defined(JOYSTICKS) || defined(SIMU_AUDIO) @@ -365,5 +374,9 @@ int finish(int exitCode) #endif qDebug() << "SIMULATOR EXIT" << exitCode; + if (simuDbgLog.isOpen()) { + AppDebugMessageHandler::instance()->removeOutputDevice(&simuDbgLog); + simuDbgLog.close(); + } return exitCode; } diff --git a/companion/src/storage/appdata.cpp b/companion/src/storage/appdata.cpp index 0f298eda7..3a16b0e11 100644 --- a/companion/src/storage/appdata.cpp +++ b/companion/src/storage/appdata.cpp @@ -460,16 +460,6 @@ QString AppData::libDir() { return _libDir; } QString AppData::snapshotDir() { return _snapshotDir; } QString AppData::updatesDir() { return _updatesDir; } -bool AppData::jsSupport() { return _jsSupport; } -bool AppData::maximized() { return _maximized; } -bool AppData::showSplash() { return _showSplash; } -bool AppData::snapToClpbrd() { return _snapToClpbrd; } -bool AppData::autoCheckApp() { return _autoCheckApp; } -bool AppData::autoCheckFw() { return _autoCheckFw; } -bool AppData::simuSW() { return _simuSW; } -bool AppData::tabbedMdi() { return _tabbedMdi; } -bool AppData::removeModelSlots() { return _remvModelSlots; } - int AppData::newModelAction() { return _newModelAction; } int AppData::backLight() { return _backLight; } int AppData::embedSplashes() { return _embedSplashes; } @@ -517,16 +507,6 @@ void AppData::libDir (const QString x) { store(x, _libDir, void AppData::snapshotDir (const QString x) { store(x, _snapshotDir, "snapshotpath" );} void AppData::updatesDir (const QString x) { store(x, _updatesDir, "lastUpdatesDir" );} -void AppData::maximized (const bool x) { store(x, _maximized, "maximized" );} -void AppData::jsSupport (const bool x) { store(x, _jsSupport, "js_support" );} -void AppData::showSplash (const bool x) { store(x, _showSplash, "show_splash" );} -void AppData::snapToClpbrd (const bool x) { store(x, _snapToClpbrd, "snapshot_to_clipboard" );} -void AppData::autoCheckApp (const bool x) { store(x, _autoCheckApp, "startup_check_companion" );} -void AppData::autoCheckFw (const bool x) { store(x, _autoCheckFw, "startup_check_fw" );} -void AppData::simuSW (const bool x) { store(x, _simuSW, "simuSW" );} -void AppData::tabbedMdi (const bool x) { store(x, _tabbedMdi, "tabbedMdi" );} -void AppData::removeModelSlots(const bool x) { store(x, _remvModelSlots, "removeModelSlots" );} - void AppData::newModelAction (const int x) { store(x, _newModelAction, "newModelAction" );} void AppData::backLight (const int x) { store(x, _backLight, "backLight" );} void AppData::embedSplashes (const int x) { store(x, _embedSplashes, "embedded_splashes" );} @@ -610,24 +590,26 @@ void AppData::init() getset( _libDir, "libraryPath" ,"" ); getset( _snapshotDir, "snapshotpath" ,"" ); getset( _updatesDir, "lastUpdatesDir" ,"" ); + appLogsDir_init(); - getset( _enableBackup, "enableBackup" ,false ); - getset( _backupOnFlash, "backupOnFlash" ,true ); - - getset( _outputDisplayDetails, "outputDisplayDetails" ,false ); - getset( _checkHardwareCompatibility, "checkHardwareCompatibility" ,true ); - getset( _useCompanionNightlyBuilds, "useCompanionNightlyBuilds" ,false ); - getset( _useFirmwareNightlyBuilds, "useFirmwareNightlyBuilds" ,false ); - - getset( _jsSupport, "js_support" ,false ); - getset( _maximized, "maximized" ,false ); - getset( _showSplash, "show_splash" ,true ); - getset( _snapToClpbrd, "snapshot_to_clipboard" ,false ); - getset( _autoCheckApp, "startup_check_companion" ,true ); - getset( _autoCheckFw, "startup_check_fw" ,true ); - getset( _simuSW, "simuSW" ,false ); - getset( _tabbedMdi, "tabbedMdi" ,false ); - getset( _remvModelSlots, "removeModelSlots" ,true ); + // booleans + enableBackup_init(); + backupOnFlash_init(); + outputDisplayDetails_init(); + checkHardwareCompatibility_init(); + useCompanionNightlyBuilds_init(); + useFirmwareNightlyBuilds_init(); + removeModelSlots_init(); + maximized_init(); + simuSW_init(); + tabbedMdi_init(); + appDebugLog_init(); + fwTraceLog_init(); + jsSupport_init(); + showSplash_init(); + snapToClpbrd_init(); + autoCheckApp_init(); + autoCheckFw_init(); getset( _newModelAction, "newModelAction" ,1 ); getset( _backLight, "backLight" ,0 ); diff --git a/companion/src/storage/appdata.h b/companion/src/storage/appdata.h index e966a091c..8603b46f3 100644 --- a/companion/src/storage/appdata.h +++ b/companion/src/storage/appdata.h @@ -29,6 +29,7 @@ #include #include #include +#include #include "simulator.h" @@ -226,21 +227,37 @@ class Profile: protected CompStoreObj QString groupId(); }; -#define BOOL_PROPERTY(name, dflt) \ + +#define PROPERTY4(type, name, key, dflt) \ public: \ - inline bool name() { return _ ## name; } \ - void name(const bool val) { store(val, _ ## name, # name); } \ + inline type name() { return _ ## name; } \ + void name(const type val) { store(val, _ ## name, # key); } \ private: \ - bool _ ## name; + void name ## _init() { getset(_ ## name, # key, dflt); } \ + type _ ## name; + +#define PROPERTY(type, name, dflt) PROPERTY4(type, name, name, dflt) class AppData: protected CompStoreObj { - BOOL_PROPERTY(enableBackup, false) - BOOL_PROPERTY(backupOnFlash, true) - BOOL_PROPERTY(outputDisplayDetails, false) - BOOL_PROPERTY(checkHardwareCompatibility, true) - BOOL_PROPERTY(useCompanionNightlyBuilds, false) - BOOL_PROPERTY(useFirmwareNightlyBuilds, false) + PROPERTY(bool, enableBackup, false) + PROPERTY(bool, backupOnFlash, true) + PROPERTY(bool, outputDisplayDetails, false) + PROPERTY(bool, checkHardwareCompatibility, true) + PROPERTY(bool, useCompanionNightlyBuilds, false) + PROPERTY(bool, useFirmwareNightlyBuilds, false) + PROPERTY(bool, removeModelSlots, true) + PROPERTY(bool, maximized, false) + PROPERTY(bool, simuSW, false) + PROPERTY(bool, tabbedMdi, false) + PROPERTY(bool, appDebugLog, false) + PROPERTY(bool, fwTraceLog, false) + + PROPERTY4(bool, jsSupport, js_support ,false) + PROPERTY4(bool, showSplash, show_splash ,true) + PROPERTY4(bool, snapToClpbrd, snapshot_to_clipboard ,false) + PROPERTY4(bool, autoCheckApp, startup_check_companion ,true) + PROPERTY4(bool, autoCheckFw, startup_check_fw ,true) // All the global variables public: @@ -280,16 +297,7 @@ class AppData: protected CompStoreObj QString _libDir; QString _snapshotDir; QString _updatesDir; - - bool _maximized; - bool _jsSupport; - bool _showSplash; - bool _snapToClpbrd; - bool _autoCheckApp; - bool _autoCheckFw; - bool _simuSW; - bool _tabbedMdi; - bool _remvModelSlots; + PROPERTY(QString, appLogsDir, QString(QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) % "/" COMPANY "/DebugLogs")) int _newModelAction; // 0=no action; 1=model wizard; 2=model edit int _backLight; @@ -341,16 +349,6 @@ class AppData: protected CompStoreObj QString snapshotDir(); QString updatesDir(); - bool jsSupport(); - bool maximized(); - bool showSplash(); - bool snapToClpbrd(); - bool autoCheckApp(); - bool autoCheckFw(); - bool simuSW(); - bool tabbedMdi(); - bool removeModelSlots(); - int newModelAction(); int backLight(); int embedSplashes(); @@ -399,16 +397,6 @@ class AppData: protected CompStoreObj void snapshotDir (const QString); void updatesDir (const QString); - void maximized (const bool); - void jsSupport (const bool); - void showSplash (const bool); - void snapToClpbrd (const bool); - void autoCheckApp (const bool); - void autoCheckFw (const bool); - void simuSW (const bool); - void tabbedMdi (const bool); - void removeModelSlots(const bool); - void newModelAction (const int); void backLight (const int); void embedSplashes (const int);