swift
Loading...
Searching...
No Matches
serializer.cpp
1// SPDX-FileCopyrightText: Copyright (C) 2019 swift Project Community / Contributors
2// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
3
5
8#include "misc/logmessage.h"
9#include "misc/verify.h"
10
11using namespace swift::config;
12using namespace swift::misc;
13using namespace swift::misc::aviation;
14using namespace swift::misc::network;
15
16namespace swift::core::fsd
17{
19
20 namespace Private
21 {
22 // log each issue only once
23 static QStringList s_invalidAtcRatings;
24 static QStringList s_invalidPilotRatings;
25 static QStringList s_invalidSimType;
26 static QStringList s_invalidFacilityType;
27 static QStringList s_invalidQueryType;
28
30 void logUnknownType(const QString &message)
31 {
33 {
34 // developers should record these types and EXPLICITLY exclude them
35 const QByteArray msg = message.toLatin1();
36 SWIFT_VERIFY_X(false, Q_FUNC_INFO, msg);
37 }
38
39 CLogMessage(CLogCategories::fsd()).info(u"%1. Please report this to the DEVELOPERS!") << message;
40 }
41 } // namespace Private
42
43 template <>
44 QString toQString(const AtcRating &value)
45 {
46 switch (value)
47 {
48 case AtcRating::Unknown: return "0";
49 case AtcRating::Observer: return "1";
50 case AtcRating::Student: return "2";
51 case AtcRating::Student2: return "3";
52 case AtcRating::Student3: return "4";
53 case AtcRating::Controller1: return "5";
54 case AtcRating::Controller2: return "6";
55 case AtcRating::Controller3: return "7";
56 case AtcRating::Instructor1: return "8";
57 case AtcRating::Instructor2: return "9";
58 case AtcRating::Instructor3: return "10";
59 case AtcRating::Supervisor: return "11";
60 case AtcRating::Administrator: return "12";
61 }
62
63 Q_UNREACHABLE();
64 return "0";
65 }
66
67 template <>
68 AtcRating fromQString(const QString &str)
69 {
70 // empty string intentionally ignored, also for UNIT test and 3rd parth networks
71 if (str.isEmpty()) return AtcRating::Unknown;
72
73 // valid types
74 if (str == "1")
76 else if (str == "2")
77 return AtcRating::Student;
78 else if (str == "3")
80 else if (str == "4")
82 else if (str == "5")
84 else if (str == "6")
86 else if (str == "7")
88 else if (str == "8")
90 else if (str == "9")
92 else if (str == "10")
94 else if (str == "11")
96 else if (str == "12")
98
99 // we should NOT get here
100 if (!Private::s_invalidAtcRatings.contains(str))
101 {
102 Private::s_invalidAtcRatings.push_back(str);
103 const QString msg = QStringLiteral("FSD unknown ATC rating '%1'").arg(str);
104 Private::logUnknownType(msg);
105 }
106 return AtcRating::Unknown;
107 }
108
109 template <>
110 QString toQString(const PilotRating &value)
111 {
112 switch (value)
113 {
114 case PilotRating::Unknown: return "0";
115 case PilotRating::Student: return "1";
116 case PilotRating::VFR: return "2";
117 case PilotRating::IFR: return "3";
118 case PilotRating::Instructor: return "4";
119 case PilotRating::Supervisor: return "5";
120 }
121
122 Q_UNREACHABLE();
123 return "0";
124 }
125
126 template <>
127 PilotRating fromQString(const QString &str)
128 {
129 // empty string intentionally ignored, also for UNIT test and 3rd parth networks
130 if (str.isEmpty()) return PilotRating::Unknown;
131
132 // valid types
133 if (str == "0")
135 else if (str == "1")
137 else if (str == "2")
138 return PilotRating::VFR;
139 else if (str == "3")
140 return PilotRating::IFR;
141 else if (str == "4")
143 else if (str == "5")
145
146 // we should NOT get here
147 if (!Private::s_invalidPilotRatings.contains(str))
148 {
149 Private::s_invalidPilotRatings.push_back(str);
150 const QString msg = QStringLiteral("FSD Unknown Pilot rating '%1'").arg(str);
151 Private::logUnknownType(msg);
152 }
154 }
155
156 template <>
157 QString toQString(const SimType &value)
158 {
159 switch (value)
160 {
161 case SimType::Unknown: return "0";
162 case SimType::MSFS95: return "1";
163 case SimType::MSFS98: return "2";
164 case SimType::MSCFS: return "3";
165 case SimType::MSFS2000: return "4";
166 case SimType::MSCFS2: return "5";
167 case SimType::MSFS2002: return "6";
168 case SimType::MSCFS3: return "7";
169 case SimType::MSFS2004: return "8";
170 case SimType::MSFSX: return "9";
171 case SimType::MSFS: return "10";
172 case SimType::MSFS2024: return "11";
173 case SimType::XPLANE8: return "12";
174 case SimType::XPLANE9: return "13";
175 case SimType::XPLANE10: return "14";
176 case SimType::XPLANE11: return "16";
177 case SimType::FlightGear: return "25";
178 case SimType::P3Dv1: return "30";
179 case SimType::P3Dv2: return "30";
180 case SimType::P3Dv3: return "30";
181 case SimType::P3Dv4: return "30";
182
183 // future versions
185 case SimType::P3Dv5: return "0";
186 }
187
188 Q_UNREACHABLE();
189 return "0";
190 }
191
192 template <>
193 SimType fromQString(const QString &str)
194 {
195 // empty string intentionally ignored, also for UNIT test and 3rd parth networks
196 if (str.isEmpty()) return SimType::Unknown;
197
198 // valid types
199 if (str == "0")
200 return SimType::Unknown;
201 else if (str == "1")
202 return SimType::MSFS95;
203 else if (str == "2")
204 return SimType::MSFS98;
205 else if (str == "3")
206 return SimType::MSCFS;
207 else if (str == "4")
208 return SimType::MSFS2000;
209 else if (str == "5")
210 return SimType::MSCFS2;
211 else if (str == "6")
212 return SimType::MSFS2002;
213 else if (str == "7")
214 return SimType::MSCFS3;
215 else if (str == "8")
216 return SimType::MSFS2004;
217 else if (str == "9")
218 return SimType::MSFSX;
219 else if (str == "10")
220 return SimType::MSFS;
221 else if (str == "11")
222 return SimType::MSFS2024;
223 else if (str == "12")
224 return SimType::XPLANE8;
225 else if (str == "13")
226 return SimType::XPLANE9;
227 else if (str == "14")
228 return SimType::XPLANE10;
229 else if (str == "16")
230 return SimType::XPLANE11;
231 else if (str == "25")
232 return SimType::FlightGear;
233 // Still ambigious which P3D version. No standard defined yet.
234 else if (str == "30")
235 return SimType::P3Dv4;
236
237 // we should NOT get here
238 if (!Private::s_invalidSimType.contains(str))
239 {
240 Private::s_invalidSimType.push_back(str);
241 const QString msg = QStringLiteral("FSD unknown SimType '%1'").arg(str);
242 Private::logUnknownType(msg);
243 }
244 return SimType::Unknown;
245 }
246
247 template <>
248 QString toQString(const CFacilityType &value)
249 {
250 switch (value.getFacilityType())
251 {
252 case CFacilityType::OBS: return "0";
253 case CFacilityType::FSS: return "1";
254 case CFacilityType::DEL: return "2";
255 case CFacilityType::GND: return "3";
256 case CFacilityType::TWR: return "4";
257 case CFacilityType::APP: return "5";
258 case CFacilityType::CTR: return "6";
259 case CFacilityType::Unknown: return {};
260 }
261
262 Q_UNREACHABLE();
263 return {};
264 }
265
266 template <>
267 CFacilityType fromQString(const QString &str)
268 {
269 // empty string intentionally ignored, also for UNIT test and 3rd parth networks
270 if (str.isEmpty()) return CFacilityType::Unknown;
271
272 if (str == "0") return CFacilityType::OBS;
273 if (str == "1")
274 return CFacilityType::FSS;
275 else if (str == "2")
276 return CFacilityType::DEL;
277 else if (str == "3")
278 return CFacilityType::GND;
279 else if (str == "4")
280 return CFacilityType::TWR;
281 else if (str == "5")
282 return CFacilityType::APP;
283 else if (str == "6")
284 return CFacilityType::CTR;
285
286 // we should NOT get here
287 if (!Private::s_invalidFacilityType.contains(str))
288 {
289 Private::s_invalidFacilityType.push_back(str);
290 const QString msg = QStringLiteral("FSD unknown CFacilityType '%1'");
291 Private::logUnknownType(msg);
292 }
293
295 }
296
297 template <>
298 QString toQString(const ClientQueryType &value)
299 {
300 switch (value)
301 {
302 case ClientQueryType::IsValidATC: return "ATC";
303 case ClientQueryType::Capabilities: return "CAPS";
304 case ClientQueryType::Com1Freq: return "C?";
305 case ClientQueryType::RealName: return "RN";
306 case ClientQueryType::Server: return "SV";
307 case ClientQueryType::ATIS: return "ATIS";
308 case ClientQueryType::PublicIP: return "IP";
309 case ClientQueryType::INF: return "INF";
310 case ClientQueryType::FP: return "FP";
311 case ClientQueryType::AircraftConfig: return "ACC";
312 case ClientQueryType::EuroscopeSimData: return "SIMDATA";
313 case ClientQueryType::Unknown: return "Unknown query type";
314 }
315
316 Q_UNREACHABLE();
317 return "Unknown query type";
318 }
319
320 template <>
321 ClientQueryType fromQString(const QString &str)
322 {
323 // empty string intentionally ignored, also for UNIT test, 3rd party networks
324 if (str.isEmpty()) return ClientQueryType::Unknown;
325
326 // valid queries
327 // second part of a $CQ:, e.g. $CQ:DI, $CQ:ATC
328 if (str == "ATC") return ClientQueryType::IsValidATC;
329 if (str == "CAPS") return ClientQueryType::Capabilities;
330 if (str == "C?") return ClientQueryType::Com1Freq;
331 if (str == "RN") return ClientQueryType::RealName;
332 if (str == "SV") return ClientQueryType::Server;
333 if (str == "ATIS") return ClientQueryType::ATIS;
334 if (str == "IP") return ClientQueryType::PublicIP;
335 if (str == "INF") return ClientQueryType::INF;
336 if (str == "FP") return ClientQueryType::FP;
337 if (str == "ACC") return ClientQueryType::AircraftConfig;
338
339 // intentionally ignored (ATC ONLY)
340 // discussion: https://discordapp.com/channels/539048679160676382/539925070550794240/669186795790925848
341 if (str == "BC") return ClientQueryType::Unknown;
342 if (str == "BY") return ClientQueryType::Unknown; // CCP_Break
343 if (str == "DI") return ClientQueryType::Unknown; // CCP_ASRC_DI
344 if (str == "DP") return ClientQueryType::Unknown; // CCP_PushToDepartureList
345 if (str == "DR") return ClientQueryType::Unknown; // CCP_DropTrack
346 if (str == "FA") return ClientQueryType::Unknown;
347 if (str == "HC") return ClientQueryType::Unknown; // CCP_HandoffCancelled
348 if (str == "HI") return ClientQueryType::Unknown; // CCP_NoBreak
349 if (str == "HT") return ClientQueryType::Unknown; // CCP_HandoffTo
350 if (str == "ID") return ClientQueryType::Unknown; // CCP_ASRC_ID
351 if (str == "IH") return ClientQueryType::Unknown; // CCP_IHave
352 if (str == "IT") return ClientQueryType::Unknown; // CCP_StartTrack
353 if (str == "PT") return ClientQueryType::Unknown; // CCP_Pointout
354 if (str == "SC") return ClientQueryType::Unknown;
355 if (str == "ST") return ClientQueryType::Unknown; // CCP_PushStrip
356 if (str == "TA") return ClientQueryType::Unknown;
357 if (str == "VT") return ClientQueryType::Unknown;
358 if (str == "VER") return ClientQueryType::Unknown; // CCP_Version
359 if (str == "WH") return ClientQueryType::Unknown; // CCP_WhoHas
360 // -- help
361 if (str == "HLP") return ClientQueryType::Unknown; // CCP_HelpOn
362 if (str == "NOHLP") return ClientQueryType::Unknown; // CCP_HelpOff
363
364 // Query types from customized FSD servers
365 if (str == "NEWATIS") return ClientQueryType::Unknown;
366 if (str == "NEWINFO") return ClientQueryType::Unknown; // probably causing the Linux crash
367
368 // we should NOT get here
369 if (!Private::s_invalidQueryType.contains(str))
370 {
371 Private::s_invalidQueryType.push_back(str);
372 const QString msg = QStringLiteral("FSD unknown ClientQueryType '%1'").arg(str);
373 Private::logUnknownType(msg);
374 }
375
377 }
378
379 template <>
380 QString toQString(const FlightType &value)
381 {
382 switch (value)
383 {
384 case FlightType::IFR: return "I";
385 case FlightType::VFR: return "V";
386 case FlightType::SVFR: return "S";
387 case FlightType::DVFR: return "D";
388 }
389
390 Q_UNREACHABLE();
391 return {};
392 }
393
394 template <>
395 FlightType fromQString(const QString &str)
396 {
397 if (str == QLatin1String("I"))
398 return FlightType::IFR;
399 else if (str == QLatin1String("V"))
400 return FlightType::VFR;
401 else if (str == QLatin1String("S"))
402 return FlightType::SVFR;
403 else if (str == QLatin1String("D"))
404 return FlightType::DVFR;
405
406 return FlightType::IFR;
407 }
408
409 template <>
410 QString toQString(const CTransponder::TransponderMode &value)
411 {
412 switch (value)
413 {
414 case CTransponder::StateStandby: return QStringLiteral("S");
415 case CTransponder::ModeMil1:
416 case CTransponder::ModeMil2:
417 case CTransponder::ModeMil3:
418 case CTransponder::ModeMil4:
420 case CTransponder::ModeA:
421 case CTransponder::ModeC:
422 case CTransponder::ModeS: return QStringLiteral("N");
423 case CTransponder::StateIdent: return QStringLiteral("Y");
424 }
425
426 Q_UNREACHABLE();
427 return QStringLiteral("S");
428 }
429
430 template <>
431 CTransponder::TransponderMode fromQString(const QString &str)
432 {
433 if (str == "S")
435 else if (str == "N")
436 return CTransponder::ModeC;
437 else if (str == "Y")
439
441 }
442
443 template <>
444 QString toQString(const Capabilities &value)
445 {
446 switch (value)
447 {
448 case Capabilities::None: return {};
449 case Capabilities::AtcInfo: return "ATCINFO";
450 case Capabilities::SecondaryPos: return "SECPOS";
451 case Capabilities::AircraftInfo: return "MODELDESC";
452 case Capabilities::OngoingCoord: return "ONGOINGCOORD";
453 case Capabilities::InterminPos: return "INTERIMPOS";
454 case Capabilities::VisPos: return "VISUPDATE";
455 case Capabilities::FastPos: return "FASTPOS";
456 case Capabilities::Stealth: return "STEALTH";
457 case Capabilities::AircraftConfig: return "ACCONFIG";
458 case Capabilities::IcaoEquipment: return "ICAOEQ";
459 }
460
461 return {};
462 }
463
464 template <>
465 Capabilities fromQString(const QString &str)
466 {
467 if (str == "ATCINFO")
469 else if (str == "SECPOS")
471 else if (str == "MODELDESC")
473 else if (str == "ONGOINGCOORD")
475 else if (str == "INTERIMPOS")
477 else if (str == "FASTPOS")
479 else if (str == "VISUPDATE")
481 else if (str == "STEALTH")
483 else if (str == "ACCONFIG")
485 else if (str == "ICAOEQ")
487
488 return Capabilities::None;
489 }
490
491 template <>
492 AtisLineType fromQString(const QString &str)
493 {
494 if (str == "V")
495 return AtisLineType::VoiceRoom;
496 else if (str == "Z")
497 return AtisLineType::ZuluLogoff;
498 else if (str == "T")
499 return AtisLineType::TextMessage;
500 else if (str == "E")
501 return AtisLineType::LineCount;
502
503 return AtisLineType::Unknown;
504 }
505
507
508} // namespace swift::core::fsd
static bool isLocalDeveloperDebugBuild()
Local build for developers.
static const QString & fsd()
FSD specific.
@ StateStandby
not a real mode, more a state
Definition transponder.h:33
@ StateIdent
not a real mode, more a state
Definition transponder.h:39
FacilityType getFacilityType() const
Get type.
FlightType
Flight types.
Definition enums.h:90
@ DVFR
Defense visual Flight Rules.
Definition enums.h:94
@ IFR
IFR flight rules.
Definition enums.h:91
@ SVFR
Special visual flight rules.
Definition enums.h:93
@ VFR
Visual flight rules.
Definition enums.h:92
AtisLineType
ATIS line type.
Definition enums.h:196
SimType
Flight simulator type.
Definition enums.h:44
@ P3Dv3
Prepar3D V3.
Definition enums.h:64
@ P3Dv5
Prepar3D V5.
Definition enums.h:66
@ P3Dv2
Prepar3D V2.
Definition enums.h:63
@ P3Dv1
Prepar3D V1.
Definition enums.h:62
@ XPLANE12
X-Plane 12.
Definition enums.h:61
@ MSFS95
MS Flight Simulator 95.
Definition enums.h:46
@ P3Dv4
Prepar3D V4.
Definition enums.h:65
@ MSCFS2
MS Combat Flight Simulator 2.
Definition enums.h:50
@ MSFS2000
MS Flight Simulator 2000.
Definition enums.h:49
@ FlightGear
Flight Gear.
Definition enums.h:67
@ MSFS
MS Flight Simulator 2020.
Definition enums.h:55
@ MSFS2002
MS Flight Simulator 2002.
Definition enums.h:51
@ Unknown
Unknown simulator type.
Definition enums.h:45
@ XPLANE9
X-Plane 9.
Definition enums.h:58
@ XPLANE8
X-Plane 8.
Definition enums.h:57
@ MSFS2024
MS Flight Simulator 2024.
Definition enums.h:56
@ MSCFS
MS Combat Flight Simulator.
Definition enums.h:48
@ XPLANE11
X-Plane 11.
Definition enums.h:60
@ XPLANE10
X-Plane 10.
Definition enums.h:59
@ MSFS2004
MS Flight Simulator 2004.
Definition enums.h:53
@ MSCFS3
MS Combat Flight Simulator 3.
Definition enums.h:52
@ MSFSX
MS Flight Simulator X.
Definition enums.h:54
@ MSFS98
MS Flight Simulator 98.
Definition enums.h:47
AtcRating
ATC ratings.
Definition enums.h:15
PilotRating
Pilot ratings.
Definition enums.h:33
@ Instructor
Instructor.
Definition enums.h:38
@ Unknown
Unknown rating.
Definition enums.h:34
ClientQueryType
Client query types.
Definition enums.h:72
@ PublicIP
What is my public IP address?
Definition enums.h:80
@ FP
Send Cached Flight Plan.
Definition enums.h:82
@ ATIS
What is your ATIS?
Definition enums.h:79
@ EuroscopeSimData
Broadcast to announce we request SIMDATA packets.
Definition enums.h:84
@ Capabilities
What capabilities does this client have?
Definition enums.h:75
@ Unknown
Unknown client query type.
Definition enums.h:73
@ INF
Supervisor Privileged Information Request.
Definition enums.h:81
@ Server
What server are you on?
Definition enums.h:78
@ AircraftConfig
Aircraft Configuration.
Definition enums.h:83
@ RealName
What is your real-name (and other ATC data).
Definition enums.h:77
@ Com1Freq
What is your COM1 Frequency?
Definition enums.h:76
@ IsValidATC
Is this client working ATC or just an observer.
Definition enums.h:74
Capabilities
Client capability flags *‍/.
Definition enums.h:130
@ SecondaryPos
Can send/receive secondary visibility center points (ATC/Server only).
Definition enums.h:138
@ AtcInfo
Can accept ATIS responses.
Definition enums.h:135
@ IcaoEquipment
Process aircraft ICAO in flightplan as ICAO equipment code (e.g.
Definition enums.h:175
@ FastPos
Can send/receive fast position updates (pilot only).
Definition enums.h:163
@ OngoingCoord
Can send/receive inter-facility coordination packets (ATC only).
Definition enums.h:153
@ AircraftConfig
Aircraft Config.
Definition enums.h:172
@ VisPos
Can send/receive visual position updates (pilot only).
Definition enums.h:166
@ InterminPos
Can send/receive Interim position updates (pilot only).
Definition enums.h:160
@ AircraftInfo
Can send/receive modern model packets.
Definition enums.h:150
Free functions in swift::misc.
bool isEmpty() const const
QByteArray toLatin1() const const
#define SWIFT_VERIFY_X(COND, WHERE, WHAT)
A weaker kind of assert.
Definition verify.h:26