swift
service.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 "service.h"
5 
6 #include <XPLM/XPLMPlanes.h>
7 #include <XPLM/XPLMUtilities.h>
8 
9 #include <algorithm>
10 #include <cmath>
11 #include <cstring>
12 
13 #include "plugin.h"
14 #include "utils.h"
15 
17 
18 // clazy:excludeall=reserve-candidates
19 
20 using namespace swift::misc::simulation::xplane::qtfreeutils;
21 
22 namespace XSwiftBus
23 {
25  struct CService::FramePeriodSampler : public CDrawable
26  {
27  DataRef<xplane::data::sim::operation::misc::frame_rate_period> m_thisFramePeriod;
28  DataRef<xplane::data::sim::time::framerate_period> m_thisFramePeriodXP11;
29  DataRef<xplane::data::sim::time::total_flight_time_sec> m_secondsSinceReset;
30  DataRef<xplane::data::sim::flightmodel::position::groundspeed> m_groundSpeed;
31 
32  std::vector<float> m_samples;
33  float m_total = 0;
34  float m_totalOverBudget = 0;
35  float m_totalMetersShort = 0;
36  float m_totalSecondsLate = 0;
37  size_t m_lastSampleIndex = 0;
38  static constexpr size_t c_maxSampleCount = 500;
39  static constexpr float c_framePeriodBudget = 0.05f;
40 
41  FramePeriodSampler() : CDrawable(xplm_Phase_Window, true) {}
42 
43  std::tuple<float, float, float, float> getFrameStats()
44  {
45  if (m_total < 0.001f) { return {}; } // no DIV by 0
46  const float fps = m_samples.size() / m_total;
47  const float ratio = 1 - m_totalOverBudget / m_total;
48  const float miles = m_totalMetersShort / 1852.0f;
49  const float minutes = m_totalSecondsLate / 60.0f;
50  m_total = 0;
51  m_totalOverBudget = 0;
52  m_samples.clear();
53  m_lastSampleIndex = 0;
54  return std::make_tuple(fps, ratio, miles, minutes);
55  }
56 
57  protected:
58  virtual void draw() override // called once per frame
59  {
60  const float current =
61  m_thisFramePeriodXP11.isValid() ? m_thisFramePeriodXP11.get() : m_thisFramePeriod.get();
62 
63  ++m_lastSampleIndex %= c_maxSampleCount;
64  if (m_samples.size() == c_maxSampleCount)
65  {
66  auto &oldSample = m_samples[m_lastSampleIndex];
67  m_total -= oldSample;
68  if (oldSample > c_framePeriodBudget) { m_totalOverBudget -= oldSample - c_framePeriodBudget; }
69  oldSample = current;
70  }
71  else { m_samples.push_back(current); }
72 
73  m_total += current;
74  if (current > c_framePeriodBudget)
75  {
76  m_totalOverBudget += current - c_framePeriodBudget;
77 
78  if (m_secondsSinceReset.get() > 10)
79  {
80  const float metersShort = m_groundSpeed.get() * std::max(0.0f, current - c_framePeriodBudget);
81  m_totalMetersShort += metersShort;
82  if (m_groundSpeed.get() > 1.0f)
83  {
84  m_totalSecondsLate += std::max(0.0f, current - c_framePeriodBudget);
85  }
86  }
87  }
88  }
89  };
90 
91  CService::CService(CSettingsProvider *settingsProvider)
92  : CDBusObject(settingsProvider), m_framePeriodSampler(std::make_unique<FramePeriodSampler>())
93  {
94  this->updateMessageBoxFromSettings();
95  m_framePeriodSampler->show();
96  m_swiftNetworkConnected.set(0);
97  m_swiftCallsign.set("");
98  }
99 
100  // Explicitly in cpp file to allow use of forward declaration
101  CService::~CService() = default;
102 
104  {
105  char filename[256];
106  char path[512];
107  XPLMGetNthAircraftModel(XPLM_USER_AIRCRAFT, filename, path);
108  if (std::strlen(filename) < 1 || std::strlen(path) < 1)
109  {
110  WARNING_LOG("Aircraft changed, but NO path or file name");
111  return;
112  }
113  const AcfProperties acfProperties = extractAcfProperties(path);
114  emitAircraftModelChanged(path, filename, getAircraftLivery(), getAircraftIcaoCode(), acfProperties.modelString,
115  acfProperties.modelName, getAircraftDescription());
116  }
117 
118  void CService::onSceneryLoaded() { emitSceneryLoaded(); }
119 
120  std::string CService::getVersionNumber() const { return XSWIFTBUS_VERSION; }
121 
122  std::string CService::getCommitHash() const { return XSWIFTBUS_COMMIT; }
123 
124  std::tuple<double, double, double, double> CService::getFrameStats()
125  {
126  if (!m_framePeriodSampler) { return {}; }
127  const auto result = m_framePeriodSampler->getFrameStats();
128  return std::make_tuple(static_cast<double>(std::get<0>(result)), static_cast<double>(std::get<1>(result)),
129  static_cast<double>(std::get<2>(result)), static_cast<double>(std::get<3>(result)));
130  }
131 
133  {
134  if (m_framePeriodSampler)
135  {
136  m_framePeriodSampler->m_totalMetersShort = 0;
137  m_framePeriodSampler->m_totalSecondsLate = 0;
138  }
139  }
140 
141  void CService::setFlightNetworkConnected(bool connected) { m_swiftNetworkConnected.set(connected); }
142 
143  void CService::setOwnCallsign(const std::string &callsign) { m_swiftCallsign.set(callsign); }
144 
145  void CService::addTextMessage(const std::string &text, double red, double green, double blue)
146  {
147  if (text.empty()) { return; }
148  static const CMessage::string ellipsis = u8"\u2026";
149  const unsigned lineLength = m_messages.maxLineLength() - 1;
150 
152  U8It begin(text.begin(), text.end());
153  auto characters = std::distance(begin, U8It(text.end(), text.end()));
154  std::vector<CMessage::string> wrappedLines;
155 
156  for (; characters > lineLength; characters -= lineLength)
157  {
158  auto end = std::next(begin, lineLength);
159  wrappedLines.emplace_back(begin.base, end.base);
160  wrappedLines.back() += ellipsis;
161  begin = end;
162  }
163  if (characters > 0) { wrappedLines.emplace_back(begin.base, text.end()); }
164  for (const auto &line : wrappedLines)
165  {
166  m_messages.addMessage(
167  { line, static_cast<float>(red), static_cast<float>(green), static_cast<float>(blue) });
168  }
169 
170  if (!m_messages.isVisible() && m_popupMessageWindow) { m_messages.toggle(); }
171 
172  if (m_disappearMessageWindow)
173  {
174  m_disappearMessageWindowTime = std::chrono::system_clock::now() +
175  std::chrono::milliseconds(std::max(m_disapperMessageWindowTimeMs, 1500));
176  }
177  }
178 
179  std::string CService::getAircraftModelPath() const
180  {
181  char filename[256];
182  char path[512];
183  XPLMGetNthAircraftModel(XPLM_USER_AIRCRAFT, filename, path);
184  return path;
185  }
186 
188  {
189  char filename[256];
190  char path[512];
191  XPLMGetNthAircraftModel(XPLM_USER_AIRCRAFT, filename, path);
192  return filename;
193  }
194 
196  {
197  char filename[256];
198  char path[512];
199  XPLMGetNthAircraftModel(XPLM_USER_AIRCRAFT, filename, path);
200  const AcfProperties acfProperties = extractAcfProperties(path);
201  return acfProperties.modelString;
202  }
203 
204  std::string CService::getAircraftName() const
205  {
206  char filename[256];
207  char path[512];
208  XPLMGetNthAircraftModel(XPLM_USER_AIRCRAFT, filename, path);
209  const AcfProperties acfProperties = extractAcfProperties(path);
210  return acfProperties.modelName;
211  }
212 
213  std::string CService::getAircraftLivery() const
214  {
215  std::string liveryPath = m_liveryPath.get();
216  if (liveryPath.empty()) { return {}; }
217 
218  // liveryPath end with / and we need to get rid of it
219  liveryPath.pop_back();
220  return getFileName(liveryPath);
221  }
222 
224  {
225  int version;
226  XPLMGetVersions(&version, nullptr, nullptr);
227  if (version > 5000) { version /= 10; }
228  return version / 100;
229  }
230 
232  {
233  int version;
234  XPLMGetVersions(&version, nullptr, nullptr);
235  if (version > 5000) { version /= 10; }
236  return version % 100;
237  }
238 
240  {
241  char path[512];
242  XPLMGetSystemPath(path);
243  return path;
244  }
245 
247  {
248  char path[512];
249  XPLMGetPrefsPath(path);
250  return path;
251  }
252 
253  void CService::setDisappearMessageWindowTimeMs(int durationMs) { m_disapperMessageWindowTimeMs = durationMs; }
254 
255  std::string CService::getSettingsJson() const { return this->getSettings().toXSwiftBusJsonString(); }
256 
257  void CService::setSettingsJson(const std::string &jsonString)
258  {
259  CSettings s;
260  s.parseXSwiftBusString(jsonString);
261  this->setSettings(s);
262  const bool w = this->writeConfig(s.isTcasEnabled(), s.isLogRenderPhases());
263  this->updateMessageBoxFromSettings();
264  INFO_LOG("Received settings " + s.convertToString());
265  if (w) { INFO_LOG("Written new config file"); }
266  }
267 
268  static const char *introspection_service = DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
269 #include "org.swift_project.xswiftbus.service.xml"
270 
271  ;
272 
273  DBusHandlerResult CService::dbusMessageHandler(const CDBusMessage &message_)
274  {
275  CDBusMessage message(message_);
276  const std::string sender = message.getSender();
277  const dbus_uint32_t serial = message.getSerial();
278  const bool wantsReply = message.wantsReply();
279 
280  if (message.getInterfaceName() == DBUS_INTERFACE_INTROSPECTABLE)
281  {
282  if (message.getMethodName() == "Introspect") { sendDBusReply(sender, serial, introspection_service); }
283  }
284  else if (message.getInterfaceName() == XSWIFTBUS_SERVICE_INTERFACENAME)
285  {
286  if (message.getMethodName() == "getVersionNumber")
287  {
288  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getVersionNumber()); });
289  }
290  else if (message.getMethodName() == "getCommitHash")
291  {
292  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getCommitHash()); });
293  }
294  else if (message.getMethodName() == "addTextMessage")
295  {
296  maybeSendEmptyDBusReply(wantsReply, sender, serial);
297  std::string text;
298  double red = 0;
299  double green = 0;
300  double blue = 0;
301  message.beginArgumentRead();
302  message.getArgument(text);
303  message.getArgument(red);
304  message.getArgument(green);
305  message.getArgument(blue);
306 
307  queueDBusCall([=, this]() { addTextMessage(text, red, green, blue); });
308  }
309  else if (message.getMethodName() == "getOwnAircraftSituationData")
310  {
311  queueDBusCall([=, this]() {
312  const double lat = m_latitude.get();
313  const double lon = m_longitude.get();
314  const double alt = m_elevation.get();
315  const double gs = m_groundSpeed.get();
316  const double pitch = m_pitch.get();
317  const double roll = m_roll.get();
318  const double trueHeading = m_heading.get();
319  const double qnh = m_qnhInhg.get();
320  CDBusMessage reply = CDBusMessage::createReply(sender, serial);
321  reply.beginArgumentWrite();
322  reply.appendArgument(lat);
323  reply.appendArgument(lon);
324  reply.appendArgument(alt);
325  reply.appendArgument(gs);
326  reply.appendArgument(pitch);
327  reply.appendArgument(roll);
328  reply.appendArgument(trueHeading);
329  reply.appendArgument(qnh);
330  sendDBusMessage(reply);
331  });
332  }
333  else if (message.getMethodName() == "getOwnAircraftVelocityData")
334  {
335  queueDBusCall([=, this]() {
336  const double velocityX = m_velocityX.get();
337  const double velocityY = m_velocityY.get();
338  const double velocityZ = m_velocityZ.get();
339  const double pitchVelocity = m_pitchVelocity.get();
340  const double rollVelocity = m_rollVelocity.get();
341  const double headingVelocity = m_headingVelocity.get();
342  CDBusMessage reply = CDBusMessage::createReply(sender, serial);
343  reply.beginArgumentWrite();
344  reply.appendArgument(velocityX);
345  reply.appendArgument(velocityY);
346  reply.appendArgument(velocityZ);
347  reply.appendArgument(pitchVelocity);
348  reply.appendArgument(rollVelocity);
349  reply.appendArgument(headingVelocity);
350  sendDBusMessage(reply);
351  });
352  }
353  else if (message.getMethodName() == "getOwnAircraftCom1Data")
354  {
355  queueDBusCall([=, this]() {
356  const int active = m_com1Active.get();
357  const int standby = m_com1Standby.get();
358  const double volume = m_com1Volume.get();
359  const bool rec = this->isCom1Receiving();
360  const bool tx = this->isCom1Transmitting();
361  CDBusMessage reply = CDBusMessage::createReply(sender, serial);
362  reply.beginArgumentWrite();
363  reply.appendArgument(active);
364  reply.appendArgument(standby);
365  reply.appendArgument(volume);
366  reply.appendArgument(rec);
367  reply.appendArgument(tx);
368  sendDBusMessage(reply);
369  });
370  }
371  else if (message.getMethodName() == "getOwnAircraftCom2Data")
372  {
373  queueDBusCall([=, this]() {
374  const int active = m_com2Active.get();
375  const int standby = m_com2Standby.get();
376  const double volume = m_com2Volume.get();
377  const bool rec = this->isCom2Receiving();
378  const bool tx = this->isCom2Transmitting();
379  CDBusMessage reply = CDBusMessage::createReply(sender, serial);
380  reply.beginArgumentWrite();
381  reply.appendArgument(active);
382  reply.appendArgument(standby);
383  reply.appendArgument(volume);
384  reply.appendArgument(rec);
385  reply.appendArgument(tx);
386  sendDBusMessage(reply);
387  });
388  }
389  else if (message.getMethodName() == "getOwnAircraftXpdr")
390  {
391  queueDBusCall([=, this]() {
392  const int code = m_xpdrCode.get();
393  const int mode = m_xpdrMode.get();
394  const bool id = m_xpdrIdent.get();
395  CDBusMessage reply = CDBusMessage::createReply(sender, serial);
396  reply.beginArgumentWrite();
397  reply.appendArgument(code);
398  reply.appendArgument(mode);
399  reply.appendArgument(id);
400  sendDBusMessage(reply);
401  });
402  }
403  else if (message.getMethodName() == "getOwnAircraftLights")
404  {
405  queueDBusCall([=, this]() {
406  const bool beaconLightsOn = m_beaconLightsOn.get();
407  const bool landingLightsOn = m_landingLightsOn.get();
408  const bool navLightsOn = m_navLightsOn.get();
409  const bool strobeLightsOn = m_strobeLightsOn.get();
410  const bool taxiLightsOn = m_taxiLightsOn.get();
411  CDBusMessage reply = CDBusMessage::createReply(sender, serial);
412  reply.beginArgumentWrite();
413  reply.appendArgument(beaconLightsOn);
414  reply.appendArgument(landingLightsOn);
415  reply.appendArgument(navLightsOn);
416  reply.appendArgument(strobeLightsOn);
417  reply.appendArgument(taxiLightsOn);
418  sendDBusMessage(reply);
419  });
420  }
421  else if (message.getMethodName() == "getOwnAircraftParts")
422  {
423  queueDBusCall([=, this]() {
424  const double flapsReployRatio = m_flapsReployRatio.get();
425  const double gearReployRatio = m_gearReployRatio.getAt(0);
426  const double speedBrakeRatio = m_speedBrakeRatio.get();
427  const std::vector<double> enginesN1Percentage = this->getEngineN1Percentage();
428  CDBusMessage reply = CDBusMessage::createReply(sender, serial);
429  reply.beginArgumentWrite();
430  reply.appendArgument(flapsReployRatio);
431  reply.appendArgument(gearReployRatio);
432  reply.appendArgument(speedBrakeRatio);
433  reply.appendArgument(enginesN1Percentage);
434  sendDBusMessage(reply);
435  });
436  }
437  else if (message.getMethodName() == "getOwnAircraftModelData")
438  {
439  queueDBusCall([=, this]() {
440  const std::string aircraftModelPath = this->getAircraftModelPath();
441  const std::string aircraftIcaoCode = this->getAircraftIcaoCode();
442  CDBusMessage reply = CDBusMessage::createReply(sender, serial);
443  reply.beginArgumentWrite();
444  reply.appendArgument(aircraftModelPath);
445  reply.appendArgument(aircraftIcaoCode);
446  sendDBusMessage(reply);
447  });
448  }
449  else if (message.getMethodName() == "getAircraftModelPath")
450  {
451  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getAircraftModelPath()); });
452  }
453  else if (message.getMethodName() == "getAircraftModelFilename")
454  {
455  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getAircraftModelFilename()); });
456  }
457  else if (message.getMethodName() == "getAircraftModelString")
458  {
459  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getAircraftModelString()); });
460  }
461  else if (message.getMethodName() == "getAircraftName")
462  {
463  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getAircraftName()); });
464  }
465  else if (message.getMethodName() == "getAircraftLivery")
466  {
467  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getAircraftLivery()); });
468  }
469  else if (message.getMethodName() == "getAircraftIcaoCode")
470  {
471  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getAircraftIcaoCode()); });
472  }
473  else if (message.getMethodName() == "getAircraftDescription")
474  {
475  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getAircraftDescription()); });
476  }
477  else if (message.getMethodName() == "getXPlaneVersionMajor")
478  {
479  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getXPlaneVersionMajor()); });
480  }
481  else if (message.getMethodName() == "getXPlaneVersionMinor")
482  {
483  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getXPlaneVersionMinor()); });
484  }
485  else if (message.getMethodName() == "getXPlaneInstallationPath")
486  {
487  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getXPlaneInstallationPath()); });
488  }
489  else if (message.getMethodName() == "getXPlanePreferencesPath")
490  {
491  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getXPlanePreferencesPath()); });
492  }
493  else if (message.getMethodName() == "isPaused")
494  {
495  queueDBusCall([=, this]() { sendDBusReply(sender, serial, isPaused()); });
496  }
497  else if (message.getMethodName() == "isUsingRealTime")
498  {
499  queueDBusCall([=, this]() { sendDBusReply(sender, serial, isUsingRealTime()); });
500  }
501  else if (message.getMethodName() == "getFrameStats")
502  {
503  queueDBusCall([=, this]() {
504  const auto stats = getFrameStats();
505  CDBusMessage reply = CDBusMessage::createReply(sender, serial);
506  reply.beginArgumentWrite();
507  reply.appendArgument(std::get<0>(stats));
508  reply.appendArgument(std::get<1>(stats));
509  reply.appendArgument(std::get<2>(stats));
510  reply.appendArgument(std::get<3>(stats));
511  sendDBusMessage(reply);
512  });
513  }
514  else if (message.getMethodName() == "resetFrameTotals")
515  {
516  maybeSendEmptyDBusReply(wantsReply, sender, serial);
517  queueDBusCall([=, this]() { resetFrameTotals(); });
518  }
519  else if (message.getMethodName() == "setFlightNetworkConnected")
520  {
521  maybeSendEmptyDBusReply(wantsReply, sender, serial);
522  bool connected = false;
523  message.beginArgumentRead();
524  message.getArgument(connected);
525  queueDBusCall([=, this]() { setFlightNetworkConnected(connected); });
526  }
527  else if (message.getMethodName() == "setOwnCallsign")
528  {
529  maybeSendEmptyDBusReply(wantsReply, sender, serial);
530  std::string callsign;
531  message.beginArgumentRead();
532  message.getArgument(callsign);
533  queueDBusCall([=, this]() { setOwnCallsign(callsign); });
534  }
535  else if (message.getMethodName() == "getLatitudeDeg")
536  {
537  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getLatitudeDeg()); });
538  }
539  else if (message.getMethodName() == "getLongitudeDeg")
540  {
541  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getLongitudeDeg()); });
542  }
543  else if (message.getMethodName() == "getAltitudeMslM")
544  {
545  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getAltitudeMslM()); });
546  }
547  else if (message.getMethodName() == "getPressureAltitudeFt")
548  {
549  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getPressureAltitudeFt()); });
550  }
551  else if (message.getMethodName() == "getHeightAglM")
552  {
553  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getHeightAglM()); });
554  }
555  else if (message.getMethodName() == "getGroundSpeedMps")
556  {
557  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getGroundSpeedMps()); });
558  }
559  else if (message.getMethodName() == "getIndicatedAirspeedKias")
560  {
561  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getIndicatedAirspeedKias()); });
562  }
563  else if (message.getMethodName() == "getTrueAirspeedKias")
564  {
565  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getTrueAirspeedKias()); });
566  }
567  else if (message.getMethodName() == "getPitchDeg")
568  {
569  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getPitchDeg()); });
570  }
571  else if (message.getMethodName() == "getRollDeg")
572  {
573  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getRollDeg()); });
574  }
575  else if (message.getMethodName() == "getTrueHeadingDeg")
576  {
577  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getTrueHeadingDeg()); });
578  }
579  else if (message.getMethodName() == "getLocalXVelocityXMps")
580  {
581  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getLocalXVelocityMps()); });
582  }
583  else if (message.getMethodName() == "getLocalYVelocityYMps")
584  {
585  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getLocalYVelocityMps()); });
586  }
587  else if (message.getMethodName() == "getLocalZVelocityZMps")
588  {
589  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getLocalZVelocityMps()); });
590  }
591  else if (message.getMethodName() == "getPitchRadPerSec")
592  {
593  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getPitchRadPerSec()); });
594  }
595  else if (message.getMethodName() == "getRollRadPerSec")
596  {
597  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getRollRadPerSec()); });
598  }
599  else if (message.getMethodName() == "getHeadingRadPerSec")
600  {
601  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getHeadingRadPerSec()); });
602  }
603  else if (message.getMethodName() == "getAnyWheelOnGround")
604  {
605  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getAnyWheelOnGround()); });
606  }
607  else if (message.getMethodName() == "getAllWheelsOnGround")
608  {
609  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getAllWheelsOnGround()); });
610  }
611  else if (message.getMethodName() == "getGroundElevation")
612  {
613  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getGroundElevation()); });
614  }
615  else if (message.getMethodName() == "getCom1ActiveKhz")
616  {
617  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getCom1ActiveKhz()); });
618  }
619  else if (message.getMethodName() == "getCom1StandbyKhz")
620  {
621  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getCom1StandbyKhz()); });
622  }
623  else if (message.getMethodName() == "getCom2ActiveKhz")
624  {
625  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getCom2ActiveKhz()); });
626  }
627  else if (message.getMethodName() == "getCom2StandbyKhz")
628  {
629  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getCom2StandbyKhz()); });
630  }
631  else if (message.getMethodName() == "isCom1Receiving")
632  {
633  queueDBusCall([=, this]() { sendDBusReply(sender, serial, isCom1Receiving()); });
634  }
635  else if (message.getMethodName() == "isCom1Transmitting")
636  {
637  queueDBusCall([=, this]() { sendDBusReply(sender, serial, isCom1Transmitting()); });
638  }
639  else if (message.getMethodName() == "getCom1Volume")
640  {
641  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getCom1Volume()); });
642  }
643  else if (message.getMethodName() == "isCom2Receiving")
644  {
645  queueDBusCall([=, this]() { sendDBusReply(sender, serial, isCom2Receiving()); });
646  }
647  else if (message.getMethodName() == "isCom2Transmitting")
648  {
649  queueDBusCall([=, this]() { sendDBusReply(sender, serial, isCom2Transmitting()); });
650  }
651  else if (message.getMethodName() == "getCom2Volume")
652  {
653  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getCom2Volume()); });
654  }
655  else if (message.getMethodName() == "getTransponderCode")
656  {
657  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getTransponderCode()); });
658  }
659  else if (message.getMethodName() == "getTransponderMode")
660  {
661  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getTransponderMode()); });
662  }
663  else if (message.getMethodName() == "getTransponderIdent")
664  {
665  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getTransponderIdent()); });
666  }
667  else if (message.getMethodName() == "getBeaconLightsOn")
668  {
669  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getBeaconLightsOn()); });
670  }
671  else if (message.getMethodName() == "getLandingLightsOn")
672  {
673  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getLandingLightsOn()); });
674  }
675  else if (message.getMethodName() == "getTaxiLightsOn")
676  {
677  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getTaxiLightsOn()); });
678  }
679  else if (message.getMethodName() == "getNavLightsOn")
680  {
681  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getNavLightsOn()); });
682  }
683  else if (message.getMethodName() == "getStrobeLightsOn")
684  {
685  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getStrobeLightsOn()); });
686  }
687  else if (message.getMethodName() == "getQNHInHg")
688  {
689  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getQNHInHg()); });
690  }
691  else if (message.getMethodName() == "setCom1ActiveKhz")
692  {
693  maybeSendEmptyDBusReply(wantsReply, sender, serial);
694  int frequency = 0;
695  message.beginArgumentRead();
696  message.getArgument(frequency);
697  queueDBusCall([=, this]() { setCom1ActiveKhz(frequency); });
698  }
699  else if (message.getMethodName() == "setCom1StandbyKhz")
700  {
701  maybeSendEmptyDBusReply(wantsReply, sender, serial);
702  int frequency = 0;
703  message.beginArgumentRead();
704  message.getArgument(frequency);
705  queueDBusCall([=, this]() { setCom1StandbyKhz(frequency); });
706  }
707  else if (message.getMethodName() == "setCom2ActiveKhz")
708  {
709  maybeSendEmptyDBusReply(wantsReply, sender, serial);
710  int frequency = 0;
711  message.beginArgumentRead();
712  message.getArgument(frequency);
713  queueDBusCall([=, this]() { setCom2ActiveKhz(frequency); });
714  }
715  else if (message.getMethodName() == "setCom2StandbyKhz")
716  {
717  maybeSendEmptyDBusReply(wantsReply, sender, serial);
718  int frequency = 0;
719  message.beginArgumentRead();
720  message.getArgument(frequency);
721  queueDBusCall([=, this]() { setCom2StandbyKhz(frequency); });
722  }
723  else if (message.getMethodName() == "setTransponderCode")
724  {
725  maybeSendEmptyDBusReply(wantsReply, sender, serial);
726  int code = 0;
727  message.beginArgumentRead();
728  message.getArgument(code);
729  queueDBusCall([=, this]() { setTransponderCode(code); });
730  }
731  else if (message.getMethodName() == "setTransponderMode")
732  {
733  maybeSendEmptyDBusReply(wantsReply, sender, serial);
734  int mode = 0;
735  message.beginArgumentRead();
736  message.getArgument(mode);
737  queueDBusCall([=, this]() { setTransponderMode(mode); });
738  }
739  else if (message.getMethodName() == "getFlapsDeployRatio")
740  {
741  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getFlapsDeployRatio()); });
742  }
743  else if (message.getMethodName() == "getGearDeployRatio")
744  {
745  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getGearDeployRatio()); });
746  }
747  else if (message.getMethodName() == "getNumberOfEngines")
748  {
749  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getNumberOfEngines()); });
750  }
751  else if (message.getMethodName() == "getEngineN1Percentage")
752  {
753  queueDBusCall([=, this]() {
754  const std::vector<double> enginesN1Percentage = getEngineN1Percentage();
755  sendDBusReply(sender, serial, enginesN1Percentage);
756  });
757  }
758  else if (message.getMethodName() == "getSpeedBrakeRatio")
759  {
760  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getSpeedBrakeRatio()); });
761  }
762  else if (message.getMethodName() == "getSettingsJson")
763  {
764  queueDBusCall([=, this]() { sendDBusReply(sender, serial, getSettingsJson()); });
765  }
766  else if (message.getMethodName() == "setSettingsJson")
767  {
768  maybeSendEmptyDBusReply(wantsReply, sender, serial);
769  std::string json;
770  message.beginArgumentRead();
771  message.getArgument(json);
772  queueDBusCall([=, this]() { setSettingsJson(json); });
773  }
774  else
775  {
776  // Unknown message. Tell DBus that we cannot handle it
777  return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
778  }
779  }
780  return DBUS_HANDLER_RESULT_HANDLED;
781  }
782 
784  {
785  if (m_sceneryIsLoading.get() != m_sceneryWasLoading)
786  {
787  if (!m_sceneryIsLoading.get()) { onSceneryLoaded(); }
788  m_sceneryWasLoading = m_sceneryIsLoading.get();
789  }
790 
792 
793  if (m_disappearMessageWindowTime != std::chrono::system_clock::time_point() &&
794  std::chrono::system_clock::now() > m_disappearMessageWindowTime && m_messages.isVisible())
795  {
796  m_messages.toggle();
797  m_disappearMessageWindowTime = std::chrono::system_clock::time_point();
798  }
799 
800  return 1;
801  }
802 
803  void CService::emitAircraftModelChanged(const std::string &path, const std::string &filename,
804  const std::string &livery, const std::string &icao,
805  const std::string &modelString, const std::string &name,
806  const std::string &description)
807  {
808  CDBusMessage signalAircraftModelChanged = CDBusMessage::createSignal(
809  XSWIFTBUS_SERVICE_OBJECTPATH, XSWIFTBUS_SERVICE_INTERFACENAME, "aircraftModelChanged");
810  signalAircraftModelChanged.beginArgumentWrite();
811  signalAircraftModelChanged.appendArgument(path);
812  signalAircraftModelChanged.appendArgument(filename);
813  signalAircraftModelChanged.appendArgument(livery);
814  signalAircraftModelChanged.appendArgument(icao);
815  signalAircraftModelChanged.appendArgument(modelString);
816  signalAircraftModelChanged.appendArgument(name);
817  signalAircraftModelChanged.appendArgument(description);
818  sendDBusMessage(signalAircraftModelChanged);
819  }
820 
821  void CService::emitSceneryLoaded()
822  {
823  CDBusMessage signal =
824  CDBusMessage::createSignal(XSWIFTBUS_SERVICE_OBJECTPATH, XSWIFTBUS_SERVICE_INTERFACENAME, "sceneryLoaded");
825  sendDBusMessage(signal);
826  }
827 
828  void CService::updateMessageBoxFromSettings()
829  {
830  // left, top, right, bottom, height size percentage
831  const std::vector<int> values = this->getSettings().getMessageBoxValuesVector();
832  if (values.size() >= 6)
833  {
834  m_messages.setValues(values[0], values[1], values[2], values[3], values[4], values[5]);
835  this->setDisappearMessageWindowTimeMs(values[5]);
836  }
837  }
838 } // namespace XSwiftBus
DataRefType getAt(int index) const
Get the value of a single element.
Definition: datarefs.h:170
bool wantsReply() const
Does this message want a reply?
Definition: dbusmessage.cpp:37
void appendArgument(bool value)
Append argument. Make sure to call.
Definition: dbusmessage.cpp:55
void getArgument(int &value)
Read single argument. Make sure to call.
std::string getSender() const
Get the message sender.
Definition: dbusmessage.cpp:39
std::string_view getMethodName() const
Get the called method name.
Definition: dbusmessage.cpp:51
dbus_uint32_t getSerial() const
Get the message serial. This is usally required for reply message.
Definition: dbusmessage.cpp:45
std::string_view getInterfaceName() const
Get the called interface name.
Definition: dbusmessage.cpp:47
void beginArgumentRead()
Begin reading arguments.
void beginArgumentWrite()
Begin writing argument.
Definition: dbusmessage.cpp:53
static CDBusMessage createReply(const std::string &destination, dbus_uint32_t serial)
Creates a DBus message containing a DBus reply.
static CDBusMessage createSignal(const std::string &path, const std::string &interfaceName, const std::string &signalName)
Creates a DBus message containing a DBus signal.
DBus base object.
Definition: dbusobject.h:20
void queueDBusCall(const std::function< void()> &func)
Queue a DBus call to be executed in a different thread.
Definition: dbusobject.cpp:56
void maybeSendEmptyDBusReply(bool wantsReply, const std::string &destination, dbus_uint32_t serial)
Maybe sends an empty DBus reply (acknowledgement)
Definition: dbusobject.cpp:47
void sendDBusMessage(const CDBusMessage &message)
Send DBus message.
Definition: dbusobject.cpp:41
void invokeQueuedDBusCalls()
Invoke all pending DBus calls. They will be executed in the calling thread.
Definition: dbusobject.cpp:62
void sendDBusReply(const std::string &destination, dbus_uint32_t serial, const T &argument)
Send DBus reply.
Definition: dbusobject.h:57
bool isVisible() const
Is message box currently visible?
Definition: messages.h:140
void addMessage(const CMessage &message)
Add a new message to the bottom of the list.
int maxLineLength() const
Returns the maximum number of characters per line.
Definition: messages.h:120
void setValues(int leftPx, int topPx, int rightPx, int bottomPx, int lines, int durationMs)
Set margin values.
Definition: messages.h:123
void toggle()
Toggles the visibility of the message box.
Definition: messages.h:133
int getXPlaneVersionMinor() const
Get minor version number.
Definition: service.cpp:231
bool isCom1Transmitting() const
Is COM1 transmitting?
Definition: service.h:218
std::string getAircraftName() const
Get name of current aircraft model.
Definition: service.cpp:204
double getRollDeg() const
Get aircraft roll in degrees.
Definition: service.h:161
float getCom1Volume() const
Get the COM1 volume 0..1.
Definition: service.h:212
double getFlapsDeployRatio() const
Get flaps deploy ratio, where 0.0 is flaps fully retracted, and 1.0 is flaps fully extended.
Definition: service.h:287
float getCom2Volume() const
Get the COM2 volume 0..1.
Definition: service.h:233
int getCom1ActiveKhz() const
Get the current COM1 active frequency in kHz.
Definition: service.h:200
virtual ~CService()
Destructor.
double getLongitudeDeg() const
Get aircraft longitude in degrees.
Definition: service.h:133
double getAltitudeMslM() const
Get aircraft altitude in meters.
Definition: service.h:136
double getGroundSpeedMps() const
Get aircraft groundspeed in meters per second.
Definition: service.h:149
std::string getAircraftIcaoCode() const
Get the ICAO code of the current aircraft model.
Definition: service.h:89
std::string getAircraftModelString() const
Get canonical swift model string of current aircraft model.
Definition: service.cpp:195
bool isPaused() const
True if sim is paused.
Definition: service.h:107
int getCom2StandbyKhz() const
Get the current COM2 standby frequency in kHz.
Definition: service.h:224
void setFlightNetworkConnected(bool connected)
Set the current connection state.
Definition: service.cpp:141
double getTrueAirspeedKias() const
Get aircraft TAS in meters per second.
Definition: service.h:155
double getRollRadPerSec() const
Get aircraft angular velocity in radians per second.
Definition: service.h:176
int getXPlaneVersionMajor() const
Get major version number.
Definition: service.cpp:223
bool isCom2Receiving() const
Is COM2 receiving?
Definition: service.h:236
std::tuple< double, double, double, double > getFrameStats()
Frames-per-second, averaged over the last 500 frames, or since this function was last called,...
Definition: service.cpp:124
void resetFrameTotals()
Reset the monitoring of total miles and minutes lost due to low frame rate.
Definition: service.cpp:132
double getLocalZVelocityMps() const
Get aircraft local velocity in world coordinates meters per second.
Definition: service.h:170
DBusHandlerResult dbusMessageHandler(const CDBusMessage &message)
DBus message handler.
Definition: service.cpp:273
bool getTaxiLightsOn() const
Get whether taxi lights are on.
Definition: service.h:263
double getPitchRadPerSec() const
Get aircraft angular velocity in radians per second.
Definition: service.h:175
double getSpeedBrakeRatio() const
Get the ratio how much the speedbrakes surfaces are extended (0.0 is fully retracted,...
Definition: service.h:310
double getHeadingRadPerSec() const
Get aircraft angular velocity in radians per second.
Definition: service.h:177
double getPitchDeg() const
Get aircraft pitch in degrees above horizon.
Definition: service.h:158
std::string getXPlaneInstallationPath() const
Get root of X-Plane install path.
Definition: service.cpp:239
std::string getCommitHash() const
Returns the SHA1 of the last commit that could influence xswiftbus.
Definition: service.cpp:122
void onAircraftModelChanged()
Called by XPluginReceiveMessage when the model changes.
Definition: service.cpp:103
int getTransponderCode() const
Get the current transponder code in decimal.
Definition: service.h:242
std::string getXPlanePreferencesPath() const
Get full path to X-Plane preferences file.
Definition: service.cpp:246
double getGearDeployRatio() const
Get gear deploy ratio, where 0 is up and 1 is down.
Definition: service.h:290
double getLocalYVelocityMps() const
Get aircraft local velocity in world coordinates meters per second.
Definition: service.h:169
bool getTransponderIdent() const
Get whether we are currently squawking ident.
Definition: service.h:248
int getCom1StandbyKhz() const
Get the current COM1 standby frequency in kHz.
Definition: service.h:203
void setOwnCallsign(const std::string &callsign)
Set the current own callsign.
Definition: service.cpp:143
bool getAnyWheelOnGround() const
Get whether any wheel is on the ground.
Definition: service.h:181
void setTransponderMode(int mode)
Set the current transponder mode (depends on the aircraft, 0 and 1 usually mean standby,...
Definition: service.h:284
void setCom1StandbyKhz(int freq)
Set the current COM1 standby frequency in kHz.
Definition: service.h:272
std::string getVersionNumber() const
Returns the xswiftbus version number.
Definition: service.cpp:120
bool getLandingLightsOn() const
Get whether landing lights are on.
Definition: service.h:254
bool isCom1Receiving() const
Is COM1 receiving?
Definition: service.h:215
void onSceneryLoaded()
Called by XPluginReceiveMessage when some scenery is loaded.
Definition: service.cpp:118
double getHeightAglM() const
Get aircraft height in meters.
Definition: service.h:146
std::string getAircraftDescription() const
Get the description of the current aircraft model.
Definition: service.h:92
void setTransponderCode(int code)
Set the current transponder code in decimal.
Definition: service.h:281
void setDisappearMessageWindowTimeMs(int durationMs)
Enable/disable message window disappearing after x ms.
Definition: service.cpp:253
double getIndicatedAirspeedKias() const
Get aircraft IAS in knots.
Definition: service.h:152
void setCom2ActiveKhz(int freq)
Set the current COM2 active frequency in kHz.
Definition: service.h:275
double getLocalXVelocityMps() const
Get aircraft local velocity in world coordinates meters per second.
Definition: service.h:168
bool getBeaconLightsOn() const
Get whether beacon lights are on.
Definition: service.h:251
int process()
Perform generic processing.
Definition: service.cpp:783
double getPressureAltitudeFt() const
Get aircraft pressure altitude in feet in standard atmosphere in X-Plane 12. NaN in earlier versions ...
Definition: service.h:140
bool getStrobeLightsOn() const
Get whether strobe lights are on.
Definition: service.h:260
std::string getAircraftModelPath() const
Get full path to current aircraft model.
Definition: service.cpp:179
void addTextMessage(const std::string &text, double red, double green, double blue)
Add a text message to the on-screen display, with RGB components in the range [0,1].
Definition: service.cpp:145
double getLatitudeDeg() const
Get aircraft latitude in degrees.
Definition: service.h:130
int getCom2ActiveKhz() const
Get the current COM2 active frequency in kHz.
Definition: service.h:221
bool isCom2Transmitting() const
Is COM2 transmitting?
Definition: service.h:239
double getTrueHeadingDeg() const
Get aircraft true heading in degrees.
Definition: service.h:164
std::string getAircraftLivery() const
Get current aircraft livery.
Definition: service.cpp:213
double getQNHInHg() const
Get barometric pressure at sea level in inches of mercury.
Definition: service.h:266
void setCom1ActiveKhz(int freq)
Set the current COM1 active frequency in kHz.
Definition: service.h:269
void setCom2StandbyKhz(int freq)
Set the current COM2 standby frequency in kHz.
Definition: service.h:278
int getTransponderMode() const
Get the current transponder mode (depends on the aircraft, 0 and 1 usually mean standby,...
Definition: service.h:245
int getNumberOfEngines() const
Get the number of engines of current aircraft.
Definition: service.h:293
std::string getSettingsJson() const
Get settings in JSON format.
Definition: service.cpp:255
bool isUsingRealTime() const
True if sim time is tracking operating system time.
Definition: service.h:110
double getGroundElevation() const
Get elevation of ground under the plane in meters.
Definition: service.h:187
std::vector< double > getEngineN1Percentage() const
Get the N1 speed as percent of max (per engine)
Definition: service.h:296
std::string getAircraftModelFilename() const
Get base filename of current aircraft model.
Definition: service.cpp:187
void setSettingsJson(const std::string &jsonString)
Set settings.
Definition: service.cpp:257
bool getAllWheelsOnGround() const
Get whether all wheels are on the ground.
Definition: service.h:184
bool getNavLightsOn() const
Get whether nav lights are on.
Definition: service.h:257
void setSettings(const CSettings &settings)
Set settings.
Definition: settings.cpp:38
CSettings getSettings() const
Get settings.
Definition: settings.cpp:36
bool writeConfig(bool tcas, bool debug)
Write a config file with these new values.
Definition: settings.cpp:42
xswiftbus/swift side settings class, JSON capable, shared among all services
Definition: settings.h:19
Something owning the settings.
Definition: settings.h:31
DataRefType get() const
Get the value of the dataref.
Definition: datarefs.h:119
std::string get() const
Get the value of the whole string.
Definition: datarefs.h:204
std::vector< int > getMessageBoxValuesVector() const
Left, top, right, bottom, lines, duration, color(freq, priv, serv, stat, sup)
std::string convertToString() const
Convert to string.
std::string toXSwiftBusJsonString() const
As JSON string.
bool parseXSwiftBusString(const std::string &json)
Load and parse config file.
Plugin loaded by X-Plane which publishes a DBus service.
Definition: command.h:14
T::const_iterator begin(const LockFreeReader< T > &reader)
Non-member begin() and end() for so LockFree containers can be used in ranged for loops.
Definition: lockfree.h:255
T::const_iterator end(const LockFreeReader< T > &reader)
Non-member begin() and end() for so LockFree containers can be used in ranged for loops.
Definition: lockfree.h:261
AcfProperties extractAcfProperties(const std::string &filePath)
Extract ACF properties from an aircraft file.
Definition: qtfreeutils.h:170
std::string getFileName(const std::string &filePath)
Get filename (including all extensions) from a filePath.
Definition: qtfreeutils.h:23
decltype(Private::empty_u8string()) string
String type.
Definition: messages.h:38
Encoding-aware iterator adaptor for std::u8string.
Definition: qtfreeutils.h:220
#define INFO_LOG(msg)
Logger convenience macros.
Definition: utils.h:49
#define WARNING_LOG(msg)
Logger convenience macros.
Definition: utils.h:50