[build] Only build companion/simulator resources files once. (#4670)
[opentx.git] / companion / src / simulator.cpp
blobd99a063139915b362eb51d2d48c23fcdb735b3e9
1 /*
2 * Copyright (C) OpenTX
4 * Based on code named
5 * th9x - http://code.google.com/p/th9x
6 * er9x - http://code.google.com/p/er9x
7 * gruvin9x - http://code.google.com/p/gruvin9x
9 * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
21 #include <QApplication>
22 #include <QDir>
23 #include <QLibraryInfo>
24 #include <QLocale>
25 #include <QMessageBox>
26 #include <QString>
27 #include <QTextStream>
28 #include <QTranslator>
29 #if defined(JOYSTICKS) || defined(SIMU_AUDIO)
30 #include <SDL.h>
31 #undef main
32 #endif
34 #include "appdata.h"
35 #include "appdebugmessagehandler.h"
36 #include "constants.h"
37 #include "customdebug.h"
38 #include "eeprominterface.h"
39 #include "simulator.h"
40 #include "simulatormainwindow.h"
41 #include "simulatorstartupdialog.h"
42 #include "storage.h"
43 #include "qxtcommandoptions.h"
44 #include "version.h"
46 using namespace Simulator;
48 int finish(int exitCode);
50 void showMessage(const QString & message, enum QMessageBox::Icon icon = QMessageBox::NoIcon)
52 QMessageBox msgBox;
53 msgBox.setText(message);
54 msgBox.setIcon(icon);
55 msgBox.exec();
58 void sharedHelpText(QTextStream &stream)
60 // list all available profiles
61 stream << endl << QObject::tr("Available profiles:") << endl;
62 QMapIterator<int, QString> pi(g.getActiveProfiles());
63 while (pi.hasNext()) {
64 pi.next();
65 stream << "\t" << QObject::tr("ID: ") << pi.key() << QObject::tr(" Name: ") << pi.value() << endl;
67 // list all available radios
68 stream << endl << QObject::tr("Available radios:") << endl;
69 foreach(QString name, SimulatorLoader::getAvailableSimulators()) {
70 stream << "\t" << name << endl;
74 int main(int argc, char *argv[])
77 QApplication app(argc, argv);
78 app.setApplicationName(APP_SIMULATOR);
79 app.setOrganizationName(COMPANY);
80 app.setOrganizationDomain(COMPANY_DOMAIN);
81 #if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
82 app.setAttribute(Qt::AA_EnableHighDpiScaling);
83 #endif
85 Q_INIT_RESOURCE(companion);
86 Q_INIT_RESOURCE(translations);
88 if (AppDebugMessageHandler::instance())
89 AppDebugMessageHandler::instance()->installAppMessageHandler();
91 CustomDebug::setFilterRules();
93 g.init();
95 QString resultMsg;
97 QTranslator companionTranslator;
98 companionTranslator.load(":/companion_" + g.locale());
99 QTranslator qtTranslator;
100 #if (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0))
101 QString qtfile = "qtbase_";
102 #else
103 QString qtfile = "qt_";
104 #endif
105 qtTranslator.load(qtfile + g.locale().left(2), QLibraryInfo::location(QLibraryInfo::TranslationsPath));
106 app.installTranslator(&companionTranslator);
107 app.installTranslator(&qtTranslator);
109 #if defined(JOYSTICKS) || defined(SIMU_AUDIO)
110 uint32_t sdlFlags = 0;
111 #ifdef JOYSTICKS
112 sdlFlags |= SDL_INIT_JOYSTICK;
113 #endif
114 #ifdef SIMU_AUDIO
115 sdlFlags |= SDL_INIT_AUDIO;
116 #endif
117 if (SDL_Init(sdlFlags) < 0) {
118 showMessage(QObject::tr("WARNING: couldn't initialize SDL:\n%1").arg(SDL_GetError()), QMessageBox::Warning);
120 #endif
122 QxtCommandOptions cliOptions;
123 bool cliOptsFound = false;
124 int profileId = (g.simuLastProfId() > -1 ? g.simuLastProfId() : g.id());
125 SimulatorOptions simOptions = g.profile[profileId].simulatorOptions();
127 registerStorageFactories();
128 registerOpenTxFirmwares();
129 SimulatorLoader::registerSimulators();
131 if (!SimulatorLoader::getAvailableSimulators().size()) {
132 showMessage(QObject::tr("ERROR: No simulator libraries available."), QMessageBox::Critical);
133 return finish(3);
136 cliOptions.add("profile", QObject::tr("Radio profile ID or Name to use for simulator."), QxtCommandOptions::ValueRequired);
137 cliOptions.alias("profile", "p");
138 cliOptions.add("radio", QObject::tr("Radio type to simulate (usually defined in profile)."), QxtCommandOptions::ValueRequired);
139 cliOptions.alias("radio", "r");
140 cliOptions.add("help", QObject::tr("show this help text"));
141 cliOptions.alias("help", "h");
142 cliOptions.parse(QCoreApplication::arguments());
143 if (cliOptions.count("help") || cliOptions.showUnrecognizedWarning()) {
144 QTextStream stream(&resultMsg);
145 stream << QObject::tr("Usage: simulator [OPTION]... [EEPROM.BIN FILE OR DATA FOLDER] ") << endl << endl;
146 stream << QObject::tr("Options:") << endl;
147 cliOptions.showUsage(false, stream);
148 sharedHelpText(stream);
149 // display
150 showMessage(resultMsg, QMessageBox::Information);
151 return finish(1);
154 // TODO : defaults should be set in Profile::init()
155 if (simOptions.firmwareId.isEmpty())
156 simOptions.firmwareId = SimulatorLoader::findSimulatorByFirmwareName(g.profile[profileId].fwType());
157 if (simOptions.dataFolder.isEmpty())
158 simOptions.dataFolder = g.eepromDir();
159 if (simOptions.sdPath.isEmpty())
160 simOptions.sdPath = g.profile[profileId].sdPath();
162 if (cliOptions.count("profile") == 1) {
163 bool chk;
164 int pid = cliOptions.value("profile").toInt(&chk);
165 if (chk)
166 profileId = pid;
167 else
168 profileId = g.getActiveProfiles().key(cliOptions.value("profile").toString(), -1);
170 if (!g.getActiveProfiles().contains(profileId)) {
171 fprintf(stderr, "Error: Profile ID %d was not found.", profileId);
172 return finish(1);
175 simOptions = g.profile[profileId].simulatorOptions();
176 cliOptsFound = true;
179 if (cliOptions.count("radio") == 1) {
180 simOptions.firmwareId = cliOptions.value("radio").toString();
181 cliOptsFound = true;
184 if (cliOptsFound || (simOptions.dataFile.isEmpty() && !simOptions.firmwareId.isEmpty()))
185 simOptions.dataFile = SimulatorStartupDialog::radioEepromFileName(simOptions.firmwareId, g.eepromDir());
187 if (!cliOptions.positional().isEmpty()) {
188 if (QString(cliOptions.positional().at(0)).contains(QRegExp(".*\\.[\\w]{2,6}$"))) {
189 simOptions.dataFile = cliOptions.positional()[0];
190 simOptions.startupDataType = SimulatorOptions::START_WITH_FILE;
192 else {
193 simOptions.dataFolder = cliOptions.positional()[0];
194 simOptions.startupDataType = SimulatorOptions::START_WITH_FOLDER;
196 cliOptsFound = true;
199 if (!cliOptsFound || profileId == -1 || simOptions.firmwareId.isEmpty() || (simOptions.dataFile.isEmpty() && simOptions.dataFolder.isEmpty())) {
200 SimulatorStartupDialog * dlg = new SimulatorStartupDialog(&simOptions, &profileId);
201 int ret = dlg->exec();
202 dlg->deleteLater();
203 if (ret != QDialog::Accepted) {
204 return finish(0);
207 qDebug() << "profileId=" << profileId << simOptions;
209 if (profileId < 0 || simOptions.firmwareId.isEmpty() || (simOptions.dataFile.isEmpty() && simOptions.dataFolder.isEmpty())) {
210 resultMsg = QObject::tr("ERROR: Couldn't start simulator, missing radio/profile/data file/folder.\n Profile ID: [%1]; Radio ID: [%2];\nData File: [%3]");
211 showMessage(resultMsg.arg(profileId).arg(simOptions.firmwareId, simOptions.dataFile), QMessageBox::Critical);
212 return finish(1);
214 if (!g.getActiveProfiles().contains(profileId) || !SimulatorLoader::getAvailableSimulators().contains(simOptions.firmwareId)) {
215 QTextStream stream(&resultMsg);
216 stream << QObject::tr("ERROR: Radio profile or simulator firmware not found.\nProfile ID: [%1]; Radio ID: [%2]")
217 .arg(profileId).arg(simOptions.firmwareId);
218 sharedHelpText(stream);
219 showMessage(resultMsg, QMessageBox::Critical);
220 return finish(2);
223 current_firmware_variant = getFirmware(simOptions.firmwareId);
225 g.sessionId(profileId);
226 g.simuLastProfId(profileId);
228 int result = 0;
229 SimulatorMainWindow * mainWindow = new SimulatorMainWindow(NULL, simOptions.firmwareId, SIMULATOR_FLAGS_STANDALONE);
230 if ((result = mainWindow->getExitStatus(&resultMsg))) {
231 if (resultMsg.isEmpty())
232 resultMsg = QObject::tr("Uknown error during Simulator startup.");
233 showMessage(resultMsg, QMessageBox::Critical);
235 else if (mainWindow->setOptions(simOptions, true)) {
236 mainWindow->start();
237 mainWindow->show();
238 result = app.exec();
239 if (!result) {
240 if ((result = mainWindow->getExitStatus(&resultMsg)) && !resultMsg.isEmpty())
241 qWarning() << "Exit message from SimulatorMainWindow:" << resultMsg;
244 else {
245 result = 3;
248 delete mainWindow;
249 return finish(result);
252 int finish(int exitCode)
254 SimulatorLoader::unregisterSimulators();
255 unregisterOpenTxFirmwares();
256 unregisterStorageFactories();
258 #if defined(JOYSTICKS) || defined(SIMU_AUDIO)
259 SDL_Quit();
260 #endif
262 qDebug() << "SIMULATOR EXIT" << exitCode;
263 return exitCode;