mirror of
https://github.com/EdgeTX/edgetx.git
synced 2025-07-25 17:25:10 +03:00
{Companion] Unload simulator libraries after each use -- reset all statically initialized firmware variables. (#4655)
* [simulatormainwindow] Move sub-window destructors to main destructor. * [simulation] Move SimulatorInterface creation/ownership to SimulatorMainWindow. * [simulation] Add option to unload simulator libraries after each use (eg. from Companion) so as to properly reset all statically initialized firmware variables; Introduce new SimulatorLoader class.
This commit is contained in:
parent
dc89d2d630
commit
e48b1fd07d
13 changed files with 268 additions and 167 deletions
|
@ -105,7 +105,7 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
registerStorageFactories();
|
registerStorageFactories();
|
||||||
registerOpenTxFirmwares();
|
registerOpenTxFirmwares();
|
||||||
registerSimulators();
|
SimulatorLoader::registerSimulators();
|
||||||
|
|
||||||
if (g.profile[g.id()].fwType().isEmpty()){
|
if (g.profile[g.id()].fwType().isEmpty()){
|
||||||
g.profile[g.id()].fwType(default_firmware_variant->getId());
|
g.profile[g.id()].fwType(default_firmware_variant->getId());
|
||||||
|
@ -135,7 +135,7 @@ int main(int argc, char *argv[])
|
||||||
delete splash;
|
delete splash;
|
||||||
delete mainWin;
|
delete mainWin;
|
||||||
|
|
||||||
unregisterSimulators();
|
SimulatorLoader::unregisterSimulators();
|
||||||
unregisterOpenTxFirmwares();
|
unregisterOpenTxFirmwares();
|
||||||
unregisterStorageFactories();
|
unregisterStorageFactories();
|
||||||
|
|
||||||
|
|
|
@ -22,15 +22,19 @@
|
||||||
|
|
||||||
Q_LOGGING_CATEGORY(eepromImport, "eeprom.import")
|
Q_LOGGING_CATEGORY(eepromImport, "eeprom.import")
|
||||||
|
|
||||||
|
Q_LOGGING_CATEGORY(simulatorInterfaceLoader, "simulator.interface.loader")
|
||||||
|
|
||||||
void CustomDebug::setFilterRules()
|
void CustomDebug::setFilterRules()
|
||||||
{
|
{
|
||||||
QString rules;
|
QString rules;
|
||||||
rules.append("eeprom.import=");
|
rules.append("eeprom.import=");
|
||||||
#if defined(DEBUG_STORAGE_IMPORT)
|
#if defined(DEBUG_STORAGE_IMPORT)
|
||||||
rules.append("true");
|
rules.append("true\n");
|
||||||
#else
|
#else
|
||||||
rules.append("false");
|
rules.append("false\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
rules.append("simulator.interface.*=true\n");
|
||||||
|
|
||||||
QLoggingCategory::setFilterRules(rules);
|
QLoggingCategory::setFilterRules(rules);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,10 @@
|
||||||
#include <QLoggingCategory>
|
#include <QLoggingCategory>
|
||||||
|
|
||||||
// Controls the generation of debug output for EEPROM import
|
// Controls the generation of debug output for EEPROM import
|
||||||
Q_DECLARE_LOGGING_CATEGORY(eepromImport)
|
Q_DECLARE_LOGGING_CATEGORY(eepromImport) // "eeprom.import"
|
||||||
|
|
||||||
|
// Controls the generation of debug output of SimulatorLoader class
|
||||||
|
Q_DECLARE_LOGGING_CATEGORY(simulatorInterfaceLoader) // "simulator.interface.loader"
|
||||||
|
|
||||||
class CustomDebug
|
class CustomDebug
|
||||||
{
|
{
|
||||||
|
|
|
@ -1837,16 +1837,6 @@ void Firmware::addOptions(Option options[])
|
||||||
this->opts.push_back(opts);
|
this->opts.push_back(opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
SimulatorInterface * getCurrentSimulator()
|
|
||||||
{
|
|
||||||
QString firmwareId = getCurrentFirmware()->getId();
|
|
||||||
SimulatorFactory * factory = getSimulatorFactory(firmwareId);
|
|
||||||
if (factory)
|
|
||||||
return factory->create();
|
|
||||||
else
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FlightModeData::clear(const int phase)
|
void FlightModeData::clear(const int phase)
|
||||||
{
|
{
|
||||||
memset(this, 0, sizeof(FlightModeData));
|
memset(this, 0, sizeof(FlightModeData));
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#ifndef _EEPROMINTERFACE_H_
|
#ifndef _EEPROMINTERFACE_H_
|
||||||
#define _EEPROMINTERFACE_H_
|
#define _EEPROMINTERFACE_H_
|
||||||
|
|
||||||
|
#include "macros.h"
|
||||||
#include "radiodata.h"
|
#include "radiodata.h"
|
||||||
#include "../../radio/src/definitions.h"
|
#include "../../radio/src/definitions.h"
|
||||||
#include "simulatorinterface.h"
|
#include "simulatorinterface.h"
|
||||||
|
@ -195,14 +196,8 @@ inline int applyStickMode(int stick, unsigned int mode)
|
||||||
return stick;
|
return stick;
|
||||||
}
|
}
|
||||||
|
|
||||||
const unsigned int stickModes[]= {
|
|
||||||
1, 2, 3, 4,
|
|
||||||
1, 3, 2, 4,
|
|
||||||
4, 2, 3, 1,
|
|
||||||
4, 3, 2, 1 };
|
|
||||||
|
|
||||||
if (stick >= 1 && stick <= 4)
|
if (stick >= 1 && stick <= 4)
|
||||||
return stickModes[(mode-1)*4 + stick - 1];
|
return modn12x3[mode-1][stick-1];
|
||||||
else
|
else
|
||||||
return stick;
|
return stick;
|
||||||
}
|
}
|
||||||
|
@ -358,8 +353,6 @@ inline Firmware * getCurrentFirmware()
|
||||||
return current_firmware_variant;
|
return current_firmware_variant;
|
||||||
}
|
}
|
||||||
|
|
||||||
SimulatorInterface * getCurrentSimulator();
|
|
||||||
|
|
||||||
inline EEPROMInterface * getCurrentEEpromInterface()
|
inline EEPROMInterface * getCurrentEEpromInterface()
|
||||||
{
|
{
|
||||||
return getCurrentFirmware()->getEEpromInterface();
|
return getCurrentFirmware()->getEEpromInterface();
|
||||||
|
@ -375,7 +368,7 @@ inline int divRoundClosest(const int n, const int d)
|
||||||
return ((n < 0) ^ (d < 0)) ? ((n - d/2)/d) : ((n + d/2)/d);
|
return ((n < 0) ^ (d < 0)) ? ((n - d/2)/d) : ((n + d/2)/d);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CHECK_IN_ARRAY(T, index) ((unsigned int)index < (unsigned int)(sizeof(T)/sizeof(T[0])) ? T[(unsigned int)index] : "???")
|
#define CHECK_IN_ARRAY(T, index) ((unsigned int)index < DIM(T) ? T[(unsigned int)index] : "???")
|
||||||
|
|
||||||
extern QList<EEPROMInterface *> eepromInterfaces;
|
extern QList<EEPROMInterface *> eepromInterfaces;
|
||||||
|
|
||||||
|
|
|
@ -25,9 +25,6 @@
|
||||||
#elif defined __GNUC__
|
#elif defined __GNUC__
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
#if defined(WIN32) && defined(WIN_USE_CONSOLE_STDIO)
|
|
||||||
#include "windows.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "appdata.h"
|
#include "appdata.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
@ -811,39 +808,45 @@ CompanionIcon::CompanionIcon(const QString &baseimage)
|
||||||
|
|
||||||
void startSimulation(QWidget * parent, RadioData & radioData, int modelIdx)
|
void startSimulation(QWidget * parent, RadioData & radioData, int modelIdx)
|
||||||
{
|
{
|
||||||
SimulatorInterface * simulator = getCurrentSimulator();
|
QString fwId = SimulatorLoader::findSimulatorByFirmwareName(getCurrentFirmware()->getId());
|
||||||
if (simulator) {
|
if (fwId.isEmpty()) {
|
||||||
RadioData * simuData = new RadioData(radioData);
|
QMessageBox::warning(NULL,
|
||||||
unsigned int flags = 0;
|
QObject::tr("Warning"),
|
||||||
|
QObject::tr("Simulator for this firmware is not yet available"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (modelIdx >= 0) {
|
RadioData * simuData = new RadioData(radioData);
|
||||||
flags |= SIMULATOR_FLAGS_NOTX;
|
unsigned int flags = 0;
|
||||||
simuData->setCurrentModel(modelIdx);
|
|
||||||
}
|
|
||||||
|
|
||||||
SimulatorMainWindow * dialog = new SimulatorMainWindow(parent, simulator, flags);
|
if (modelIdx >= 0) {
|
||||||
if (!dialog->setRadioData(simuData)) {
|
flags |= SIMULATOR_FLAGS_NOTX;
|
||||||
QMessageBox::critical(NULL, QObject::tr("Data Load Error"), QObject::tr("Error occurred while starting simulator."));
|
simuData->setCurrentModel(modelIdx);
|
||||||
delete dialog;
|
}
|
||||||
delete simuData;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dialog->setWindowModality(Qt::ApplicationModal);
|
SimulatorMainWindow * dialog = new SimulatorMainWindow(parent, fwId, flags);
|
||||||
dialog->setAttribute(Qt::WA_DeleteOnClose);
|
dialog->setWindowModality(Qt::ApplicationModal);
|
||||||
|
dialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
|
||||||
|
QObject::connect(dialog, &SimulatorMainWindow::destroyed, [simuData] (void) {
|
||||||
|
// TODO simuData and Horus tmp directory is deleted on simulator close OR we could use it to get back data from the simulation
|
||||||
|
delete simuData;
|
||||||
|
});
|
||||||
|
|
||||||
|
QString resultMsg;
|
||||||
|
if (dialog->getExitStatus(&resultMsg)) {
|
||||||
|
if (resultMsg.isEmpty())
|
||||||
|
resultMsg = QObject::tr("Uknown error during Simulator startup.");
|
||||||
|
QMessageBox::critical(NULL, QObject::tr("Simulator Error"), resultMsg);
|
||||||
|
dialog->deleteLater();
|
||||||
|
}
|
||||||
|
else if (dialog->setRadioData(simuData)) {
|
||||||
dialog->start();
|
dialog->start();
|
||||||
|
|
||||||
QObject::connect(dialog, &SimulatorMainWindow::destroyed, [simuData] (void) {
|
|
||||||
// TODO simuData and Horus tmp directory is deleted on simulator close OR we could use it to get back data from the simulation
|
|
||||||
delete simuData;
|
|
||||||
});
|
|
||||||
|
|
||||||
dialog->show();
|
dialog->show();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
QMessageBox::warning(NULL,
|
QMessageBox::critical(NULL, QObject::tr("Data Load Error"), QObject::tr("Error occurred while starting simulator."));
|
||||||
QObject::tr("Warning"),
|
dialog->deleteLater();
|
||||||
QObject::tr("Simulator for this firmware is not yet available"));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,38 +19,29 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "simulatorinterface.h"
|
#include "simulatorinterface.h"
|
||||||
#include <QDebug>
|
#include "customdebug.h"
|
||||||
#include <QDir>
|
|
||||||
#include <QLibrary>
|
|
||||||
#include <QLibraryInfo>
|
|
||||||
#include <QMap>
|
|
||||||
#include <QMessageBox>
|
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QLibraryInfo>
|
||||||
|
|
||||||
#if defined _MSC_VER || !defined __GNUC__
|
#if defined _MSC_VER || !defined __GNUC__
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
QMap<QString, SimulatorFactory *> registered_simulators;
|
#ifndef SIMULATOR_INTERFACE_LOADER_METHOD
|
||||||
|
#define SIMULATOR_INTERFACE_LOADER_DYNAMIC 1 // How to load simulator libraries: 1=dynamic load and unload; 0=load once (old way)
|
||||||
|
#endif
|
||||||
|
|
||||||
void registerSimulator(const QString & filename)
|
QMap<QString, QLibrary *> SimulatorLoader::registeredSimulators;
|
||||||
|
|
||||||
|
QStringList SimulatorLoader::getAvailableSimulators()
|
||||||
{
|
{
|
||||||
QLibrary lib(filename);
|
return registeredSimulators.keys();
|
||||||
typedef SimulatorFactory * (*RegisterSimulator)();
|
|
||||||
qDebug() << "trying to register simulator in " << filename;
|
|
||||||
RegisterSimulator registerFunc = (RegisterSimulator)lib.resolve("registerSimu");
|
|
||||||
if (registerFunc) {
|
|
||||||
SimulatorFactory * factory = registerFunc();
|
|
||||||
registered_simulators[factory->name()] = factory;
|
|
||||||
qDebug() << "Registered" << factory->name() << "simulator";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
qWarning() << "Library error" << filename << lib.errorString();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int registerSimulators(const QDir & dir)
|
int SimulatorLoader::registerSimulators(const QDir & dir)
|
||||||
{
|
{
|
||||||
int noSimulatorsFound = 0;
|
|
||||||
QStringList filters;
|
QStringList filters;
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
filters << "*-simulator.dylib";
|
filters << "*-simulator.dylib";
|
||||||
|
@ -59,17 +50,41 @@ int registerSimulators(const QDir & dir)
|
||||||
#else
|
#else
|
||||||
filters << "*-simulator.so";
|
filters << "*-simulator.so";
|
||||||
#endif
|
#endif
|
||||||
|
registeredSimulators.clear();
|
||||||
|
|
||||||
|
qCDebug(simulatorInterfaceLoader) << "Searching for simulators in" << dir.path() << "matching pattern" << filters;
|
||||||
|
|
||||||
qDebug() << "Searching for simulators in" << dir.path();
|
|
||||||
foreach(QString filename, dir.entryList(filters, QDir::Files)) {
|
foreach(QString filename, dir.entryList(filters, QDir::Files)) {
|
||||||
QString libraryFilename = dir.path() + "/" + filename;
|
QLibrary * lib = new QLibrary( dir.path() + "/" + filename);
|
||||||
registerSimulator(libraryFilename);
|
|
||||||
noSimulatorsFound++;
|
qCDebug(simulatorInterfaceLoader) << "Trying to register simulator in " << filename;
|
||||||
|
|
||||||
|
SimulatorFactory * factory;
|
||||||
|
RegisterSimulator registerFunc = (RegisterSimulator)lib->resolve("registerSimu");
|
||||||
|
|
||||||
|
if (registerFunc && (factory = registerFunc())) {
|
||||||
|
if (getAvailableSimulators().contains(factory->name()))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
lib->setProperty("instances_used", 0);
|
||||||
|
registeredSimulators.insert(factory->name(), lib);
|
||||||
|
delete factory;
|
||||||
|
#if SIMULATOR_INTERFACE_LOADER_DYNAMIC
|
||||||
|
lib->unload();
|
||||||
|
#endif
|
||||||
|
qCDebug(simulatorInterfaceLoader) << "Registered" << registeredSimulators.lastKey() << "simulator in " << lib->fileName() << "and unloaded:" << !lib->isLoaded();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
qWarning() << "Library error" << lib->fileName() << lib->errorString();
|
||||||
|
delete lib;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return noSimulatorsFound;
|
qCDebug(simulatorInterfaceLoader) << "Found libraries:" << (registeredSimulators.size() ? registeredSimulators.keys() : QStringList() << "none");
|
||||||
|
return registeredSimulators.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void registerSimulators()
|
void SimulatorLoader::registerSimulators()
|
||||||
{
|
{
|
||||||
QDir dir(".");
|
QDir dir(".");
|
||||||
if (registerSimulators(dir)) {
|
if (registerSimulators(dir)) {
|
||||||
|
@ -90,31 +105,93 @@ void registerSimulators()
|
||||||
registerSimulators(dir);
|
registerSimulators(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
SimulatorFactory * getSimulatorFactory(const QString & name)
|
void SimulatorLoader::unregisterSimulators()
|
||||||
{
|
{
|
||||||
|
foreach(QLibrary * lib, registeredSimulators)
|
||||||
|
delete lib;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString SimulatorLoader::findSimulatorByFirmwareName(const QString & name)
|
||||||
|
{
|
||||||
|
int pos;
|
||||||
|
QString ret;
|
||||||
QString simuName = name;
|
QString simuName = name;
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
qDebug() << "searching" << simuName << "simulator";
|
qCDebug(simulatorInterfaceLoader) << "searching" << simuName << "simulator";
|
||||||
foreach (QString name, registered_simulators.keys()) {
|
if (registeredSimulators.contains(simuName)) {
|
||||||
if (name.contains(simuName)) {
|
ret = simuName;
|
||||||
simuName = name;
|
break;
|
||||||
qDebug() << "found" << simuName;
|
|
||||||
return registered_simulators[simuName];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
int pos = simuName.lastIndexOf('-');
|
if ((pos = simuName.lastIndexOf('-')) <= 0)
|
||||||
if (pos <= 0)
|
|
||||||
break;
|
break;
|
||||||
simuName = simuName.mid(0, pos);
|
simuName = simuName.mid(0, pos);
|
||||||
if (simuName.count('-') == 0)
|
if (simuName.count('-') == 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return NULL;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void unregisterSimulators()
|
SimulatorInterface * SimulatorLoader::loadSimulator(const QString & name)
|
||||||
{
|
{
|
||||||
foreach(SimulatorFactory *factory, registered_simulators) {
|
SimulatorInterface * si = NULL;
|
||||||
|
QString libname = findSimulatorByFirmwareName(name);
|
||||||
|
|
||||||
|
if (libname.isEmpty()) {
|
||||||
|
qWarning() << "Simulator" << name << "not found.";
|
||||||
|
return si;
|
||||||
|
}
|
||||||
|
|
||||||
|
QLibrary * lib = registeredSimulators.value(libname, NULL);
|
||||||
|
if (!lib) {
|
||||||
|
qWarning() << "Simulator library is NULL";
|
||||||
|
return si;
|
||||||
|
}
|
||||||
|
|
||||||
|
qCDebug(simulatorInterfaceLoader) << "Trying to load simulator in " << lib->fileName();
|
||||||
|
|
||||||
|
SimulatorFactory * factory;
|
||||||
|
RegisterSimulator registerFunc = (RegisterSimulator)lib->resolve("registerSimu");
|
||||||
|
if (registerFunc && (factory = registerFunc()) && (si = factory->create())) {
|
||||||
|
quint8 instance = lib->property("instances_used").toUInt();
|
||||||
|
lib->setProperty("instances_used", ++instance);
|
||||||
|
qCDebug(simulatorInterfaceLoader) << "Loaded" << factory->name() << "simulator instance" << instance;
|
||||||
delete factory;
|
delete factory;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
qWarning() << "Library error" << lib->fileName() << lib->errorString();
|
||||||
|
}
|
||||||
|
return si;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SimulatorLoader::unloadSimulator(const QString & name)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
#if SIMULATOR_INTERFACE_LOADER_DYNAMIC
|
||||||
|
QString simuName = findSimulatorByFirmwareName(name);
|
||||||
|
if (simuName.isEmpty())
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
QLibrary * lib = registeredSimulators.value(simuName, NULL);
|
||||||
|
|
||||||
|
if (lib && lib->isLoaded()) {
|
||||||
|
quint8 instance = lib->property("instances_used").toUInt();
|
||||||
|
lib->setProperty("instances_used", --instance);
|
||||||
|
if (!instance) {
|
||||||
|
ret = lib->unload();
|
||||||
|
qCDebug(simulatorInterfaceLoader) << "Unloading" << simuName << "(" << lib->fileName() << ")" << "result:" << ret;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ret = true;
|
||||||
|
qCDebug(simulatorInterfaceLoader) << "Simulator" << simuName << "instances remaining:" << instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
qCDebug(simulatorInterfaceLoader) << "Simulator library for " << simuName << "already unloaded.";
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
qCDebug(simulatorInterfaceLoader) << "Keeping simulator library" << simuName << "loaded.";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,11 +23,16 @@
|
||||||
|
|
||||||
#include "boards.h"
|
#include "boards.h"
|
||||||
#include "constants.h"
|
#include "constants.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QLibrary>
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
struct TxInputs
|
struct TxInputs
|
||||||
{
|
{
|
||||||
|
@ -122,9 +127,21 @@ class SimulatorFactory {
|
||||||
virtual SimulatorInterface *create() = 0;
|
virtual SimulatorInterface *create() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
void registerSimulators();
|
class SimulatorLoader
|
||||||
void unregisterSimulators();
|
{
|
||||||
SimulatorFactory *getSimulatorFactory(const QString &name);
|
public:
|
||||||
extern QMap<QString, SimulatorFactory *> registered_simulators;
|
static void registerSimulators();
|
||||||
|
static void unregisterSimulators();
|
||||||
|
static QStringList getAvailableSimulators();
|
||||||
|
static QString findSimulatorByFirmwareName(const QString & name);
|
||||||
|
static SimulatorInterface * loadSimulator(const QString & name);
|
||||||
|
static bool unloadSimulator(const QString & name);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
typedef SimulatorFactory * (*RegisterSimulator)();
|
||||||
|
|
||||||
|
static int registerSimulators(const QDir & dir);
|
||||||
|
static QMap<QString, QLibrary *> registeredSimulators;
|
||||||
|
};
|
||||||
|
|
||||||
#endif // _SIMULATORINTERFACE_H_
|
#endif // _SIMULATORINTERFACE_H_
|
||||||
|
|
|
@ -40,9 +40,8 @@ extern AppData g; // ensure what "g" means
|
||||||
|
|
||||||
const quint16 SimulatorMainWindow::m_savedUiStateVersion = 2;
|
const quint16 SimulatorMainWindow::m_savedUiStateVersion = 2;
|
||||||
|
|
||||||
SimulatorMainWindow::SimulatorMainWindow(QWidget *parent, SimulatorInterface * simulator, quint8 flags, Qt::WindowFlags wflags) :
|
SimulatorMainWindow::SimulatorMainWindow(QWidget *parent, const QString & firmwareId, quint8 flags, Qt::WindowFlags wflags) :
|
||||||
QMainWindow(parent, wflags),
|
QMainWindow(parent, wflags),
|
||||||
m_simulator(simulator),
|
|
||||||
ui(new Ui::SimulatorMainWindow),
|
ui(new Ui::SimulatorMainWindow),
|
||||||
m_simulatorWidget(NULL),
|
m_simulatorWidget(NULL),
|
||||||
m_consoleWidget(NULL),
|
m_consoleWidget(NULL),
|
||||||
|
@ -52,12 +51,24 @@ SimulatorMainWindow::SimulatorMainWindow(QWidget *parent, SimulatorInterface * s
|
||||||
m_telemetryDockWidget(NULL),
|
m_telemetryDockWidget(NULL),
|
||||||
m_trainerDockWidget(NULL),
|
m_trainerDockWidget(NULL),
|
||||||
m_outputsDockWidget(NULL),
|
m_outputsDockWidget(NULL),
|
||||||
|
m_simulatorId(firmwareId),
|
||||||
|
m_exitStatusCode(0),
|
||||||
m_radioProfileId(g.sessionId()),
|
m_radioProfileId(g.sessionId()),
|
||||||
m_radioSizeConstraint(Qt::Horizontal | Qt::Vertical),
|
m_radioSizeConstraint(Qt::Horizontal | Qt::Vertical),
|
||||||
m_firstShow(true),
|
m_firstShow(true),
|
||||||
m_showRadioDocked(true),
|
m_showRadioDocked(true),
|
||||||
m_showMenubar(true)
|
m_showMenubar(true)
|
||||||
{
|
{
|
||||||
|
if (m_simulatorId.isEmpty()) {
|
||||||
|
m_simulatorId = SimulatorLoader::findSimulatorByFirmwareName(getCurrentFirmware()->getId());
|
||||||
|
}
|
||||||
|
m_simulator = SimulatorLoader::loadSimulator(m_simulatorId);
|
||||||
|
if (!m_simulator) {
|
||||||
|
m_exitStatusMsg = tr("ERROR: Failed to create simulator interface, possibly missing or bad library.");
|
||||||
|
m_exitStatusCode = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea);
|
setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea);
|
||||||
|
@ -128,25 +139,30 @@ SimulatorMainWindow::SimulatorMainWindow(QWidget *parent, SimulatorInterface * s
|
||||||
|
|
||||||
SimulatorMainWindow::~SimulatorMainWindow()
|
SimulatorMainWindow::~SimulatorMainWindow()
|
||||||
{
|
{
|
||||||
delete ui;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SimulatorMainWindow::closeEvent(QCloseEvent *)
|
|
||||||
{
|
|
||||||
saveUiState();
|
|
||||||
|
|
||||||
if (m_telemetryDockWidget)
|
if (m_telemetryDockWidget)
|
||||||
delete m_telemetryDockWidget;
|
delete m_telemetryDockWidget;
|
||||||
if (m_trainerDockWidget)
|
if (m_trainerDockWidget)
|
||||||
delete m_trainerDockWidget;
|
delete m_trainerDockWidget;
|
||||||
if (m_outputsDockWidget)
|
if (m_outputsDockWidget)
|
||||||
delete m_outputsDockWidget;
|
delete m_outputsDockWidget;
|
||||||
if (m_consoleDockWidget)
|
|
||||||
delete m_consoleDockWidget;
|
|
||||||
if (m_simulatorDockWidget)
|
if (m_simulatorDockWidget)
|
||||||
delete m_simulatorDockWidget;
|
delete m_simulatorDockWidget;
|
||||||
else if (m_simulatorWidget)
|
else if (m_simulatorWidget)
|
||||||
delete m_simulatorWidget;
|
delete m_simulatorWidget;
|
||||||
|
if (m_consoleDockWidget)
|
||||||
|
delete m_consoleDockWidget;
|
||||||
|
|
||||||
|
delete ui;
|
||||||
|
|
||||||
|
if (m_simulator)
|
||||||
|
delete m_simulator;
|
||||||
|
|
||||||
|
SimulatorLoader::unloadSimulator(m_simulatorId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimulatorMainWindow::closeEvent(QCloseEvent *)
|
||||||
|
{
|
||||||
|
saveUiState();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimulatorMainWindow::show()
|
void SimulatorMainWindow::show()
|
||||||
|
@ -173,7 +189,8 @@ void SimulatorMainWindow::changeEvent(QEvent *e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QMenu * SimulatorMainWindow::createPopupMenu(){
|
QMenu * SimulatorMainWindow::createPopupMenu()
|
||||||
|
{
|
||||||
QMenu * menu = QMainWindow::createPopupMenu();
|
QMenu * menu = QMainWindow::createPopupMenu();
|
||||||
menu->clear();
|
menu->clear();
|
||||||
menu->addActions(ui->menuView->actions());
|
menu->addActions(ui->menuView->actions());
|
||||||
|
@ -214,6 +231,13 @@ void SimulatorMainWindow::restoreUiState()
|
||||||
restoreState(windowState, m_savedUiStateVersion);
|
restoreState(windowState, m_savedUiStateVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int SimulatorMainWindow::getExitStatus(QString * msg)
|
||||||
|
{
|
||||||
|
if (msg)
|
||||||
|
*msg = m_exitStatusMsg;
|
||||||
|
return m_exitStatusCode;
|
||||||
|
}
|
||||||
|
|
||||||
bool SimulatorMainWindow::setRadioData(RadioData * radioData)
|
bool SimulatorMainWindow::setRadioData(RadioData * radioData)
|
||||||
{
|
{
|
||||||
return m_simulatorWidget->setRadioData(radioData);
|
return m_simulatorWidget->setRadioData(radioData);
|
||||||
|
|
|
@ -25,7 +25,6 @@
|
||||||
|
|
||||||
#include <QDockWidget>
|
#include <QDockWidget>
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
#include <QPointer>
|
|
||||||
|
|
||||||
class DebugOutput;
|
class DebugOutput;
|
||||||
class RadioData;
|
class RadioData;
|
||||||
|
@ -48,13 +47,14 @@ class SimulatorMainWindow : public QMainWindow
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit SimulatorMainWindow(QWidget * parent, SimulatorInterface * simulator, quint8 flags=0, Qt::WindowFlags wflags = Qt::WindowFlags());
|
explicit SimulatorMainWindow(QWidget * parent, const QString & firmwareId = "", quint8 flags=0, Qt::WindowFlags wflags = Qt::WindowFlags());
|
||||||
~SimulatorMainWindow();
|
~SimulatorMainWindow();
|
||||||
|
|
||||||
|
int getExitStatus(QString * msg = Q_NULLPTR);
|
||||||
bool setRadioData(RadioData * radioData);
|
bool setRadioData(RadioData * radioData);
|
||||||
bool useTempDataPath(bool deleteOnClose = true);
|
bool useTempDataPath(bool deleteOnClose = true);
|
||||||
bool setOptions(SimulatorOptions & options, bool withSave = true);
|
bool setOptions(SimulatorOptions & options, bool withSave = true);
|
||||||
QMenu * createPopupMenu();
|
virtual QMenu * createPopupMenu();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
virtual void show();
|
virtual void show();
|
||||||
|
@ -95,6 +95,9 @@ class SimulatorMainWindow : public QMainWindow
|
||||||
QDockWidget * m_outputsDockWidget;
|
QDockWidget * m_outputsDockWidget;
|
||||||
|
|
||||||
QVector<keymapHelp_t> m_keymapHelp;
|
QVector<keymapHelp_t> m_keymapHelp;
|
||||||
|
QString m_simulatorId;
|
||||||
|
QString m_exitStatusMsg;
|
||||||
|
int m_exitStatusCode;
|
||||||
int m_radioProfileId;
|
int m_radioProfileId;
|
||||||
int m_radioSizeConstraint;
|
int m_radioSizeConstraint;
|
||||||
bool m_firstShow;
|
bool m_firstShow;
|
||||||
|
|
|
@ -23,13 +23,14 @@
|
||||||
|
|
||||||
#include "appdata.h"
|
#include "appdata.h"
|
||||||
#include "constants.h"
|
#include "constants.h"
|
||||||
#include "eeprominterface.h"
|
#include "simulatorinterface.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
|
|
||||||
|
using namespace Simulator;
|
||||||
|
|
||||||
extern AppData g;
|
extern AppData g;
|
||||||
extern QMap<QString, SimulatorFactory *> registered_simulators;
|
|
||||||
|
|
||||||
SimulatorStartupDialog::SimulatorStartupDialog(SimulatorOptions * options, int * profId, QWidget *parent) :
|
SimulatorStartupDialog::SimulatorStartupDialog(SimulatorOptions * options, int * profId, QWidget *parent) :
|
||||||
QDialog(parent),
|
QDialog(parent),
|
||||||
|
@ -45,7 +46,7 @@ SimulatorStartupDialog::SimulatorStartupDialog(SimulatorOptions * options, int *
|
||||||
ui->radioProfile->addItem(pi.value(), pi.key());
|
ui->radioProfile->addItem(pi.value(), pi.key());
|
||||||
}
|
}
|
||||||
|
|
||||||
ui->radioType->addItems(registered_simulators.keys());
|
ui->radioType->addItems(SimulatorLoader::getAvailableSimulators());
|
||||||
|
|
||||||
ui->optGrp_dataSource->setId(ui->optFile, SimulatorOptions::START_WITH_FILE);
|
ui->optGrp_dataSource->setId(ui->optFile, SimulatorOptions::START_WITH_FILE);
|
||||||
ui->optGrp_dataSource->setId(ui->optFolder, SimulatorOptions::START_WITH_FOLDER);
|
ui->optGrp_dataSource->setId(ui->optFolder, SimulatorOptions::START_WITH_FOLDER);
|
||||||
|
@ -151,7 +152,7 @@ void SimulatorStartupDialog::updateContainerTypes(void)
|
||||||
|
|
||||||
void SimulatorStartupDialog::loadRadioProfile(int id)
|
void SimulatorStartupDialog::loadRadioProfile(int id)
|
||||||
{
|
{
|
||||||
QString tmpstr;
|
QString tmpstr, tmpstr2;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (id < 0 || !g.getActiveProfiles().contains(id))
|
if (id < 0 || !g.getActiveProfiles().contains(id))
|
||||||
|
@ -166,8 +167,8 @@ void SimulatorStartupDialog::loadRadioProfile(int id)
|
||||||
tmpstr = m_options->firmwareId;
|
tmpstr = m_options->firmwareId;
|
||||||
if (tmpstr.isEmpty() && !g.profile[id].fwType().isEmpty())
|
if (tmpstr.isEmpty() && !g.profile[id].fwType().isEmpty())
|
||||||
tmpstr = g.profile[id].fwType();
|
tmpstr = g.profile[id].fwType();
|
||||||
else if (getSimulatorFactory(tmpstr))
|
else if (!(tmpstr2 = SimulatorLoader::findSimulatorByFirmwareName(m_options->firmwareId)).isEmpty())
|
||||||
tmpstr = getSimulatorFactory(tmpstr)->name();
|
tmpstr = tmpstr2;
|
||||||
i = ui->radioType->findText(findRadioId(tmpstr), Qt::MatchContains);
|
i = ui->radioType->findText(findRadioId(tmpstr), Qt::MatchContains);
|
||||||
if (i > -1)
|
if (i > -1)
|
||||||
ui->radioType->setCurrentIndex(i);
|
ui->radioType->setCurrentIndex(i);
|
||||||
|
|
|
@ -28,8 +28,6 @@ namespace Ui {
|
||||||
class SimulatorStartupDialog;
|
class SimulatorStartupDialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
using namespace Simulator;
|
|
||||||
|
|
||||||
class SimulatorStartupDialog : public QDialog
|
class SimulatorStartupDialog : public QDialog
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
|
@ -19,13 +19,13 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QTranslator>
|
#include <QDir>
|
||||||
#include <QLibraryInfo>
|
#include <QLibraryInfo>
|
||||||
#include <QLocale>
|
#include <QLocale>
|
||||||
#include <QString>
|
|
||||||
#include <QDir>
|
|
||||||
#include <QTextStream>
|
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
#include <QString>
|
||||||
|
#include <QTextStream>
|
||||||
|
#include <QTranslator>
|
||||||
#if defined(JOYSTICKS) || defined(SIMU_AUDIO)
|
#if defined(JOYSTICKS) || defined(SIMU_AUDIO)
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
#undef main
|
#undef main
|
||||||
|
@ -66,20 +66,11 @@ void sharedHelpText(QTextStream &stream)
|
||||||
}
|
}
|
||||||
// list all available radios
|
// list all available radios
|
||||||
stream << endl << QObject::tr("Available radios:") << endl;
|
stream << endl << QObject::tr("Available radios:") << endl;
|
||||||
foreach(QString name, registered_simulators.keys()) {
|
foreach(QString name, SimulatorLoader::getAvailableSimulators()) {
|
||||||
stream << "\t" << name << endl;
|
stream << "\t" << name << endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString findFirmwareId(int profileId)
|
|
||||||
{
|
|
||||||
SimulatorFactory * sf = getSimulatorFactory(g.profile[profileId].fwType());
|
|
||||||
if (sf)
|
|
||||||
return sf->name();
|
|
||||||
else
|
|
||||||
return QString();
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
Q_INIT_RESOURCE(companion);
|
Q_INIT_RESOURCE(companion);
|
||||||
|
@ -100,6 +91,8 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
g.init();
|
g.init();
|
||||||
|
|
||||||
|
QString resultMsg;
|
||||||
|
|
||||||
QTranslator companionTranslator;
|
QTranslator companionTranslator;
|
||||||
companionTranslator.load(":/companion_" + g.locale());
|
companionTranslator.load(":/companion_" + g.locale());
|
||||||
QTranslator qtTranslator;
|
QTranslator qtTranslator;
|
||||||
|
@ -127,9 +120,9 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
registerStorageFactories();
|
registerStorageFactories();
|
||||||
registerOpenTxFirmwares();
|
registerOpenTxFirmwares();
|
||||||
registerSimulators();
|
SimulatorLoader::registerSimulators();
|
||||||
|
|
||||||
if (!registered_simulators.size()) {
|
if (!SimulatorLoader::getAvailableSimulators().size()) {
|
||||||
showMessage(QObject::tr("ERROR: No simulator libraries available."), QMessageBox::Critical);
|
showMessage(QObject::tr("ERROR: No simulator libraries available."), QMessageBox::Critical);
|
||||||
return finish(3);
|
return finish(3);
|
||||||
}
|
}
|
||||||
|
@ -142,20 +135,19 @@ int main(int argc, char *argv[])
|
||||||
cliOptions.alias("help", "h");
|
cliOptions.alias("help", "h");
|
||||||
cliOptions.parse(QCoreApplication::arguments());
|
cliOptions.parse(QCoreApplication::arguments());
|
||||||
if (cliOptions.count("help") || cliOptions.showUnrecognizedWarning()) {
|
if (cliOptions.count("help") || cliOptions.showUnrecognizedWarning()) {
|
||||||
QString msg;
|
QTextStream stream(&resultMsg);
|
||||||
QTextStream stream(&msg);
|
|
||||||
stream << QObject::tr("Usage: simulator [OPTION]... [EEPROM.BIN FILE OR DATA FOLDER] ") << endl << endl;
|
stream << QObject::tr("Usage: simulator [OPTION]... [EEPROM.BIN FILE OR DATA FOLDER] ") << endl << endl;
|
||||||
stream << QObject::tr("Options:") << endl;
|
stream << QObject::tr("Options:") << endl;
|
||||||
cliOptions.showUsage(false, stream);
|
cliOptions.showUsage(false, stream);
|
||||||
sharedHelpText(stream);
|
sharedHelpText(stream);
|
||||||
// display
|
// display
|
||||||
showMessage(msg, QMessageBox::Information);
|
showMessage(resultMsg, QMessageBox::Information);
|
||||||
return finish(1);
|
return finish(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO : defaults should be set in Profile::init()
|
// TODO : defaults should be set in Profile::init()
|
||||||
if (simOptions.firmwareId.isEmpty())
|
if (simOptions.firmwareId.isEmpty())
|
||||||
simOptions.firmwareId = findFirmwareId(profileId);
|
simOptions.firmwareId = SimulatorLoader::findSimulatorByFirmwareName(g.profile[profileId].fwType());
|
||||||
if (simOptions.dataFolder.isEmpty())
|
if (simOptions.dataFolder.isEmpty())
|
||||||
simOptions.dataFolder = g.eepromDir();
|
simOptions.dataFolder = g.eepromDir();
|
||||||
if (simOptions.sdPath.isEmpty())
|
if (simOptions.sdPath.isEmpty())
|
||||||
|
@ -209,28 +201,16 @@ int main(int argc, char *argv[])
|
||||||
qDebug() << "profileId=" << profileId << simOptions;
|
qDebug() << "profileId=" << profileId << simOptions;
|
||||||
|
|
||||||
if (profileId < 0 || simOptions.firmwareId.isEmpty() || (simOptions.dataFile.isEmpty() && simOptions.dataFolder.isEmpty())) {
|
if (profileId < 0 || simOptions.firmwareId.isEmpty() || (simOptions.dataFile.isEmpty() && simOptions.dataFolder.isEmpty())) {
|
||||||
showMessage(QObject::tr("ERROR: Couldn't start simulator, missing radio/profile/data file/folder.\n Profile ID: [%1]; Radio ID: [%2];\nData File: [%3]")
|
resultMsg = QObject::tr("ERROR: Couldn't start simulator, missing radio/profile/data file/folder.\n Profile ID: [%1]; Radio ID: [%2];\nData File: [%3]");
|
||||||
.arg(profileId).arg(simOptions.firmwareId, simOptions.dataFile), QMessageBox::Critical);
|
showMessage(resultMsg.arg(profileId).arg(simOptions.firmwareId, simOptions.dataFile), QMessageBox::Critical);
|
||||||
return finish(1);
|
return finish(1);
|
||||||
}
|
}
|
||||||
if (!g.getActiveProfiles().contains(profileId) || !registered_simulators.keys().contains(simOptions.firmwareId)) {
|
if (!g.getActiveProfiles().contains(profileId) || !SimulatorLoader::getAvailableSimulators().contains(simOptions.firmwareId)) {
|
||||||
QString msg;
|
QTextStream stream(&resultMsg);
|
||||||
QTextStream stream(&msg);
|
|
||||||
stream << QObject::tr("ERROR: Radio profile or simulator firmware not found.\nProfile ID: [%1]; Radio ID: [%2]")
|
stream << QObject::tr("ERROR: Radio profile or simulator firmware not found.\nProfile ID: [%1]; Radio ID: [%2]")
|
||||||
.arg(profileId).arg(simOptions.firmwareId);
|
.arg(profileId).arg(simOptions.firmwareId);
|
||||||
sharedHelpText(stream);
|
sharedHelpText(stream);
|
||||||
showMessage(msg, QMessageBox::Critical);
|
showMessage(resultMsg, QMessageBox::Critical);
|
||||||
return finish(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
SimulatorFactory * factory = getSimulatorFactory(simOptions.firmwareId);
|
|
||||||
if (!factory) {
|
|
||||||
showMessage(QObject::tr("ERROR: Simulator %1 not found").arg(simOptions.firmwareId), QMessageBox::Critical);
|
|
||||||
return finish(2);
|
|
||||||
}
|
|
||||||
SimulatorInterface * simulator = factory->create();
|
|
||||||
if (!simulator) {
|
|
||||||
showMessage(QObject::tr("ERROR: Failed to create simulator interface, possibly missing or bad library."), QMessageBox::Critical);
|
|
||||||
return finish(2);
|
return finish(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,26 +219,33 @@ int main(int argc, char *argv[])
|
||||||
g.sessionId(profileId);
|
g.sessionId(profileId);
|
||||||
g.simuLastProfId(profileId);
|
g.simuLastProfId(profileId);
|
||||||
|
|
||||||
int result = 1;
|
int result = 0;
|
||||||
SimulatorMainWindow * mainWindow = new SimulatorMainWindow(NULL, simulator, SIMULATOR_FLAGS_STANDALONE);
|
SimulatorMainWindow * mainWindow = new SimulatorMainWindow(NULL, simOptions.firmwareId, SIMULATOR_FLAGS_STANDALONE);
|
||||||
if (mainWindow->setOptions(simOptions, true)) {
|
if ((result = mainWindow->getExitStatus(&resultMsg))) {
|
||||||
|
if (resultMsg.isEmpty())
|
||||||
|
resultMsg = QObject::tr("Uknown error during Simulator startup.");
|
||||||
|
showMessage(resultMsg, QMessageBox::Critical);
|
||||||
|
}
|
||||||
|
else if (mainWindow->setOptions(simOptions, true)) {
|
||||||
mainWindow->start();
|
mainWindow->start();
|
||||||
mainWindow->show();
|
mainWindow->show();
|
||||||
result = app.exec();
|
result = app.exec();
|
||||||
|
if (!result) {
|
||||||
|
if ((result = mainWindow->getExitStatus(&resultMsg)) && !resultMsg.isEmpty())
|
||||||
|
qWarning() << "Exit message from SimulatorMainWindow:" << resultMsg;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
result = 3;
|
result = 3;
|
||||||
}
|
}
|
||||||
delete mainWindow;
|
|
||||||
delete simulator;
|
|
||||||
|
|
||||||
|
delete mainWindow;
|
||||||
return finish(result);
|
return finish(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
int finish(int exitCode)
|
int finish(int exitCode)
|
||||||
{
|
{
|
||||||
qDebug() << "SIMULATOR EXIT" << exitCode;
|
SimulatorLoader::unregisterSimulators();
|
||||||
unregisterSimulators();
|
|
||||||
unregisterOpenTxFirmwares();
|
unregisterOpenTxFirmwares();
|
||||||
unregisterStorageFactories();
|
unregisterStorageFactories();
|
||||||
|
|
||||||
|
@ -266,5 +253,6 @@ int finish(int exitCode)
|
||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
qDebug() << "SIMULATOR EXIT" << exitCode;
|
||||||
return exitCode;
|
return exitCode;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue