RTXI  3.0.0
The Real-Time eXperiment Interface Reference Manual
workspace.cpp
Go to the documentation of this file.
1 /*
2  The Real-Time eXperiment Interface (RTXI)
3  Copyright (C) 2011 Georgia Institute of Technology, University of Utah,
4  Will Cornell Medical College This program is free software: you can
5  redistribute it and/or modify it under the terms of the GNU General Public
6  License as published by the Free Software Foundation, either version 3 of the
7  License, or (at your option) any later version. This program is distributed
8  in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
9  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10  See the GNU General Public License for more details. You should have received
11  a copy of the GNU General Public License along with this program. If not,
12  see <http://www.gnu.org/licenses/>.
13 */
14 
15 #include <optional>
16 #include <variant>
17 
18 #include "workspace.hpp"
19 
20 #include "connector/connector.hpp"
25 #include "rtxiConfig.h"
27 #include "userprefs/userprefs.hpp"
28 
29 std::optional<Widgets::FactoryMethods> Workspace::get_core_plugin_factory(
30  const std::string& plugin_name)
31 {
32  std::optional<Widgets::FactoryMethods> fact_methods;
33  if (plugin_name == std::string(PerformanceMeasurement::MODULE_NAME)) {
34  fact_methods = PerformanceMeasurement::getFactories();
35  } else if (plugin_name == std::string(UserPrefs::MODULE_NAME)) {
36  fact_methods = UserPrefs::getFactories();
37  } else if (plugin_name == std::string(SystemControl::MODULE_NAME)) {
38  fact_methods = SystemControl::getFactories();
39  } else if (plugin_name == std::string(Connector::MODULE_NAME)) {
40  fact_methods = Connector::getFactories();
41  } else if (plugin_name == std::string(Oscilloscope::MODULE_NAME)) {
42  fact_methods = Oscilloscope::getFactories();
43  } else if (plugin_name == std::string(DataRecorder::MODULE_NAME)) {
44  fact_methods = DataRecorder::getFactories();
45  } else if (plugin_name == std::string(RTXIWizard::MODULE_NAME)) {
46  fact_methods = RTXIWizard::getFactories();
47  } else {
48  return fact_methods;
49  }
50  return fact_methods;
51 }
52 
54  : event_manager(ev_manager)
55 {
56  this->event_manager->registerHandler(this);
57  this->m_plugin_loader = std::make_unique<DLL::Loader>();
58  this->m_driver_loader = std::make_unique<DLL::Loader>();
59  const QDir bin_dir = QCoreApplication::applicationDirPath();
60  const std::string nidaq_driver_name = "librtxinidaqdriver.so";
61  if (bin_dir.exists(QString::fromStdString(nidaq_driver_name))) {
62  this->registerDriver(bin_dir.path().toStdString() + std::string("/")
63  + nidaq_driver_name);
64  }
65 }
66 
68 {
69  for (const auto& plugin_list : this->rtxi_widgets_registry) {
70  for (const auto& plugin : plugin_list.second) {
71  this->event_manager->unregisterHandler(plugin.get());
72  }
73  }
74  const std::vector<DAQ::Device*> devices = getAllDevices();
75  std::vector<Event::Object> unregister_device_events(
77  for (size_t i = 0; i < devices.size(); ++i) {
78  unregister_device_events[i].setParam(
79  "device", std::any(static_cast<RT::Device*>(devices[i])));
80  }
81  this->event_manager->postEvent(unregister_device_events);
82  // we should unload all drivers
83  void (*unloadDriversFunc)() = nullptr;
84  for (auto& driver : m_driver_registry) {
85  unloadDriversFunc = this->m_driver_loader->dlsym<void (*)()>(
86  driver.first.c_str(), "deleteRTXIDAQDriver");
87  unloadDriversFunc();
88  }
89  this->event_manager->unregisterHandler(this);
90 }
91 
93 {
94  std::vector<std::unique_ptr<Widgets::Plugin>>::iterator start_iter;
95  std::vector<std::unique_ptr<Widgets::Plugin>>::iterator end_iter;
96  bool registered = false;
97  for (auto& widgets_list : rtxi_widgets_registry) {
98  start_iter = widgets_list.second.begin();
99  end_iter = widgets_list.second.end();
100  registered = std::any_of(
101  start_iter,
102  end_iter,
103  [plugin](const std::unique_ptr<Widgets::Plugin>& temp_plugin)
104  { return plugin == temp_plugin.get(); });
105  if (registered) {
106  break;
107  }
108  }
109  return registered;
110 }
111 
112 std::vector<DAQ::Device*> Workspace::Manager::getDevices(
113  const std::string& driver)
114 {
115  auto iter = std::find_if(m_driver_registry.begin(),
116  m_driver_registry.end(),
117  [&](const driver_registry_entry& entry)
118  { return entry.second->getDriverName() == driver; });
119  if (iter == m_driver_registry.end()) {
120  return {};
121  }
122  return iter->second->getDevices();
123 }
124 
125 std::vector<DAQ::Device*> Workspace::Manager::getAllDevices()
126 {
127  std::vector<DAQ::Device*> devices;
128  std::vector<DAQ::Device*> temp_driver_devices;
129  for (auto& entry : this->m_driver_registry) {
130  temp_driver_devices = entry.second->getDevices();
131  devices.insert(
132  devices.end(), temp_driver_devices.begin(), temp_driver_devices.end());
133  }
134  return devices;
135 }
136 
137 template<class... Ts>
138 struct overload : Ts...
139 {
140  using Ts::operator()...;
141 };
142 template<class... Ts>
143 overload(Ts...) -> overload<Ts...>;
144 void Workspace::Manager::saveSettings(const QString& profile_name)
145 {
146  QSettings settings(settings_prefix + profile_name, QSettings::IniFormat);
147  settings.beginGroup("widgets");
148  QString widget_name;
149  int widget_count = 0;
150  for (const auto& entry : this->rtxi_widgets_registry) {
151  widget_name = QString::fromStdString(entry.first);
152  settings.beginGroup(widget_name);
153  for (const auto& plugin : entry.second) {
154  settings.beginGroup(QString::number(widget_count));
155  for (const auto& param_info : plugin->getComponentParametersInfo()) {
156  settings.setValue(
157  QString::fromStdString(param_info.name),
158  std::visit(overload {[](const int64_t& val) -> QString
159  { return QString::number(val); },
160  [](const double& val) -> QString
161  { return QString::number(val); },
162  [](const uint64_t& val) -> QString
163  { return QString::number(val); },
164  [](const std::string& val) -> QString
165  { return QString::fromStdString(val); },
166  [](const RT::State::state_t& val) -> QString {
167  return QString::number(
168  static_cast<int8_t>(val));
169  }},
170  param_info.value));
171  }
172  settings.endGroup();
173  widget_count++;
174  }
175  settings.endGroup();
176  }
177  settings.endGroup();
178 }
179 
180 void Workspace::Manager::loadSettings(const QString& profile_name)
181 {
182  QSettings settings(profile_name, QSettings::IniFormat);
183 }
184 
185 Widgets::Plugin* Workspace::Manager::loadCorePlugin(const std::string& library)
186 {
187  Widgets::Plugin* plugin_ptr = nullptr;
188  std::optional<Widgets::FactoryMethods> fact_methods =
190  if (!fact_methods.has_value()) {
191  return nullptr;
192  }
193  std::unique_ptr<Widgets::Plugin> plugin;
194  this->registerFactories(library, *fact_methods);
195  plugin = this->rtxi_factories_registry[library].createPlugin(event_manager);
196  plugin_ptr = this->registerWidget(std::move(plugin));
197  return plugin_ptr;
198 }
199 
200 // TODO: extract plugin dynamic loading to another class
202 {
203  const std::string& library_loc = library;
204  Widgets::Plugin* plugin_ptr = nullptr;
205  // if widget factory is already registered then all we have to do is run it
206  if (this->rtxi_factories_registry.find(library_loc)
207  != this->rtxi_factories_registry.end())
208  {
209  std::unique_ptr<Widgets::Plugin> plugin =
210  this->rtxi_factories_registry[library_loc].createPlugin(
211  this->event_manager);
212  plugin_ptr = this->registerWidget(std::move(plugin));
213  plugin_ptr->attachComponent(
214  this->rtxi_factories_registry[library_loc].createComponent(plugin_ptr));
215  return plugin_ptr;
216  }
217 
218  // If it is just a core plugin then handle that elsewhere and return
219  plugin_ptr = this->loadCorePlugin(library_loc);
220  if (plugin_ptr != nullptr) {
221  return plugin_ptr;
222  }
223 
224  if (this->m_plugin_loader->load(library_loc.c_str()) != 0) {
225  ERROR_MSG("Plugin::load : failed to load {}", library_loc.c_str());
226  return nullptr;
227  }
228 
229  auto gen_fact_methods =
230  this->m_plugin_loader->dlsym<Widgets::FactoryMethods* (*)()>(
231  library_loc.c_str(), "getFactories");
232 
233  if (gen_fact_methods == nullptr) {
234  ERROR_MSG("Plugin::load : failed to retrieve getFactories symbol");
235  // If we got here it means we loaded the lirbary but not the symbol.
236  // Let's just unload the library and exit before we regret it.
237  this->m_plugin_loader->unload(library_loc.c_str());
238  return nullptr;
239  }
240 
241  Widgets::FactoryMethods* fact_methods = gen_fact_methods();
242  this->rtxi_factories_registry[library] = *fact_methods;
243  std::unique_ptr<Widgets::Plugin> plugin =
244  fact_methods->createPlugin(this->event_manager);
245  plugin->setLibrary(library);
246  if (plugin == nullptr) {
247  ERROR_MSG("Plugin::load : failed to create plugin from library {} ",
248  library);
249  this->m_plugin_loader->unload(library_loc.c_str());
250  return nullptr;
251  }
252  std::unique_ptr<Widgets::Component> component =
253  fact_methods->createComponent(plugin.get());
254  plugin->attachComponent(std::move(component));
255  // if (plugin->magic_number != Plugin::Object::MAGIC_NUMBER) {
256  // ERROR_MSG(
257  // "Plugin::load : the pointer returned from {}::createRTXIPlugin()
258  // isn't " "a valid Plugin::Object *.\n",
259  // library.toStdString().c_str());
260  // dlclose(handle);
261  // return 0;
262  // }
263  plugin_ptr = this->registerWidget(std::move(plugin));
264 
265  return plugin_ptr;
266 }
267 
269 {
270  const std::string library = plugin->getName();
271  this->unregisterWidget(plugin);
272  if (this->rtxi_widgets_registry[library].empty()) {
273  this->m_plugin_loader->unload(library.c_str());
274  this->unregisterFactories(library);
275  }
276 }
277 
278 void Workspace::Manager::registerDriver(const std::string& driver_location)
279 {
280  auto iter = std::find_if(m_driver_registry.begin(),
281  m_driver_registry.end(),
282  [&](const driver_registry_entry& entry)
283  { return entry.first == driver_location; });
284  if (iter != this->m_driver_registry.end()) {
285  return;
286  }
287  if (this->m_driver_loader->load(driver_location.c_str()) < 0) {
288  return;
289  }
290  auto getDriver = this->m_driver_loader->dlsym<DAQ::Driver* (*)()>(
291  driver_location.c_str(), "getRTXIDAQDriver");
292  if (getDriver == nullptr) {
293  ERROR_MSG(
294  "Workspace::Manager::registerDriver : Unable to load dynamic library "
295  "file {}",
296  driver_location);
297  return;
298  }
299  DAQ::Driver* driver = getDriver();
300  if (driver == nullptr) {
301  ERROR_MSG(
302  "Workspace::Manager::registerDriver : Unable to load driver from "
303  "library {}",
304  driver_location);
305  return;
306  }
307  this->m_driver_registry.emplace_back(driver_location, driver);
308  std::vector<Event::Object> plug_device_events;
309  for (auto* device : driver->getDevices()) {
310  plug_device_events.emplace_back(Event::Type::RT_DEVICE_INSERT_EVENT);
311  plug_device_events.back().setParam(
312  "device", std::any(static_cast<RT::Device*>(device)));
313  }
314  this->event_manager->postEvent(plug_device_events);
315 }
316 
317 void Workspace::Manager::unregisterDriver(const std::string& driver_location)
318 {
319  auto iter = std::find_if(m_driver_registry.begin(),
320  m_driver_registry.end(),
321  [&](const driver_registry_entry& entry)
322  { return entry.first == driver_location; });
323 
324  if (iter == this->m_driver_registry.end()) {
325  return;
326  }
327  std::vector<Event::Object> unplug_device_events;
328  for (auto* device : iter->second->getDevices()) {
329  unplug_device_events.emplace_back(Event::Type::RT_DEVICE_REMOVE_EVENT);
330  unplug_device_events.back().setParam(
331  "device", std::any(static_cast<RT::Device*>(device)));
332  }
333  this->event_manager->postEvent(unplug_device_events);
334  this->m_driver_registry.erase(iter);
335  this->m_driver_loader->unload(driver_location.c_str());
336 }
337 
338 Widgets::Plugin* Workspace::Manager::registerWidget(
339  std::unique_ptr<Widgets::Plugin> widget)
340 {
341  const std::unique_lock<std::mutex> lk(this->m_widgets_mut);
342  const std::string mod_name = widget->getName();
343  this->rtxi_widgets_registry[mod_name].push_back(std::move(widget));
344  return this->rtxi_widgets_registry[mod_name].back().get();
345 }
346 
347 void Workspace::Manager::unregisterWidget(Widgets::Plugin* plugin)
348 {
349  if (plugin == nullptr) {
350  return;
351  }
352  const std::unique_lock<std::mutex> lk(this->m_widgets_mut);
353  const std::string plugin_name = plugin->getName();
354  auto start_iter = this->rtxi_widgets_registry[plugin_name].begin();
355  auto end_iter = this->rtxi_widgets_registry[plugin_name].end();
356  auto loc =
357  std::find_if(start_iter,
358  end_iter,
359  [plugin](const std::unique_ptr<Widgets::Plugin>& widget)
360  { return plugin == widget.get(); });
361  if (loc == end_iter) {
362  return;
363  }
364  // this->m_plugin_loader->unload(plugin->getLibrary().c_str());
365  this->rtxi_widgets_registry[plugin_name].erase(loc);
366 }
367 
368 void Workspace::Manager::registerFactories(const std::string& widget_name,
370 {
371  this->rtxi_factories_registry[widget_name] = fact;
372 }
373 
374 void Workspace::Manager::unregisterFactories(const std::string& widget_name)
375 {
376  if (this->rtxi_factories_registry.find(widget_name)
377  != this->rtxi_factories_registry.end())
378  {
379  this->rtxi_factories_registry.erase(widget_name);
380  }
381 }
382 
384 {
385  std::string plugin_name;
386  Widgets::Plugin* plugin_ptr = nullptr;
387  switch (event->getType()) {
389  plugin_ptr =
390  std::any_cast<Widgets::Plugin*>(event->getParam("pluginPointer"));
391  this->unloadPlugin(plugin_ptr);
392  break;
394  plugin_name = std::any_cast<std::string>(event->getParam("pluginName"));
395  plugin_ptr = this->loadPlugin(plugin_name);
396  if (plugin_ptr != nullptr) {
397  event->setParam("status", std::any(std::string("success")));
398  event->setParam(
399  "createRTXIPanel",
400  std::any(this->rtxi_factories_registry[plugin_name].createPanel));
401  event->setParam("pluginPointer", std::any(plugin_ptr));
402  } else {
403  event->setParam("status", std::any(std::string("failure")));
404  }
405  break;
407  event->setParam("devices", std::any(this->getAllDevices()));
408  break;
409  default:
410  return;
411  }
412 }
virtual std::vector< DAQ::Device * > getDevices()=0
void registerHandler(Handler *handler)
Definition: event.cpp:336
Event::Type getType() const
Definition: event.cpp:228
std::any getParam(const std::string &param_name) const
Definition: event.cpp:170
std::string getName() const
Definition: widgets.hpp:586
void attachComponent(std::unique_ptr< Widgets::Component > component)
Definition: widgets.cpp:504
void saveSettings(const QString &profile_name)
Definition: workspace.cpp:144
void loadSettings(const QString &profile_name)
Definition: workspace.cpp:180
void receiveEvent(Event::Object *event) override
Definition: workspace.cpp:383
~Manager() override
Definition: workspace.cpp:67
bool isRegistered(const Widgets::Plugin *plugin)
Definition: workspace.cpp:92
Widgets::Plugin * loadPlugin(const std::string &library)
Definition: workspace.cpp:201
std::vector< DAQ::Device * > getAllDevices()
Definition: workspace.cpp:125
Manager(const Manager &)=delete
std::vector< DAQ::Device * > getDevices(const std::string &driver)
Definition: workspace.cpp:112
void unloadPlugin(Widgets::Plugin *plugin)
Definition: workspace.cpp:268
void ERROR_MSG(const std::string &errmsg, Args... args)
Definition: debug.hpp:36
constexpr std::string_view MODULE_NAME
Definition: connector.hpp:35
Widgets::FactoryMethods getFactories()
Definition: connector.cpp:491
constexpr std::string_view MODULE_NAME
Widgets::FactoryMethods getFactories()
@ PLUGIN_INSERT_EVENT
Definition: event.hpp:77
@ DAQ_DEVICE_QUERY_EVENT
Definition: event.hpp:79
@ PLUGIN_REMOVE_EVENT
Definition: event.hpp:78
@ RT_DEVICE_INSERT_EVENT
Definition: event.hpp:64
@ RT_DEVICE_REMOVE_EVENT
Definition: event.hpp:65
constexpr std::string_view MODULE_NAME
Widgets::FactoryMethods getFactories()
Widgets::FactoryMethods getFactories()
constexpr std::string_view MODULE_NAME
state_t
Definition: rt.hpp:53
Widgets::FactoryMethods getFactories()
constexpr std::string_view MODULE_NAME
Definition: rtxi_wizard.hpp:35
constexpr std::string_view MODULE_NAME
Widgets::FactoryMethods getFactories()
Widgets::FactoryMethods getFactories()
Definition: userprefs.cpp:204
constexpr std::string_view MODULE_NAME
Definition: userprefs.hpp:31
std::optional< Widgets::FactoryMethods > get_core_plugin_factory(const std::string &plugin_name)
Definition: workspace.cpp:29
std::unique_ptr< Widgets::Plugin >(* createPlugin)(Event::Manager *)
Function that returns a smart pointer to plugin object.
Definition: widgets.hpp:145
std::unique_ptr< Widgets::Component >(* createComponent)(Widgets::Plugin *)
Definition: widgets.hpp:156
overload(Ts...) -> overload< Ts... >