swift
plugin.cpp
1 // SPDX-FileCopyrightText: Copyright (C) 2013 swift Project Community / Contributors
2 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
3 
4 #include "plugin.h"
5 
6 #include <cmath>
7 #include <functional>
8 #include <thread>
9 
10 #include "XPLM/XPLMProcessing.h"
11 #include "service.h"
12 #include "traffic.h"
13 #include "utils.h"
14 
15 namespace
16 {
17  inline std::string xswiftbusServiceName() { return std::string("org.swift-project.xswiftbus"); }
18 } // namespace
19 
20 namespace XSwiftBus
21 {
23  : m_dbusConnection(std::make_shared<CDBusConnection>()), m_menu(CMenu::mainMenu().subMenu("xswiftbus"))
24  {
25  m_showHideLabelsMenuItem = m_menu.item("Show/Hide Aircraft Labels",
26  [this] { m_traffic->setDrawingLabels(!m_traffic->isDrawingLabels()); });
27  m_enableDisableXPlaneAtisMenuItem =
28  m_menu.item("Enable/Disable X-Plane ATIS", [this] { m_atisEnabled.set(m_atisEnabled.get() ? 0 : 1); });
29  m_messageWindowSubMenu = m_menu.subMenu("Message Window");
30  m_toggleMessageWindowMenuItem =
31  m_messageWindowSubMenu.item("Show/Hide", [this] { m_service->toggleMessageBoxVisibility(); });
32  m_popupMessageWindowMenuItem =
33  m_messageWindowSubMenu.checkableItem("Pop up Window on new Message", true, [this](bool checked) {
34  m_popupMessageWindowMenuItem.setChecked(!checked);
35  m_service->setPopupMessageWindow(!checked);
36  });
37  m_disappearMessageWindowMenuItem =
38  m_messageWindowSubMenu.checkableItem("Hide Message Window automatically", true, [this](bool checked) {
39  m_disappearMessageWindowMenuItem.setChecked(!checked);
40  m_service->setDisappearMessageWindow(!checked);
41  });
42  m_planeViewSubMenu = m_menu.subMenu("Follow Plane View");
43  m_planeViewOwnAircraftMenuItem = m_planeViewSubMenu.item(
44  "Own Aircraft", [this] { m_traffic->setFollowedAircraft(CTraffic::ownAircraftString()); });
45 
46  /*m_dbusThread = std::thread([this]()
47  {
48  while(!m_shouldStop)
49  {
50  m_dbusConnection->runBlockingEventLoop();
51  }
52  });*/
53 
54  // Delay the start of xswiftbus.
55  // http://www.xsquawkbox.net/xpsdk/mediawiki/DeferredInitialization
56  XPLMRegisterFlightLoopCallback(startServerDeferred, -1, this);
57 
58  m_atisSaved = m_atisEnabled.get();
59  m_atisEnabled.set(0);
60  }
61 
63  {
64  m_atisEnabled.set(m_atisSaved);
65 
66  XPLMUnregisterFlightLoopCallback(flightLoopCallback, this);
67  m_dbusConnection->close();
68  m_shouldStop = true;
69  if (m_dbusThread.joinable()) { m_dbusThread.join(); }
70  }
71 
72  void CPlugin::readConfig()
73  {
75  const std::string configFilePath =
76  g_xplanePath + "Resources" + g_sep + "plugins" + g_sep + "xswiftbus" + g_sep + "xswiftbus.conf";
77  m_pluginConfig.setFilePath(configFilePath);
78  m_pluginConfig.parse();
79  m_pluginConfig.print();
80  }
81 
82  void CPlugin::startServer()
83  {
84  XPLMRegisterFlightLoopCallback(flightLoopCallback, -1, this);
85 
86  readConfig();
87 
88  m_service = std::make_unique<CService>(this);
89  m_traffic = std::make_unique<CTraffic>(this);
90 
91  m_traffic->setPlaneViewMenu(m_planeViewSubMenu);
92 
93  if (m_pluginConfig.getDBusMode() == CConfig::DBusP2P)
94  {
95  m_dbusP2PServer = std::make_unique<CDBusServer>();
96 
97  // FIXME: make listen address configurable
98  std::string listenAddress =
99  "tcp:host=" + m_pluginConfig.getDBusAddress() + ",port=" + std::to_string(m_pluginConfig.getDBusPort());
100  if (!m_dbusP2PServer->listen(listenAddress))
101  {
102  m_service->addTextMessage("xswiftbus startup failed!", 255, 0, 0);
103  return;
104  }
105  m_dbusP2PServer->setDispatcher(&m_dbusDispatcher);
106 
107  m_dbusP2PServer->setNewConnectionFunc([this](const std::shared_ptr<CDBusConnection> &conn) {
108  m_dbusConnection = conn;
109  m_dbusConnection->setDispatcher(&m_dbusDispatcher);
110  m_service->setDBusConnection(m_dbusConnection);
111  m_service->registerDBusObjectPath(m_service->InterfaceName(), m_service->ObjectPath());
112  m_traffic->setDBusConnection(m_dbusConnection);
113  m_traffic->registerDBusObjectPath(m_traffic->InterfaceName(), m_traffic->ObjectPath());
114  });
115  }
116  else
117  {
118  // Todo: retry if it fails
119  bool success = m_dbusConnection->connect(CDBusConnection::SessionBus);
120 
121  if (!success)
122  {
123  // Print error
124  return;
125  }
126 
127  m_dbusConnection->setDispatcher(&m_dbusDispatcher);
128  m_dbusConnection->requestName(xswiftbusServiceName());
129 
130  m_service->setDBusConnection(m_dbusConnection);
131  m_service->registerDBusObjectPath(m_service->InterfaceName(), m_service->ObjectPath());
132  m_traffic->setDBusConnection(m_dbusConnection);
133  m_traffic->registerDBusObjectPath(m_traffic->InterfaceName(), m_traffic->ObjectPath());
134  }
135 
137  const std::string msg = "xswiftbus " + m_service->getVersionNumber() + " started.";
138  INFO_LOG(msg);
139  m_service->addTextMessage(msg, 0, 255, 255);
140  }
141 
143  {
144  if (m_service)
145  {
146  m_service->onAircraftModelChanged();
147  m_service->resetFrameTotals();
148  }
149  }
150 
152  {
153  if (m_service) { m_service->resetFrameTotals(); }
154  }
155 
157  {
158  if (m_service) { m_service->onSceneryLoaded(); }
159  }
160 
161  float CPlugin::startServerDeferred(float, float, int, void *refcon)
162  {
163  auto *plugin = static_cast<CPlugin *>(refcon);
164  if (!plugin->m_isRunning)
165  {
166  plugin->startServer();
167  plugin->m_isRunning = true;
168  INFO_LOG("xswiftbus plugin started (deferred)");
169  }
170  return 0;
171  }
172 
173  float CPlugin::flightLoopCallback(float, float, int, void *refcon)
174  {
175  auto *plugin = static_cast<CPlugin *>(refcon);
176 
177  plugin->m_dbusDispatcher.runOnce();
178  if (plugin->m_service) { plugin->m_service->process(); }
179  if (plugin->m_traffic) { plugin->m_traffic->process(); }
180  return -1;
181  }
182 } // namespace XSwiftBus
int getDBusPort() const
Get current DBus server port.
Definition: config.h:46
void setFilePath(const std::string &filePath)
Set config file path.
Definition: config.h:31
void print()
Print the current configuration to the X-Plane log.
Definition: config.cpp:72
DBusMode getDBusMode() const
Get current DBus mode.
Definition: config.h:40
void parse()
Load and parse config file.
Definition: config.cpp:25
std::string getDBusAddress() const
Get current DBus server address.
Definition: config.h:43
Class-based interface to X-Plane SDK menus.
Definition: menus.h:63
CMenuItem item(const std::string &name, std::function< void()> callback)
Appends an item to the menu and returns it.
CMenuItem checkableItem(const std::string &name, bool checked, std::function< void(bool)> callback)
Appends a checkbox item to the menu and returns it.
CMenu subMenu(const std::string &name)
Appends an item to the menu which opens a sub-menu, and returns it.
void setChecked(bool checked)
Sets the checked status of the menu item.
Main plugin class.
Definition: plugin.h:42
CPlugin()
Constructor.
Definition: plugin.cpp:22
void onSceneryLoaded()
Called by XPluginReceiveMessage when some scenery is loaded.
Definition: plugin.cpp:156
void onAircraftRepositioned()
Called by XPluginReceiveMessage when the aircraft is positioned at an airport.
Definition: plugin.cpp:151
void onAircraftModelChanged()
Called by XPluginReceiveMessage when the model is changed.
Definition: plugin.cpp:142
~CPlugin()
Destructor.
Definition: plugin.cpp:62
static const std::string & ownAircraftString()
Returns the own aircraft string to be used as callsign for setFollowedAircraft()
Definition: traffic.h:135
void set(DataRefType d)
Set the value of the dataref (if it is writable)
Definition: datarefs.h:104
DataRefType get() const
Get the value of the dataref.
Definition: datarefs.h:117
Plugin loaded by X-Plane which publishes a DBus service.
Definition: command.h:14
std::string g_xplanePath
Absolute xplane path.
std::string g_sep
Platform specific dir separator.
void initXPlanePath()
Init global xplane path.
#define INFO_LOG(msg)
Logger convenience macros.
Definition: utils.h:50