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