[Simulator] Asynchronous SimulatorInterface & a few new features. (#4738)
[opentx.git] / companion / src / simulation / simulatorinterface.cpp
blob24919e05556e0b89c15e7b341be0f8356468446c
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 "simulatorinterface.h"
22 #include "customdebug.h"
23 #include "version.h"
25 #include <QDebug>
26 #include <QLibraryInfo>
28 #if defined _MSC_VER || !defined __GNUC__
29 #include <windows.h>
30 #endif
32 #ifndef SIMULATOR_INTERFACE_LOADER_METHOD
33 #define SIMULATOR_INTERFACE_LOADER_DYNAMIC 1 // How to load simulator libraries: 1=dynamic load and unload; 0=load once (old way)
34 #endif
36 QMap<QString, QLibrary *> SimulatorLoader::registeredSimulators;
38 QStringList SimulatorLoader::getAvailableSimulators()
40 return registeredSimulators.keys();
43 int SimulatorLoader::registerSimulators(const QDir & dir)
45 QStringList filters;
46 #if defined(__APPLE__)
47 filters << "*-simulator.dylib";
48 #elif defined(WIN32) || defined(__CYGWIN__)
49 filters << "*-simulator.dll";
50 #else
51 filters << "*-simulator.so";
52 #endif
53 registeredSimulators.clear();
55 qCDebug(simulatorInterfaceLoader) << "Searching for simulators in" << dir.path() << "matching pattern" << filters;
57 foreach(QString filename, dir.entryList(filters, QDir::Files)) {
58 QLibrary * lib = new QLibrary( dir.path() + "/" + filename);
60 qCDebug(simulatorInterfaceLoader) << "Trying to register simulator in " << filename;
62 SimulatorFactory * factory;
63 RegisterSimulator registerFunc = (RegisterSimulator)lib->resolve("registerSimu");
65 if (registerFunc && (factory = registerFunc())) {
66 if (getAvailableSimulators().contains(factory->name()))
67 continue;
69 lib->setProperty("instances_used", 0);
70 registeredSimulators.insert(factory->name(), lib);
71 delete factory;
72 #if SIMULATOR_INTERFACE_LOADER_DYNAMIC
73 lib->unload();
74 #endif
75 qCDebug(simulatorInterfaceLoader) << "Registered" << registeredSimulators.lastKey() << "simulator in " << lib->fileName() << "and unloaded:" << !lib->isLoaded();
77 else {
78 qWarning() << "Library error" << lib->fileName() << lib->errorString();
79 delete lib;
83 qCDebug(simulatorInterfaceLoader) << "Found libraries:" << (registeredSimulators.size() ? registeredSimulators.keys() : QStringList() << "none");
84 return registeredSimulators.size();
87 void SimulatorLoader::registerSimulators()
89 QDir dir(".");
90 if (registerSimulators(dir)) {
91 return;
94 #if defined(__APPLE__)
95 dir = QLibraryInfo::location(QLibraryInfo::PrefixPath) + "/Resources";
96 #elif (!defined __GNUC__)
97 char name[MAX_PATH];
98 GetModuleFileName(NULL, name, MAX_PATH);
99 QString path(name);
100 path.truncate(path.lastIndexOf('\\'));
101 dir.setPath(path);
102 #else
103 dir = SIMULATOR_LIB_SEARCH_PATH;
104 #endif
105 registerSimulators(dir);
108 void SimulatorLoader::unregisterSimulators()
110 foreach(QLibrary * lib, registeredSimulators)
111 delete lib;
114 QString SimulatorLoader::findSimulatorByFirmwareName(const QString & name)
116 int pos;
117 QString ret;
118 QString simuName = name;
120 while(1) {
121 qCDebug(simulatorInterfaceLoader) << "searching" << simuName << "simulator";
122 if (registeredSimulators.contains(simuName)) {
123 ret = simuName;
124 break;
126 if ((pos = simuName.lastIndexOf('-')) <= 0)
127 break;
128 simuName = simuName.mid(0, pos);
129 if (simuName.count('-') == 0)
130 break;
132 return ret;
135 SimulatorInterface * SimulatorLoader::loadSimulator(const QString & name)
137 SimulatorInterface * si = NULL;
138 QString libname = findSimulatorByFirmwareName(name);
140 if (libname.isEmpty()) {
141 qWarning() << "Simulator" << name << "not found.";
142 return si;
145 QLibrary * lib = registeredSimulators.value(libname, NULL);
146 if (!lib) {
147 qWarning() << "Simulator library is NULL";
148 return si;
151 qCDebug(simulatorInterfaceLoader) << "Trying to load simulator in " << lib->fileName();
153 SimulatorFactory * factory;
154 RegisterSimulator registerFunc = (RegisterSimulator)lib->resolve("registerSimu");
155 if (registerFunc && (factory = registerFunc()) && (si = factory->create())) {
156 quint8 instance = lib->property("instances_used").toUInt();
157 lib->setProperty("instances_used", ++instance);
158 qCDebug(simulatorInterfaceLoader) << "Loaded" << factory->name() << "simulator instance" << instance;
159 delete factory;
161 else {
162 qWarning() << "Library error" << lib->fileName() << lib->errorString();
164 return si;
167 bool SimulatorLoader::unloadSimulator(const QString & name)
169 bool ret = false;
170 #if SIMULATOR_INTERFACE_LOADER_DYNAMIC
171 QString simuName = findSimulatorByFirmwareName(name);
172 if (simuName.isEmpty())
173 return ret;
175 QLibrary * lib = registeredSimulators.value(simuName, NULL);
177 if (lib && lib->isLoaded()) {
178 quint8 instance = lib->property("instances_used").toUInt();
179 lib->setProperty("instances_used", --instance);
180 if (!instance) {
181 ret = lib->unload();
182 qCDebug(simulatorInterfaceLoader) << "Unloading" << simuName << "(" << lib->fileName() << ")" << "result:" << ret;
184 else {
185 ret = true;
186 qCDebug(simulatorInterfaceLoader) << "Simulator" << simuName << "instances remaining:" << instance;
189 else {
190 qCDebug(simulatorInterfaceLoader) << "Simulator library for " << simuName << "already unloaded.";
192 #else
193 qCDebug(simulatorInterfaceLoader) << "Keeping simulator library" << simuName << "loaded.";
194 #endif
196 return ret;