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  }
97 
98  // Explicitly in cpp file to allow use of forward declaration
99  CService::~CService() = default;
100 
102  {
103  char filename[256];
104  char path[512];
105  XPLMGetNthAircraftModel(XPLM_USER_AIRCRAFT, filename, path);
106  if (std::strlen(filename) < 1 || std::strlen(path) < 1)
107  {
108  WARNING_LOG("Aircraft changed, but NO path or file name");
109  return;
110  }
111  const AcfProperties acfProperties = extractAcfProperties(path);
112  emitAircraftModelChanged(path, filename, getAircraftLivery(), getAircraftIcaoCode(), acfProperties.modelString,
113  acfProperties.modelName, getAircraftDescription());
114  }
115 
116  void CService::onSceneryLoaded() { emitSceneryLoaded(); }
117 
118  std::string CService::getVersionNumber() const { return XSWIFTBUS_VERSION; }
119 
120  std::string CService::getCommitHash() const { return XSWIFTBUS_COMMIT; }
121 
122  std::tuple<double, double, double, double> CService::getFrameStats()
123  {
124  if (!m_framePeriodSampler) { return {}; }
125  const auto result = m_framePeriodSampler->getFrameStats();
126  return std::make_tuple(static_cast<double>(std::get<0>(result)), static_cast<double>(std::get<1>(result)),
127  static_cast<double>(std::get<2>(result)), static_cast<double>(std::get<3>(result)));
128  }
129 
131  {
132  if (m_framePeriodSampler)
133  {
134  m_framePeriodSampler->m_totalMetersShort = 0;
135  m_framePeriodSampler->m_totalSecondsLate = 0;
136  }
137  }
138 
139  void CService::addTextMessage(const std::string &text, double red, double green, double blue)
140  {
141  if (text.empty()) { return; }
142  static const CMessage::string ellipsis = u8"\u2026";
143  const unsigned lineLength = m_messages.maxLineLength() - 1;
144 
146  U8It begin(text.begin(), text.end());
147  auto characters = std::distance(begin, U8It(text.end(), text.end()));
148  std::vector<CMessage::string> wrappedLines;
149 
150  for (; characters > lineLength; characters -= lineLength)
151  {
152  auto end = std::next(begin, lineLength);
153  wrappedLines.emplace_back(begin.base, end.base);
154  wrappedLines.back() += ellipsis;
155  begin = end;
156  }
157  if (characters > 0) { wrappedLines.emplace_back(begin.base, text.end()); }
158  for (const auto &line : wrappedLines)
159  {
160  m_messages.addMessage(
161  { line, static_cast<float>(red), static_cast<float>(green), static_cast<float>(blue) });
162  }
163 
164  if (!m_messages.isVisible() && m_popupMessageWindow) { m_messages.toggle(); }
165 
166  if (m_disappearMessageWindow)
167  {
168  m_disappearMessageWindowTime = std::chrono::system_clock::now() +
169  std::chrono::milliseconds(std::max(m_disapperMessageWindowTimeMs, 1500));
170  }
171  }
172 
173  std::string CService::getAircraftModelPath() const
174  {
175  char filename[256];
176  char path[512];
177  XPLMGetNthAircraftModel(XPLM_USER_AIRCRAFT, filename, path);
178  return path;
179  }
180 
182  {
183  char filename[256];
184  char path[512];
185  XPLMGetNthAircraftModel(XPLM_USER_AIRCRAFT, filename, path);
186  return filename;
187  }
188 
190  {
191  char filename[256];
192  char path[512];
193  XPLMGetNthAircraftModel(XPLM_USER_AIRCRAFT, filename, path);
194  const AcfProperties acfProperties = extractAcfProperties(path);
195  return acfProperties.modelString;
196  }
197 
198  std::string CService::getAircraftName() const
199  {
200  char filename[256];
201  char path[512];
202  XPLMGetNthAircraftModel(XPLM_USER_AIRCRAFT, filename, path);
203  const AcfProperties acfProperties = extractAcfProperties(path);
204  return acfProperties.modelName;
205  }
206 
207  std::string CService::getAircraftLivery() const
208  {
209  std::string liveryPath = m_liveryPath.get();
210  if (liveryPath.empty()) { return {}; }
211 
212  // liveryPath end with / and we need to get rid of it
213  liveryPath.pop_back();
214  return getFileName(liveryPath);
215  }
216 
218  {
219  int version;
220  XPLMGetVersions(&version, nullptr, nullptr);
221  if (version > 5000) { version /= 10; }
222  return version / 100;
223  }
224 
226  {
227  int version;
228  XPLMGetVersions(&version, nullptr, nullptr);
229  if (version > 5000) { version /= 10; }
230  return version % 100;
231  }
232 
234  {
235  char path[512];
236  XPLMGetSystemPath(path);
237  return path;
238  }
239 
241  {
242  char path[512];
243  XPLMGetPrefsPath(path);
244  return path;
245  }
246 
247  void CService::setDisappearMessageWindowTimeMs(int durationMs) { m_disapperMessageWindowTimeMs = durationMs; }
248 
249  std::string CService::getSettingsJson() const { return this->getSettings().toXSwiftBusJsonString(); }
250 
251  void CService::setSettingsJson(const std::string &jsonString)
252  {
253  CSettings s;
254  s.parseXSwiftBusString(jsonString);
255  this->setSettings(s);
256  const bool w = this->writeConfig(s.isTcasEnabled(), s.isLogRenderPhases());
257  this->updateMessageBoxFromSettings();
258  INFO_LOG("Received settings " + s.convertToString());
259  if (w) { INFO_LOG("Written new config file"); }
260  }
261 
262  static const char *introspection_service = DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
263 #include "org.swift_project.xswiftbus.service.xml"
264  ;
265 
266  DBusHandlerResult CService::dbusMessageHandler(const CDBusMessage &message_)
267  {
268  CDBusMessage message(message_);
269  const std::string sender = message.getSender();
270  const dbus_uint32_t serial = message.getSerial();
271  const bool wantsReply = message.wantsReply();
272 
273  if (message.getInterfaceName() == DBUS_INTERFACE_INTROSPECTABLE)
274  {
275  if (message.getMethodName() == "Introspect") { sendDBusReply(sender, serial, introspection_service); }
276  }
277  else if (message.getInterfaceName() == XSWIFTBUS_SERVICE_INTERFACENAME)
278  {
279  if (message.getMethodName() == "getVersionNumber")
280  {
281  queueDBusCall([=]() { sendDBusReply(sender, serial, getVersionNumber()); });
282  }
283  else if (message.getMethodName() == "getCommitHash")
284  {
285  queueDBusCall([=]() { sendDBusReply(sender, serial, getCommitHash()); });
286  }
287  else if (message.getMethodName() == "addTextMessage")
288  {
289  maybeSendEmptyDBusReply(wantsReply, sender, serial);
290  std::string text;
291  double red = 0;
292  double green = 0;
293  double blue = 0;
294  message.beginArgumentRead();
295  message.getArgument(text);
296  message.getArgument(red);
297  message.getArgument(green);
298  message.getArgument(blue);
299 
300  queueDBusCall([=]() { addTextMessage(text, red, green, blue); });
301  }
302  else if (message.getMethodName() == "getOwnAircraftSituationData")
303  {
304  queueDBusCall([=]() {
305  const double lat = m_latitude.get();
306  const double lon = m_longitude.get();
307  const double alt = m_elevation.get();
308  const double gs = m_groundSpeed.get();
309  const double pitch = m_pitch.get();
310  const double roll = m_roll.get();
311  const double trueHeading = m_heading.get();
312  const double qnh = m_qnhInhg.get();
313  CDBusMessage reply = CDBusMessage::createReply(sender, serial);
314  reply.beginArgumentWrite();
315  reply.appendArgument(lat);
316  reply.appendArgument(lon);
317  reply.appendArgument(alt);
318  reply.appendArgument(gs);
319  reply.appendArgument(pitch);
320  reply.appendArgument(roll);
321  reply.appendArgument(trueHeading);
322  reply.appendArgument(qnh);
323  sendDBusMessage(reply);
324  });
325  }
326  else if (message.getMethodName() == "getOwnAircraftVelocityData")
327  {
328  queueDBusCall([=]() {
329  const double velocityX = m_velocityX.get();
330  const double velocityY = m_velocityY.get();
331  const double velocityZ = m_velocityZ.get();
332  const double pitchVelocity = m_pitchVelocity.get();
333  const double rollVelocity = m_rollVelocity.get();
334  const double headingVelocity = m_headingVelocity.get();
335  CDBusMessage reply = CDBusMessage::createReply(sender, serial);
336  reply.beginArgumentWrite();
337  reply.appendArgument(velocityX);
338  reply.appendArgument(velocityY);
339  reply.appendArgument(velocityZ);
340  reply.appendArgument(pitchVelocity);
341  reply.appendArgument(rollVelocity);
342  reply.appendArgument(headingVelocity);
343  sendDBusMessage(reply);
344  });
345  }
346  else if (message.getMethodName() == "getOwnAircraftCom1Data")
347  {
348  queueDBusCall([=]() {
349  const int active = m_com1Active.get();
350  const int standby = m_com1Standby.get();
351  const double volume = m_com1Volume.get();
352  const bool rec = this->isCom1Receiving();
353  const bool tx = this->isCom1Transmitting();
354  CDBusMessage reply = CDBusMessage::createReply(sender, serial);
355  reply.beginArgumentWrite();
356  reply.appendArgument(active);
357  reply.appendArgument(standby);
358  reply.appendArgument(volume);
359  reply.appendArgument(rec);
360  reply.appendArgument(tx);
361  sendDBusMessage(reply);
362  });
363  }
364  else if (message.getMethodName() == "getOwnAircraftCom2Data")
365  {
366  queueDBusCall([=]() {
367  const int active = m_com2Active.get();
368  const int standby = m_com2Standby.get();
369  const double volume = m_com2Volume.get();
370  const bool rec = this->isCom2Receiving();
371  const bool tx = this->isCom2Transmitting();
372  CDBusMessage reply = CDBusMessage::createReply(sender, serial);
373  reply.beginArgumentWrite();
374  reply.appendArgument(active);
375  reply.appendArgument(standby);
376  reply.appendArgument(volume);
377  reply.appendArgument(rec);
378  reply.appendArgument(tx);
379  sendDBusMessage(reply);
380  });
381  }
382  else if (message.getMethodName() == "getOwnAircraftXpdr")
383  {
384  queueDBusCall([=]() {
385  const int code = m_xpdrCode.get();
386  const int mode = m_xpdrMode.get();
387  const bool id = m_xpdrIdent.get();
388  CDBusMessage reply = CDBusMessage::createReply(sender, serial);
389  reply.beginArgumentWrite();
390  reply.appendArgument(code);
391  reply.appendArgument(mode);
392  reply.appendArgument(id);
393  sendDBusMessage(reply);
394  });
395  }
396  else if (message.getMethodName() == "getOwnAircraftLights")
397  {
398  queueDBusCall([=]() {
399  const bool beaconLightsOn = m_beaconLightsOn.get();
400  const bool landingLightsOn = m_landingLightsOn.get();
401  const bool navLightsOn = m_navLightsOn.get();
402  const bool strobeLightsOn = m_strobeLightsOn.get();
403  const bool taxiLightsOn = m_taxiLightsOn.get();
404  CDBusMessage reply = CDBusMessage::createReply(sender, serial);
405  reply.beginArgumentWrite();
406  reply.appendArgument(beaconLightsOn);
407  reply.appendArgument(landingLightsOn);
408  reply.appendArgument(navLightsOn);
409  reply.appendArgument(strobeLightsOn);
410  reply.appendArgument(taxiLightsOn);
411  sendDBusMessage(reply);
412  });
413  }
414  else if (message.getMethodName() == "getOwnAircraftParts")
415  {
416  queueDBusCall([=]() {
417  const double flapsReployRatio = m_flapsReployRatio.get();
418  const double gearReployRatio = m_gearReployRatio.getAt(0);
419  const double speedBrakeRatio = m_speedBrakeRatio.get();
420  const std::vector<double> enginesN1Percentage = this->getEngineN1Percentage();
421  CDBusMessage reply = CDBusMessage::createReply(sender, serial);
422  reply.beginArgumentWrite();
423  reply.appendArgument(flapsReployRatio);
424  reply.appendArgument(gearReployRatio);
425  reply.appendArgument(speedBrakeRatio);
426  reply.appendArgument(enginesN1Percentage);
427  sendDBusMessage(reply);
428  });
429  }
430  else if (message.getMethodName() == "getOwnAircraftModelData")
431  {
432  queueDBusCall([=]() {
433  const std::string aircraftModelPath = this->getAircraftModelPath();
434  const std::string aircraftIcaoCode = this->getAircraftIcaoCode();
435  CDBusMessage reply = CDBusMessage::createReply(sender, serial);
436  reply.beginArgumentWrite();
437  reply.appendArgument(aircraftModelPath);
438  reply.appendArgument(aircraftIcaoCode);
439  sendDBusMessage(reply);
440  });
441  }
442  else if (message.getMethodName() == "getAircraftModelPath")
443  {
444  queueDBusCall([=]() { sendDBusReply(sender, serial, getAircraftModelPath()); });
445  }
446  else if (message.getMethodName() == "getAircraftModelFilename")
447  {
448  queueDBusCall([=]() { sendDBusReply(sender, serial, getAircraftModelFilename()); });
449  }
450  else if (message.getMethodName() == "getAircraftModelString")
451  {
452  queueDBusCall([=]() { sendDBusReply(sender, serial, getAircraftModelString()); });
453  }
454  else if (message.getMethodName() == "getAircraftName")
455  {
456  queueDBusCall([=]() { sendDBusReply(sender, serial, getAircraftName()); });
457  }
458  else if (message.getMethodName() == "getAircraftLivery")
459  {
460  queueDBusCall([=]() { sendDBusReply(sender, serial, getAircraftLivery()); });
461  }
462  else if (message.getMethodName() == "getAircraftIcaoCode")
463  {
464  queueDBusCall([=]() { sendDBusReply(sender, serial, getAircraftIcaoCode()); });
465  }
466  else if (message.getMethodName() == "getAircraftDescription")
467  {
468  queueDBusCall([=]() { sendDBusReply(sender, serial, getAircraftDescription()); });
469  }
470  else if (message.getMethodName() == "getXPlaneVersionMajor")
471  {
472  queueDBusCall([=]() { sendDBusReply(sender, serial, getXPlaneVersionMajor()); });
473  }
474  else if (message.getMethodName() == "getXPlaneVersionMinor")
475  {
476  queueDBusCall([=]() { sendDBusReply(sender, serial, getXPlaneVersionMinor()); });
477  }
478  else if (message.getMethodName() == "getXPlaneInstallationPath")
479  {
480  queueDBusCall([=]() { sendDBusReply(sender, serial, getXPlaneInstallationPath()); });
481  }
482  else if (message.getMethodName() == "getXPlanePreferencesPath")
483  {
484  queueDBusCall([=]() { sendDBusReply(sender, serial, getXPlanePreferencesPath()); });
485  }
486  else if (message.getMethodName() == "isPaused")
487  {
488  queueDBusCall([=]() { sendDBusReply(sender, serial, isPaused()); });
489  }
490  else if (message.getMethodName() == "isUsingRealTime")
491  {
492  queueDBusCall([=]() { sendDBusReply(sender, serial, isUsingRealTime()); });
493  }
494  else if (message.getMethodName() == "getFrameStats")
495  {
496  queueDBusCall([=]() {
497  const auto stats = getFrameStats();
498  CDBusMessage reply = CDBusMessage::createReply(sender, serial);
499  reply.beginArgumentWrite();
500  reply.appendArgument(std::get<0>(stats));
501  reply.appendArgument(std::get<1>(stats));
502  reply.appendArgument(std::get<2>(stats));
503  reply.appendArgument(std::get<3>(stats));
504  sendDBusMessage(reply);
505  });
506  }
507  else if (message.getMethodName() == "resetFrameTotals")
508  {
509  maybeSendEmptyDBusReply(wantsReply, sender, serial);
510  queueDBusCall([=]() { resetFrameTotals(); });
511  }
512  else if (message.getMethodName() == "getLatitudeDeg")
513  {
514  queueDBusCall([=]() { sendDBusReply(sender, serial, getLatitudeDeg()); });
515  }
516  else if (message.getMethodName() == "getLongitudeDeg")
517  {
518  queueDBusCall([=]() { sendDBusReply(sender, serial, getLongitudeDeg()); });
519  }
520  else if (message.getMethodName() == "getAltitudeMslM")
521  {
522  queueDBusCall([=]() { sendDBusReply(sender, serial, getAltitudeMslM()); });
523  }
524  else if (message.getMethodName() == "getPressureAltitudeFt")
525  {
526  queueDBusCall([=]() { sendDBusReply(sender, serial, getPressureAltitudeFt()); });
527  }
528  else if (message.getMethodName() == "getHeightAglM")
529  {
530  queueDBusCall([=]() { sendDBusReply(sender, serial, getHeightAglM()); });
531  }
532  else if (message.getMethodName() == "getGroundSpeedMps")
533  {
534  queueDBusCall([=]() { sendDBusReply(sender, serial, getGroundSpeedMps()); });
535  }
536  else if (message.getMethodName() == "getIndicatedAirspeedKias")
537  {
538  queueDBusCall([=]() { sendDBusReply(sender, serial, getIndicatedAirspeedKias()); });
539  }
540  else if (message.getMethodName() == "getTrueAirspeedKias")
541  {
542  queueDBusCall([=]() { sendDBusReply(sender, serial, getTrueAirspeedKias()); });
543  }
544  else if (message.getMethodName() == "getPitchDeg")
545  {
546  queueDBusCall([=]() { sendDBusReply(sender, serial, getPitchDeg()); });
547  }
548  else if (message.getMethodName() == "getRollDeg")
549  {
550  queueDBusCall([=]() { sendDBusReply(sender, serial, getRollDeg()); });
551  }
552  else if (message.getMethodName() == "getTrueHeadingDeg")
553  {
554  queueDBusCall([=]() { sendDBusReply(sender, serial, getTrueHeadingDeg()); });
555  }
556  else if (message.getMethodName() == "getLocalXVelocityXMps")
557  {
558  queueDBusCall([=]() { sendDBusReply(sender, serial, getLocalXVelocityMps()); });
559  }
560  else if (message.getMethodName() == "getLocalYVelocityYMps")
561  {
562  queueDBusCall([=]() { sendDBusReply(sender, serial, getLocalYVelocityMps()); });
563  }
564  else if (message.getMethodName() == "getLocalZVelocityZMps")
565  {
566  queueDBusCall([=]() { sendDBusReply(sender, serial, getLocalZVelocityMps()); });
567  }
568  else if (message.getMethodName() == "getPitchRadPerSec")
569  {
570  queueDBusCall([=]() { sendDBusReply(sender, serial, getPitchRadPerSec()); });
571  }
572  else if (message.getMethodName() == "getRollRadPerSec")
573  {
574  queueDBusCall([=]() { sendDBusReply(sender, serial, getRollRadPerSec()); });
575  }
576  else if (message.getMethodName() == "getHeadingRadPerSec")
577  {
578  queueDBusCall([=]() { sendDBusReply(sender, serial, getHeadingRadPerSec()); });
579  }
580  else if (message.getMethodName() == "getAnyWheelOnGround")
581  {
582  queueDBusCall([=]() { sendDBusReply(sender, serial, getAnyWheelOnGround()); });
583  }
584  else if (message.getMethodName() == "getAllWheelsOnGround")
585  {
586  queueDBusCall([=]() { sendDBusReply(sender, serial, getAllWheelsOnGround()); });
587  }
588  else if (message.getMethodName() == "getGroundElevation")
589  {
590  queueDBusCall([=]() { sendDBusReply(sender, serial, getGroundElevation()); });
591  }
592  else if (message.getMethodName() == "getCom1ActiveKhz")
593  {
594  queueDBusCall([=]() { sendDBusReply(sender, serial, getCom1ActiveKhz()); });
595  }
596  else if (message.getMethodName() == "getCom1StandbyKhz")
597  {
598  queueDBusCall([=]() { sendDBusReply(sender, serial, getCom1StandbyKhz()); });
599  }
600  else if (message.getMethodName() == "getCom2ActiveKhz")
601  {
602  queueDBusCall([=]() { sendDBusReply(sender, serial, getCom2ActiveKhz()); });
603  }
604  else if (message.getMethodName() == "getCom2StandbyKhz")
605  {
606  queueDBusCall([=]() { sendDBusReply(sender, serial, getCom2StandbyKhz()); });
607  }
608  else if (message.getMethodName() == "isCom1Receiving")
609  {
610  queueDBusCall([=]() { sendDBusReply(sender, serial, isCom1Receiving()); });
611  }
612  else if (message.getMethodName() == "isCom1Transmitting")
613  {
614  queueDBusCall([=]() { sendDBusReply(sender, serial, isCom1Transmitting()); });
615  }
616  else if (message.getMethodName() == "getCom1Volume")
617  {
618  queueDBusCall([=]() { sendDBusReply(sender, serial, getCom1Volume()); });
619  }
620  else if (message.getMethodName() == "isCom2Receiving")
621  {
622  queueDBusCall([=]() { sendDBusReply(sender, serial, isCom2Receiving()); });
623  }
624  else if (message.getMethodName() == "isCom2Transmitting")
625  {
626  queueDBusCall([=]() { sendDBusReply(sender, serial, isCom2Transmitting()); });
627  }
628  else if (message.getMethodName() == "getCom2Volume")
629  {
630  queueDBusCall([=]() { sendDBusReply(sender, serial, getCom2Volume()); });
631  }
632  else if (message.getMethodName() == "getTransponderCode")
633  {
634  queueDBusCall([=]() { sendDBusReply(sender, serial, getTransponderCode()); });
635  }
636  else if (message.getMethodName() == "getTransponderMode")
637  {
638  queueDBusCall([=]() { sendDBusReply(sender, serial, getTransponderMode()); });
639  }
640  else if (message.getMethodName() == "getTransponderIdent")
641  {
642  queueDBusCall([=]() { sendDBusReply(sender, serial, getTransponderIdent()); });
643  }
644  else if (message.getMethodName() == "getBeaconLightsOn")
645  {
646  queueDBusCall([=]() { sendDBusReply(sender, serial, getBeaconLightsOn()); });
647  }
648  else if (message.getMethodName() == "getLandingLightsOn")
649  {
650  queueDBusCall([=]() { sendDBusReply(sender, serial, getLandingLightsOn()); });
651  }
652  else if (message.getMethodName() == "getTaxiLightsOn")
653  {
654  queueDBusCall([=]() { sendDBusReply(sender, serial, getTaxiLightsOn()); });
655  }
656  else if (message.getMethodName() == "getNavLightsOn")
657  {
658  queueDBusCall([=]() { sendDBusReply(sender, serial, getNavLightsOn()); });
659  }
660  else if (message.getMethodName() == "getStrobeLightsOn")
661  {
662  queueDBusCall([=]() { sendDBusReply(sender, serial, getStrobeLightsOn()); });
663  }
664  else if (message.getMethodName() == "getQNHInHg")
665  {
666  queueDBusCall([=]() { sendDBusReply(sender, serial, getQNHInHg()); });
667  }
668  else if (message.getMethodName() == "setCom1ActiveKhz")
669  {
670  maybeSendEmptyDBusReply(wantsReply, sender, serial);
671  int frequency = 0;
672  message.beginArgumentRead();
673  message.getArgument(frequency);
674  queueDBusCall([=]() { setCom1ActiveKhz(frequency); });
675  }
676  else if (message.getMethodName() == "setCom1StandbyKhz")
677  {
678  maybeSendEmptyDBusReply(wantsReply, sender, serial);
679  int frequency = 0;
680  message.beginArgumentRead();
681  message.getArgument(frequency);
682  queueDBusCall([=]() { setCom1StandbyKhz(frequency); });
683  }
684  else if (message.getMethodName() == "setCom2ActiveKhz")
685  {
686  maybeSendEmptyDBusReply(wantsReply, sender, serial);
687  int frequency = 0;
688  message.beginArgumentRead();
689  message.getArgument(frequency);
690  queueDBusCall([=]() { setCom2ActiveKhz(frequency); });
691  }
692  else if (message.getMethodName() == "setCom2StandbyKhz")
693  {
694  maybeSendEmptyDBusReply(wantsReply, sender, serial);
695  int frequency = 0;
696  message.beginArgumentRead();
697  message.getArgument(frequency);
698  queueDBusCall([=]() { setCom2StandbyKhz(frequency); });
699  }
700  else if (message.getMethodName() == "setTransponderCode")
701  {
702  maybeSendEmptyDBusReply(wantsReply, sender, serial);
703  int code = 0;
704  message.beginArgumentRead();
705  message.getArgument(code);
706  queueDBusCall([=]() { setTransponderCode(code); });
707  }
708  else if (message.getMethodName() == "setTransponderMode")
709  {
710  maybeSendEmptyDBusReply(wantsReply, sender, serial);
711  int mode = 0;
712  message.beginArgumentRead();
713  message.getArgument(mode);
714  queueDBusCall([=]() { setTransponderMode(mode); });
715  }
716  else if (message.getMethodName() == "getFlapsDeployRatio")
717  {
718  queueDBusCall([=]() { sendDBusReply(sender, serial, getFlapsDeployRatio()); });
719  }
720  else if (message.getMethodName() == "getGearDeployRatio")
721  {
722  queueDBusCall([=]() { sendDBusReply(sender, serial, getGearDeployRatio()); });
723  }
724  else if (message.getMethodName() == "getNumberOfEngines")
725  {
726  queueDBusCall([=]() { sendDBusReply(sender, serial, getNumberOfEngines()); });
727  }
728  else if (message.getMethodName() == "getEngineN1Percentage")
729  {
730  queueDBusCall([=]() {
731  const std::vector<double> enginesN1Percentage = getEngineN1Percentage();
732  sendDBusReply(sender, serial, enginesN1Percentage);
733  });
734  }
735  else if (message.getMethodName() == "getSpeedBrakeRatio")
736  {
737  queueDBusCall([=]() { sendDBusReply(sender, serial, getSpeedBrakeRatio()); });
738  }
739  else if (message.getMethodName() == "getSettingsJson")
740  {
741  queueDBusCall([=]() { sendDBusReply(sender, serial, getSettingsJson()); });
742  }
743  else if (message.getMethodName() == "setSettingsJson")
744  {
745  maybeSendEmptyDBusReply(wantsReply, sender, serial);
746  std::string json;
747  message.beginArgumentRead();
748  message.getArgument(json);
749  queueDBusCall([=]() { setSettingsJson(json); });
750  }
751  else
752  {
753  // Unknown message. Tell DBus that we cannot handle it
754  return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
755  }
756  }
757  return DBUS_HANDLER_RESULT_HANDLED;
758  }
759 
761  {
762  if (m_sceneryIsLoading.get() != m_sceneryWasLoading)
763  {
764  if (!m_sceneryIsLoading.get()) { onSceneryLoaded(); }
765  m_sceneryWasLoading = m_sceneryIsLoading.get();
766  }
767 
769 
770  if (m_disappearMessageWindowTime != std::chrono::system_clock::time_point() &&
771  std::chrono::system_clock::now() > m_disappearMessageWindowTime && m_messages.isVisible())
772  {
773  m_messages.toggle();
774  m_disappearMessageWindowTime = std::chrono::system_clock::time_point();
775  }
776 
777  return 1;
778  }
779 
780  void CService::emitAircraftModelChanged(const std::string &path, const std::string &filename,
781  const std::string &livery, const std::string &icao,
782  const std::string &modelString, const std::string &name,
783  const std::string &description)
784  {
785  CDBusMessage signalAircraftModelChanged = CDBusMessage::createSignal(
786  XSWIFTBUS_SERVICE_OBJECTPATH, XSWIFTBUS_SERVICE_INTERFACENAME, "aircraftModelChanged");
787  signalAircraftModelChanged.beginArgumentWrite();
788  signalAircraftModelChanged.appendArgument(path);
789  signalAircraftModelChanged.appendArgument(filename);
790  signalAircraftModelChanged.appendArgument(livery);
791  signalAircraftModelChanged.appendArgument(icao);
792  signalAircraftModelChanged.appendArgument(modelString);
793  signalAircraftModelChanged.appendArgument(name);
794  signalAircraftModelChanged.appendArgument(description);
795  sendDBusMessage(signalAircraftModelChanged);
796  }
797 
798  void CService::emitSceneryLoaded()
799  {
800  CDBusMessage signal =
801  CDBusMessage::createSignal(XSWIFTBUS_SERVICE_OBJECTPATH, XSWIFTBUS_SERVICE_INTERFACENAME, "sceneryLoaded");
802  sendDBusMessage(signal);
803  }
804 
805  void CService::updateMessageBoxFromSettings()
806  {
807  // left, top, right, bottom, height size percentage
808  const std::vector<int> values = this->getSettings().getMessageBoxValuesVector();
809  if (values.size() >= 6)
810  {
811  m_messages.setValues(values[0], values[1], values[2], values[3], values[4], values[5]);
812  this->setDisappearMessageWindowTimeMs(values[5]);
813  }
814  }
815 } // namespace XSwiftBus
DataRefType getAt(int index) const
Get the value of a single element.
Definition: datarefs.h:168
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:225
bool isCom1Transmitting() const
Is COM1 transmitting?
Definition: service.h:211
std::string getAircraftName() const
Get name of current aircraft model.
Definition: service.cpp:198
double getRollDeg() const
Get aircraft roll in degrees.
Definition: service.h:154
float getCom1Volume() const
Get the COM1 volume 0..1.
Definition: service.h:205
double getFlapsDeployRatio() const
Get flaps deploy ratio, where 0.0 is flaps fully retracted, and 1.0 is flaps fully extended.
Definition: service.h:280
float getCom2Volume() const
Get the COM2 volume 0..1.
Definition: service.h:226
int getCom1ActiveKhz() const
Get the current COM1 active frequency in kHz.
Definition: service.h:193
virtual ~CService()
Destructor.
double getLongitudeDeg() const
Get aircraft longitude in degrees.
Definition: service.h:126
double getAltitudeMslM() const
Get aircraft altitude in meters.
Definition: service.h:129
double getGroundSpeedMps() const
Get aircraft groundspeed in meters per second.
Definition: service.h:142
std::string getAircraftIcaoCode() const
Get the ICAO code of the current aircraft model.
Definition: service.h:88
std::string getAircraftModelString() const
Get canonical swift model string of current aircraft model.
Definition: service.cpp:189
bool isPaused() const
True if sim is paused.
Definition: service.h:106
int getCom2StandbyKhz() const
Get the current COM2 standby frequency in kHz.
Definition: service.h:217
double getTrueAirspeedKias() const
Get aircraft TAS in meters per second.
Definition: service.h:148
double getRollRadPerSec() const
Get aircraft angular velocity in radians per second.
Definition: service.h:169
int getXPlaneVersionMajor() const
Get major version number.
Definition: service.cpp:217
bool isCom2Receiving() const
Is COM2 receiving?
Definition: service.h:229
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:122
void resetFrameTotals()
Reset the monitoring of total miles and minutes lost due to low frame rate.
Definition: service.cpp:130
double getLocalZVelocityMps() const
Get aircraft local velocity in world coordinates meters per second.
Definition: service.h:163
DBusHandlerResult dbusMessageHandler(const CDBusMessage &message)
DBus message handler.
Definition: service.cpp:266
bool getTaxiLightsOn() const
Get whether taxi lights are on.
Definition: service.h:256
double getPitchRadPerSec() const
Get aircraft angular velocity in radians per second.
Definition: service.h:168
double getSpeedBrakeRatio() const
Get the ratio how much the speedbrakes surfaces are extended (0.0 is fully retracted,...
Definition: service.h:303
double getHeadingRadPerSec() const
Get aircraft angular velocity in radians per second.
Definition: service.h:170
double getPitchDeg() const
Get aircraft pitch in degrees above horizon.
Definition: service.h:151
std::string getXPlaneInstallationPath() const
Get root of X-Plane install path.
Definition: service.cpp:233
std::string getCommitHash() const
Returns the SHA1 of the last commit that could influence xswiftbus.
Definition: service.cpp:120
void onAircraftModelChanged()
Called by XPluginReceiveMessage when the model changes.
Definition: service.cpp:101
int getTransponderCode() const
Get the current transponder code in decimal.
Definition: service.h:235
std::string getXPlanePreferencesPath() const
Get full path to X-Plane preferences file.
Definition: service.cpp:240
double getGearDeployRatio() const
Get gear deploy ratio, where 0 is up and 1 is down.
Definition: service.h:283
double getLocalYVelocityMps() const
Get aircraft local velocity in world coordinates meters per second.
Definition: service.h:162
bool getTransponderIdent() const
Get whether we are currently squawking ident.
Definition: service.h:241
int getCom1StandbyKhz() const
Get the current COM1 standby frequency in kHz.
Definition: service.h:196
bool getAnyWheelOnGround() const
Get whether any wheel is on the ground.
Definition: service.h:174
void setTransponderMode(int mode)
Set the current transponder mode (depends on the aircraft, 0 and 1 usually mean standby,...
Definition: service.h:277
void setCom1StandbyKhz(int freq)
Set the current COM1 standby frequency in kHz.
Definition: service.h:265
std::string getVersionNumber() const
Returns the xswiftbus version number.
Definition: service.cpp:118
bool getLandingLightsOn() const
Get whether landing lights are on.
Definition: service.h:247
bool isCom1Receiving() const
Is COM1 receiving?
Definition: service.h:208
void onSceneryLoaded()
Called by XPluginReceiveMessage when some scenery is loaded.
Definition: service.cpp:116
double getHeightAglM() const
Get aircraft height in meters.
Definition: service.h:139
std::string getAircraftDescription() const
Get the description of the current aircraft model.
Definition: service.h:91
void setTransponderCode(int code)
Set the current transponder code in decimal.
Definition: service.h:274
void setDisappearMessageWindowTimeMs(int durationMs)
Enable/disable message window disappearing after x ms.
Definition: service.cpp:247
double getIndicatedAirspeedKias() const
Get aircraft IAS in knots.
Definition: service.h:145
void setCom2ActiveKhz(int freq)
Set the current COM2 active frequency in kHz.
Definition: service.h:268
double getLocalXVelocityMps() const
Get aircraft local velocity in world coordinates meters per second.
Definition: service.h:161
bool getBeaconLightsOn() const
Get whether beacon lights are on.
Definition: service.h:244
int process()
Perform generic processing.
Definition: service.cpp:760
double getPressureAltitudeFt() const
Get aircraft pressure altitude in feet in standard atmosphere in X-Plane 12. NaN in earlier versions ...
Definition: service.h:133
bool getStrobeLightsOn() const
Get whether strobe lights are on.
Definition: service.h:253
std::string getAircraftModelPath() const
Get full path to current aircraft model.
Definition: service.cpp:173
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:139
double getLatitudeDeg() const
Get aircraft latitude in degrees.
Definition: service.h:123
int getCom2ActiveKhz() const
Get the current COM2 active frequency in kHz.
Definition: service.h:214
bool isCom2Transmitting() const
Is COM2 transmitting?
Definition: service.h:232
double getTrueHeadingDeg() const
Get aircraft true heading in degrees.
Definition: service.h:157
std::string getAircraftLivery() const
Get current aircraft livery.
Definition: service.cpp:207
double getQNHInHg() const
Get barometric pressure at sea level in inches of mercury.
Definition: service.h:259
void setCom1ActiveKhz(int freq)
Set the current COM1 active frequency in kHz.
Definition: service.h:262
void setCom2StandbyKhz(int freq)
Set the current COM2 standby frequency in kHz.
Definition: service.h:271
int getTransponderMode() const
Get the current transponder mode (depends on the aircraft, 0 and 1 usually mean standby,...
Definition: service.h:238
int getNumberOfEngines() const
Get the number of engines of current aircraft.
Definition: service.h:286
std::string getSettingsJson() const
Get settings in JSON format.
Definition: service.cpp:249
bool isUsingRealTime() const
True if sim time is tracking operating system time.
Definition: service.h:109
double getGroundElevation() const
Get elevation of ground under the plane in meters.
Definition: service.h:180
std::vector< double > getEngineN1Percentage() const
Get the N1 speed as percent of max (per engine)
Definition: service.h:289
std::string getAircraftModelFilename() const
Get base filename of current aircraft model.
Definition: service.cpp:181
void setSettingsJson(const std::string &jsonString)
Set settings.
Definition: service.cpp:251
bool getAllWheelsOnGround() const
Get whether all wheels are on the ground.
Definition: service.h:177
bool getNavLightsOn() const
Get whether nav lights are on.
Definition: service.h:250
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:117
std::string get() const
Get the value of the whole string.
Definition: datarefs.h:202
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:332
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:338
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