diff --git a/companion/src/helpers.cpp b/companion/src/helpers.cpp index c84ef4b6e..e59e39c11 100644 --- a/companion/src/helpers.cpp +++ b/companion/src/helpers.cpp @@ -40,6 +40,8 @@ #include #include #include +#include +#include using namespace Helpers; @@ -369,35 +371,63 @@ void startSimulation(QWidget * parent, RadioData & radioData, int modelIdx) simuData->setCurrentModel(modelIdx); } - SimulatorMainWindow * dialog = new SimulatorMainWindow(parent, simulatorId, flags); - dialog->setWindowModality(Qt::ApplicationModal); - dialog->setAttribute(Qt::WA_DeleteOnClose); - - QObject::connect(dialog, &SimulatorMainWindow::destroyed, [simuData] (void) { -#ifdef __APPLE__ - simulatorRunning = false; -#endif - // 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 = QCoreApplication::translate("Companion", "Uknown error during Simulator startup."); - QMessageBox::critical(NULL, QCoreApplication::translate("Companion", "Simulator Error"), resultMsg); - dialog->deleteLater(); - } - else if (dialog->setRadioData(simuData)) { -#ifdef __APPLE__ - simulatorRunning = true; -#endif - dialog->show(); + // the directory will be automatically deleted when QTemporaryDir goes out of scope + QTemporaryDir tmpDir(QDir::tempPath() + "/etx-XXXXXX"); + if (tmpDir.isValid()) { + qDebug() << "Created temporary settings directory" << tmpDir.path(); } else { - QMessageBox::critical(NULL, QCoreApplication::translate("Companion", "Data Load Error"), QCoreApplication::translate("Companion", "Error occurred while starting simulator.")); - dialog->deleteLater(); + QString resultMsg = QCoreApplication::translate("Companion", "Error creating temporary directory for models and settings."); + QMessageBox::critical(NULL, QCoreApplication::translate("Companion", "Simulator Error"), resultMsg); + return; } + + simuData->fixModelFilenames(); + Storage storage(tmpDir.path()); + if (!storage.write(*simuData)) { + QString resultMsg = QCoreApplication::translate("Companion", "Error writing models and settings to temporary directory."); + QMessageBox::critical(NULL, QCoreApplication::translate("Companion", "Simulator Error"), resultMsg); + return; + } + + const QString path = QCoreApplication::applicationDirPath(); + +#if defined Q_OS_WIN + const QString program = "simulator.exe"; +#elif defined Q_OS_APPLE + const QString program = "simulator.dmg"; +#else + const QString program = QString("simulator%1%2").arg(VERSION_MAJOR).arg(VERSION_MINOR); +#endif + + QStringList arguments; + arguments << "--profile" << g.currentProfile().name() + << "--start-with" << "folder" + << "--flags" << QString::number(flags) + << tmpDir.path(); + + QProcess *simu = new QProcess(parent); + + qDebug() << "Launching simulator with command:" << QDir::toNativeSeparators(path % "/" % program) << arguments; + + // wait for the simulator to finish + int result = simu->execute(path % "/" % program, arguments); + + QString resultMsg; + + if (result == -2) + resultMsg = QCoreApplication::translate("Companion", "Unable to start."); + else if (result == -1) + resultMsg = QCoreApplication::translate("Companion", "Crashed."); + else if (result > 0) + resultMsg = QCoreApplication::translate("Companion", "Exited with result code:") % QString(result); + + if (result != 0) + QMessageBox::critical(NULL, QCoreApplication::translate("Companion", "Simulator Error"), resultMsg); + + if (simuData) + delete simuData; + } QPixmap makePixMap(const QImage & image) diff --git a/companion/src/simulation/simulator.h b/companion/src/simulation/simulator.h index 689bcdf9b..e00ebd4f6 100644 --- a/companion/src/simulation/simulator.h +++ b/companion/src/simulation/simulator.h @@ -32,7 +32,7 @@ #define SIMULATOR_FLAGS_NOTX 0x01 // simulating a single model from Companion #define SIMULATOR_FLAGS_STANDALONE 0x02 // started from stanalone simulator -#define SIMULATOR_OPTIONS_VERSION 3 +#define SIMULATOR_OPTIONS_VERSION 4 namespace Simulator { @@ -131,6 +131,8 @@ struct SimulatorOptions QByteArray radioOutputsState; // RadioOutputsWidget UI state // added in v3 QString simulatorId; + // added in v4 + quint8 flags; // Flags passed from Companion quint16 loadedVersion() const { return m_version; } //! loaded structure definition version (0 if none/error) @@ -138,7 +140,7 @@ struct SimulatorOptions { out << quint16(SIMULATOR_OPTIONS_VERSION) << o.startupDataType << o.firmwareId << o.dataFile << o.dataFolder << o.sdPath << o.windowGeometry << o.controlsState << o.lcdColor << o.windowState << o.dbgConsoleState << o.radioOutputsState - << o.simulatorId; + << o.simulatorId << o.flags; return out; } @@ -152,6 +154,8 @@ struct SimulatorOptions in >> o.windowState >> o.dbgConsoleState >> o.radioOutputsState; if (o.m_version >= 3) in >> o.simulatorId; + if (o.m_version >= 4) + in >> o.simulatorId; } else { qWarning() << "Error loading SimulatorOptions, saved version not valid:" << o.m_version << "Expected <=" << SIMULATOR_OPTIONS_VERSION; diff --git a/companion/src/simulator.cpp b/companion/src/simulator.cpp index cf2fb1ffe..2a7465f15 100644 --- a/companion/src/simulator.cpp +++ b/companion/src/simulator.cpp @@ -129,6 +129,10 @@ CommandLineParseResult cliOptions(SimulatorOptions * simOptions, int * profileId QApplication::translate("SimulatorMain", "Data source type to use. One of:") + " (file|folder|sd)", QApplication::translate("SimulatorMain", "type")); + const QCommandLineOption optFlags(QStringList() << "flags" << "f", + QApplication::translate("SimulatorMain", "Flags passed from Companion"), + QApplication::translate("SimulatorMain", "flags")); + cliOptions.addPositionalArgument(QApplication::translate("SimulatorMain", "data-source"), QApplication::translate("SimulatorMain", "Radio data (.bin/.eeprom/.etx) image file to use OR data folder path (for Horus-style radios).\n" "NOTE: any existing EEPROM data incompatible with the selected radio type may be overwritten!"), @@ -138,6 +142,7 @@ CommandLineParseResult cliOptions(SimulatorOptions * simOptions, int * profileId cliOptions.addOption(optRadio); cliOptions.addOption(optSdDir); cliOptions.addOption(optStart); + cliOptions.addOption(optFlags); QStringList args = QCoreApplication::arguments(); #ifdef Q_OS_WIN @@ -211,10 +216,10 @@ CommandLineParseResult cliOptions(SimulatorOptions * simOptions, int * profileId if (stTyp == "file") { simOptions->startupDataType = SimulatorOptions::START_WITH_FILE; } - else if (stTyp == "folder") { + else if (stTyp == "folder") { simOptions->startupDataType = SimulatorOptions::START_WITH_FOLDER; } - else if (stTyp == "sd") { + else if (stTyp == "sd") { simOptions->startupDataType = SimulatorOptions::START_WITH_SDPATH; } else { @@ -225,6 +230,17 @@ CommandLineParseResult cliOptions(SimulatorOptions * simOptions, int * profileId cliOptsFound = true; } + int flags = 0; + + if (cliOptions.isSet(optFlags)) { + bool chk; + flags = cliOptions.value(optFlags).toInt(&chk); + if (!chk) + flags = 0; + } + + simOptions->flags = flags; + *profileId = pId; if (cliOptsFound) return CommandLineFound; @@ -292,19 +308,6 @@ int main(int argc, char *argv[]) int profileId = (g.simuLastProfId() > -1 ? g.simuLastProfId() : g.id()); SimulatorOptions simOptions = g.profile[profileId].simulatorOptions(); - // TODO : defaults should be set in Profile::init() - if (simOptions.firmwareId.isEmpty()) { - simOptions.firmwareId = g.profile[profileId].fwType(); - } - - // DO NOT use saved simulatorId as could be changed in later releases - simOptions.simulatorId = SimulatorLoader::findSimulatorByName(Firmware::getFirmwareForId(simOptions.firmwareId)->getSimulatorId()); - - if (simOptions.dataFolder.isEmpty()) - simOptions.dataFolder = g.eepromDir(); - if (simOptions.sdPath.isEmpty()) - simOptions.sdPath = g.profile[profileId].sdPath(); - // Handle startup options // check for command-line options @@ -315,7 +318,21 @@ int main(int argc, char *argv[]) if (cliResult == CommandLineExitErr) return finish(1); - // Present GUI startup options dialog if necessary + // TODO : defaults should be set in Profile::init() + if (simOptions.firmwareId.isEmpty()) { + simOptions.firmwareId = g.profile[profileId].fwType(); + } + + if (simOptions.dataFolder.isEmpty()) + simOptions.dataFolder = g.eepromDir(); + if (simOptions.sdPath.isEmpty()) + simOptions.sdPath = g.profile[profileId].sdPath(); + + // DO NOT use saved simulatorId as could be changed in later releases + // must be set after cli parse as --profile will load old data or blank + simOptions.simulatorId = SimulatorLoader::findSimulatorByName(Firmware::getFirmwareForId(simOptions.firmwareId)->getSimulatorId()); + + // Present GUI startup options dialog if necessary if (cliResult == CommandLineNone || profileId == -1 || simOptions.simulatorId.isEmpty() || (simOptions.dataFile.isEmpty() && simOptions.dataFolder.isEmpty())) { SimulatorStartupDialog * dlg = new SimulatorStartupDialog(&simOptions, &profileId); int ret = dlg->exec(); @@ -357,7 +374,7 @@ int main(int argc, char *argv[]) //qDebug() << "current firmware:" << getCurrentFirmware()->getId(); int result = 0; - SimulatorMainWindow * mainWindow = new SimulatorMainWindow(NULL, simOptions.simulatorId, SIMULATOR_FLAGS_STANDALONE); + SimulatorMainWindow * mainWindow = new SimulatorMainWindow(nullptr, simOptions.simulatorId, (simOptions.flags ? simOptions.flags : SIMULATOR_FLAGS_STANDALONE)); if ((result = mainWindow->getExitStatus(&resultMsg))) { if (resultMsg.isEmpty()) resultMsg = QApplication::translate("SimulatorMain", "Unknown error during Simulator startup.");