feat: Add ICAO equipment code classes

This commit is contained in:
Lars Toenning
2023-12-19 11:34:34 +01:00
parent 1f4f60d793
commit cdd4690adf
10 changed files with 1326 additions and 0 deletions

View File

@@ -71,10 +71,14 @@ add_library(misc SHARED
aviation/callsignobjectlist.h aviation/callsignobjectlist.h
aviation/callsignset.cpp aviation/callsignset.cpp
aviation/callsignset.h aviation/callsignset.h
aviation/comnavequipment.cpp
aviation/comnavequipment.h
aviation/comsystem.cpp aviation/comsystem.cpp
aviation/comsystem.h aviation/comsystem.h
aviation/flightplan.cpp aviation/flightplan.cpp
aviation/flightplan.h aviation/flightplan.h
aviation/flightplanaircraftinfo.cpp
aviation/flightplanaircraftinfo.h
aviation/flightplanlist.cpp aviation/flightplanlist.cpp
aviation/flightplanlist.h aviation/flightplanlist.h
aviation/heading.cpp aviation/heading.cpp
@@ -95,6 +99,8 @@ add_library(misc SHARED
aviation/selcal.h aviation/selcal.h
aviation/simbriefdata.cpp aviation/simbriefdata.cpp
aviation/simbriefdata.h aviation/simbriefdata.h
aviation/ssrequipment.cpp
aviation/ssrequipment.h
aviation/track.cpp aviation/track.cpp
aviation/track.h aviation/track.h
aviation/transponder.cpp aviation/transponder.cpp

View File

@@ -0,0 +1,212 @@
// SPDX-FileCopyrightText: Copyright (C) swift Project Community / Contributors
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
#include "comnavequipment.h"
BLACK_DEFINE_VALUEOBJECT_MIXINS(BlackMisc::Aviation, CComNavEquipment)
namespace BlackMisc::Aviation
{
CComNavEquipment::CComNavEquipment(ComNavEquipment comNavEquipment, CpdlcSatcomEquipment cpdlcSatcomEquipment) : m_equipment(comNavEquipment), m_cpdlcSatcomEquipment(cpdlcSatcomEquipment)
{
if (m_equipment == ComNavEquipment())
{
m_equipment = NoEquip;
}
}
CComNavEquipment::CComNavEquipment(QString equipment)
{
if (equipment.isEmpty())
{
return;
}
m_equipment = {}; // Clear default flag
auto append_equipment_flag_if_exist = [&equipment, this](ComNavEquipmentOption flag) {
QString str = flagToString(flag);
if (equipment.contains(str))
{
equipment = equipment.remove(str);
m_equipment |= flag;
}
};
auto append_satcom_flag_if_exist = [&equipment, this](CpdlcSatcomEquipmentOption flag) {
QString str = flagToString(flag);
if (equipment.contains(str))
{
equipment = equipment.remove(str);
m_cpdlcSatcomEquipment |= flag;
}
};
append_equipment_flag_if_exist(Standard);
append_equipment_flag_if_exist(Gbas);
append_equipment_flag_if_exist(Lpv);
append_equipment_flag_if_exist(LoranC);
append_equipment_flag_if_exist(Dme);
append_equipment_flag_if_exist(FmcAcars);
append_equipment_flag_if_exist(DFisAcars);
append_equipment_flag_if_exist(PdcAcars);
append_equipment_flag_if_exist(Adf);
append_equipment_flag_if_exist(Gnss);
append_equipment_flag_if_exist(HfRtf);
append_equipment_flag_if_exist(InertiaNavigation);
append_equipment_flag_if_exist(Mls);
append_equipment_flag_if_exist(Ils);
append_equipment_flag_if_exist(NoEquip);
append_equipment_flag_if_exist(Vor);
append_equipment_flag_if_exist(Pbn);
append_equipment_flag_if_exist(Tacan);
append_equipment_flag_if_exist(UhfRtf);
append_equipment_flag_if_exist(VhfRtf);
append_equipment_flag_if_exist(Rvsm);
append_equipment_flag_if_exist(Mnps);
append_equipment_flag_if_exist(Vhf833);
append_equipment_flag_if_exist(Other);
append_satcom_flag_if_exist(CpdlcAtn);
append_satcom_flag_if_exist(CpdlcFansHfdl);
append_satcom_flag_if_exist(CpdlcFansVdlA);
append_satcom_flag_if_exist(CpdlcFansVdl2);
append_satcom_flag_if_exist(CpdlcFansSatcomInmarsat);
append_satcom_flag_if_exist(CpdlcFansSatcomMtsat);
append_satcom_flag_if_exist(CpdlcFansSatcomIridium);
append_satcom_flag_if_exist(AtcSatvoiceInmarsat);
append_satcom_flag_if_exist(AtcSatvoiceMtsat);
append_satcom_flag_if_exist(AtcSatvoiceIridium);
append_satcom_flag_if_exist(CpdlcRcp400);
append_satcom_flag_if_exist(CpdlcRcp240);
append_satcom_flag_if_exist(SatvoiceRcp400);
if (!equipment.isEmpty() && m_equipment == ComNavEquipment())
{
// Default if nothing correct is provided
m_equipment = NoEquip;
m_cpdlcSatcomEquipment = {};
}
}
QStringList CComNavEquipment::enabledOptions() const
{
QStringList list;
auto append_equipment_flag_if_exist = [&list, this](ComNavEquipmentOption flag) {
if (m_equipment.testFlag(flag)) list << flagToString(flag);
};
auto append_satcom_flag_if_exist = [&list, this](CpdlcSatcomEquipmentOption flag) {
if (m_cpdlcSatcomEquipment.testFlag(flag)) list << flagToString(flag);
};
append_equipment_flag_if_exist(Standard);
append_equipment_flag_if_exist(Gbas);
append_equipment_flag_if_exist(Lpv);
append_equipment_flag_if_exist(LoranC);
append_equipment_flag_if_exist(Dme);
append_equipment_flag_if_exist(FmcAcars);
append_equipment_flag_if_exist(DFisAcars);
append_equipment_flag_if_exist(PdcAcars);
append_equipment_flag_if_exist(Adf);
append_equipment_flag_if_exist(Gnss);
append_equipment_flag_if_exist(HfRtf);
append_equipment_flag_if_exist(InertiaNavigation);
append_satcom_flag_if_exist(CpdlcAtn);
append_satcom_flag_if_exist(CpdlcFansHfdl);
append_satcom_flag_if_exist(CpdlcFansVdlA);
append_satcom_flag_if_exist(CpdlcFansVdl2);
append_satcom_flag_if_exist(CpdlcFansSatcomInmarsat);
append_satcom_flag_if_exist(CpdlcFansSatcomMtsat);
append_satcom_flag_if_exist(CpdlcFansSatcomIridium);
append_equipment_flag_if_exist(Mls);
append_equipment_flag_if_exist(Ils);
append_satcom_flag_if_exist(AtcSatvoiceInmarsat);
append_satcom_flag_if_exist(AtcSatvoiceMtsat);
append_satcom_flag_if_exist(AtcSatvoiceIridium);
append_equipment_flag_if_exist(NoEquip);
append_equipment_flag_if_exist(Vor);
append_satcom_flag_if_exist(CpdlcRcp400);
append_satcom_flag_if_exist(CpdlcRcp240);
append_satcom_flag_if_exist(SatvoiceRcp400);
append_equipment_flag_if_exist(Pbn);
append_equipment_flag_if_exist(Tacan);
append_equipment_flag_if_exist(UhfRtf);
append_equipment_flag_if_exist(VhfRtf);
append_equipment_flag_if_exist(Rvsm);
append_equipment_flag_if_exist(Mnps);
append_equipment_flag_if_exist(Vhf833);
append_equipment_flag_if_exist(Other);
return list;
}
QString CComNavEquipment::convertToQString(bool) const
{
const QString equipmentString = enabledOptions().join("");
Q_ASSERT_X(!equipmentString.isEmpty(), Q_FUNC_INFO, "Equipment string should not be empty");
return equipmentString;
}
QString CComNavEquipment::flagToString(CpdlcSatcomEquipmentOption flag)
{
switch (flag)
{
case CpdlcAtn: return QStringLiteral("J1");
case CpdlcFansHfdl: return QStringLiteral("J2");
case CpdlcFansVdlA: return QStringLiteral("J3");
case CpdlcFansVdl2: return QStringLiteral("J4");
case CpdlcFansSatcomInmarsat: return QStringLiteral("J5");
case CpdlcFansSatcomMtsat: return QStringLiteral("J6");
case CpdlcFansSatcomIridium: return QStringLiteral("J7");
case AtcSatvoiceInmarsat: return QStringLiteral("M1");
case AtcSatvoiceMtsat: return QStringLiteral("M2");
case AtcSatvoiceIridium: return QStringLiteral("M3");
case CpdlcRcp400: return QStringLiteral("P1");
case CpdlcRcp240: return QStringLiteral("P2");
case SatvoiceRcp400: return QStringLiteral("P3");
default: return {};
}
}
QString CComNavEquipment::flagToString(ComNavEquipmentOption flag)
{
switch (flag)
{
case Standard: return QStringLiteral("S");
case Gbas: return QStringLiteral("A");
case Lpv: return QStringLiteral("B");
case LoranC: return QStringLiteral("C");
case Dme: return QStringLiteral("D");
case FmcAcars: return QStringLiteral("E1");
case DFisAcars: return QStringLiteral("E2");
case PdcAcars: return QStringLiteral("E3");
case Adf: return QStringLiteral("F");
case Gnss: return QStringLiteral("G");
case HfRtf: return QStringLiteral("H");
case InertiaNavigation: return QStringLiteral("I");
case Mls: return QStringLiteral("K");
case Ils: return QStringLiteral("L");
case NoEquip: return QStringLiteral("N");
case Vor: return QStringLiteral("O");
case Pbn: return QStringLiteral("R");
case Tacan: return QStringLiteral("T");
case UhfRtf: return QStringLiteral("U");
case VhfRtf: return QStringLiteral("V");
case Rvsm: return QStringLiteral("W");
case Mnps: return QStringLiteral("X");
case Vhf833: return QStringLiteral("Y");
case Other: return QStringLiteral("Z");
default: return {};
}
}
QStringList CComNavEquipment::allEquipmentLetters()
{
// In order as they appear in the final string
static const QStringList r({ "S", "A", "B", "C", "D", "E1", "E2", "E3", "F", "G", "H", "I", "J1", "J2", "J3", "J4", "J5", "J6", "J7", "K", "L", "M1", "M2", "M3",
"N", "O", "P1", "P2", "P3", "R", "T", "U", "V", "W", "X", "Y", "Z" });
return r;
}
}

View File

@@ -0,0 +1,116 @@
// SPDX-FileCopyrightText: Copyright (C) swift Project Community / Contributors
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
#ifndef BLACKMISC_AVIATION_COMNAVEQUIPMENT_H
#define BLACKMISC_AVIATION_COMNAVEQUIPMENT_H
#include "blackmisc/blackmiscexport.h"
#include "blackmisc/valueobject.h"
BLACK_DECLARE_VALUEOBJECT_MIXINS(BlackMisc::Aviation, CComNavEquipment)
namespace BlackMisc::Aviation
{
//! ICAO flightplan field 10a
class BLACKMISC_EXPORT CComNavEquipment : public BlackMisc::CValueObject<CComNavEquipment>
{
public:
// QFlag uses int as an underlying type. Hence, the equipment is split up into two enums.
// Once Qt adds a QFlag64, these can be united.
// See https://bugreports.qt.io/browse/QTBUG-53178
//! CPLDC and SATCOM equipment options
enum CpdlcSatcomEquipmentOption : int
{
CpdlcAtn = (1 << 0),
CpdlcFansHfdl = (1 << 1),
CpdlcFansVdlA = (1 << 2),
CpdlcFansVdl2 = (1 << 3),
CpdlcFansSatcomInmarsat = (1 << 4),
CpdlcFansSatcomMtsat = (1 << 5),
CpdlcFansSatcomIridium = (1 << 6),
AtcSatvoiceInmarsat = (1 << 7),
AtcSatvoiceMtsat = (1 << 8),
AtcSatvoiceIridium = (1 << 9),
CpdlcRcp400 = (1 << 10),
CpdlcRcp240 = (1 << 11),
SatvoiceRcp400 = (1 << 12),
};
//! COM/NAV equipment options
enum ComNavEquipmentOption : int
{
Standard = (1 << 0),
Gbas = (1 << 1),
Lpv = (1 << 2),
LoranC = (1 << 3),
Dme = (1 << 4),
FmcAcars = (1 << 5),
DFisAcars = (1 << 6),
PdcAcars = (1 << 7),
Adf = (1 << 8),
Gnss = (1 << 9),
HfRtf = (1 << 10),
InertiaNavigation = (1 << 11),
Mls = (1 << 12),
Ils = (1 << 13),
NoEquip = (1 << 14),
Vor = (1 << 15),
Pbn = (1 << 16),
Tacan = (1 << 17),
UhfRtf = (1 << 18),
VhfRtf = (1 << 19),
Rvsm = (1 << 20),
Mnps = (1 << 21),
Vhf833 = (1 << 22),
Other = (1 << 23)
};
Q_DECLARE_FLAGS(ComNavEquipment, ComNavEquipmentOption);
Q_DECLARE_FLAGS(CpdlcSatcomEquipment, CpdlcSatcomEquipmentOption);
//! Create default equipment with Standard COM/NAV
CComNavEquipment() = default;
//! Create object with given COM/NAV, CPDLC and SATCOM equipment
CComNavEquipment(ComNavEquipment comNavEquipment, CpdlcSatcomEquipment cpdlcSatcomEquipment);
//! Create object from an ICAO equipment string (for example "SDE2E3FGHIJ1RWXY")
explicit CComNavEquipment(QString equipment);
//! Get all possible equipment code letters
static QStringList allEquipmentLetters();
//! @{
//! Does this object contains \p equip?
bool hasEquipment(ComNavEquipmentOption equip) const { return m_equipment.testFlag(equip); }
bool hasEquipment(CpdlcSatcomEquipmentOption equip) const { return m_cpdlcSatcomEquipment.testFlag(equip); }
//! @}
//! Get all enabled equipment codes of this object as a list
QStringList enabledOptions() const;
//! Get the equipment string of this object (for example "SDE2E3FGHIJ1RWXY")
QString convertToQString(bool i18n = false) const;
private:
//! @{
//! Get the string for the specific equipment
static QString flagToString(CpdlcSatcomEquipmentOption flag);
static QString flagToString(ComNavEquipmentOption flag);
//! @}
ComNavEquipment m_equipment = Standard;
CpdlcSatcomEquipment m_cpdlcSatcomEquipment;
BLACK_METACLASS(
CComNavEquipment,
BLACK_METAMEMBER(equipment),
BLACK_METAMEMBER(cpdlcSatcomEquipment)
);
};
}
Q_DECLARE_METATYPE(BlackMisc::Aviation::CComNavEquipment)
#endif // BLACKMISC_AVIATION_COMNAVEQUIPMENT_H

View File

@@ -0,0 +1,388 @@
// SPDX-FileCopyrightText: Copyright (C) swift Project Community / Contributors
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
#include "flightplanaircraftinfo.h"
BLACK_DEFINE_VALUEOBJECT_MIXINS(BlackMisc::Aviation, CFlightPlanAircraftInfo)
namespace BlackMisc::Aviation
{
CFlightPlanAircraftInfo::CFlightPlanAircraftInfo(const CAircraftIcaoCode &aircraftIcao, const CComNavEquipment &comNavEquipment,
const CSsrEquipment &ssrEquipment, const CWakeTurbulenceCategory &wtc) : m_aircraftIcao(aircraftIcao),
m_comNavEquipment(comNavEquipment),
m_ssrEquipment(ssrEquipment),
m_wtc(wtc) {}
CFlightPlanAircraftInfo::CFlightPlanAircraftInfo(QString equipmentCodeAndAircraft)
{
equipmentCodeAndAircraft = equipmentCodeAndAircraft.trimmed().toUpper().replace(" ", "");
const int numberSlash = equipmentCodeAndAircraft.count("/");
const int numberHypen = equipmentCodeAndAircraft.count("-");
if (numberHypen == 1 && numberSlash == 2)
{
parseIcaoEquipmentCode(equipmentCodeAndAircraft);
}
else if (numberSlash >= 1 && numberSlash <= 2 && numberHypen == 0)
{
parseFaaEquipmentCode(equipmentCodeAndAircraft);
}
else
{
parseUnknownEquipmentCode(equipmentCodeAndAircraft);
}
}
QString CFlightPlanAircraftInfo::asIcaoString() const
{
// Avoid returning empty wake turbulence categories and send it to the server.
// This can in particular happen when translating from FAA codes to ICAO codes.
// This sets a default wake turbulence category of MEDIUM if the category is unknown otherwise.
QChar wtc;
if (!m_wtc.isUnknown())
{
wtc = m_wtc.toQString().at(0);
}
else
{
wtc = CWakeTurbulenceCategory(CWakeTurbulenceCategory::MEDIUM).toQString().at(0);
}
return m_aircraftIcao.getDesignator() % "/" % wtc % "-" % m_comNavEquipment.toQString() % "/" % m_ssrEquipment.toQString();
}
QString CFlightPlanAircraftInfo::asFaaString() const
{
// TCAS prefix (T/) is not used
QString s;
if (m_wtc.isCategory(CWakeTurbulenceCategory::HEAVY))
{
s = "H/";
}
else if (m_wtc.isCategory(CWakeTurbulenceCategory::SUPER))
{
s = "J/";
}
s += m_aircraftIcao.getDesignator() % "/" % equipmentToFaaCode(m_comNavEquipment, m_ssrEquipment);
return s;
}
CAircraftIcaoCode CFlightPlanAircraftInfo::getAircraftIcao() const
{
return m_aircraftIcao;
}
CComNavEquipment CFlightPlanAircraftInfo::getComNavEquipment() const
{
return m_comNavEquipment;
}
CSsrEquipment CFlightPlanAircraftInfo::getSsrEquipment() const
{
return m_ssrEquipment;
}
CWakeTurbulenceCategory CFlightPlanAircraftInfo::getWtc() const
{
return m_wtc;
}
QString CFlightPlanAircraftInfo::convertToQString(bool) const
{
return asIcaoString();
}
void CFlightPlanAircraftInfo::parseIcaoEquipmentCode(const QString &equipment)
{
// Example: B789/H-SDE1E2E3FGHIJ2J3J4J5M1RWXY/LB1D1
QStringList firstSplit = equipment.split("/");
Q_ASSERT_X(firstSplit.size() == 3, Q_FUNC_INFO, "Cannot split string as required for the ICAO format");
if (!CAircraftIcaoCode::isValidDesignator(firstSplit[0]) || firstSplit[1].isEmpty() || firstSplit[2].isEmpty())
{
return; // Invalid equipment code, leave everything default initialized
}
m_aircraftIcao = CAircraftIcaoCode(firstSplit[0]);
try
{
m_ssrEquipment = CSsrEquipment(firstSplit[2]);
}
catch (const std::invalid_argument &)
{
m_ssrEquipment = CSsrEquipment();
}
QStringList secondSplit = firstSplit[1].split("-");
if (secondSplit.size() != 2)
{
return; // Invalid code, leave everything else default initialized
}
if (!secondSplit[0].isEmpty())
{
try
{
// if the wake turbulence category incorrectly contains more than one letter
// just take the first letter
m_wtc = CWakeTurbulenceCategory(secondSplit[0].at(0));
}
catch (std::invalid_argument &)
{
m_wtc = CWakeTurbulenceCategory();
}
}
else
{
m_wtc = CWakeTurbulenceCategory();
}
try
{
m_comNavEquipment = CComNavEquipment(secondSplit[1]);
}
catch (std::runtime_error &)
{
m_comNavEquipment = CComNavEquipment();
}
}
void CFlightPlanAircraftInfo::parseFaaEquipmentCode(const QString &equipment)
{
// Example: H/A346/L
QStringList split = equipment.split('/');
Q_ASSERT_X(split.size() == 2 || split.size() == 3, Q_FUNC_INFO, "Cannot split string as required for the FAA format");
bool missingEquipmentCode = false;
if (CAircraftIcaoCode::isValidDesignator(split.at(split.size() - 2)))
{
m_aircraftIcao = CAircraftIcaoCode(split.at(split.size() - 2));
}
else if (CAircraftIcaoCode::isValidDesignator(split.at(split.size() - 1)))
{
// the equipment code is missing (like J/A388)
m_aircraftIcao = CAircraftIcaoCode(split.at(split.size() - 1));
missingEquipmentCode = true;
}
else
{
m_aircraftIcao = CAircraftIcaoCode();
}
// Check prefix (wake turbulence category)
if (split.length() == 3)
{
const QString &prefix = split.at(0);
if (prefix == "H" || prefix == "J")
{
m_wtc = CWakeTurbulenceCategory(prefix.at(0));
}
}
else if (split.length() == 2 && split.at(0).size() == 1)
{
// the equipment code is missing (like J/A388)
m_wtc = CWakeTurbulenceCategory(split.at(0).at(0));
missingEquipmentCode = true;
}
else
{
m_wtc = CWakeTurbulenceCategory();
}
// Equipment Code
if (missingEquipmentCode || split.at(split.size() - 1).isEmpty())
{
return; // No (empty) equipment code
}
// Always taking the first character. If the code contains more than one character, this is likely an error, but we will try it anyway
QChar equipmentCode = split.at(split.size() - 1).at(0);
auto [comNavEquipment, ssrEquipment] = faaCodeToEquipment(equipmentCode);
m_comNavEquipment = comNavEquipment;
m_ssrEquipment = ssrEquipment;
}
void CFlightPlanAircraftInfo::parseUnknownEquipmentCode(const QString &equipment)
{
// likely one part only
QStringList split = equipment.split("/");
if (split[0].length() > 1 && CAircraftIcaoCode::isValidDesignator(split[0]))
{
// only ICAO
m_aircraftIcao = split[0];
}
else
{
// something invalid. Keep default initialized
}
}
std::tuple<CComNavEquipment, CSsrEquipment> CFlightPlanAircraftInfo::faaCodeToEquipment(QChar equipmentCode)
{
CComNavEquipment equip;
CSsrEquipment ssr;
// COM/NAV equipment
if (equipmentCode == 'H' || equipmentCode == 'O' || equipmentCode == 'W')
{
equip = CComNavEquipment({ CComNavEquipment::Rvsm }, {});
}
else if (equipmentCode == 'Z')
{
// PBN might not be the correct translation for "RNAV" but we use it to differentiate the codes
equip = CComNavEquipment({ CComNavEquipment::Rvsm | CComNavEquipment::Pbn }, {});
}
else if (equipmentCode == 'L')
{
equip = CComNavEquipment({ CComNavEquipment::Rvsm | CComNavEquipment::Gnss }, {});
}
else if (equipmentCode == 'X' || equipmentCode == 'T' || equipmentCode == 'U')
{
equip = CComNavEquipment({}, {});
}
else if (equipmentCode == 'D' || equipmentCode == 'B' || equipmentCode == 'A')
{
equip = CComNavEquipment({ CComNavEquipment::Dme }, {});
}
else if (equipmentCode == 'M' || equipmentCode == 'N' || equipmentCode == 'P')
{
equip = CComNavEquipment({ CComNavEquipment::Tacan }, {});
}
else if (equipmentCode == 'Y' || equipmentCode == 'C' || equipmentCode == 'I')
{
// PBN might not be the correct translation for "RNAV" but we use it to differentiate the codes
equip = CComNavEquipment({ CComNavEquipment::Pbn }, {});
}
else if (equipmentCode == 'V' || equipmentCode == 'S' || equipmentCode == 'G')
{
equip = CComNavEquipment({ CComNavEquipment::Gnss }, {});
}
// SSR equipment
if (equipmentCode == 'W' || equipmentCode == 'Z' || equipmentCode == 'L' || equipmentCode == 'U' ||
equipmentCode == 'A' || equipmentCode == 'P' || equipmentCode == 'I' || equipmentCode == 'G')
{
ssr = CSsrEquipment::SSrEquipment { CSsrEquipment::ModeAC };
}
else if (equipmentCode == 'H' || equipmentCode == 'O' || equipmentCode == 'X' || equipmentCode == 'D' ||
equipmentCode == 'M' || equipmentCode == 'Y' || equipmentCode == 'V')
{
// "O" corresponds to a failed Mode C transponder.
// The ICAO format does not contain a separate code for a failed Mode C transponder
ssr = CSsrEquipment::SSrEquipment { CSsrEquipment::None };
}
else if (equipmentCode == 'T' || equipmentCode == 'B' || equipmentCode == 'N' || equipmentCode == 'C' ||
equipmentCode == 'S')
{
// The ICAO format does not contain a separate code for a general NONE Mode C transponder. We use Mode A instead.
ssr = CSsrEquipment::SSrEquipment { CSsrEquipment::ModeA };
}
return { equip, ssr };
}
QChar CFlightPlanAircraftInfo::equipmentToFaaCode(const CComNavEquipment &equip, const CSsrEquipment &ssr)
{
if (equip.hasEquipment(CComNavEquipment::Rvsm))
{
if (ssr.hasEquipment(CSsrEquipment::None))
{
// This could also be 'O' as we cannot differentiate between a failed transponder and a failed Mode C transponder
return 'H';
}
// In the following, do not check the transponder capability, as the FAA codes only work with Mode C and not Mode S transponders
if (equip.hasEquipment(CComNavEquipment::Gnss))
{
return 'L';
}
if (equip.hasEquipment(CComNavEquipment::Pbn))
{
// PBN is used for RNAV when converting from FAA string to CFlightPlanAircraftInfo
return 'Z';
}
else
{
return 'W';
}
}
else
{
if (equip.hasEquipment(CComNavEquipment::Gnss))
{
if (ssr.hasEquipment(CSsrEquipment::None))
{
return 'V';
}
if (ssr.hasEquipment(CSsrEquipment::ModeAC))
{
return 'G';
}
else
{
return 'S';
}
}
if (equip.hasEquipment(CComNavEquipment::Tacan))
{
if (ssr.hasEquipment(CSsrEquipment::None))
{
return 'M';
}
if (ssr.hasEquipment(CSsrEquipment::ModeAC))
{
return 'P';
}
else
{
return 'N';
}
}
if (equip.hasEquipment(CComNavEquipment::Pbn))
{
// PBN is used for RNAV when converting from FAA string to CFlightPlanAircraftInfo
if (ssr.hasEquipment(CSsrEquipment::None))
{
return 'Y';
}
if (ssr.hasEquipment(CSsrEquipment::ModeAC))
{
return 'I';
}
else
{
return 'C';
}
}
if (equip.hasEquipment(CComNavEquipment::Dme))
{
if (ssr.hasEquipment(CSsrEquipment::None))
{
return 'D';
}
if (ssr.hasEquipment(CSsrEquipment::ModeAC))
{
return 'A';
}
else
{
return 'B';
}
}
// No DME
if (ssr.hasEquipment(CSsrEquipment::None))
{
return 'X';
}
if (ssr.hasEquipment(CSsrEquipment::ModeAC))
{
return 'U';
}
else
{
return 'T';
}
}
}
}

View File

@@ -0,0 +1,84 @@
// SPDX-FileCopyrightText: Copyright (C) swift Project Community / Contributors
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
#ifndef BLACKMISC_AVIATION_FLIGHTPLAN_AIRCRAFT_INFO_H
#define BLACKMISC_AVIATION_FLIGHTPLAN_AIRCRAFT_INFO_H
#include "blackmisc/blackmiscexport.h"
#include "blackmisc/valueobject.h"
#include "blackmisc/aviation/aircrafticaocode.h"
#include "blackmisc/aviation/comnavequipment.h"
#include "blackmisc/aviation/ssrequipment.h"
#include "blackmisc/aviation/waketurbulencecategory.h"
#include <QString>
BLACK_DECLARE_VALUEOBJECT_MIXINS(BlackMisc::Aviation, CFlightPlanAircraftInfo)
namespace BlackMisc::Aviation
{
//! Flightplan-related information about an aircraft (aircraft ICAO, equipment and WTC)
class BLACKMISC_EXPORT CFlightPlanAircraftInfo : public CValueObject<CFlightPlanAircraftInfo>
{
public:
CFlightPlanAircraftInfo() = default;
//! Create info from given aircraft ICAO, equipment and wake turbulence category
CFlightPlanAircraftInfo(const CAircraftIcaoCode &aircraftIcao, const CComNavEquipment &comNavEquipment,
const CSsrEquipment &ssrEquipment, const CWakeTurbulenceCategory &wtc);
//! Create aircraft info from a string that contains the 4 parts of an ICAO equipment code (AIRCRAFT_ICAO/WTC-EQUIPMENT/SSR).
//! Passing FAA equipment codes like "H/B772/F" is supported as well
explicit CFlightPlanAircraftInfo(QString equipmentCodeAndAircraft);
//! Full string in ICAO format: "AIRCRAFT_ICAO/WTC-EQUIPMENT/SSR"
QString asIcaoString() const;
//! Full string in FAA format: "H/J (if heavy/super)/AIRCRAFT_ICAO/EQUIPMENT-CODE"
QString asFaaString() const;
//! Get Aircraft ICAO
CAircraftIcaoCode getAircraftIcao() const;
//! Get COM/NAV equipment
CComNavEquipment getComNavEquipment() const;
//! Get SSR equipment
CSsrEquipment getSsrEquipment() const;
//! Get Wake Turbulence Category
CWakeTurbulenceCategory getWtc() const;
//! \copydoc BlackMisc::Mixin::String::toQString
QString convertToQString(bool i18n = false) const;
//! Transform single character FAA equipment code to ICAO-based COM/NAV and SSR equipment
static std::tuple<CComNavEquipment, CSsrEquipment> faaCodeToEquipment(QChar equipmentCode);
//! Transform ICAO-based COM/NAV and SSR equipment to a single character FAA equipment code
static QChar equipmentToFaaCode(const CComNavEquipment &equip, const CSsrEquipment &ssr);
private:
CAircraftIcaoCode m_aircraftIcao; //!< Aircraft ICAO code
CComNavEquipment m_comNavEquipment; //!< COM & NAV equipment (flight plan field 10a)
CSsrEquipment m_ssrEquipment; //!< secondary surveillance radar equipment (flight plan field 10b)
CWakeTurbulenceCategory m_wtc; //!< wake turbulence category. This information is also part of m_aircraftIcao, but is not always filled.
void parseIcaoEquipmentCode(const QString &equipment); //!< Initialize members from ICAO format equipment codes
void parseFaaEquipmentCode(const QString &equipment); //!< Initialize members from FAA format equipment codes
void parseUnknownEquipmentCode(const QString &equipment); //!< Initialize members from unknown format equipment strings (best guesses)
BLACK_METACLASS(
CFlightPlanAircraftInfo,
BLACK_METAMEMBER(aircraftIcao),
BLACK_METAMEMBER(comNavEquipment),
BLACK_METAMEMBER(ssrEquipment),
BLACK_METAMEMBER(wtc)
);
};
}
Q_DECLARE_METATYPE(BlackMisc::Aviation::CFlightPlanAircraftInfo)
#endif // BLACKMISC_AVIATION_FLIGHTPLAN_AIRCRAFT_INFO_H

View File

@@ -70,8 +70,11 @@ namespace BlackMisc
CCallsign::registerMetadata(); CCallsign::registerMetadata();
CCallsignSet::registerMetadata(); CCallsignSet::registerMetadata();
CComSystem::registerMetadata(); CComSystem::registerMetadata();
CSsrEquipment::registerMetadata();
CComNavEquipment::registerMetadata();
CWakeTurbulenceCategory::registerMetadata(); CWakeTurbulenceCategory::registerMetadata();
CFlightPlan::registerMetadata(); CFlightPlan::registerMetadata();
CFlightPlanAircraftInfo::registerMetadata();
CFlightPlanList::registerMetadata(); CFlightPlanList::registerMetadata();
CSimBriefData::registerMetadata(); CSimBriefData::registerMetadata();
CFlightPlanRemarks::registerMetadata(); CFlightPlanRemarks::registerMetadata();

View File

@@ -0,0 +1,203 @@
// SPDX-FileCopyrightText: Copyright (C) swift Project Community / Contributors
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
#include "ssrequipment.h"
BLACK_DEFINE_VALUEOBJECT_MIXINS(BlackMisc::Aviation, CSsrEquipment)
namespace BlackMisc::Aviation
{
CSsrEquipment::CSsrEquipment(SSrEquipment equipment) : m_equipment(equipment)
{
if (m_equipment == SSrEquipment())
{
m_equipment = None;
}
}
CSsrEquipment::CSsrEquipment(QString equipment)
{
if (equipment.isEmpty())
{
return;
}
m_equipment = {}; // Clear default flag
auto append_equipment_flag_if_exist = [&equipment, this](SsrEquipmentOption flag) {
QString str = flagToString(flag);
if (equipment.contains(str))
{
equipment = equipment.remove(str);
m_equipment |= flag;
}
};
append_equipment_flag_if_exist(None);
append_equipment_flag_if_exist(ModeA);
append_equipment_flag_if_exist(ModeAC);
append_equipment_flag_if_exist(ModeSTypeE);
append_equipment_flag_if_exist(ModeSTypeH);
append_equipment_flag_if_exist(ModeSTypeI);
append_equipment_flag_if_exist(ModeSTypeL);
append_equipment_flag_if_exist(ModeSTypeX);
append_equipment_flag_if_exist(ModeSTypeP);
append_equipment_flag_if_exist(ModeSTypeS);
append_equipment_flag_if_exist(AdsBB1);
append_equipment_flag_if_exist(AdsBB2);
append_equipment_flag_if_exist(AdsBU1);
append_equipment_flag_if_exist(AdsBU2);
append_equipment_flag_if_exist(AdsBV1);
append_equipment_flag_if_exist(AdsBV2);
append_equipment_flag_if_exist(AdsCD1);
append_equipment_flag_if_exist(AdsCG1);
if (!equipment.isEmpty() && m_equipment == SSrEquipment())
{
// Default if nothing correct is provided
m_equipment = None;
}
}
QStringList CSsrEquipment::enabledOptions() const
{
QStringList list;
// Append flag (as string) to list if flag exists in current equipment
auto append_flag_if_exist = [&list, this](SsrEquipmentOption flag) {
if (m_equipment.testFlag(flag)) list << flagToString(flag);
};
append_flag_if_exist(None);
append_flag_if_exist(ModeA);
append_flag_if_exist(ModeAC);
append_flag_if_exist(ModeSTypeE);
append_flag_if_exist(ModeSTypeH);
append_flag_if_exist(ModeSTypeI);
append_flag_if_exist(ModeSTypeL);
append_flag_if_exist(ModeSTypeX);
append_flag_if_exist(ModeSTypeP);
append_flag_if_exist(ModeSTypeS);
append_flag_if_exist(AdsBB1);
append_flag_if_exist(AdsBB2);
append_flag_if_exist(AdsBU1);
append_flag_if_exist(AdsBU2);
append_flag_if_exist(AdsBV1);
append_flag_if_exist(AdsBV2);
append_flag_if_exist(AdsCD1);
append_flag_if_exist(AdsCG1);
return list;
}
QString CSsrEquipment::convertToQString(bool) const
{
const QString equipmentString = enabledOptions().join("");
Q_ASSERT_X(!equipmentString.isEmpty(), Q_FUNC_INFO, "Equipment string should not be empty");
return equipmentString;
}
QString CSsrEquipment::flagToString(CSsrEquipment::SSrEquipment flag)
{
if (flag == None)
{
static const QString q("N");
return q;
}
if (flag == ModeA)
{
static const QString q("A");
return q;
}
if (flag == ModeAC)
{
static const QString q("C");
return q;
}
if (flag == ModeSTypeE)
{
static const QString q("E");
return q;
}
if (flag == ModeSTypeH)
{
static const QString q("H");
return q;
}
if (flag == ModeSTypeI)
{
static const QString q("I");
return q;
}
if (flag == ModeSTypeL)
{
static const QString q("L");
return q;
}
if (flag == ModeSTypeX)
{
static const QString q("X");
return q;
}
if (flag == ModeSTypeP)
{
static const QString q("P");
return q;
}
if (flag == ModeSTypeS)
{
static const QString q("S");
return q;
}
if (flag == AdsBB1)
{
static const QString q("B1");
return q;
}
if (flag == AdsBB2)
{
static const QString q("B2");
return q;
}
if (flag == AdsBU1)
{
static const QString q("U1");
return q;
}
if (flag == AdsBU2)
{
static const QString q("U2");
return q;
}
if (flag == AdsBV1)
{
static const QString q("V1");
return q;
}
if (flag == AdsBV2)
{
static const QString q("V2");
return q;
}
if (flag == AdsCD1)
{
static const QString q("D1");
return q;
}
if (flag == AdsCG1)
{
static const QString q("G1");
return q;
}
return {};
}
QStringList CSsrEquipment::allEquipmentLetters()
{
// In order as they appear in the final string
static const QStringList r({ "N", "A", "C", "E", "H", "I", "L", "X", "P", "S", "B1", "B2", "U1", "U2", "V1", "V2", "D1", "G1" });
return r;
}
}

View File

@@ -0,0 +1,79 @@
// SPDX-FileCopyrightText: Copyright (C) swift Project Community / Contributors
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
#ifndef BLACKMISC_AVIATION_SSREQUIPMENT_H
#define BLACKMISC_AVIATION_SSREQUIPMENT_H
#include "blackmisc/blackmiscexport.h"
#include "blackmisc/valueobject.h"
BLACK_DECLARE_VALUEOBJECT_MIXINS(BlackMisc::Aviation, CSsrEquipment)
namespace BlackMisc::Aviation
{
//! ICAO flightplan field 10b
class BLACKMISC_EXPORT CSsrEquipment : public BlackMisc::CValueObject<CSsrEquipment>
{
public:
enum SsrEquipmentOption : int
{
None = (1 << 0),
ModeA = (1 << 1),
ModeAC = (1 << 2),
ModeSTypeE = (1 << 3),
ModeSTypeH = (1 << 4),
ModeSTypeI = (1 << 5),
ModeSTypeL = (1 << 6),
ModeSTypeX = (1 << 7),
ModeSTypeP = (1 << 8),
ModeSTypeS = (1 << 9),
AdsBB1 = (1 << 10),
AdsBB2 = (1 << 11),
AdsBU1 = (1 << 12),
AdsBU2 = (1 << 13),
AdsBV1 = (1 << 14),
AdsBV2 = (1 << 15),
AdsCD1 = (1 << 16),
AdsCG1 = (1 << 17)
};
Q_DECLARE_FLAGS(SSrEquipment, SsrEquipmentOption);
//! Create default SSR equipment with "None" equipment enabled
CSsrEquipment() = default;
//! Create object with given equipment
CSsrEquipment(SSrEquipment equipment);
//! Create object from an ICAO SSR equipment string (for example "LB1")
explicit CSsrEquipment(QString equipment);
//! Get all possible SSR equipment code letters
static QStringList allEquipmentLetters();
//! Get all enabled SSR equipment codes of this object as a list
QStringList enabledOptions() const;
//! Get the SSR equipment string of this object (for example "LB1")
QString convertToQString(bool i18n = false) const;
//! Does this object contains \p equip?
bool hasEquipment(SsrEquipmentOption equip) const { return m_equipment.testFlag(equip); }
private:
//! Get the string for the specific SSR equipment
static QString flagToString(SSrEquipment flag);
SSrEquipment m_equipment = None;
BLACK_METACLASS(
CSsrEquipment,
BLACK_METAMEMBER(equipment)
);
};
}
Q_DECLARE_METATYPE(BlackMisc::Aviation::CSsrEquipment)
#endif // BLACKMISC_AVIATION_SSREQUIPMENT_H

View File

@@ -30,6 +30,12 @@ add_swift_test(
LINK_LIBRARIES misc tests_test Qt::Core LINK_LIBRARIES misc tests_test Qt::Core
) )
add_swift_test(
NAME misc_aviation_flightplanaircraftinfo
SOURCES aviation/testflightplan/testflightplanaircraftinfo.cpp
LINK_LIBRARIES misc tests_test Qt::Core
)
############## ##############
## Geo ## ## Geo ##
############## ##############

View File

@@ -0,0 +1,229 @@
// SPDX-FileCopyrightText: Copyright (C) swift Project Community / Contributors
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
//! \cond PRIVATE_TESTS
//! \file
//! \ingroup testblackmisc
#include "blackmisc/aviation/flightplanaircraftinfo.h"
#include "test.h"
#include <QTest>
using namespace BlackMisc::Aviation;
namespace BlackMiscTest
{
//! Flightplan unit tests
class CTestFlightPlanAircraftInfo : public QObject
{
Q_OBJECT
private slots:
//! Convert ICAO equipment code to CFlightPlanAircraftInfo and vice versa
void icaoConvert();
//! Convert FAA equipment code to CFlightPlanAircraftInfo and vice versa
void faaConvert();
//! Convert non FAA/ICAO equipment code to CFlightPlanAircraftInfo and vice versa
void nonValidConvert();
private:
struct TestEntry
{
QString m_icaoEquipment;
QString m_faaEquipment;
QString m_aircraftIcao;
CWakeTurbulenceCategory m_wtc;
CComNavEquipment m_equipment;
CSsrEquipment m_ssrEquipment;
};
QList<TestEntry> m_testEntries {
{ "B737/M-SDE2E3FGHIRWXY/LB1",
"B737/L",
"B737",
CWakeTurbulenceCategory::MEDIUM,
CComNavEquipment(CComNavEquipment::ComNavEquipment(CComNavEquipment::Standard | CComNavEquipment::Dme | CComNavEquipment::DFisAcars | CComNavEquipment::PdcAcars | CComNavEquipment::Adf | CComNavEquipment::Gnss | CComNavEquipment::HfRtf | CComNavEquipment::InertiaNavigation | CComNavEquipment::Pbn | CComNavEquipment::Rvsm | CComNavEquipment::Mnps | CComNavEquipment::Vhf833),
CComNavEquipment::CpdlcSatcomEquipment()),
CSsrEquipment::SSrEquipment(CSsrEquipment::ModeSTypeL | CSsrEquipment::AdsBB1) },
{ "B748/H-SDE3FGHIM1M2RWXY/LB1",
"H/B748/L",
"B748",
CWakeTurbulenceCategory::HEAVY,
CComNavEquipment(CComNavEquipment::ComNavEquipment(CComNavEquipment::Standard | CComNavEquipment::Dme | CComNavEquipment::PdcAcars | CComNavEquipment::Adf | CComNavEquipment::Gnss | CComNavEquipment::HfRtf | CComNavEquipment::InertiaNavigation | CComNavEquipment::Pbn | CComNavEquipment::Rvsm | CComNavEquipment::Mnps | CComNavEquipment::Vhf833),
CComNavEquipment::CpdlcSatcomEquipment(CComNavEquipment::AtcSatvoiceInmarsat | CComNavEquipment::AtcSatvoiceMtsat)),
CSsrEquipment::SSrEquipment(CSsrEquipment::ModeSTypeL | CSsrEquipment::AdsBB1) },
{ "C172/L-DGV/C",
"C172/G",
"C172",
CWakeTurbulenceCategory::LIGHT,
CComNavEquipment(CComNavEquipment::ComNavEquipment(CComNavEquipment::VhfRtf | CComNavEquipment::Gnss | CComNavEquipment::Dme),
CComNavEquipment::CpdlcSatcomEquipment()),
CSsrEquipment::SSrEquipment(CSsrEquipment::ModeAC) },
{ "A388/J-SADE2E3FGHIJ3J4J5M1RWXY/LB1D1",
"J/A388/L",
"A388",
CWakeTurbulenceCategory::SUPER,
CComNavEquipment(CComNavEquipment::ComNavEquipment(CComNavEquipment::Standard | CComNavEquipment::Gbas | CComNavEquipment::Dme | CComNavEquipment::DFisAcars | CComNavEquipment::PdcAcars | CComNavEquipment::Adf | CComNavEquipment::Gnss | CComNavEquipment::HfRtf | CComNavEquipment::InertiaNavigation | CComNavEquipment::Pbn | CComNavEquipment::Rvsm | CComNavEquipment::Mnps | CComNavEquipment::Vhf833),
CComNavEquipment::CpdlcSatcomEquipment(CComNavEquipment::CpdlcFansVdlA | CComNavEquipment::CpdlcFansVdl2 | CComNavEquipment::CpdlcFansSatcomInmarsat | CComNavEquipment::AtcSatvoiceInmarsat)),
CSsrEquipment::SSrEquipment(CSsrEquipment::ModeSTypeL | CSsrEquipment::AdsBB1 | CSsrEquipment::AdsCD1) }
};
};
void CTestFlightPlanAircraftInfo::icaoConvert()
{
for (const TestEntry &entry : m_testEntries)
{
CFlightPlanAircraftInfo info(entry.m_icaoEquipment);
QVERIFY2(info.getAircraftIcao().hasDesignator(), "Should have designator");
QVERIFY2(info.getAircraftIcao().getDesignator() == entry.m_aircraftIcao, "Should have same aircraft ICAO code");
QCOMPARE(info.getWtc(), entry.m_wtc);
QCOMPARE(info.getComNavEquipment(), entry.m_equipment);
QCOMPARE(info.getSsrEquipment(), entry.m_ssrEquipment);
QCOMPARE(info.asIcaoString(), entry.m_icaoEquipment);
}
}
void CTestFlightPlanAircraftInfo::faaConvert()
{
for (const TestEntry &entry : m_testEntries)
{
CFlightPlanAircraftInfo info(entry.m_faaEquipment);
QVERIFY2(info.getAircraftIcao().hasDesignator(), "Should have designator");
QCOMPARE(info.getAircraftIcao().getDesignator(), entry.m_aircraftIcao);
// FAA code only contains information about heavy and super wake turbulence category
if (entry.m_wtc.isCategory(CWakeTurbulenceCategory::HEAVY) || entry.m_wtc.isCategory(CWakeTurbulenceCategory::SUPER))
{
QCOMPARE(info.getWtc(), entry.m_wtc);
}
else
{
QVERIFY2(info.getWtc().isUnknown(), "Should have UNKNOWN wake turbulence category");
}
// Cannot compare COM/NAV equipment and SSR equipment as the FAA code does not contain that much detail
QCOMPARE(info.asFaaString(), entry.m_faaEquipment);
}
}
void CTestFlightPlanAircraftInfo::nonValidConvert()
{
// Missing WTC and equipment code
CFlightPlanAircraftInfo info("A388");
QCOMPARE(info.asFaaString(), "A388/X");
QCOMPARE(info.asIcaoString(), "A388/M-S/N");
// FAA format: Missing equipment code
info = CFlightPlanAircraftInfo("J/A388");
QCOMPARE(info.asFaaString(), "J/A388/X");
QCOMPARE(info.asIcaoString(), "A388/J-S/N");
// FAA format: Wrong aircraft ICAO (but correct length according to CAircraftIcaoCode::isValidDesignator)
info = CFlightPlanAircraftInfo("H/A1/W");
QCOMPARE(info.asFaaString(), "H/A1/W");
QCOMPARE(info.asIcaoString(), "A1/H-W/C");
// FAA format: Missing aircraft ICAO with WTC
info = CFlightPlanAircraftInfo("H//W");
QCOMPARE(info.asFaaString(), "H//W");
QCOMPARE(info.asIcaoString(), "/H-W/C");
// FAA format: Equipment code only
info = CFlightPlanAircraftInfo("/W");
QCOMPARE(info.asFaaString(), "/W");
QCOMPARE(info.asIcaoString(), "/M-W/C");
// Wrong aircraft ICAO (too short) without WTC and equipment
info = CFlightPlanAircraftInfo("X");
QCOMPARE(info.asFaaString(), "/X");
QCOMPARE(info.asIcaoString(), "/M-S/N");
// Wrong aircraft ICAO (too long) without WTC and equipment
info = CFlightPlanAircraftInfo("ABCDEFGHIJKL");
QCOMPARE(info.asFaaString(), "/X");
QCOMPARE(info.asIcaoString(), "/M-S/N");
// Empty
info = CFlightPlanAircraftInfo("");
QCOMPARE(info.asFaaString(), "/X");
QCOMPARE(info.asIcaoString(), "/M-S/N");
// FAA format: Lower case (all)
info = CFlightPlanAircraftInfo("h/b744/L");
QCOMPARE(info.asFaaString(), "H/B744/L");
QCOMPARE(info.asIcaoString(), "B744/H-GW/C");
// FAA format: Lower case without WTC
info = CFlightPlanAircraftInfo("b738/w");
QCOMPARE(info.asFaaString(), "B738/W");
QCOMPARE(info.asIcaoString(), "B738/M-W/C");
// Lower case without WTC and equipment
info = CFlightPlanAircraftInfo("dh8d");
QCOMPARE(info.asFaaString(), "DH8D/X");
QCOMPARE(info.asIcaoString(), "DH8D/M-S/N");
// FAA format: Invalid WTC
info = CFlightPlanAircraftInfo("Q/A346");
QCOMPARE(info.asFaaString(), "A346/X");
QCOMPARE(info.asIcaoString(), "A346/M-S/N");
// FAA format: Leading whitespace
info = CFlightPlanAircraftInfo(" H/B748/L");
QCOMPARE(info.asFaaString(), "H/B748/L");
QCOMPARE(info.asIcaoString(), "B748/H-GW/C");
// FAA format: Trailing whitespace
info = CFlightPlanAircraftInfo("H/B748/L ");
QCOMPARE(info.asFaaString(), "H/B748/L");
QCOMPARE(info.asIcaoString(), "B748/H-GW/C");
// FAA format: Whitespaces in between
info = CFlightPlanAircraftInfo("H / B7 48 /L");
QCOMPARE(info.asFaaString(), "H/B748/L");
QCOMPARE(info.asIcaoString(), "B748/H-GW/C");
// ICAO format: Invalid WTC
info = CFlightPlanAircraftInfo("A339/?-S/N");
QCOMPARE(info.asFaaString(), "A339/X");
QCOMPARE(info.asIcaoString(), "A339/M-S/N");
// ICAO format: Missing SSR equipment code
info = CFlightPlanAircraftInfo("A339/H-S");
QCOMPARE(info.asFaaString(), "A339/X");
QCOMPARE(info.asIcaoString(), "A339/M-S/N");
// ICAO format: Lowercase
info = CFlightPlanAircraftInfo("b737/m-sde2e3fghirwxy/lb1");
QCOMPARE(info.asFaaString(), "B737/L");
QCOMPARE(info.asIcaoString(), "B737/M-SDE2E3FGHIRWXY/LB1");
// ICAO format: Leading whitespace
info = CFlightPlanAircraftInfo(" B737/M-SDE2E3FGHIRWXY/LB1");
QCOMPARE(info.asFaaString(), "B737/L");
QCOMPARE(info.asIcaoString(), "B737/M-SDE2E3FGHIRWXY/LB1");
// ICAO format: Trailing whitespace
info = CFlightPlanAircraftInfo("B737/M-SDE2E3FGHIRWXY/LB1 ");
QCOMPARE(info.asFaaString(), "B737/L");
QCOMPARE(info.asIcaoString(), "B737/M-SDE2E3FGHIRWXY/LB1");
// ICAO format: Whitespaces in between
info = CFlightPlanAircraftInfo("B737/ M - SDE2E3FGH IRWXY / LB1");
QCOMPARE(info.asFaaString(), "B737/L");
QCOMPARE(info.asIcaoString(), "B737/M-SDE2E3FGHIRWXY/LB1");
}
} // ns
//! main
BLACKTEST_APPLESS_MAIN(BlackMiscTest::CTestFlightPlanAircraftInfo);
#include "testflightplanaircraftinfo.moc"
//! \endcond