4 #if defined(SWIFT_USING_FSUIPC32) || defined(SWIFT_USING_FSUIPC64)
15 # ifdef SWIFT_USING_FSUIPC32
18 # include "../fsuipc32/FSUIPC_User.h"
19 # include "../fsuipc32/IPCuser.h"
20 # include "../fsuipc32/NewWeather.h"
22 # elif SWIFT_USING_FSUIPC64
25 # include "../fsuipc64/FSUIPC_User64.h"
26 # include "../fsuipc64/IPCuser64.h"
27 # include "../fsuipc64/NewWeather.h"
33 # include <QLatin1Char>
40 using namespace swift::misc::simulation::fscommon;
41 using namespace swift::misc::aviation;
42 using namespace swift::misc::network;
43 using namespace swift::misc::geo;
44 using namespace swift::misc::simulation;
45 using namespace swift::misc::physical_quantities;
47 namespace swift::simplugin::fscommon
49 CFsuipc::CFsuipc(QObject *parent) : QObject(parent) { startTimer(100); }
51 CFsuipc::~CFsuipc() { this->close(); }
53 bool CFsuipc::open(
bool force)
55 Q_ASSERT_X(CThreadUtils::isInThisThread(
this), Q_FUNC_INFO,
"Open not threadsafe");
57 m_lastErrorMessage =
"";
59 if (!force && m_opened) {
return m_opened; }
61 if (FSUIPC_Open(SIM_ANY, &dwResult))
68 const int simIndex =
static_cast<int>(FSUIPC_FS_Version);
69 const QString sim = CFsuipc::simulator(simIndex);
71 QStringLiteral(
"%1.%2.%3.%4%5")
72 .arg(QLatin1Char(48 + (0x0f & (FSUIPC_Version >> 28))))
73 .arg(QLatin1Char(48 + (0x0f & (FSUIPC_Version >> 24))))
74 .arg(QLatin1Char(48 + (0x0f & (FSUIPC_Version >> 20))))
75 .arg(QLatin1Char(48 + (0x0f & (FSUIPC_Version >> 16))))
76 .arg((FSUIPC_Version & 0xffff) ?
77 QString(QLatin1Char(
'a' +
static_cast<char>(FSUIPC_Version & 0xff) - 1)) :
79 m_fsuipcVersion = QStringLiteral(
"FSUIPC %1 (%2)").arg(ver, sim);
91 const int index =
static_cast<int>(dwResult);
92 m_lastErrorIndex = index;
93 m_lastErrorMessage = CFsuipc::errorMessages().at(index);
102 void CFsuipc::close()
104 Q_ASSERT_X(CThreadUtils::isInThisThread(
this), Q_FUNC_INFO,
"Open not threadsafe");
105 if (m_opened) {
CLogMessage(
this).
info(u
"Closing FSUIPC: %1") << m_fsuipcVersion; }
111 bool CFsuipc::isOpened()
const {
return m_opened; }
113 bool CFsuipc::isOpen()
const
115 if (!this->isOpened()) {
return false; }
119 char localFsTimeRaw[3];
120 if (FSUIPC_Read(0x0238, 3, localFsTimeRaw, &dwResult) && FSUIPC_Process(&dwResult)) {
return dwResult == 0; }
126 Q_ASSERT_X(CThreadUtils::isInThisThread(
this), Q_FUNC_INFO,
"Open not threadsafe");
127 if (!this->isOpened()) {
return false; }
131 transponderCodeRaw =
static_cast<quint16
>(CBcdConversions::dec2Bcd(transponderCodeRaw));
133 byte xpdrModeSb3Raw = xpdr.
isInStandby() ? 1U : 0U;
135 const bool ok = FSUIPC_Write(0x7b91, 1, &xpdrModeSb3Raw, &dwResult) &&
136 FSUIPC_Write(0x7b93, 1, &xpdrIdentSb3Raw, &dwResult) &&
137 FSUIPC_Write(0x0354, 2, &transponderCodeRaw, &dwResult);
138 if (ok) { FSUIPC_Process(&dwResult); }
139 return ok && dwResult == 0;
142 bool CFsuipc::setSimulatorTime(
int hour,
int minute)
144 Q_ASSERT_X(CThreadUtils::isInThisThread(
this), Q_FUNC_INFO,
"Open not threadsafe");
145 if (!this->isOpened()) {
return false; }
149 quint8 hourRaw =
static_cast<quint8
>(hour);
150 quint8 minuteRaw =
static_cast<quint8
>(minute);
152 const bool ok = FSUIPC_Write(0x023b, 1, &hourRaw, &dwResult) && FSUIPC_Write(0x023c, 1, &minuteRaw, &dwResult);
153 if (ok) { FSUIPC_Process(&dwResult); }
154 return ok && dwResult == 0;
157 QString CFsuipc::getVersion()
const {
return m_fsuipcVersion; }
159 bool CFsuipc::read(
CSimulatedAircraft &aircraft,
bool cockpit,
bool situation,
bool aircraftParts)
161 Q_ASSERT_X(CThreadUtils::isInThisThread(
this), Q_FUNC_INFO,
"Open not threadsafe");
163 char localFsTimeRaw[3];
164 char modelNameRaw[256];
165 qint16 com1ActiveRaw = 0, com2ActiveRaw = 0, com1StandbyRaw = 0, com2StandbyRaw = 0;
166 qint16 transponderCodeRaw = 0;
167 byte xpdrModeSb3Raw = 1, xpdrIdentSb3Raw = 1;
168 qint32 groundspeedRaw = 0, pitchRaw = 0, bankRaw = 0, headingRaw = 0;
169 qint64 altitudeRaw = 0;
170 double pressureAltitudeRaw = 0;
171 qint32 groundAltitudeRaw = 0;
172 qint64 latitudeRaw = 0, longitudeRaw = 0;
173 qint16 lightsRaw = 0;
174 qint16 onGroundRaw = 0;
175 qint32 flapsControlRaw = 0, gearControlRaw = 0, spoilersControlRaw = 0;
176 qint16 numberOfEngines = 0;
177 qint16 engine1CombustionFlag = 0, engine2CombustionFlag = 0, engine3CombustionFlag = 0,
178 engine4CombustionFlag = 0;
179 double velocityWorld[3];
180 double rotationVelocityBody[3];
186 if (!this->isOpened()) {
return false; }
187 if (!(aircraftParts || situation || cockpit)) {
return false; }
190 bool cockpitN = !cockpit;
191 bool situationN = !situation;
192 bool aircraftPartsN = !aircraftParts;
194 if (FSUIPC_Read(0x0238, 3, localFsTimeRaw, &dwResult) &&
197 (cockpitN || FSUIPC_Read(0x034e, 2, &com1ActiveRaw, &dwResult)) &&
198 (cockpitN || FSUIPC_Read(0x3118, 2, &com2ActiveRaw, &dwResult)) &&
199 (cockpitN || FSUIPC_Read(0x311a, 2, &com1StandbyRaw, &dwResult)) &&
200 (cockpitN || FSUIPC_Read(0x311c, 2, &com2StandbyRaw, &dwResult)) &&
201 (cockpitN || FSUIPC_Read(0x0354, 2, &transponderCodeRaw, &dwResult)) &&
204 (cockpitN || FSUIPC_Read(0x7b91, 1, &xpdrModeSb3Raw, &dwResult)) &&
205 (cockpitN || FSUIPC_Read(0x7b93, 1, &xpdrIdentSb3Raw, &dwResult)) &&
208 (situationN || FSUIPC_Read(0x02b4, 4, &groundspeedRaw, &dwResult)) &&
209 (situationN || FSUIPC_Read(0x0578, 4, &pitchRaw, &dwResult)) &&
210 (situationN || FSUIPC_Read(0x057c, 4, &bankRaw, &dwResult)) &&
211 (situationN || FSUIPC_Read(0x0580, 4, &headingRaw, &dwResult)) &&
212 (situationN || FSUIPC_Read(0x0570, 8, &altitudeRaw, &dwResult)) &&
214 (situationN || FSUIPC_Read(0x3198, 8, &velocityWorld[0], &dwResult)) &&
215 (situationN || FSUIPC_Read(0x31a0, 8, &velocityWorld[1], &dwResult)) &&
216 (situationN || FSUIPC_Read(0x3190, 8, &velocityWorld[2], &dwResult)) &&
218 (situationN || FSUIPC_Read(0x30A8, 8, &rotationVelocityBody[0], &dwResult)) &&
219 (situationN || FSUIPC_Read(0x30B0, 8, &rotationVelocityBody[1], &dwResult)) &&
220 (situationN || FSUIPC_Read(0x30B8, 8, &rotationVelocityBody[2], &dwResult)) &&
223 (situationN || FSUIPC_Read(0x0560, 8, &latitudeRaw, &dwResult)) &&
224 (situationN || FSUIPC_Read(0x0568, 8, &longitudeRaw, &dwResult)) &&
225 (situationN || FSUIPC_Read(0x0020, 4, &groundAltitudeRaw, &dwResult)) &&
226 (situationN || FSUIPC_Read(0x34B0, 8, &pressureAltitudeRaw, &dwResult)) &&
229 FSUIPC_Read(0x3d00, 256, &modelNameRaw, &dwResult) &&
232 (aircraftPartsN || FSUIPC_Read(0x0D0C, 2, &lightsRaw, &dwResult)) &&
233 (aircraftPartsN || FSUIPC_Read(0x0366, 2, &onGroundRaw, &dwResult)) &&
234 (aircraftPartsN || FSUIPC_Read(0x0BDC, 4, &flapsControlRaw, &dwResult)) &&
235 (aircraftPartsN || FSUIPC_Read(0x0BE8, 4, &gearControlRaw, &dwResult)) &&
236 (aircraftPartsN || FSUIPC_Read(0x0BD0, 4, &spoilersControlRaw, &dwResult)) &&
239 (aircraftPartsN || FSUIPC_Read(0x0AEC, 2, &numberOfEngines, &dwResult)) &&
240 (aircraftPartsN || FSUIPC_Read(0x0894, 2, &engine1CombustionFlag, &dwResult)) &&
241 (aircraftPartsN || FSUIPC_Read(0x092C, 2, &engine2CombustionFlag, &dwResult)) &&
242 (aircraftPartsN || FSUIPC_Read(0x09C4, 2, &engine3CombustionFlag, &dwResult)) &&
243 (aircraftPartsN || FSUIPC_Read(0x0A5C, 2, &engine4CombustionFlag, &dwResult)) &&
246 FSUIPC_Process(&dwResult))
258 com1ActiveRaw =
static_cast<short>(10000 + CBcdConversions::bcd2Dec(com1ActiveRaw));
259 com2ActiveRaw =
static_cast<short>(10000 + CBcdConversions::bcd2Dec(com2ActiveRaw));
260 com1StandbyRaw =
static_cast<short>(10000 + CBcdConversions::bcd2Dec(com1StandbyRaw));
261 com2StandbyRaw =
static_cast<short>(10000 + CBcdConversions::bcd2Dec(com2StandbyRaw));
267 transponderCodeRaw =
static_cast<qint16
>(CBcdConversions::bcd2Dec(transponderCodeRaw));
271 xpdr.
setTransponderMode(xpdrModeSb3Raw == 0 ? CTransponder::ModeC : CTransponder::StateStandby);
272 if (xpdrIdentSb3Raw != 0)
283 const double latCorrectionFactor = 90.0 / (10001750.0 * 65536.0 * 65536.0);
284 const double lonCorrectionFactor = 360.0 / (65536.0 * 65536.0 * 65536.0 * 65536.0);
287 CLatitude lat(latitudeRaw * latCorrectionFactor, CAngleUnit::deg());
288 CLongitude lon(longitudeRaw * lonCorrectionFactor, CAngleUnit::deg());
289 CAltitude groundAltitude(groundAltitudeRaw / 256.0, CAltitude::MeanSeaLevel, CLengthUnit::m());
295 const double angleCorrectionFactor = 360.0 / 65536.0 / 65536.0;
296 pitchRaw = qRound(std::floor(pitchRaw * angleCorrectionFactor));
297 bankRaw = qRound(std::floor(bankRaw * angleCorrectionFactor));
300 pitchRaw = ~pitchRaw;
302 if (pitchRaw < -90 || pitchRaw > 89)
310 CHeading heading =
CHeading(headingRaw * angleCorrectionFactor, CHeading::True, CAngleUnit::deg());
311 CSpeed groundspeed(groundspeedRaw / 65536.0, CSpeedUnit::m_s());
312 CAltitude altitude(altitudeRaw / (65536.0 * 65536.0), CAltitude::MeanSeaLevel, CLengthUnit::m());
313 CAltitude pressureAltitude(pressureAltitudeRaw, CAltitude::MeanSeaLevel, CAltitude::PressureAltitude,
321 situation.
setVelocity({ velocityWorld[0], velocityWorld[1], velocityWorld[2], CSpeedUnit::ft_s(),
322 rotationVelocityBody[0], rotationVelocityBody[1], rotationVelocityBody[2],
323 CAngleUnit::rad(), CTimeUnit::s() });
330 const QString modelName = QString(modelNameRaw);
335 const CAircraftLights lights(lightsRaw & (1 << 4), lightsRaw & (1 << 2), lightsRaw & (1 << 3),
336 lightsRaw & (1 << 1), lightsRaw & (1 << 0), lightsRaw & (1 << 8));
338 const QList<bool> helperList { engine1CombustionFlag != 0, engine2CombustionFlag != 0,
339 engine3CombustionFlag != 0, engine4CombustionFlag != 0 };
342 for (
int index = 0; index < numberOfEngines; ++index)
347 CAircraftParts parts(lights, gearControlRaw == 16383, flapsControlRaw * 100 / 16383,
348 spoilersControlRaw == 16383, engines, onGroundRaw == 1);
354 const int result =
static_cast<int>(dwResult);
355 if (m_lastErrorIndex != result && result > 0)
357 m_lastErrorIndex = result;
358 m_lastErrorMessage = CFsuipc::errorMessage(result);
364 double CFsuipc::intToFractional(
double fractional)
366 const double f = fractional / 10.0;
367 if (f < 1.0) {
return f; }
368 return intToFractional(f);
Class for emitting a log message.
Derived & warning(const char16_t(&format)[N])
Set the severity to warning, providing a format string.
Derived & info(const char16_t(&format)[N])
Set the severity to info, providing a format string.
void push_back(const T &value)
Appends an element at the end of the sequence.
Value object encapsulating information about aircraft's engines.
Value object encapsulating a list of aircraft engines.
Value object encapsulating information about aircraft's lights.
Value object encapsulating information of aircraft's parts.
Value object encapsulating information of an aircraft's situation.
void setPressureAltitude(const CAltitude &altitude)
Set pressure altitude.
void setGroundSpeed(const physical_quantities::CSpeed &groundspeed)
Set ground speed.
bool setGroundElevation(const aviation::CAltitude &altitude, GndElevationInfo info, bool transferred=false)
Elevation of the ground directly beneath at the given situation.
void setBank(const physical_quantities::CAngle &bank)
Set bank (angle)
void setHeading(const CHeading &heading)
Set heading.
void setAltitude(const CAltitude &altitude)
Set altitude.
void setPitch(const physical_quantities::CAngle &pitch)
Set pitch.
void setVelocity(const CAircraftVelocity &velocity)
Set 6DOF velocity.
const geo::CCoordinateGeodetic & getPosition() const
Get position.
void setPosition(const geo::CCoordinateGeodetic &position)
Set position.
Altitude as used in aviation, can be AGL or MSL altitude.
void setFrequencyActiveMHz(double frequencyMHz)
Set active frequency.
void setFrequencyStandbyMHz(double frequencyMHz)
Set standby frequency.
Heading as used in aviation, can be true or magnetic heading.
bool isIdentifying() const
Standby?
bool isInStandby() const
Standby?
void setTransponderCode(int transponderCode)
Set transponder code.
int getTransponderCode() const
Transponder code.
bool setTransponderMode(TransponderMode mode)
Set transponder mode.
void setLatitude(const CLatitude &latitude)
Set latitude.
void setGeodeticHeight(const aviation::CAltitude &height)
Set height (ellipsoidal or geodetic height)
void setLongitude(const CLongitude &longitude)
Set longitude.
Physical unit angle (radians, degrees)
Comprehensive information of an aircraft.
const aviation::CAircraftSituation & getSituation() const
Get situation.
void setCockpit(const CSimulatedAircraft &aircraft)
Set COM unit (all values + transponder and SELCAL)
const aviation::CComSystem & getCom2System() const
Get COM2 system.
const aviation::CTransponder & getTransponder() const
Get transponder.
void setModelString(const QString &modelString)
Set model string.
void setSituation(const aviation::CAircraftSituation &situation)
Set situation. Won't overwrite the velocity unless it held the default value.
void setParts(const aviation::CAircraftParts &parts)
Set aircraft parts.
const aviation::CComSystem & getCom1System() const
Get COM1 system.
Free functions in swift::misc.
unsigned long DWORD
Fake Windows DWORD.