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