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  DBusHandlerResult CService::dbusMessageHandler(const CDBusMessage &message_)
273  {
274  CDBusMessage message(message_);
275  const std::string sender = message.getSender();
276  const dbus_uint32_t serial = message.getSerial();
277  const bool wantsReply = message.wantsReply();
278 
279  if (message.getInterfaceName() == DBUS_INTERFACE_INTROSPECTABLE)
280  {
281  if (message.getMethodName() == "Introspect") { sendDBusReply(sender, serial, introspection_service); }
282  }
283  else if (message.getInterfaceName() == XSWIFTBUS_SERVICE_INTERFACENAME)
284  {
285  if (message.getMethodName() == "getVersionNumber")
286  {
287  queueDBusCall([=]() { sendDBusReply(sender, serial, getVersionNumber()); });
288  }
289  else if (message.getMethodName() == "getCommitHash")
290  {
291  queueDBusCall([=]() { sendDBusReply(sender, serial, getCommitHash()); });
292  }
293  else if (message.getMethodName() == "addTextMessage")
294  {
295  maybeSendEmptyDBusReply(wantsReply, sender, serial);
296  std::string text;
297  double red = 0;
298  double green = 0;
299  double blue = 0;
300  message.beginArgumentRead();
301  message.getArgument(text);
302  message.getArgument(red);
303  message.getArgument(green);
304  message.getArgument(blue);
305 
306  queueDBusCall([=]() { addTextMessage(text, red, green, blue); });
307  }
308  else if (message.getMethodName() == "getOwnAircraftSituationData")
309  {
310  queueDBusCall([=]() {
311  const double lat = m_latitude.get();
312  const double lon = m_longitude.get();
313  const double alt = m_elevation.get();
314  const double gs = m_groundSpeed.get();
315  const double pitch = m_pitch.get();
316  const double roll = m_roll.get();
317  const double trueHeading = m_heading.get();
318  const double qnh = m_qnhInhg.get();
319  CDBusMessage reply = CDBusMessage::createReply(sender, serial);
320  reply.beginArgumentWrite();
321  reply.appendArgument(lat);
322  reply.appendArgument(lon);
323  reply.appendArgument(alt);
324  reply.appendArgument(gs);
325  reply.appendArgument(pitch);
326  reply.appendArgument(roll);
327  reply.appendArgument(trueHeading);
328  reply.appendArgument(qnh);
329  sendDBusMessage(reply);
330  });
331  }
332  else if (message.getMethodName() == "getOwnAircraftVelocityData")
333  {
334  queueDBusCall([=]() {
335  const double velocityX = m_velocityX.get();
336  const double velocityY = m_velocityY.get();
337  const double velocityZ = m_velocityZ.get();
338  const double pitchVelocity = m_pitchVelocity.get();
339  const double rollVelocity = m_rollVelocity.get();
340  const double headingVelocity = m_headingVelocity.get();
341  CDBusMessage reply = CDBusMessage::createReply(sender, serial);
342  reply.beginArgumentWrite();
343  reply.appendArgument(velocityX);
344  reply.appendArgument(velocityY);
345  reply.appendArgument(velocityZ);
346  reply.appendArgument(pitchVelocity);
347  reply.appendArgument(rollVelocity);
348  reply.appendArgument(headingVelocity);
349  sendDBusMessage(reply);
350  });
351  }
352  else if (message.getMethodName() == "getOwnAircraftCom1Data")
353  {
354  queueDBusCall([=]() {
355  const int active = m_com1Active.get();
356  const int standby = m_com1Standby.get();
357  const double volume = m_com1Volume.get();
358  const bool rec = this->isCom1Receiving();
359  const bool tx = this->isCom1Transmitting();
360  CDBusMessage reply = CDBusMessage::createReply(sender, serial);
361  reply.beginArgumentWrite();
362  reply.appendArgument(active);
363  reply.appendArgument(standby);
364  reply.appendArgument(volume);
365  reply.appendArgument(rec);
366  reply.appendArgument(tx);
367  sendDBusMessage(reply);
368  });
369  }
370  else if (message.getMethodName() == "getOwnAircraftCom2Data")
371  {
372  queueDBusCall([=]() {
373  const int active = m_com2Active.get();
374  const int standby = m_com2Standby.get();
375  const double volume = m_com2Volume.get();
376  const bool rec = this->isCom2Receiving();
377  const bool tx = this->isCom2Transmitting();
378  CDBusMessage reply = CDBusMessage::createReply(sender, serial);
379  reply.beginArgumentWrite();
380  reply.appendArgument(active);
381  reply.appendArgument(standby);
382  reply.appendArgument(volume);
383  reply.appendArgument(rec);
384  reply.appendArgument(tx);
385  sendDBusMessage(reply);
386  });
387  }
388  else if (message.getMethodName() == "getOwnAircraftXpdr")
389  {
390  queueDBusCall([=]() {
391  const int code = m_xpdrCode.get();
392  const int mode = m_xpdrMode.get();
393  const bool id = m_xpdrIdent.get();
394  CDBusMessage reply = CDBusMessage::createReply(sender, serial);
395  reply.beginArgumentWrite();
396  reply.appendArgument(code);
397  reply.appendArgument(mode);
398  reply.appendArgument(id);
399  sendDBusMessage(reply);
400  });
401  }
402  else if (message.getMethodName() == "getOwnAircraftLights")
403  {
404  queueDBusCall([=]() {
405  const bool beaconLightsOn = m_beaconLightsOn.get();
406  const bool landingLightsOn = m_landingLightsOn.get();
407  const bool navLightsOn = m_navLightsOn.get();
408  const bool strobeLightsOn = m_strobeLightsOn.get();
409  const bool taxiLightsOn = m_taxiLightsOn.get();
410  CDBusMessage reply = CDBusMessage::createReply(sender, serial);
411  reply.beginArgumentWrite();
412  reply.appendArgument(beaconLightsOn);
413  reply.appendArgument(landingLightsOn);
414  reply.appendArgument(navLightsOn);
415  reply.appendArgument(strobeLightsOn);
416  reply.appendArgument(taxiLightsOn);
417  sendDBusMessage(reply);
418  });
419  }
420  else if (message.getMethodName() == "getOwnAircraftParts")
421  {
422  queueDBusCall([=]() {
423  const double flapsReployRatio = m_flapsReployRatio.get();
424  const double gearReployRatio = m_gearReployRatio.getAt(0);
425  const double speedBrakeRatio = m_speedBrakeRatio.get();
426  const std::vector<double> enginesN1Percentage = this->getEngineN1Percentage();
427  CDBusMessage reply = CDBusMessage::createReply(sender, serial);
428  reply.beginArgumentWrite();
429  reply.appendArgument(flapsReployRatio);
430  reply.appendArgument(gearReployRatio);
431  reply.appendArgument(speedBrakeRatio);
432  reply.appendArgument(enginesN1Percentage);
433  sendDBusMessage(reply);
434  });
435  }
436  else if (message.getMethodName() == "getOwnAircraftModelData")
437  {
438  queueDBusCall([=]() {
439  const std::string aircraftModelPath = this->getAircraftModelPath();
440  const std::string aircraftIcaoCode = this->getAircraftIcaoCode();
441  CDBusMessage reply = CDBusMessage::createReply(sender, serial);
442  reply.beginArgumentWrite();
443  reply.appendArgument(aircraftModelPath);
444  reply.appendArgument(aircraftIcaoCode);
445  sendDBusMessage(reply);
446  });
447  }
448  else if (message.getMethodName() == "getAircraftModelPath")
449  {
450  queueDBusCall([=]() { sendDBusReply(sender, serial, getAircraftModelPath()); });
451  }
452  else if (message.getMethodName() == "getAircraftModelFilename")
453  {
454  queueDBusCall([=]() { sendDBusReply(sender, serial, getAircraftModelFilename()); });
455  }
456  else if (message.getMethodName() == "getAircraftModelString")
457  {
458  queueDBusCall([=]() { sendDBusReply(sender, serial, getAircraftModelString()); });
459  }
460  else if (message.getMethodName() == "getAircraftName")
461  {
462  queueDBusCall([=]() { sendDBusReply(sender, serial, getAircraftName()); });
463  }
464  else if (message.getMethodName() == "getAircraftLivery")
465  {
466  queueDBusCall([=]() { sendDBusReply(sender, serial, getAircraftLivery()); });
467  }
468  else if (message.getMethodName() == "getAircraftIcaoCode")
469  {
470  queueDBusCall([=]() { sendDBusReply(sender, serial, getAircraftIcaoCode()); });
471  }
472  else if (message.getMethodName() == "getAircraftDescription")
473  {
474  queueDBusCall([=]() { sendDBusReply(sender, serial, getAircraftDescription()); });
475  }
476  else if (message.getMethodName() == "getXPlaneVersionMajor")
477  {
478  queueDBusCall([=]() { sendDBusReply(sender, serial, getXPlaneVersionMajor()); });
479  }
480  else if (message.getMethodName() == "getXPlaneVersionMinor")
481  {
482  queueDBusCall([=]() { sendDBusReply(sender, serial, getXPlaneVersionMinor()); });
483  }
484  else if (message.getMethodName() == "getXPlaneInstallationPath")
485  {
486  queueDBusCall([=]() { sendDBusReply(sender, serial, getXPlaneInstallationPath()); });
487  }
488  else if (message.getMethodName() == "getXPlanePreferencesPath")
489  {
490  queueDBusCall([=]() { sendDBusReply(sender, serial, getXPlanePreferencesPath()); });
491  }
492  else if (message.getMethodName() == "isPaused")
493  {
494  queueDBusCall([=]() { sendDBusReply(sender, serial, isPaused()); });
495  }
496  else if (message.getMethodName() == "isUsingRealTime")
497  {
498  queueDBusCall([=]() { sendDBusReply(sender, serial, isUsingRealTime()); });
499  }
500  else if (message.getMethodName() == "getFrameStats")
501  {
502  queueDBusCall([=]() {
503  const auto stats = getFrameStats();
504  CDBusMessage reply = CDBusMessage::createReply(sender, serial);
505  reply.beginArgumentWrite();
506  reply.appendArgument(std::get<0>(stats));
507  reply.appendArgument(std::get<1>(stats));
508  reply.appendArgument(std::get<2>(stats));
509  reply.appendArgument(std::get<3>(stats));
510  sendDBusMessage(reply);
511  });
512  }
513  else if (message.getMethodName() == "resetFrameTotals")
514  {
515  maybeSendEmptyDBusReply(wantsReply, sender, serial);
516  queueDBusCall([=]() { resetFrameTotals(); });
517  }
518  else if (message.getMethodName() == "setFlightNetworkConnected")
519  {
520  maybeSendEmptyDBusReply(wantsReply, sender, serial);
521  bool connected = false;
522  message.beginArgumentRead();
523  message.getArgument(connected);
524  queueDBusCall([=]() { setFlightNetworkConnected(connected); });
525  }
526  else if (message.getMethodName() == "setOwnCallsign")
527  {
528  maybeSendEmptyDBusReply(wantsReply, sender, serial);
529  std::string callsign;
530  message.beginArgumentRead();
531  message.getArgument(callsign);
532  queueDBusCall([=]() { setOwnCallsign(callsign); });
533  }
534  else if (message.getMethodName() == "getLatitudeDeg")
535  {
536  queueDBusCall([=]() { sendDBusReply(sender, serial, getLatitudeDeg()); });
537  }
538  else if (message.getMethodName() == "getLongitudeDeg")
539  {
540  queueDBusCall([=]() { sendDBusReply(sender, serial, getLongitudeDeg()); });
541  }
542  else if (message.getMethodName() == "getAltitudeMslM")
543  {
544  queueDBusCall([=]() { sendDBusReply(sender, serial, getAltitudeMslM()); });
545  }
546  else if (message.getMethodName() == "getPressureAltitudeFt")
547  {
548  queueDBusCall([=]() { sendDBusReply(sender, serial, getPressureAltitudeFt()); });
549  }
550  else if (message.getMethodName() == "getHeightAglM")
551  {
552  queueDBusCall([=]() { sendDBusReply(sender, serial, getHeightAglM()); });
553  }
554  else if (message.getMethodName() == "getGroundSpeedMps")
555  {
556  queueDBusCall([=]() { sendDBusReply(sender, serial, getGroundSpeedMps()); });
557  }
558  else if (message.getMethodName() == "getIndicatedAirspeedKias")
559  {
560  queueDBusCall([=]() { sendDBusReply(sender, serial, getIndicatedAirspeedKias()); });
561  }
562  else if (message.getMethodName() == "getTrueAirspeedKias")
563  {
564  queueDBusCall([=]() { sendDBusReply(sender, serial, getTrueAirspeedKias()); });
565  }
566  else if (message.getMethodName() == "getPitchDeg")
567  {
568  queueDBusCall([=]() { sendDBusReply(sender, serial, getPitchDeg()); });
569  }
570  else if (message.getMethodName() == "getRollDeg")
571  {
572  queueDBusCall([=]() { sendDBusReply(sender, serial, getRollDeg()); });
573  }
574  else if (message.getMethodName() == "getTrueHeadingDeg")
575  {
576  queueDBusCall([=]() { sendDBusReply(sender, serial, getTrueHeadingDeg()); });
577  }
578  else if (message.getMethodName() == "getLocalXVelocityXMps")
579  {
580  queueDBusCall([=]() { sendDBusReply(sender, serial, getLocalXVelocityMps()); });
581  }
582  else if (message.getMethodName() == "getLocalYVelocityYMps")
583  {
584  queueDBusCall([=]() { sendDBusReply(sender, serial, getLocalYVelocityMps()); });
585  }
586  else if (message.getMethodName() == "getLocalZVelocityZMps")
587  {
588  queueDBusCall([=]() { sendDBusReply(sender, serial, getLocalZVelocityMps()); });
589  }
590  else if (message.getMethodName() == "getPitchRadPerSec")
591  {
592  queueDBusCall([=]() { sendDBusReply(sender, serial, getPitchRadPerSec()); });
593  }
594  else if (message.getMethodName() == "getRollRadPerSec")
595  {
596  queueDBusCall([=]() { sendDBusReply(sender, serial, getRollRadPerSec()); });
597  }
598  else if (message.getMethodName() == "getHeadingRadPerSec")
599  {
600  queueDBusCall([=]() { sendDBusReply(sender, serial, getHeadingRadPerSec()); });
601  }
602  else if (message.getMethodName() == "getAnyWheelOnGround")
603  {
604  queueDBusCall([=]() { sendDBusReply(sender, serial, getAnyWheelOnGround()); });
605  }
606  else if (message.getMethodName() == "getAllWheelsOnGround")
607  {
608  queueDBusCall([=]() { sendDBusReply(sender, serial, getAllWheelsOnGround()); });
609  }
610  else if (message.getMethodName() == "getGroundElevation")
611  {
612  queueDBusCall([=]() { sendDBusReply(sender, serial, getGroundElevation()); });
613  }
614  else if (message.getMethodName() == "getCom1ActiveKhz")
615  {
616  queueDBusCall([=]() { sendDBusReply(sender, serial, getCom1ActiveKhz()); });
617  }
618  else if (message.getMethodName() == "getCom1StandbyKhz")
619  {
620  queueDBusCall([=]() { sendDBusReply(sender, serial, getCom1StandbyKhz()); });
621  }
622  else if (message.getMethodName() == "getCom2ActiveKhz")
623  {
624  queueDBusCall([=]() { sendDBusReply(sender, serial, getCom2ActiveKhz()); });
625  }
626  else if (message.getMethodName() == "getCom2StandbyKhz")
627  {
628  queueDBusCall([=]() { sendDBusReply(sender, serial, getCom2StandbyKhz()); });
629  }
630  else if (message.getMethodName() == "isCom1Receiving")
631  {
632  queueDBusCall([=]() { sendDBusReply(sender, serial, isCom1Receiving()); });
633  }
634  else if (message.getMethodName() == "isCom1Transmitting")
635  {
636  queueDBusCall([=]() { sendDBusReply(sender, serial, isCom1Transmitting()); });
637  }
638  else if (message.getMethodName() == "getCom1Volume")
639  {
640  queueDBusCall([=]() { sendDBusReply(sender, serial, getCom1Volume()); });
641  }
642  else if (message.getMethodName() == "isCom2Receiving")
643  {
644  queueDBusCall([=]() { sendDBusReply(sender, serial, isCom2Receiving()); });
645  }
646  else if (message.getMethodName() == "isCom2Transmitting")
647  {
648  queueDBusCall([=]() { sendDBusReply(sender, serial, isCom2Transmitting()); });
649  }
650  else if (message.getMethodName() == "getCom2Volume")
651  {
652  queueDBusCall([=]() { sendDBusReply(sender, serial, getCom2Volume()); });
653  }
654  else if (message.getMethodName() == "getTransponderCode")
655  {
656  queueDBusCall([=]() { sendDBusReply(sender, serial, getTransponderCode()); });
657  }
658  else if (message.getMethodName() == "getTransponderMode")
659  {
660  queueDBusCall([=]() { sendDBusReply(sender, serial, getTransponderMode()); });
661  }
662  else if (message.getMethodName() == "getTransponderIdent")
663  {
664  queueDBusCall([=]() { sendDBusReply(sender, serial, getTransponderIdent()); });
665  }
666  else if (message.getMethodName() == "getBeaconLightsOn")
667  {
668  queueDBusCall([=]() { sendDBusReply(sender, serial, getBeaconLightsOn()); });
669  }
670  else if (message.getMethodName() == "getLandingLightsOn")
671  {
672  queueDBusCall([=]() { sendDBusReply(sender, serial, getLandingLightsOn()); });
673  }
674  else if (message.getMethodName() == "getTaxiLightsOn")
675  {
676  queueDBusCall([=]() { sendDBusReply(sender, serial, getTaxiLightsOn()); });
677  }
678  else if (message.getMethodName() == "getNavLightsOn")
679  {
680  queueDBusCall([=]() { sendDBusReply(sender, serial, getNavLightsOn()); });
681  }
682  else if (message.getMethodName() == "getStrobeLightsOn")
683  {
684  queueDBusCall([=]() { sendDBusReply(sender, serial, getStrobeLightsOn()); });
685  }
686  else if (message.getMethodName() == "getQNHInHg")
687  {
688  queueDBusCall([=]() { sendDBusReply(sender, serial, getQNHInHg()); });
689  }
690  else if (message.getMethodName() == "setCom1ActiveKhz")
691  {
692  maybeSendEmptyDBusReply(wantsReply, sender, serial);
693  int frequency = 0;
694  message.beginArgumentRead();
695  message.getArgument(frequency);
696  queueDBusCall([=]() { setCom1ActiveKhz(frequency); });
697  }
698  else if (message.getMethodName() == "setCom1StandbyKhz")
699  {
700  maybeSendEmptyDBusReply(wantsReply, sender, serial);
701  int frequency = 0;
702  message.beginArgumentRead();
703  message.getArgument(frequency);
704  queueDBusCall([=]() { setCom1StandbyKhz(frequency); });
705  }
706  else if (message.getMethodName() == "setCom2ActiveKhz")
707  {
708  maybeSendEmptyDBusReply(wantsReply, sender, serial);
709  int frequency = 0;
710  message.beginArgumentRead();
711  message.getArgument(frequency);
712  queueDBusCall([=]() { setCom2ActiveKhz(frequency); });
713  }
714  else if (message.getMethodName() == "setCom2StandbyKhz")
715  {
716  maybeSendEmptyDBusReply(wantsReply, sender, serial);
717  int frequency = 0;
718  message.beginArgumentRead();
719  message.getArgument(frequency);
720  queueDBusCall([=]() { setCom2StandbyKhz(frequency); });
721  }
722  else if (message.getMethodName() == "setTransponderCode")
723  {
724  maybeSendEmptyDBusReply(wantsReply, sender, serial);
725  int code = 0;
726  message.beginArgumentRead();
727  message.getArgument(code);
728  queueDBusCall([=]() { setTransponderCode(code); });
729  }
730  else if (message.getMethodName() == "setTransponderMode")
731  {
732  maybeSendEmptyDBusReply(wantsReply, sender, serial);
733  int mode = 0;
734  message.beginArgumentRead();
735  message.getArgument(mode);
736  queueDBusCall([=]() { setTransponderMode(mode); });
737  }
738  else if (message.getMethodName() == "getFlapsDeployRatio")
739  {
740  queueDBusCall([=]() { sendDBusReply(sender, serial, getFlapsDeployRatio()); });
741  }
742  else if (message.getMethodName() == "getGearDeployRatio")
743  {
744  queueDBusCall([=]() { sendDBusReply(sender, serial, getGearDeployRatio()); });
745  }
746  else if (message.getMethodName() == "getNumberOfEngines")
747  {
748  queueDBusCall([=]() { sendDBusReply(sender, serial, getNumberOfEngines()); });
749  }
750  else if (message.getMethodName() == "getEngineN1Percentage")
751  {
752  queueDBusCall([=]() {
753  const std::vector<double> enginesN1Percentage = getEngineN1Percentage();
754  sendDBusReply(sender, serial, enginesN1Percentage);
755  });
756  }
757  else if (message.getMethodName() == "getSpeedBrakeRatio")
758  {
759  queueDBusCall([=]() { sendDBusReply(sender, serial, getSpeedBrakeRatio()); });
760  }
761  else if (message.getMethodName() == "getSettingsJson")
762  {
763  queueDBusCall([=]() { sendDBusReply(sender, serial, getSettingsJson()); });
764  }
765  else if (message.getMethodName() == "setSettingsJson")
766  {
767  maybeSendEmptyDBusReply(wantsReply, sender, serial);
768  std::string json;
769  message.beginArgumentRead();
770  message.getArgument(json);
771  queueDBusCall([=]() { setSettingsJson(json); });
772  }
773  else
774  {
775  // Unknown message. Tell DBus that we cannot handle it
776  return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
777  }
778  }
779  return DBUS_HANDLER_RESULT_HANDLED;
780  }
781 
783  {
784  if (m_sceneryIsLoading.get() != m_sceneryWasLoading)
785  {
786  if (!m_sceneryIsLoading.get()) { onSceneryLoaded(); }
787  m_sceneryWasLoading = m_sceneryIsLoading.get();
788  }
789 
791 
792  if (m_disappearMessageWindowTime != std::chrono::system_clock::time_point() &&
793  std::chrono::system_clock::now() > m_disappearMessageWindowTime && m_messages.isVisible())
794  {
795  m_messages.toggle();
796  m_disappearMessageWindowTime = std::chrono::system_clock::time_point();
797  }
798 
799  return 1;
800  }
801 
802  void CService::emitAircraftModelChanged(const std::string &path, const std::string &filename,
803  const std::string &livery, const std::string &icao,
804  const std::string &modelString, const std::string &name,
805  const std::string &description)
806  {
807  CDBusMessage signalAircraftModelChanged = CDBusMessage::createSignal(
808  XSWIFTBUS_SERVICE_OBJECTPATH, XSWIFTBUS_SERVICE_INTERFACENAME, "aircraftModelChanged");
809  signalAircraftModelChanged.beginArgumentWrite();
810  signalAircraftModelChanged.appendArgument(path);
811  signalAircraftModelChanged.appendArgument(filename);
812  signalAircraftModelChanged.appendArgument(livery);
813  signalAircraftModelChanged.appendArgument(icao);
814  signalAircraftModelChanged.appendArgument(modelString);
815  signalAircraftModelChanged.appendArgument(name);
816  signalAircraftModelChanged.appendArgument(description);
817  sendDBusMessage(signalAircraftModelChanged);
818  }
819 
820  void CService::emitSceneryLoaded()
821  {
822  CDBusMessage signal =
823  CDBusMessage::createSignal(XSWIFTBUS_SERVICE_OBJECTPATH, XSWIFTBUS_SERVICE_INTERFACENAME, "sceneryLoaded");
824  sendDBusMessage(signal);
825  }
826 
827  void CService::updateMessageBoxFromSettings()
828  {
829  // left, top, right, bottom, height size percentage
830  const std::vector<int> values = this->getSettings().getMessageBoxValuesVector();
831  if (values.size() >= 6)
832  {
833  m_messages.setValues(values[0], values[1], values[2], values[3], values[4], values[5]);
834  this->setDisappearMessageWindowTimeMs(values[5]);
835  }
836  }
837 } // 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:272
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:782
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: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