From c4ab9895fb290e60a6c0bc80e809421b47f76bb7 Mon Sep 17 00:00:00 2001 From: Frank Kopp Date: Fri, 13 Sep 2024 11:58:32 +0200 Subject: [PATCH] chore: cpp framework improvements and additions (#8640) * Added getDataDefinitionVarByName to DataManager * Cleanup, formatting and commenting * Added additional libs and functions * Added GTest framework and some initial tests * Added arinc library and initial unit tests * Added arinc library and initial unit tests * Refactored test folders and move dampener class to lib * Improved clang-format to align assignment expressions * Code documentation * Removed unnecessary include definition * Code documentation * Improved handling of aircraft prefix * removed old comment * Code reformatting * Fix Master Alarm when pressing T.O CONFIG when Flaps or not yet deployed. --- .clang-format | 9 + .gitignore | 34 ++- .../wasm/extra-backend-a32nx/CMakeLists.txt | 1 - .../AircraftPresetProcedures_A32NX.h | 11 +- .../src/Gauge_Extra_Backend.cpp | 7 +- .../src/Pushback/Pushback_A32NX.h | 8 +- fbw-a32nx/src/wasm/fadec_a32nx/README.md | 2 +- .../src/Fadec/EngineControlA32NX.cpp | 8 +- .../src/Fadec/EngineControlA32NX.h | 76 +++--- .../src/Fadec/FuelConfiguration_A32NX.h | 28 +- .../src/Fadec/Polynomials_A32NX.hpp | 13 +- .../src/Fadec/Tables1502_A32NX.hpp | 31 ++- .../src/Fadec/ThrustLimits_A32NX.hpp | 248 +++++++++--------- .../wasm/extra-backend-a380x/CMakeLists.txt | 1 - .../AircraftPresetProcedures_A380X.h | 4 +- .../src/Gauge_Extra_Backend.cpp | 4 +- .../LightingPresets/LightingPresets_A380X.cpp | 130 ++++----- .../LightingPresets/LightingPresets_A380X.h | 38 +-- .../src/Pushback/Pushback_A380X.h | 8 +- fbw-a380x/src/wasm/fadec_a380x/README.md | 2 +- .../src/Fadec/EngineControl_A380X.cpp | 4 +- .../src/Fadec/EngineControl_A380X.h | 2 +- .../src/Fadec/Polynomials_A380X.hpp | 4 +- .../fadec_a380x/src/Fadec/Table1502_A380X.hpp | 29 +- .../src/Fadec/ThrustLimits_A380X.hpp | 239 +++++++++-------- .../wasm/cpp-msfs-framework/CMakeLists.txt | 5 +- .../src/wasm/cpp-msfs-framework/GUIDELINES.md | 79 +++--- .../MsfsHandler/DataManager.cpp | 50 ++-- .../MsfsHandler/DataManager.h | 137 ++++++---- .../MsfsHandler/DataTypes/AircraftVariable.h | 38 +-- .../DataTypes/CacheableVariable.cpp | 3 +- .../MsfsHandler/DataTypes/CacheableVariable.h | 14 +- .../DataTypes/ClientDataAreaVariable.hpp | 43 ++- .../MsfsHandler/DataTypes/ClientEvent.cpp | 28 +- .../MsfsHandler/DataTypes/ClientEvent.h | 30 +-- .../DataTypes/DataDefinitionVariable.hpp | 38 +-- .../MsfsHandler/DataTypes/DataObjectBase.hpp | 8 +- .../DataTypes/ManagedDataObjectBase.hpp | 22 +- .../MsfsHandler/DataTypes/NamedVariable.cpp | 11 + .../MsfsHandler/DataTypes/NamedVariable.h | 46 ++-- .../MsfsHandler/DataTypes/SimObjectBase.hpp | 20 +- .../StreamingClientDataAreaVariable.hpp | 26 +- .../cpp-msfs-framework/MsfsHandler/Module.h | 6 +- .../MsfsHandler/MsfsHandler.cpp | 17 +- .../MsfsHandler/MsfsHandler.h | 11 +- .../cpp-msfs-framework/MsfsHandler/SimUnits.h | 2 +- .../src/wasm/cpp-msfs-framework/README.md | 231 ++++++++-------- .../lib/DampingController.hpp} | 23 +- .../cpp-msfs-framework/lib/ProfileBuffer.hpp | 22 +- .../cpp-msfs-framework/lib/ScopedTimer.hpp | 17 +- .../cpp-msfs-framework/lib/SimpleProfiler.hpp | 17 +- .../wasm/cpp-msfs-framework/lib/arinc429.hpp | 237 +++++++++++++++++ .../cpp-msfs-framework/lib/fingerprint.hpp | 18 +- .../src/wasm/cpp-msfs-framework/lib/logging.h | 6 +- .../cpp-msfs-framework/lib/math_utils.hpp | 11 +- .../wasm/cpp-msfs-framework/lib/quantity.hpp | 19 +- .../cpp-msfs-framework/lib/string_utils.hpp | 216 ++++++++++++++- .../cpp-msfs-framework/test/CMakeLists.txt | 69 +++++ .../test/src/lib/DampingController-tests.cpp | 32 +++ .../test/src/lib/ProfileBuffer-tests.cpp | 77 ++++++ .../test/src/lib/arinc429-tests.cpp | 97 +++++++ .../test/src/lib/fingerprint-tests.cpp | 35 +++ .../test/src/lib/math_utils-tests.cpp | 29 ++ .../test/src/lib/quantity-tests.cpp | 211 +++++++++++++++ .../test/src/lib/string_utils-tests.cpp | 180 +++++++++++++ .../wasm/cpp-msfs-framework/test/test-cpp.sh | 20 ++ .../AircraftPresets/AircraftPresets.cpp | 19 +- .../AircraftPresets/AircraftPresets.h | 5 +- .../AircraftPresets/PresetProcedures.h | 4 +- .../AircraftPresets/ProcedureStep.h | 11 +- .../LightingPresets/LightingPresets.cpp | 12 +- .../wasm/extra-backend/Pushback/Pushback.cpp | 108 ++++---- .../wasm/extra-backend/Pushback/Pushback.h | 6 +- .../wasm/fadec_common/src/EngineRatios.hpp | 15 +- .../src/wasm/fadec_common/src/Fadec.cpp | 16 +- fbw-common/src/wasm/fadec_common/src/Fadec.h | 10 +- package.json | 38 +-- 77 files changed, 2336 insertions(+), 1050 deletions(-) rename fbw-common/src/wasm/{extra-backend/Pushback/InertialDampener.hpp => cpp-msfs-framework/lib/DampingController.hpp} (67%) create mode 100644 fbw-common/src/wasm/cpp-msfs-framework/lib/arinc429.hpp create mode 100644 fbw-common/src/wasm/cpp-msfs-framework/test/CMakeLists.txt create mode 100644 fbw-common/src/wasm/cpp-msfs-framework/test/src/lib/DampingController-tests.cpp create mode 100644 fbw-common/src/wasm/cpp-msfs-framework/test/src/lib/ProfileBuffer-tests.cpp create mode 100644 fbw-common/src/wasm/cpp-msfs-framework/test/src/lib/arinc429-tests.cpp create mode 100644 fbw-common/src/wasm/cpp-msfs-framework/test/src/lib/fingerprint-tests.cpp create mode 100644 fbw-common/src/wasm/cpp-msfs-framework/test/src/lib/math_utils-tests.cpp create mode 100644 fbw-common/src/wasm/cpp-msfs-framework/test/src/lib/quantity-tests.cpp create mode 100644 fbw-common/src/wasm/cpp-msfs-framework/test/src/lib/string_utils-tests.cpp create mode 100755 fbw-common/src/wasm/cpp-msfs-framework/test/test-cpp.sh diff --git a/.clang-format b/.clang-format index 97bff4f8b4e..f827f908798 100644 --- a/.clang-format +++ b/.clang-format @@ -3,3 +3,12 @@ BasedOnStyle: Chromium --- Language: Cpp ColumnLimit: 140 +AlignArrayOfStructures: Left +AlignConsecutiveAssignments: Consecutive +AlignConsecutiveDeclarations: Consecutive +AlignConsecutiveShortCaseStatements: + Enabled: true + + + + diff --git a/.gitignore b/.gitignore index 2a9267ca5b1..ced979a71a6 100644 --- a/.gitignore +++ b/.gitignore @@ -36,6 +36,7 @@ # Project folders +# === A32NX === /fbw-a32nx/* /fbw-a32nx/.env.local !/fbw-a32nx/README.md @@ -51,14 +52,13 @@ /fbw-a32nx/src/base/flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/model/*.gltf /fbw-a32nx/src/systems/instruments/aceBundles /fbw-a32nx/src/systems/instruments/buildSrc/custom/* - /fbw-a32nx/src/localization/msfs/downloaded/*.locPak /fbw-a32nx/src/systems/instruments/src/EFB/dist /fbw-a32nx/src/systems/instruments/src/EFB/web/ - /fbw-a32nx/src/wasm/systems/a320_hydraulic_simulation_graphs/*.png /fbw-a32nx/src/wasm/systems/a320_pneumatic_simulation_graph_data/*.txt +# === A380X === /fbw-a380x/* /fbw-a380x/.env.local !/fbw-a380x/README.md @@ -72,9 +72,11 @@ /fbw-a380x/src/systems/instruments/aceBundles /fbw-a380x/src/localization/msfs/downloaded/*.locPak +# === Common === !/fbw-common/** /fbw-common/src/systems/instruments/src/EFB/Localization/data/downloaded/*.json +# === Ingame Panels Checklist Fix === /fbw-ingamepanels-checklist-fix/* !/fbw-ingamepanels-checklist-fix/README.md !/fbw-ingamepanels-checklist-fix/docs/ @@ -83,34 +85,30 @@ !/fbw-ingamepanels-checklist-fix/src/** /fbw-ingamepanels-checklist-fix/out -!/scripts/** - -!/build-utils.js - +# === Tools === !/tools/** /tools/fdr2csv/*.exe /tools/fdr2csv/build/ /tools/fdr2csv/cmake-build* -# avoid issues when switching branches during transistion from old to new structure -/src/ -/fbw-common/msfs-avionics-mirror/src/sdk/build -/fbw-common/msfs-avionics-mirror/src/sdk/build/** -/msfs-avionics-mirror/ -/flybywire-aircraft-a320-neo/ -/flybywire-aircraft-a320-neo-lock-highlight/ + +# Build scripts +!/scripts/** +!/build-utils.js # explicit exclusions /.env +*.tgz +localazy.keys.json + +# build artifacts node_modules/ target/ obj/ -cmake-build*/ -*.tgz +build/ +out/ +cmake-*/ *.wasm -cmake-build* - -localazy.keys.json # MacOS files **/.DS_Store diff --git a/fbw-a32nx/src/wasm/extra-backend-a32nx/CMakeLists.txt b/fbw-a32nx/src/wasm/extra-backend-a32nx/CMakeLists.txt index 99ef239ab8d..7463889f81d 100644 --- a/fbw-a32nx/src/wasm/extra-backend-a32nx/CMakeLists.txt +++ b/fbw-a32nx/src/wasm/extra-backend-a32nx/CMakeLists.txt @@ -30,7 +30,6 @@ set(INCLUDE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/src/Pushback/Pushback_A32NX.h ${FBW_COMMON}/cpp-msfs-framework/Example/ExampleModule.h ${FBW_COMMON}/cpp-msfs-framework/Example/longtext.h - ${FBW_COMMON}/extra-backend/Pushback/InertialDampener.hpp ${FBW_COMMON}/extra-backend/Pushback/Pushback.h ${FBW_COMMON}/extra-backend/AircraftPresets/AircraftPresets.h ${FBW_COMMON}/extra-backend/AircraftPresets/PresetProcedures.h diff --git a/fbw-a32nx/src/wasm/extra-backend-a32nx/src/AircraftPresets/AircraftPresetProcedures_A32NX.h b/fbw-a32nx/src/wasm/extra-backend-a32nx/src/AircraftPresets/AircraftPresetProcedures_A32NX.h index 0b3bab241a5..c7a26aacf49 100644 --- a/fbw-a32nx/src/wasm/extra-backend-a32nx/src/AircraftPresets/AircraftPresetProcedures_A32NX.h +++ b/fbw-a32nx/src/wasm/extra-backend-a32nx/src/AircraftPresets/AircraftPresetProcedures_A32NX.h @@ -15,7 +15,7 @@ class AircraftPresetProcedures_A32NX { public: const inline static PresetProceduresDefinition aircraftProcedureDefinition{ - // clang-format off + // clang-format off // @formatter:off .POWERED_CONFIG_ON { @@ -156,6 +156,7 @@ class AircraftPresetProcedures_A32NX { ProcedureStep{"Spoiler Arm", 3090, false, 2000, "(L:A32NX_SPOILERS_ARMED) 1 ==", "1 (>K:SPOILERS_ARM_SET)"}, ProcedureStep{"Rudder Trim Reset", 3100, false, 2000, "(A:RUDDER TRIM, Radians) 0 ==", "0 (>K:RUDDER_TRIM_SET)"}, ProcedureStep{"Flaps 1", 3110, false, 3000, "(L:A32NX_FLAPS_HANDLE_INDEX) 1 ==", "1 (>L:A32NX_FLAPS_HANDLE_INDEX)"}, + // SOP: TAXI ProcedureStep{"NOSE Lt Taxi", 3120, false, 1000, "(A:CIRCUIT SWITCH ON:20, Bool)", "0 (>L:LIGHTING_LANDING_1) (A:CIRCUIT SWITCH ON:20, Bool) ! if{ 20 (>K:ELECTRICAL_CIRCUIT_TOGGLE)"}, ProcedureStep{"RWY TURN OFF Lt L On", 3130, false, 0, "(A:CIRCUIT SWITCH ON:21, Bool)", "(A:CIRCUIT SWITCH ON:21, Bool) ! if{ 21 (>K:ELECTRICAL_CIRCUIT_TOGGLE)"}, @@ -166,6 +167,12 @@ class AircraftPresetProcedures_A32NX { ProcedureStep{"TCAS TRAFFIC Abv", 2100, false, 2000, "(L:A32NX_SWITCH_TCAS_TRAFFIC_POSITION) 2 ==", "2 (>L:A32NX_SWITCH_TCAS_TRAFFIC_POSITION)"}, ProcedureStep{"Autobrake Max", 3080, false, 2000, "(L:A32NX_AUTOBRAKES_ARMED_MODE) 3 ==", "3 (>L:A32NX_AUTOBRAKES_ARMED_MODE_SET)"}, ProcedureStep{"TERR ON ND Capt. On", 3080, false, 2000, "(L:A32NX_EFIS_TERR_L_ACTIVE) 1 ==", "1 (>L:A32NX_EFIS_TERR_L_ACTIVE)"}, + + ProcedureStep{"Await Flaps 1+F", 3110, true, 1000, "", "(L:A32NX_LEFT_FLAPS_POSITION_PERCENT) 24 >= " + "(L:A32NX_RIGHT_FLAPS_POSITION_PERCENT) 24 >= && "}, + ProcedureStep{"Await Slats 1+F", 3110, true, 1000, "", "(L:A32NX_LEFT_SLATS_POSITION_PERCENT) 66 >= " + "(L:A32NX_RIGHT_SLATS_POSITION_PERCENT) 66 >= && "}, + ProcedureStep{"T.O Config", 3085, false, 200, "", "1 (>L:A32NX_BTN_TOCONFIG)"}, ProcedureStep{"T.O Config", 3085, false, 2000, "", "0 (>L:A32NX_BTN_TOCONFIG)"}, }, @@ -219,7 +226,7 @@ class AircraftPresetProcedures_A32NX { } // @formatter:on - // clang-format on + // clang-format on }; }; diff --git a/fbw-a32nx/src/wasm/extra-backend-a32nx/src/Gauge_Extra_Backend.cpp b/fbw-a32nx/src/wasm/extra-backend-a32nx/src/Gauge_Extra_Backend.cpp index a421bd9db89..156a2d8b5af 100644 --- a/fbw-a32nx/src/wasm/extra-backend-a32nx/src/Gauge_Extra_Backend.cpp +++ b/fbw-a32nx/src/wasm/extra-backend-a32nx/src/Gauge_Extra_Backend.cpp @@ -13,7 +13,6 @@ #include #include -#include #include "MsfsHandler.h" @@ -34,8 +33,8 @@ ExampleModule exampleModule(msfsHandler); // ADD ADDITIONAL MODULES HERE // This is the only place these have to be added - everything else is handled automatically LightingPresets_A32NX lightingPresets(msfsHandler); -Pushback_A32NX pushback(msfsHandler); -AircraftPresets aircraftPresets(msfsHandler, AircraftPresetProcedures_A32NX::aircraftProcedureDefinition); +Pushback_A32NX pushback(msfsHandler); +AircraftPresets aircraftPresets(msfsHandler, AircraftPresetProcedures_A32NX::aircraftProcedureDefinition); /** * Gauge Callback @@ -49,7 +48,7 @@ AircraftPresets aircraftPresets(msfsHandler, AircraftPresetProcedures_A32NX::air * https://docs.flightsimulator.com/html/Content_Configuration/SimObjects/Aircraft_SimO/Instruments/C_C++_Gauges.htm?rhhlterm=_gauge_callback&rhsearch=_gauge_callback */ extern "C" { -[[maybe_unused]] MSFS_CALLBACK bool Gauge_Extra_Backend_gauge_callback([[maybe_unused]] FsContext ctx, int svcId, void* pData) { +MSFS_CALLBACK bool Gauge_Extra_Backend_gauge_callback([[maybe_unused]] FsContext ctx, int svcId, void* pData) { switch (svcId) { case PANEL_SERVICE_PRE_INSTALL: { return msfsHandler.initialize(); diff --git a/fbw-a32nx/src/wasm/extra-backend-a32nx/src/Pushback/Pushback_A32NX.h b/fbw-a32nx/src/wasm/extra-backend-a32nx/src/Pushback/Pushback_A32NX.h index 7af7d6d60f0..a748d5e614c 100644 --- a/fbw-a32nx/src/wasm/extra-backend-a32nx/src/Pushback/Pushback_A32NX.h +++ b/fbw-a32nx/src/wasm/extra-backend-a32nx/src/Pushback/Pushback_A32NX.h @@ -10,9 +10,9 @@ * @brief Aircraft specific pushback implementation for the A32NX */ class Pushback_A32NX : public Pushback { - static constexpr FLOAT64 PARKING_BRAKE_FACTOR = 100.0; // slow down when parking brake is engaged by this factor - static constexpr FLOAT64 SPEED_FACTOR = 18.0; // ft/sec for "VELOCITY BODY Z" (also max speed) - static constexpr FLOAT64 TURN_SPEED_FACTOR = 0.5; // ft/sec for "ROTATION VELOCITY BODY Y" + static constexpr FLOAT64 PARKING_BRAKE_FACTOR = 100.0; // slow down when parking brake is engaged by this factor + static constexpr FLOAT64 SPEED_FACTOR = 18.0; // ft/sec for "VELOCITY BODY Z" (also max speed) + static constexpr FLOAT64 TURN_SPEED_FACTOR = 0.5; // ft/sec for "ROTATION VELOCITY BODY Y" public: /** @@ -22,7 +22,7 @@ class Pushback_A32NX : public Pushback { explicit Pushback_A32NX(MsfsHandler& msfsHandler) : Pushback(msfsHandler) {} private: - constexpr int getParkBrakeFactor() const override final { return PARKING_BRAKE_FACTOR; } + constexpr int getParkBrakeFactor() const override final { return PARKING_BRAKE_FACTOR; } constexpr FLOAT64 getSpeedFactor() const override final { return SPEED_FACTOR; } constexpr FLOAT64 getTurnSpeedFactor() const override final { return TURN_SPEED_FACTOR; } }; diff --git a/fbw-a32nx/src/wasm/fadec_a32nx/README.md b/fbw-a32nx/src/wasm/fadec_a32nx/README.md index cbb3dadb936..9af21e1bee0 100644 --- a/fbw-a32nx/src/wasm/fadec_a32nx/README.md +++ b/fbw-a32nx/src/wasm/fadec_a32nx/README.md @@ -1,5 +1,5 @@ # A32NX FADEC -This is a new version of the FADEC system for the A32NX. +This is a new version of the FADEC system for the A32NX. It is a migration and cleanup of the original FADEC system, and is designed to be more modular and easier to maintain. diff --git a/fbw-a32nx/src/wasm/fadec_a32nx/src/Fadec/EngineControlA32NX.cpp b/fbw-a32nx/src/wasm/fadec_a32nx/src/Fadec/EngineControlA32NX.cpp index e1e909addbc..bc91a05e60b 100644 --- a/fbw-a32nx/src/wasm/fadec_a32nx/src/Fadec/EngineControlA32NX.cpp +++ b/fbw-a32nx/src/wasm/fadec_a32nx/src/Fadec/EngineControlA32NX.cpp @@ -556,9 +556,9 @@ double EngineControl_A32NX::updateFF(int engine, double outFlow = 0; if (correctedFuelFlow >= 1) { outFlow = std::max(0.0, // - (correctedFuelFlow * Fadec::LBS_TO_KGS * EngineRatios::delta2(mach, ambientPressure) // - * (std::sqrt)(EngineRatios::theta2(mach, ambientTemperature))) // - - paramImbalance); // + (correctedFuelFlow * Fadec::LBS_TO_KGS * EngineRatios::delta2(mach, ambientPressure) // + * (std::sqrt)(EngineRatios::theta2(mach, ambientTemperature))) // + - paramImbalance); // } simData.engineFF[engine - 1]->set(outFlow); @@ -1029,7 +1029,7 @@ void EngineControl_A32NX::updateThrustLimits(double simulationT deltaThrust = (std::min)(clb - flex, timeDifference * transitionFactor); } if (flex + deltaThrust >= clb) { - wasFlexActive = false; + wasFlexActive = false; isTransitionActive = false; } } diff --git a/fbw-a32nx/src/wasm/fadec_a32nx/src/Fadec/EngineControlA32NX.h b/fbw-a32nx/src/wasm/fadec_a32nx/src/Fadec/EngineControlA32NX.h index c40d7ea4e42..3a0a0b6b252 100644 --- a/fbw-a32nx/src/wasm/fadec_a32nx/src/Fadec/EngineControlA32NX.h +++ b/fbw-a32nx/src/wasm/fadec_a32nx/src/Fadec/EngineControlA32NX.h @@ -40,11 +40,11 @@ class EngineControl_A32NX { FuelConfiguration_A32NX fuelConfiguration{}; // previous time the fuel levels were saved to file - double lastFuelSaveTime = 0.0; + double lastFuelSaveTime = 0.0; static constexpr double FUEL_SAVE_INTERVAL = 5.0; // seconds // some pump timings - unclear why these are needed - double pumpStateLeftTimeStamp = 0.0; + double pumpStateLeftTimeStamp = 0.0; double pumpStateRightTimeStamp = 0.0; bool isTransitionActive = false; @@ -52,19 +52,19 @@ class EngineControl_A32NX { static constexpr double TRANSITION_WAIT_TIME = 10; // values that need previous state - double prevFlexTemperature = 0.0; - double prevThrustLimitType = 0.0; - double prevEngineMasterPos[2] = {0, 0}; - bool prevEngineStarterState[2] = {false, false}; + double prevFlexTemperature = 0.0; + double prevThrustLimitType = 0.0; + double prevEngineMasterPos[2] = {0, 0}; + bool prevEngineStarterState[2] = {false, false}; // FLX->CLB thrust limit transition double transitionStartTime; double transitionFactor; - bool wasFlexActive = false; + bool wasFlexActive = false; // additional constants - static constexpr int MAX_OIL = 200; - static constexpr int MIN_OIL = 140; + static constexpr int MAX_OIL = 200; + static constexpr int MIN_OIL = 140; static constexpr double FUEL_RATE_THRESHOLD = 661; // lbs/sec for determining fuel ui tampering /** @@ -78,11 +78,11 @@ class EngineControl_A32NX { * @var SHUTTING The engine is in the process of shutting down. */ enum EngineState { - OFF = 0, - ON = 1, - STARTING = 2, + OFF = 0, + ON = 1, + STARTING = 2, RESTARTING = 3, - SHUTTING = 4, + SHUTTING = 4, }; #ifdef PROFILING @@ -209,12 +209,12 @@ class EngineControl_A32NX { * @return The current state of the engine as an enum of type EngineState. * @see EngineState */ - EngineControl_A32NX::EngineState engineStateMachine(int engine, + EngineControl_A32NX::EngineState engineStateMachine(int engine, double engineIgniter, - bool engineStarter, - bool engineStarterTurnedOff, - bool engineMasterTurnedOn, - bool engineMasterTurnedOff, + bool engineStarter, + bool engineStarterTurnedOff, + bool engineMasterTurnedOn, + bool engineMasterTurnedOff, double simN2, double idleN2, double ambientTemperature); @@ -233,14 +233,14 @@ class EngineControl_A32NX { * * @see EngineState */ - void engineStartProcedure(int engine, + void engineStartProcedure(int engine, EngineState engineState, - double imbalance, - double deltaTime, - double engineTimer, - double simN2, - double pressureAltitude, - double ambientTemperature); + double imbalance, + double deltaTime, + double engineTimer, + double simN2, + double pressureAltitude, + double ambientTemperature); /** * @brief This function manages the engine shutdown procedure. @@ -266,7 +266,7 @@ class EngineControl_A32NX { * @param ambientPressure The current ambient pressure in hPa. * @return The updated fuel flow as a double. */ - double updateFF(int engine, // + double updateFF(int engine, // double imbalance, // double simCN1, // double mach, // @@ -301,16 +301,16 @@ class EngineControl_A32NX { * * @see EngineState */ - void updateEGT(int engine, - double imbalance, - double deltaTime, - double simOnGround, + void updateEGT(int engine, + double imbalance, + double deltaTime, + double simOnGround, EngineState engineState, - double simCN1, - double customFuelFlow, - double mach, - double pressureAltitude, - double ambientTemperature); + double simCN1, + double customFuelFlow, + double mach, + double pressureAltitude, + double ambientTemperature); /** * @brief FBW Fuel Consumption and Tanking. Updates Fuel Consumption with realistic values @@ -338,9 +338,9 @@ class EngineControl_A32NX { double ambientPressure, double mach, double simN1highest, - int packs, - int nai, - int wai); + int packs, + int nai, + int wai); }; #endif // FLYBYWIRE_AIRCRAFT_ENGINECONTROL_A32NX_H diff --git a/fbw-a32nx/src/wasm/fadec_a32nx/src/Fadec/FuelConfiguration_A32NX.h b/fbw-a32nx/src/wasm/fadec_a32nx/src/Fadec/FuelConfiguration_A32NX.h index 4911463168c..dccfd8e9af9 100644 --- a/fbw-a32nx/src/wasm/fadec_a32nx/src/Fadec/FuelConfiguration_A32NX.h +++ b/fbw-a32nx/src/wasm/fadec_a32nx/src/Fadec/FuelConfiguration_A32NX.h @@ -24,17 +24,17 @@ class FuelConfiguration_A32NX { private: // Fuel tank default quantities in gallons - static constexpr double fuelCenterDefault = 0; - static constexpr double fuelLeftDefault = 411.34; - static constexpr double fuelRightDefault = fuelLeftDefault; - static constexpr double fuelLeftAuxDefault = 0; + static constexpr double fuelCenterDefault = 0; + static constexpr double fuelLeftDefault = 411.34; + static constexpr double fuelRightDefault = fuelLeftDefault; + static constexpr double fuelLeftAuxDefault = 0; static constexpr double fuelRightAuxDefault = fuelLeftAuxDefault; // Actual fuel tank quantities in gallons - double fuelCenter = fuelCenterDefault; - double fuelLeft = fuelLeftDefault; - double fuelRight = fuelRightDefault; - double fuelLeftAux = fuelLeftAuxDefault; + double fuelCenter = fuelCenterDefault; + double fuelLeft = fuelLeftDefault; + double fuelRight = fuelRightDefault; + double fuelLeftAux = fuelLeftAuxDefault; double fuelRightAux = fuelRightAuxDefault; std::string configFilename{"A32NX-default-fuel-config.ini"}; @@ -72,12 +72,12 @@ class FuelConfiguration_A32NX { void saveConfigurationToIni(); /** - * @brief Converts the current fuel configuration to a string. - * - * This method is used to convert the current state of the fuel configuration into a string format. - * The string includes the quantities of fuel in each tank. - * - * @return A string representation of the current fuel configuration. + * @brief Converts the current fuel configuration to a string. + * + * This method is used to convert the current state of the fuel configuration into a string format. + * The string includes the quantities of fuel in each tank. + * + * @return A string representation of the current fuel configuration. */ std::string toString() const; diff --git a/fbw-a32nx/src/wasm/fadec_a32nx/src/Fadec/Polynomials_A32NX.hpp b/fbw-a32nx/src/wasm/fadec_a32nx/src/Fadec/Polynomials_A32NX.hpp index 9552594172b..8d5bc898ecf 100644 --- a/fbw-a32nx/src/wasm/fadec_a32nx/src/Fadec/Polynomials_A32NX.hpp +++ b/fbw-a32nx/src/wasm/fadec_a32nx/src/Fadec/Polynomials_A32NX.hpp @@ -112,7 +112,7 @@ class Polynomial_A32NX { */ static double startFF(double fbwN2, double idleN2, double idleFF) { const double normalN2 = fbwN2 / idleN2; - double normalFF = 0; + double normalFF = 0; // If the normalized N2 percentage is less than or equal to 0.37, the FF is 0. if (normalN2 <= 0.37) { @@ -153,7 +153,6 @@ class Polynomial_A32NX { // Normalize the current N2 percentage by dividing it with the idle N2 percentage. const double normalizedN2 = fbwN2 / idleN2; - // Calculate the normalized EGT value based on the normalized N2 value double normalizedEGT; if (normalizedN2 < 0.17) { @@ -255,8 +254,8 @@ class Polynomial_A32NX { // data or a mathematical model of the engine's behavior. // The choice to use different decay rates and steady state temperatures based on the previous // EGT suggests that the engine's shutdown behavior changes at this threshold. - double threshold = ambientTemp + 140; - double decayRate = previousEGT > threshold ? 0.0257743 : 0.00072756; + double threshold = ambientTemp + 140; + double decayRate = previousEGT > threshold ? 0.0257743 : 0.00072756; double steadyStateTemp = previousEGT > threshold ? 135 + ambientTemp : 30 + ambientTemp; return steadyStateTemp + (previousEGT - steadyStateTemp) * exp(-decayRate * deltaTime); } @@ -380,9 +379,9 @@ class Polynomial_A32NX { static double oilTemperature(double thermalEnergy, double previousOilTemp, double maxOilTemperature, double deltaTime) { // these constants are likely derived from empirical data or a mathematical model of the engine's behavior // they were not documented in the original code, and their names here are inferred from their usage - const double heatTransferCoefficient = 0.001; - const double energyScalingFactor = 0.002; - const double temperatureThreshold = 10; + const double heatTransferCoefficient = 0.001; + const double energyScalingFactor = 0.002; + const double temperatureThreshold = 10; const double temperatureScalingFactor = 0.999997; const double changeInThermalEnergy = thermalEnergy * deltaTime * energyScalingFactor; diff --git a/fbw-a32nx/src/wasm/fadec_a32nx/src/Fadec/Tables1502_A32NX.hpp b/fbw-a32nx/src/wasm/fadec_a32nx/src/Fadec/Tables1502_A32NX.hpp index 5bfd8691629..841f34eb132 100644 --- a/fbw-a32nx/src/wasm/fadec_a32nx/src/Fadec/Tables1502_A32NX.hpp +++ b/fbw-a32nx/src/wasm/fadec_a32nx/src/Fadec/Tables1502_A32NX.hpp @@ -30,23 +30,22 @@ class Tables1502_A32NX { * @return A 2D array representing the CN2 - correctedN1 pairs. */ static constexpr double table1502[13][4] = { - {18.20, 0.00, 0.00, 17.00}, // CN2 = 18.20, correctedN1 = [0.00, 0.00] at Mach 0.2, correctedN1 = 17.00 at Mach 0.9 - {22.00, 1.90, 1.90, 17.40}, // CN2 = 22.00, correctedN1 = [1.90, 1.90] at Mach 0.2, correctedN1 = 17.40 at Mach 0.9 - {26.00, 2.50, 2.50, 18.20}, // CN2 = 26.00, correctedN1 = [2.50, 2.50] at Mach 0.2, correctedN1 = 18.20 at Mach 0.9 - {57.00, 12.80, 12.80, 27.00}, // CN2 = 57.00, correctedN1 = [12.80, 12.80] at Mach 0.2, correctedN1 = 27.00 at Mach 0.9 - {68.20, 19.60, 19.60, 34.83}, // CN2 = 68.20, correctedN1 = [19.60, 19.60] at Mach 0.2, correctedN1 = 34.83 at Mach 0.9 - {77.00, 26.00, 26.00, 40.84}, // CN2 = 77.00, correctedN1 = [26.00, 26.00] at Mach 0.2, correctedN1 = 40.84 at Mach 0.9 - {83.00, 31.42, 31.42, 44.77}, // CN2 = 83.00, correctedN1 = [31.42, 31.42] at Mach 0.2, correctedN1 = 44.77 at Mach 0.9 - {89.00, 40.97, 40.97, 50.09}, // CN2 = 89.00, correctedN1 = [40.97, 40.97] at Mach 0.2, correctedN1 = 50.09 at Mach 0.9 - {92.80, 51.00, 51.00, 55.04}, // CN2 = 92.80, correctedN1 = [51.00, 51.00] at Mach 0.2, correctedN1 = 55.04 at Mach 0.9 - {97.00, 65.00, 65.00, 65.00}, // CN2 = 97.00, correctedN1 = [65.00, 65.00] at Mach 0.2, correctedN1 = 65.00 at Mach 0.9 - {100.00, 77.00, 77.00, 77.00}, // CN2 = 100.00, correctedN1 = [77.00, 77.00] at Mach 0.2, correctedN1 = 77.00 at Mach 0.9 - {104.00, 85.00, 85.00, 85.50}, // CN2 = 104.00, correctedN1 = [85.00, 85.00] at Mach 0.2, correctedN1 = 85.50 at Mach 0.9 + {18.20, 0.00, 0.00, 17.00 }, // CN2 = 18.20, correctedN1 = [0.00, 0.00] at Mach 0.2, correctedN1 = 17.00 at Mach 0.9 + {22.00, 1.90, 1.90, 17.40 }, // CN2 = 22.00, correctedN1 = [1.90, 1.90] at Mach 0.2, correctedN1 = 17.40 at Mach 0.9 + {26.00, 2.50, 2.50, 18.20 }, // CN2 = 26.00, correctedN1 = [2.50, 2.50] at Mach 0.2, correctedN1 = 18.20 at Mach 0.9 + {57.00, 12.80, 12.80, 27.00 }, // CN2 = 57.00, correctedN1 = [12.80, 12.80] at Mach 0.2, correctedN1 = 27.00 at Mach 0.9 + {68.20, 19.60, 19.60, 34.83 }, // CN2 = 68.20, correctedN1 = [19.60, 19.60] at Mach 0.2, correctedN1 = 34.83 at Mach 0.9 + {77.00, 26.00, 26.00, 40.84 }, // CN2 = 77.00, correctedN1 = [26.00, 26.00] at Mach 0.2, correctedN1 = 40.84 at Mach 0.9 + {83.00, 31.42, 31.42, 44.77 }, // CN2 = 83.00, correctedN1 = [31.42, 31.42] at Mach 0.2, correctedN1 = 44.77 at Mach 0.9 + {89.00, 40.97, 40.97, 50.09 }, // CN2 = 89.00, correctedN1 = [40.97, 40.97] at Mach 0.2, correctedN1 = 50.09 at Mach 0.9 + {92.80, 51.00, 51.00, 55.04 }, // CN2 = 92.80, correctedN1 = [51.00, 51.00] at Mach 0.2, correctedN1 = 55.04 at Mach 0.9 + {97.00, 65.00, 65.00, 65.00 }, // CN2 = 97.00, correctedN1 = [65.00, 65.00] at Mach 0.2, correctedN1 = 65.00 at Mach 0.9 + {100.00, 77.00, 77.00, 77.00 }, // CN2 = 100.00, correctedN1 = [77.00, 77.00] at Mach 0.2, correctedN1 = 77.00 at Mach 0.9 + {104.00, 85.00, 85.00, 85.50 }, // CN2 = 104.00, correctedN1 = [85.00, 85.00] at Mach 0.2, correctedN1 = 85.50 at Mach 0.9 {116.50, 101.00, 101.00, 101.00} // CN2 = 116.50, correctedN1 = [101.00, 101.00] at Mach 0.2, correctedN1 = 101.00 at Mach 0.9 }; - public: - + public: /** * @brief Calculates the expected CN2 at idle. * @@ -79,8 +78,8 @@ class Tables1502_A32NX { } // Retrieve the lower and upper bounds of the CN2 value and the correctedN1 value at Mach 0.2 and Mach 0.9 - const double cn2lo = table1502[i - 1][0]; - const double cn2hi = table1502[i][0]; + const double cn2lo = table1502[i - 1][0]; + const double cn2hi = table1502[i][0]; const double cn1lolo = table1502[i - 1][1]; const double cn1hilo = table1502[i][1]; const double cn1lohi = table1502[i - 1][3]; diff --git a/fbw-a32nx/src/wasm/fadec_a32nx/src/Fadec/ThrustLimits_A32NX.hpp b/fbw-a32nx/src/wasm/fadec_a32nx/src/Fadec/ThrustLimits_A32NX.hpp index 392ddbdb94d..d435857f42b 100644 --- a/fbw-a32nx/src/wasm/fadec_a32nx/src/Fadec/ThrustLimits_A32NX.hpp +++ b/fbw-a32nx/src/wasm/fadec_a32nx/src/Fadec/ThrustLimits_A32NX.hpp @@ -34,82 +34,82 @@ class ThrustLimits_A32NX { * Climb (CLB), and Maximum Continuous Thrust (MCT). */ static constexpr double limits[72][6] = { - // TO - {-2000, 48.000, 55.000, 81.351, 79.370, 61.535}, // row 0 - {-1000, 46.000, 55.000, 82.605, 80.120, 62.105}, // - {0, 44.000, 55.000, 83.832, 80.776, 62.655}, // - {500, 42.000, 52.000, 84.210, 81.618, 62.655}, // - {1000, 42.000, 52.000, 84.579, 81.712, 62.655}, // - {2000, 40.000, 50.000, 85.594, 82.720, 62.655}, // - {3000, 36.000, 48.000, 86.657, 83.167, 61.960}, // - {4000, 32.000, 46.000, 87.452, 83.332, 61.206}, // - {5000, 29.000, 44.000, 88.833, 84.166, 61.206}, // - {6000, 25.000, 42.000, 90.232, 84.815, 61.206}, // - {7000, 21.000, 40.000, 91.711, 85.565, 61.258}, // - {8000, 17.000, 38.000, 93.247, 86.225, 61.777}, // - {9000, 15.000, 36.000, 94.031, 86.889, 60.968}, // - {10000, 13.000, 34.000, 94.957, 88.044, 60.935}, // - {11000, 12.000, 32.000, 95.295, 88.526, 59.955}, // - {12000, 11.000, 30.000, 95.568, 88.818, 58.677}, // - {13000, 10.000, 28.000, 95.355, 88.819, 59.323}, // - {14000, 10.000, 26.000, 95.372, 89.311, 59.965}, // - {15000, 8.000, 24.000, 95.686, 89.907, 58.723}, // - {16000, 5.000, 22.000, 96.160, 89.816, 57.189}, // - {16600, 5.000, 22.000, 96.560, 89.816, 57.189}, // row 20 - // GA - {-2000, 47.751, 54.681, 84.117, 81.901, 63.498}, // row 21 - {-1000, 45.771, 54.681, 85.255, 82.461, 63.920}, // - {0, 43.791, 54.681, 86.411, 83.021, 64.397}, // - {500, 42.801, 52.701, 86.978, 83.740, 64.401}, // - {1000, 41.811, 52.701, 87.568, 83.928, 64.525}, // - {2000, 38.841, 50.721, 88.753, 84.935, 64.489}, // - {3000, 36.861, 48.741, 89.930, 85.290, 63.364}, // - {4000, 32.901, 46.761, 91.004, 85.836, 62.875}, // - {5000, 28.941, 44.781, 92.198, 86.293, 62.614}, // - {6000, 24.981, 42.801, 93.253, 86.563, 62.290}, // - {7000, 21.022, 40.821, 94.273, 86.835, 61.952}, // - {8000, 17.062, 38.841, 94.919, 87.301, 62.714}, // - {9000, 15.082, 36.861, 95.365, 87.676, 61.692}, // - {10000, 13.102, 34.881, 95.914, 88.150, 60.906}, // - {11000, 12.112, 32.901, 96.392, 88.627, 59.770}, // - {12000, 11.122, 30.921, 96.640, 89.206, 58.933}, // - {13000, 10.132, 28.941, 96.516, 89.789, 60.503}, // - {14000, 9.142, 26.961, 96.516, 90.475, 62.072}, // - {15000, 9.142, 24.981, 96.623, 90.677, 59.333}, // - {16000, 7.162, 23.001, 96.845, 90.783, 58.045}, // - {16600, 5.182, 21.022, 97.366, 91.384, 58.642}, // row 41 - // CLB - {-2000, 30.800, 56.870, 80.280, 72.000, 0.000}, // row 42 - {2000, 20.990, 48.157, 82.580, 74.159, 0.000}, // - {5000, 16.139, 43.216, 84.642, 75.737, 0.000}, // - {8000, 7.342, 38.170, 86.835, 77.338, 0.000}, // - {10000, 4.051, 34.518, 88.183, 77.999, 0.000}, // - {10000.1, 4.051, 34.518, 87.453, 77.353, 0.000}, // - {12000, 0.760, 30.865, 88.303, 78.660, 0.000}, // - {15000, -4.859, 25.039, 89.748, 79.816, 0.000}, // - {17000, -9.934, 19.813, 90.668, 80.895, 0.000}, // - {20000, -15.822, 13.676, 92.106, 81.894, 0.000}, // - {24000, -22.750, 6.371, 93.651, 82.716, 0.000}, // - {27000, -29.105, -0.304, 93.838, 83.260, 0.000}, // - {29314, -32.049, -3.377, 93.502, 82.962, 0.000}, // - {31000, -34.980, -6.452, 95.392, 84.110, 0.000}, // - {35000, -45.679, -17.150, 96.104, 85.248, 0.000}, // - {39000, -45.679, -17.150, 96.205, 84.346, 0.000}, // - {41500, -45.679, -17.150, 95.676, 83.745, 0.000}, // row 58 - // MCT - {-1000, 26.995, 54.356, 82.465, 74.086, 0.000}, // row 59 - {3000, 18.170, 45.437, 86.271, 77.802, 0.000}, // - {7000, 9.230, 40.266, 89.128, 79.604, 0.000}, // - {11000, 4.019, 31.046, 92.194, 82.712, 0.000}, // - {15000, -5.226, 21.649, 95.954, 85.622, 0.000}, // - {17000, -9.913, 20.702, 97.520, 85.816, 0.000}, // - {20000, -15.129, 15.321, 99.263, 86.770, 0.000}, // - {22000, -19.947, 10.382, 98.977, 86.661, 0.000}, // - {25000, -25.397, 4.731, 98.440, 85.765, 0.000}, // - {27000, -30.369, -0.391, 97.279, 85.556, 0.000}, // - {31000, -36.806, -7.165, 98.674, 86.650, 0.000}, // - {35000, -43.628, -14.384, 98.386, 85.747, 0.000}, // - {39000, -47.286, -18.508, 97.278, 85.545, 0.000} // row 71 + // TO + {-2000, 48.000, 55.000, 81.351, 79.370, 61.535}, // row 0 + {-1000, 46.000, 55.000, 82.605, 80.120, 62.105}, // + {0, 44.000, 55.000, 83.832, 80.776, 62.655}, // + {500, 42.000, 52.000, 84.210, 81.618, 62.655}, // + {1000, 42.000, 52.000, 84.579, 81.712, 62.655}, // + {2000, 40.000, 50.000, 85.594, 82.720, 62.655}, // + {3000, 36.000, 48.000, 86.657, 83.167, 61.960}, // + {4000, 32.000, 46.000, 87.452, 83.332, 61.206}, // + {5000, 29.000, 44.000, 88.833, 84.166, 61.206}, // + {6000, 25.000, 42.000, 90.232, 84.815, 61.206}, // + {7000, 21.000, 40.000, 91.711, 85.565, 61.258}, // + {8000, 17.000, 38.000, 93.247, 86.225, 61.777}, // + {9000, 15.000, 36.000, 94.031, 86.889, 60.968}, // + {10000, 13.000, 34.000, 94.957, 88.044, 60.935}, // + {11000, 12.000, 32.000, 95.295, 88.526, 59.955}, // + {12000, 11.000, 30.000, 95.568, 88.818, 58.677}, // + {13000, 10.000, 28.000, 95.355, 88.819, 59.323}, // + {14000, 10.000, 26.000, 95.372, 89.311, 59.965}, // + {15000, 8.000, 24.000, 95.686, 89.907, 58.723}, // + {16000, 5.000, 22.000, 96.160, 89.816, 57.189}, // + {16600, 5.000, 22.000, 96.560, 89.816, 57.189}, // row 20 + // GA + {-2000, 47.751, 54.681, 84.117, 81.901, 63.498}, // row 21 + {-1000, 45.771, 54.681, 85.255, 82.461, 63.920}, // + {0, 43.791, 54.681, 86.411, 83.021, 64.397}, // + {500, 42.801, 52.701, 86.978, 83.740, 64.401}, // + {1000, 41.811, 52.701, 87.568, 83.928, 64.525}, // + {2000, 38.841, 50.721, 88.753, 84.935, 64.489}, // + {3000, 36.861, 48.741, 89.930, 85.290, 63.364}, // + {4000, 32.901, 46.761, 91.004, 85.836, 62.875}, // + {5000, 28.941, 44.781, 92.198, 86.293, 62.614}, // + {6000, 24.981, 42.801, 93.253, 86.563, 62.290}, // + {7000, 21.022, 40.821, 94.273, 86.835, 61.952}, // + {8000, 17.062, 38.841, 94.919, 87.301, 62.714}, // + {9000, 15.082, 36.861, 95.365, 87.676, 61.692}, // + {10000, 13.102, 34.881, 95.914, 88.150, 60.906}, // + {11000, 12.112, 32.901, 96.392, 88.627, 59.770}, // + {12000, 11.122, 30.921, 96.640, 89.206, 58.933}, // + {13000, 10.132, 28.941, 96.516, 89.789, 60.503}, // + {14000, 9.142, 26.961, 96.516, 90.475, 62.072}, // + {15000, 9.142, 24.981, 96.623, 90.677, 59.333}, // + {16000, 7.162, 23.001, 96.845, 90.783, 58.045}, // + {16600, 5.182, 21.022, 97.366, 91.384, 58.642}, // row 41 + // CLB + {-2000, 30.800, 56.870, 80.280, 72.000, 0.000 }, // row 42 + {2000, 20.990, 48.157, 82.580, 74.159, 0.000 }, // + {5000, 16.139, 43.216, 84.642, 75.737, 0.000 }, // + {8000, 7.342, 38.170, 86.835, 77.338, 0.000 }, // + {10000, 4.051, 34.518, 88.183, 77.999, 0.000 }, // + {10000.1, 4.051, 34.518, 87.453, 77.353, 0.000 }, // + {12000, 0.760, 30.865, 88.303, 78.660, 0.000 }, // + {15000, -4.859, 25.039, 89.748, 79.816, 0.000 }, // + {17000, -9.934, 19.813, 90.668, 80.895, 0.000 }, // + {20000, -15.822, 13.676, 92.106, 81.894, 0.000 }, // + {24000, -22.750, 6.371, 93.651, 82.716, 0.000 }, // + {27000, -29.105, -0.304, 93.838, 83.260, 0.000 }, // + {29314, -32.049, -3.377, 93.502, 82.962, 0.000 }, // + {31000, -34.980, -6.452, 95.392, 84.110, 0.000 }, // + {35000, -45.679, -17.150, 96.104, 85.248, 0.000 }, // + {39000, -45.679, -17.150, 96.205, 84.346, 0.000 }, // + {41500, -45.679, -17.150, 95.676, 83.745, 0.000 }, // row 58 + // MCT + {-1000, 26.995, 54.356, 82.465, 74.086, 0.000 }, // row 59 + {3000, 18.170, 45.437, 86.271, 77.802, 0.000 }, // + {7000, 9.230, 40.266, 89.128, 79.604, 0.000 }, // + {11000, 4.019, 31.046, 92.194, 82.712, 0.000 }, // + {15000, -5.226, 21.649, 95.954, 85.622, 0.000 }, // + {17000, -9.913, 20.702, 97.520, 85.816, 0.000 }, // + {20000, -15.129, 15.321, 99.263, 86.770, 0.000 }, // + {22000, -19.947, 10.382, 98.977, 86.661, 0.000 }, // + {25000, -25.397, 4.731, 98.440, 85.765, 0.000 }, // + {27000, -30.369, -0.391, 97.279, 85.556, 0.000 }, // + {31000, -36.806, -7.165, 98.674, 86.650, 0.000 }, // + {35000, -43.628, -14.384, 98.386, 85.747, 0.000 }, // + {39000, -47.286, -18.508, 97.278, 85.545, 0.000 } // row 71 }; public: @@ -156,7 +156,8 @@ class ThrustLimits_A32NX { * @param type The type of operation (0-TO, 1-GA, 2-CLB, 3-MCT). * @param altitude The current altitude of the aircraft in feet. * @param oat The outside air temperature in degrees Celsius. - * @param cp The corner point - the temperature below which the engine can operate at full thrust without any restrictions (in degrees Celsius). + * @param cp The corner point - the temperature below which the engine can operate at full thrust without any restrictions (in degrees + * Celsius). * @param lp The limit point - the temperature above which the engine thrust starts to be limited (in degrees Celsius). * @param flexTemp The flex temperature in degrees Celsius. * @param packs The status of the air conditioning (0 for off, 1 for on). @@ -164,15 +165,15 @@ class ThrustLimits_A32NX { * @param wing The status of the wing anti-ice (0 for off, 1 for on). * @return The total bleed for the engine */ - static double bleedTotal(int type, // + static double bleedTotal(int type, // double altitude, // double oat, // double cp, // double lp, // double flexTemp, // - int packs, // - int nacelle, // - int wing // + int packs, // + int nacelle, // + int wing // ) { if (flexTemp > lp && type <= 1) { return packs * -0.6 + nacelle * -0.7 + wing * -0.7; @@ -188,23 +189,23 @@ class ThrustLimits_A32NX { // double - Represents the bleed value for the nacelle anti-ice. // double - Represents the bleed value for the wing anti-ice. std::map, std::tuple> bleedValues = { - {{0, true, true}, {-0.4, -0.6, -0.7}}, // - {{0, true, false}, {-0.5, -0.6, -0.7}}, // - {{0, false, true}, {-0.6, -0.8, -0.8}}, // - {{0, false, false}, {-0.7, -0.8, -0.8}}, // - {{1, true, true}, {-0.4, -0.6, -0.6}}, // - {{1, true, false}, {-0.4, -0.6, -0.6}}, // - {{1, false, true}, {-0.6, -0.7, -0.8}}, // - {{1, false, false}, {-0.6, -0.7, -0.8}}, // - {{2, true, false}, {-0.2, -0.8, -0.4}}, // - {{2, false, false}, {-0.3, -0.8, -0.4}}, // - {{3, true, false}, {-0.6, -0.9, -1.2}}, // - {{3, false, false}, {-0.6, -0.9, -1.2}} // + {{0, true, true}, {-0.4, -0.6, -0.7}}, // + {{0, true, false}, {-0.5, -0.6, -0.7}}, // + {{0, false, true}, {-0.6, -0.8, -0.8}}, // + {{0, false, false}, {-0.7, -0.8, -0.8}}, // + {{1, true, true}, {-0.4, -0.6, -0.6}}, // + {{1, true, false}, {-0.4, -0.6, -0.6}}, // + {{1, false, true}, {-0.6, -0.7, -0.8}}, // + {{1, false, false}, {-0.6, -0.7, -0.8}}, // + {{2, true, false}, {-0.2, -0.8, -0.4}}, // + {{2, false, false}, {-0.3, -0.8, -0.4}}, // + {{3, true, false}, {-0.6, -0.9, -1.2}}, // + {{3, false, false}, {-0.6, -0.9, -1.2}} // }; double n1Packs = 0; - double n1Nai = 0; - double n1Wai = 0; + double n1Nai = 0; + double n1Wai = 0; // Use the map to get the bleed values std::tie(n1Packs, n1Nai, n1Wai) = bleedValues[{type, altitude < 8000, oat < cp}]; @@ -229,34 +230,34 @@ class ThrustLimits_A32NX { * @param wing The status of the wing anti-ice (0 for off, 1 for on). * @return The N1 limit for the engine. */ - static double limitN1(int type, // + static double limitN1(int type, // double altitude, // double ambientTemp, // double ambientPressure, // double flexTemp, // - int packs, // - int nacelle, // - int wing // + int packs, // + int nacelle, // + int wing // ) { - int rowMin = 0; - int rowMax = 0; - int loAltRow = 0; - int hiAltRow = 0; - double mach = 0; + int rowMin = 0; + int rowMax = 0; + int loAltRow = 0; + int hiAltRow = 0; + double mach = 0; // Set main variables per Limit Type switch (type) { - case 0: // TO + case 0: // TO rowMin = 0; rowMax = 20; - mach = 0; + mach = 0; break; - case 1: // GA + case 1: // GA rowMin = 21; rowMax = 41; - mach = 0.225; + mach = 0.225; break; - case 2: // CLB + case 2: // CLB rowMin = 42; rowMax = 58; if (altitude <= 10000) { @@ -267,10 +268,10 @@ class ThrustLimits_A32NX { mach = 0.78; } break; - case 3: // MCT + case 3: // MCT rowMin = 59; rowMax = 71; - mach = Fadec::cas2mach(230, ambientPressure); + mach = Fadec::cas2mach(230, ambientPressure); break; } @@ -287,34 +288,33 @@ class ThrustLimits_A32NX { } // Define key table variables and interpolation - const double cp = Fadec::interpolate(altitude, limits[loAltRow][0], limits[hiAltRow][0], limits[loAltRow][1], limits[hiAltRow][1]); - const double lp = Fadec::interpolate(altitude, limits[loAltRow][0], limits[hiAltRow][0], limits[loAltRow][2], limits[hiAltRow][2]); + const double cp = Fadec::interpolate(altitude, limits[loAltRow][0], limits[hiAltRow][0], limits[loAltRow][1], limits[hiAltRow][1]); + const double lp = Fadec::interpolate(altitude, limits[loAltRow][0], limits[hiAltRow][0], limits[loAltRow][2], limits[hiAltRow][2]); const double cn1Flat = Fadec::interpolate(altitude, limits[loAltRow][0], limits[hiAltRow][0], limits[loAltRow][3], limits[hiAltRow][3]); const double cn1Last = Fadec::interpolate(altitude, limits[loAltRow][0], limits[hiAltRow][0], limits[loAltRow][4], limits[hiAltRow][4]); const double cn1Flex = Fadec::interpolate(altitude, limits[loAltRow][0], limits[hiAltRow][0], limits[loAltRow][5], limits[hiAltRow][5]); double cn1 = 0; - double m = 0; - double b = 0; - if (flexTemp > 0 && type <= 1) { // CN1 for Flex Case + double m = 0; + double b = 0; + if (flexTemp > 0 && type <= 1) { // CN1 for Flex Case if (flexTemp <= cp) { cn1 = cn1Flat; } else if (flexTemp > lp) { - m = (cn1Flex - cn1Last) / (100 - lp); - b = cn1Flex - m * 100; + m = (cn1Flex - cn1Last) / (100 - lp); + b = cn1Flex - m * 100; cn1 = (m * flexTemp) + b; } else { - m = (cn1Last - cn1Flat) / (lp - cp); - b = cn1Last - m * lp; + m = (cn1Last - cn1Flat) / (lp - cp); + b = cn1Last - m * lp; cn1 = (m * flexTemp) + b; } - } - else { // CN1 for All other cases + } else { // CN1 for All other cases if (ambientTemp <= cp) { cn1 = cn1Flat; } else { - m = (cn1Last - cn1Flat) / (lp - cp); - b = cn1Last - m * lp; + m = (cn1Last - cn1Flat) / (lp - cp); + b = cn1Last - m * lp; cn1 = (m * ambientTemp) + b; } } diff --git a/fbw-a380x/src/wasm/extra-backend-a380x/CMakeLists.txt b/fbw-a380x/src/wasm/extra-backend-a380x/CMakeLists.txt index 4127b3c5da7..92946e5cf2a 100644 --- a/fbw-a380x/src/wasm/extra-backend-a380x/CMakeLists.txt +++ b/fbw-a380x/src/wasm/extra-backend-a380x/CMakeLists.txt @@ -30,7 +30,6 @@ set(INCLUDE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/src/Pushback/Pushback_A380X.h ${FBW_COMMON}/cpp-msfs-framework/Example/ExampleModule.h ${FBW_COMMON}/cpp-msfs-framework/Example/longtext.h - ${FBW_COMMON}/extra-backend/Pushback/InertialDampener.hpp ${FBW_COMMON}/extra-backend/Pushback/Pushback.h ${FBW_COMMON}/extra-backend/AircraftPresets/AircraftPresets.h ${FBW_COMMON}/extra-backend/AircraftPresets/PresetProcedures.h diff --git a/fbw-a380x/src/wasm/extra-backend-a380x/src/AircraftPresets/AircraftPresetProcedures_A380X.h b/fbw-a380x/src/wasm/extra-backend-a380x/src/AircraftPresets/AircraftPresetProcedures_A380X.h index 439ff46186b..142fa7973e0 100644 --- a/fbw-a380x/src/wasm/extra-backend-a380x/src/AircraftPresets/AircraftPresetProcedures_A380X.h +++ b/fbw-a380x/src/wasm/extra-backend-a380x/src/AircraftPresets/AircraftPresetProcedures_A380X.h @@ -17,7 +17,7 @@ class AircraftPresetProcedures_A380X { public: const inline static PresetProceduresDefinition aircraftProcedureDefinition{ - // clang-format off + // clang-format off // @formatter:off .POWERED_CONFIG_ON { @@ -267,7 +267,7 @@ class AircraftPresetProcedures_A380X { } // @formatter:on - // clang-format on + // clang-format on }; }; diff --git a/fbw-a380x/src/wasm/extra-backend-a380x/src/Gauge_Extra_Backend.cpp b/fbw-a380x/src/wasm/extra-backend-a380x/src/Gauge_Extra_Backend.cpp index ef69dc548af..ff4b5c14e27 100644 --- a/fbw-a380x/src/wasm/extra-backend-a380x/src/Gauge_Extra_Backend.cpp +++ b/fbw-a380x/src/wasm/extra-backend-a380x/src/Gauge_Extra_Backend.cpp @@ -36,8 +36,8 @@ ExampleModule exampleModule(msfsHandler); // ADD ADDITIONAL MODULES HERE // This is the only place these have to be added - everything else is handled automatically LightingPresets_A380X lightingPresets(msfsHandler); -Pushback_A380X pushback(msfsHandler); -AircraftPresets aircraftPresets(msfsHandler, AircraftPresetProcedures_A380X::aircraftProcedureDefinition); +Pushback_A380X pushback(msfsHandler); +AircraftPresets aircraftPresets(msfsHandler, AircraftPresetProcedures_A380X::aircraftProcedureDefinition); /** * Gauge Callback diff --git a/fbw-a380x/src/wasm/extra-backend-a380x/src/LightingPresets/LightingPresets_A380X.cpp b/fbw-a380x/src/wasm/extra-backend-a380x/src/LightingPresets/LightingPresets_A380X.cpp index ba8c8d19b8f..3877745ab1d 100644 --- a/fbw-a380x/src/wasm/extra-backend-a380x/src/LightingPresets/LightingPresets_A380X.cpp +++ b/fbw-a380x/src/wasm/extra-backend-a380x/src/LightingPresets/LightingPresets_A380X.cpp @@ -40,35 +40,35 @@ bool LightingPresets_A380X::initialize_aircraft() { // Light Potentiometers - manual update and write when load/saving is requested readingLightCptLevel = createLightPotentiometerVar(96); - readingLightFoLevel = createLightPotentiometerVar(97); + readingLightFoLevel = createLightPotentiometerVar(97); glareshieldIntegralLightLevel = createLightPotentiometerVar(84); - glareshieldLcdLightLevel = createLightPotentiometerVar(87); - tableLightCptLevel = createLightPotentiometerVar(10); - tableLightFoLevel = createLightPotentiometerVar(11); + glareshieldLcdLightLevel = createLightPotentiometerVar(87); + tableLightCptLevel = createLightPotentiometerVar(10); + tableLightFoLevel = createLightPotentiometerVar(11); - pfdBrtCptLevel = createLightPotentiometerVar(88); - ndBrtCptLevel = createLightPotentiometerVar(89); + pfdBrtCptLevel = createLightPotentiometerVar(88); + ndBrtCptLevel = createLightPotentiometerVar(89); wxTerrainBrtCptLevel = createLightPotentiometerVar(94); - mfdBrtCptLevel = createLightPotentiometerVar(98); + mfdBrtCptLevel = createLightPotentiometerVar(98); consoleLightCptLevel = createLightPotentiometerVar(8); - pfdBrtFoLevel = createLightPotentiometerVar(90); - ndBrtFoLevel = createLightPotentiometerVar(91); + pfdBrtFoLevel = createLightPotentiometerVar(90); + ndBrtFoLevel = createLightPotentiometerVar(91); wxTerrainBrtFoLevel = createLightPotentiometerVar(95); - mfdBrtFoLevel = createLightPotentiometerVar(99); + mfdBrtFoLevel = createLightPotentiometerVar(99); consoleLightFoLevel = createLightPotentiometerVar(9); - rmpCptLightLevel = createLightPotentiometerVar(80); - rmpFoLightLevel = createLightPotentiometerVar(81); - rmpOvhdLightLevel = createLightPotentiometerVar(82); + rmpCptLightLevel = createLightPotentiometerVar(80); + rmpFoLightLevel = createLightPotentiometerVar(81); + rmpOvhdLightLevel = createLightPotentiometerVar(82); ecamUpperLightLevel = createLightPotentiometerVar(92); ecamLowerLightLevel = createLightPotentiometerVar(93); - pedFloodLightLevel = createLightPotentiometerVar(76); + pedFloodLightLevel = createLightPotentiometerVar(76); mainPnlFloodLightLevel = createLightPotentiometerVar(83); - integralLightLevel = createLightPotentiometerVar(85); - ambientLightLevel = createLightPotentiometerVar(7); + integralLightLevel = createLightPotentiometerVar(85); + ambientLightLevel = createLightPotentiometerVar(7); loadLightingPresetRequest->setAsInt64(0); saveLightingPresetRequest->setAsInt64(0); @@ -86,35 +86,35 @@ void LightingPresets_A380X::readFromAircraft() { currentLightValues.efbBrightness = efbBrightness->readFromSim(); currentLightValues.readingLightCptLevel = readingLightCptLevel->readFromSim(); - currentLightValues.readingLightFoLevel = readingLightFoLevel->readFromSim(); + currentLightValues.readingLightFoLevel = readingLightFoLevel->readFromSim(); currentLightValues.glareshieldIntegralLightLevel = glareshieldIntegralLightLevel->readFromSim(); - currentLightValues.glareshieldLcdLightLevel = glareshieldLcdLightLevel->readFromSim(); - currentLightValues.tableLightCptLevel = tableLightCptLevel->readFromSim(); - currentLightValues.tableLightFoLevel = tableLightFoLevel->readFromSim(); + currentLightValues.glareshieldLcdLightLevel = glareshieldLcdLightLevel->readFromSim(); + currentLightValues.tableLightCptLevel = tableLightCptLevel->readFromSim(); + currentLightValues.tableLightFoLevel = tableLightFoLevel->readFromSim(); - currentLightValues.pfdBrtCptLevel = pfdBrtCptLevel->readFromSim(); - currentLightValues.ndBrtCptLevel = ndBrtCptLevel->readFromSim(); + currentLightValues.pfdBrtCptLevel = pfdBrtCptLevel->readFromSim(); + currentLightValues.ndBrtCptLevel = ndBrtCptLevel->readFromSim(); currentLightValues.wxTerrainBrtCptLevel = wxTerrainBrtCptLevel->readFromSim(); - currentLightValues.mfdBrtCptLevel = mfdBrtCptLevel->readFromSim(); + currentLightValues.mfdBrtCptLevel = mfdBrtCptLevel->readFromSim(); currentLightValues.consoleLightCptLevel = consoleLightCptLevel->readFromSim(); - currentLightValues.pfdBrtFoLevel = pfdBrtFoLevel->readFromSim(); - currentLightValues.ndBrtFoLevel = ndBrtFoLevel->readFromSim(); + currentLightValues.pfdBrtFoLevel = pfdBrtFoLevel->readFromSim(); + currentLightValues.ndBrtFoLevel = ndBrtFoLevel->readFromSim(); currentLightValues.wxTerrainBrtFoLevel = wxTerrainBrtFoLevel->readFromSim(); - currentLightValues.mfdBrtFoLevel = mfdBrtFoLevel->readFromSim(); + currentLightValues.mfdBrtFoLevel = mfdBrtFoLevel->readFromSim(); currentLightValues.consoleLightFoLevel = consoleLightFoLevel->readFromSim(); - currentLightValues.rmpCptLightLevel = rmpCptLightLevel->readFromSim(); - currentLightValues.rmpFoLightLevel = rmpFoLightLevel->readFromSim(); - currentLightValues.rmpOvhdLightLevel = rmpOvhdLightLevel->readFromSim(); + currentLightValues.rmpCptLightLevel = rmpCptLightLevel->readFromSim(); + currentLightValues.rmpFoLightLevel = rmpFoLightLevel->readFromSim(); + currentLightValues.rmpOvhdLightLevel = rmpOvhdLightLevel->readFromSim(); currentLightValues.ecamUpperLightLevel = ecamUpperLightLevel->readFromSim(); currentLightValues.ecamLowerLightLevel = ecamLowerLightLevel->readFromSim(); currentLightValues.mainPnlFloodLightLevel = mainPnlFloodLightLevel->readFromSim(); - currentLightValues.integralLightLevel = integralLightLevel->readFromSim(); - currentLightValues.pedFloodLightLevel = pedFloodLightLevel->readFromSim(); - currentLightValues.ambientLightLevel = ambientLightLevel->readFromSim(); + currentLightValues.integralLightLevel = integralLightLevel->readFromSim(); + currentLightValues.pedFloodLightLevel = pedFloodLightLevel->readFromSim(); + currentLightValues.ambientLightLevel = ambientLightLevel->readFromSim(); } void LightingPresets_A380X::applyToAircraft() { @@ -164,70 +164,70 @@ void LightingPresets_A380X::loadFromIni(const mINI::INIStructure& ini, const std loadedLightValues.efbBrightness = iniGetOrDefault(ini, iniSectionName, "efb_brightness", 80.0); loadedLightValues.readingLightCptLevel = iniGetOrDefault(ini, iniSectionName, "reading_cpt_lt", 50.0); - loadedLightValues.readingLightFoLevel = iniGetOrDefault(ini, iniSectionName, "reading_fo_lt", 50.0); + loadedLightValues.readingLightFoLevel = iniGetOrDefault(ini, iniSectionName, "reading_fo_lt", 50.0); loadedLightValues.glareshieldIntegralLightLevel = iniGetOrDefault(ini, iniSectionName, "glareshield_int_lt", 50.0); - loadedLightValues.glareshieldLcdLightLevel = iniGetOrDefault(ini, iniSectionName, "glareshield_lcd_lt", 50.0); - loadedLightValues.tableLightCptLevel = iniGetOrDefault(ini, iniSectionName, "table_cpt_lt", 50.0); - loadedLightValues.tableLightFoLevel = iniGetOrDefault(ini, iniSectionName, "table_fo_lt", 50.0); + loadedLightValues.glareshieldLcdLightLevel = iniGetOrDefault(ini, iniSectionName, "glareshield_lcd_lt", 50.0); + loadedLightValues.tableLightCptLevel = iniGetOrDefault(ini, iniSectionName, "table_cpt_lt", 50.0); + loadedLightValues.tableLightFoLevel = iniGetOrDefault(ini, iniSectionName, "table_fo_lt", 50.0); - loadedLightValues.pfdBrtCptLevel = iniGetOrDefault(ini, iniSectionName, "pfd_cpt_lvl", 50.0); - loadedLightValues.ndBrtCptLevel = iniGetOrDefault(ini, iniSectionName, "nd_cpt_lvl", 50.0); + loadedLightValues.pfdBrtCptLevel = iniGetOrDefault(ini, iniSectionName, "pfd_cpt_lvl", 50.0); + loadedLightValues.ndBrtCptLevel = iniGetOrDefault(ini, iniSectionName, "nd_cpt_lvl", 50.0); loadedLightValues.wxTerrainBrtCptLevel = iniGetOrDefault(ini, iniSectionName, "wx_cpt_lvl", 50.0); - loadedLightValues.mfdBrtCptLevel = iniGetOrDefault(ini, iniSectionName, "mfd_cpt_lvl", 50.0); + loadedLightValues.mfdBrtCptLevel = iniGetOrDefault(ini, iniSectionName, "mfd_cpt_lvl", 50.0); loadedLightValues.consoleLightCptLevel = iniGetOrDefault(ini, iniSectionName, "console_cpt_lt", 50.0); - loadedLightValues.pfdBrtFoLevel = iniGetOrDefault(ini, iniSectionName, "pfd_fo_lvl", 50.0); - loadedLightValues.ndBrtFoLevel = iniGetOrDefault(ini, iniSectionName, "nd_fo_lvl", 50.0); + loadedLightValues.pfdBrtFoLevel = iniGetOrDefault(ini, iniSectionName, "pfd_fo_lvl", 50.0); + loadedLightValues.ndBrtFoLevel = iniGetOrDefault(ini, iniSectionName, "nd_fo_lvl", 50.0); loadedLightValues.wxTerrainBrtFoLevel = iniGetOrDefault(ini, iniSectionName, "wx_fo_lvl", 50.0); - loadedLightValues.mfdBrtFoLevel = iniGetOrDefault(ini, iniSectionName, "mfd_fo_lvl", 50.0); + loadedLightValues.mfdBrtFoLevel = iniGetOrDefault(ini, iniSectionName, "mfd_fo_lvl", 50.0); loadedLightValues.consoleLightFoLevel = iniGetOrDefault(ini, iniSectionName, "console_fo_lt", 50.0); - loadedLightValues.rmpCptLightLevel = iniGetOrDefault(ini, iniSectionName, "rmp_cpt_lt", 50.0); - loadedLightValues.rmpFoLightLevel = iniGetOrDefault(ini, iniSectionName, "rmp_fo_lt", 50.0); - loadedLightValues.rmpOvhdLightLevel = iniGetOrDefault(ini, iniSectionName, "rmp_ovhd_lt", 50.0); + loadedLightValues.rmpCptLightLevel = iniGetOrDefault(ini, iniSectionName, "rmp_cpt_lt", 50.0); + loadedLightValues.rmpFoLightLevel = iniGetOrDefault(ini, iniSectionName, "rmp_fo_lt", 50.0); + loadedLightValues.rmpOvhdLightLevel = iniGetOrDefault(ini, iniSectionName, "rmp_ovhd_lt", 50.0); loadedLightValues.ecamUpperLightLevel = iniGetOrDefault(ini, iniSectionName, "ecam_upper_lvl", 50.0); loadedLightValues.ecamLowerLightLevel = iniGetOrDefault(ini, iniSectionName, "ecam_lower_lvl", 50.0); - loadedLightValues.pedFloodLightLevel = iniGetOrDefault(ini, iniSectionName, "flood_ped_lvl", 50.0); + loadedLightValues.pedFloodLightLevel = iniGetOrDefault(ini, iniSectionName, "flood_ped_lvl", 50.0); loadedLightValues.mainPnlFloodLightLevel = iniGetOrDefault(ini, iniSectionName, "flood_pnl_lt", 50.0); - loadedLightValues.integralLightLevel = iniGetOrDefault(ini, iniSectionName, "pedestal_int_lt", 50.0); - loadedLightValues.ambientLightLevel = iniGetOrDefault(ini, iniSectionName, "cabin_light", 50.0); + loadedLightValues.integralLightLevel = iniGetOrDefault(ini, iniSectionName, "pedestal_int_lt", 50.0); + loadedLightValues.ambientLightLevel = iniGetOrDefault(ini, iniSectionName, "cabin_light", 50.0); } void LightingPresets_A380X::saveToIni(mINI::INIStructure& ini, const std::string& iniSectionName) const { ini[iniSectionName]["efb_brightness"] = std::to_string(currentLightValues.efbBrightness); ini[iniSectionName]["reading_cpt_lt"] = std::to_string(currentLightValues.readingLightCptLevel); - ini[iniSectionName]["reading_fo_lt"] = std::to_string(currentLightValues.readingLightFoLevel); + ini[iniSectionName]["reading_fo_lt"] = std::to_string(currentLightValues.readingLightFoLevel); ini[iniSectionName]["glareshield_int_lt"] = std::to_string(currentLightValues.glareshieldIntegralLightLevel); ini[iniSectionName]["glareshield_lcd_lt"] = std::to_string(currentLightValues.glareshieldLcdLightLevel); - ini[iniSectionName]["table_cpt_lt"] = std::to_string(currentLightValues.tableLightCptLevel); - ini[iniSectionName]["table_fo_lt"] = std::to_string(currentLightValues.tableLightFoLevel); + ini[iniSectionName]["table_cpt_lt"] = std::to_string(currentLightValues.tableLightCptLevel); + ini[iniSectionName]["table_fo_lt"] = std::to_string(currentLightValues.tableLightFoLevel); - ini[iniSectionName]["pfd_cpt_lvl"] = std::to_string(currentLightValues.pfdBrtCptLevel); - ini[iniSectionName]["nd_cpt_lvl"] = std::to_string(currentLightValues.ndBrtCptLevel); - ini[iniSectionName]["wx_cpt_lvl"] = std::to_string(currentLightValues.wxTerrainBrtCptLevel); - ini[iniSectionName]["mfd_cpt_lvl"] = std::to_string(currentLightValues.mfdBrtCptLevel); + ini[iniSectionName]["pfd_cpt_lvl"] = std::to_string(currentLightValues.pfdBrtCptLevel); + ini[iniSectionName]["nd_cpt_lvl"] = std::to_string(currentLightValues.ndBrtCptLevel); + ini[iniSectionName]["wx_cpt_lvl"] = std::to_string(currentLightValues.wxTerrainBrtCptLevel); + ini[iniSectionName]["mfd_cpt_lvl"] = std::to_string(currentLightValues.mfdBrtCptLevel); ini[iniSectionName]["console_cpt_lt"] = std::to_string(currentLightValues.consoleLightCptLevel); - ini[iniSectionName]["pfd_fo_lvl"] = std::to_string(currentLightValues.pfdBrtFoLevel); - ini[iniSectionName]["nd_fo_lvl"] = std::to_string(currentLightValues.ndBrtFoLevel); - ini[iniSectionName]["wx_fo_lvl"] = std::to_string(currentLightValues.wxTerrainBrtFoLevel); - ini[iniSectionName]["mfd_fo_lvl"] = std::to_string(currentLightValues.mfdBrtFoLevel); + ini[iniSectionName]["pfd_fo_lvl"] = std::to_string(currentLightValues.pfdBrtFoLevel); + ini[iniSectionName]["nd_fo_lvl"] = std::to_string(currentLightValues.ndBrtFoLevel); + ini[iniSectionName]["wx_fo_lvl"] = std::to_string(currentLightValues.wxTerrainBrtFoLevel); + ini[iniSectionName]["mfd_fo_lvl"] = std::to_string(currentLightValues.mfdBrtFoLevel); ini[iniSectionName]["console_fo_lt"] = std::to_string(currentLightValues.consoleLightFoLevel); - ini[iniSectionName]["rmp_cpt_lt"] = std::to_string(currentLightValues.rmpCptLightLevel); - ini[iniSectionName]["rmp_fo_lt"] = std::to_string(currentLightValues.rmpFoLightLevel); - ini[iniSectionName]["rmp_ovhd_lt"] = std::to_string(currentLightValues.rmpOvhdLightLevel); + ini[iniSectionName]["rmp_cpt_lt"] = std::to_string(currentLightValues.rmpCptLightLevel); + ini[iniSectionName]["rmp_fo_lt"] = std::to_string(currentLightValues.rmpFoLightLevel); + ini[iniSectionName]["rmp_ovhd_lt"] = std::to_string(currentLightValues.rmpOvhdLightLevel); ini[iniSectionName]["ecam_upper_lvl"] = std::to_string(currentLightValues.ecamUpperLightLevel); ini[iniSectionName]["ecam_lower_lvl"] = std::to_string(currentLightValues.ecamLowerLightLevel); - ini[iniSectionName]["flood_ped_lvl"] = std::to_string(currentLightValues.pedFloodLightLevel); - ini[iniSectionName]["flood_pnl_lt"] = std::to_string(currentLightValues.mainPnlFloodLightLevel); + ini[iniSectionName]["flood_ped_lvl"] = std::to_string(currentLightValues.pedFloodLightLevel); + ini[iniSectionName]["flood_pnl_lt"] = std::to_string(currentLightValues.mainPnlFloodLightLevel); ini[iniSectionName]["pedestal_int_lt"] = std::to_string(currentLightValues.integralLightLevel); - ini[iniSectionName]["cabin_light"] = std::to_string(currentLightValues.ambientLightLevel); + ini[iniSectionName]["cabin_light"] = std::to_string(currentLightValues.ambientLightLevel); } [[maybe_unused]] std::string LightingPresets_A380X::str() const { diff --git a/fbw-a380x/src/wasm/extra-backend-a380x/src/LightingPresets/LightingPresets_A380X.h b/fbw-a380x/src/wasm/extra-backend-a380x/src/LightingPresets/LightingPresets_A380X.h index 92c337bd4f1..52d7b733432 100644 --- a/fbw-a380x/src/wasm/extra-backend-a380x/src/LightingPresets/LightingPresets_A380X.h +++ b/fbw-a380x/src/wasm/extra-backend-a380x/src/LightingPresets/LightingPresets_A380X.h @@ -18,8 +18,8 @@ struct LightingValues_A380X { FLOAT64 efbBrightness; // A32NX_EFB_BRIGHTNESS // OVHD - FLOAT64 readingLightCptLevel; // 96 - FLOAT64 readingLightFoLevel; // 97 + FLOAT64 readingLightCptLevel; // 96 + FLOAT64 readingLightFoLevel; // 97 // Glareshield FLOAT64 glareshieldIntegralLightLevel; // 84 @@ -34,23 +34,23 @@ struct LightingValues_A380X { FLOAT64 mfdBrtCptLevel; // 98 FLOAT64 consoleLightCptLevel; // 8 (0, 50, 100) - FLOAT64 pfdBrtFoLevel; // 90 - FLOAT64 ndBrtFoLevel; // 91 - FLOAT64 wxTerrainBrtFoLevel; // 95 - FLOAT64 mfdBrtFoLevel; // 99 - FLOAT64 consoleLightFoLevel; // 9 (0, 50, 100) + FLOAT64 pfdBrtFoLevel; // 90 + FLOAT64 ndBrtFoLevel; // 91 + FLOAT64 wxTerrainBrtFoLevel; // 95 + FLOAT64 mfdBrtFoLevel; // 99 + FLOAT64 consoleLightFoLevel; // 9 (0, 50, 100) // Pedestal - FLOAT64 rmpCptLightLevel; // 80 - FLOAT64 rmpFoLightLevel; // 81 - FLOAT64 rmpOvhdLightLevel; // 82 - FLOAT64 ecamUpperLightLevel; // 92 - FLOAT64 ecamLowerLightLevel; // 93 - - FLOAT64 pedFloodLightLevel; // 76 - FLOAT64 mainPnlFloodLightLevel; // 83 - FLOAT64 integralLightLevel; // 85 - FLOAT64 ambientLightLevel; // 7 + FLOAT64 rmpCptLightLevel; // 80 + FLOAT64 rmpFoLightLevel; // 81 + FLOAT64 rmpOvhdLightLevel; // 82 + FLOAT64 ecamUpperLightLevel; // 92 + FLOAT64 ecamLowerLightLevel; // 93 + + FLOAT64 pedFloodLightLevel; // 76 + FLOAT64 mainPnlFloodLightLevel; // 83 + FLOAT64 integralLightLevel; // 85 + FLOAT64 ambientLightLevel; // 7 }; /** @@ -137,8 +137,8 @@ class LightingPresets_A380X : public LightingPresets { void loadFromIni(const mINI::INIStructure& ini, const std::string& iniSectionName) override; void saveToIni(mINI::INIStructure& ini, const std::string& iniSectionName) const override; - const LightingValues_A380X DEFAULT_50 = {50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, - 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0}; + const LightingValues_A380X DEFAULT_50 = {50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, + 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0}; }; inline bool operator==(const LightingValues_A380X& p1, const LightingValues_A380X& p2) { diff --git a/fbw-a380x/src/wasm/extra-backend-a380x/src/Pushback/Pushback_A380X.h b/fbw-a380x/src/wasm/extra-backend-a380x/src/Pushback/Pushback_A380X.h index a4154d07f3d..a73dfdfbb9f 100644 --- a/fbw-a380x/src/wasm/extra-backend-a380x/src/Pushback/Pushback_A380X.h +++ b/fbw-a380x/src/wasm/extra-backend-a380x/src/Pushback/Pushback_A380X.h @@ -10,9 +10,9 @@ * @brief Aircraft specific pushback implementation for the A380X */ class Pushback_A380X : public Pushback { - static constexpr FLOAT64 PARKING_BRAKE_FACTOR = 100.0; // slow down when parking brake is engaged by this factor - static constexpr FLOAT64 SPEED_FACTOR = 15.0; // ft/sec for "VELOCITY BODY Z" (also max speed) - static constexpr FLOAT64 TURN_SPEED_FACTOR = 0.25; // ft/sec for "ROTATION VELOCITY BODY Y" + static constexpr FLOAT64 PARKING_BRAKE_FACTOR = 100.0; // slow down when parking brake is engaged by this factor + static constexpr FLOAT64 SPEED_FACTOR = 15.0; // ft/sec for "VELOCITY BODY Z" (also max speed) + static constexpr FLOAT64 TURN_SPEED_FACTOR = 0.25; // ft/sec for "ROTATION VELOCITY BODY Y" public: /** @@ -22,7 +22,7 @@ class Pushback_A380X : public Pushback { explicit Pushback_A380X(MsfsHandler& msfsHandler) : Pushback(msfsHandler) {} private: - constexpr int getParkBrakeFactor() const override final { return PARKING_BRAKE_FACTOR; } + constexpr int getParkBrakeFactor() const override final { return PARKING_BRAKE_FACTOR; } constexpr FLOAT64 getSpeedFactor() const override final { return SPEED_FACTOR; } constexpr FLOAT64 getTurnSpeedFactor() const override final { return TURN_SPEED_FACTOR; } }; diff --git a/fbw-a380x/src/wasm/fadec_a380x/README.md b/fbw-a380x/src/wasm/fadec_a380x/README.md index b3d2525a9f8..14ab32b202c 100644 --- a/fbw-a380x/src/wasm/fadec_a380x/README.md +++ b/fbw-a380x/src/wasm/fadec_a380x/README.md @@ -1,5 +1,5 @@ # A380X FADEC This is a new version of the FADEC system for the A380X. -It is a migration and cleanup of the original FADEC system, +It is a migration and cleanup of the original FADEC system, and is designed to be more modular and easier to maintain. diff --git a/fbw-a380x/src/wasm/fadec_a380x/src/Fadec/EngineControl_A380X.cpp b/fbw-a380x/src/wasm/fadec_a380x/src/Fadec/EngineControl_A380X.cpp index fa5fb96ac59..96e504ffe48 100644 --- a/fbw-a380x/src/wasm/fadec_a380x/src/Fadec/EngineControl_A380X.cpp +++ b/fbw-a380x/src/wasm/fadec_a380x/src/Fadec/EngineControl_A380X.cpp @@ -488,8 +488,8 @@ int EngineControl_A380X::updateFF(int engine, double outFlow = 0; // kg/hour if (correctedFuelFlow >= 1) { outFlow = std::max(0.0, // - (correctedFuelFlow * Fadec::LBS_TO_KGS * EngineRatios::delta2(mach, ambientPressure) // - * (std::sqrt)(EngineRatios::theta2(mach, ambientTemperature)))); + (correctedFuelFlow * Fadec::LBS_TO_KGS * EngineRatios::delta2(mach, ambientPressure) // + * (std::sqrt)(EngineRatios::theta2(mach, ambientTemperature)))); } simData.engineFF[engine - 1]->set(outFlow); diff --git a/fbw-a380x/src/wasm/fadec_a380x/src/Fadec/EngineControl_A380X.h b/fbw-a380x/src/wasm/fadec_a380x/src/Fadec/EngineControl_A380X.h index d0c084f5ae8..e4322013d1d 100644 --- a/fbw-a380x/src/wasm/fadec_a380x/src/Fadec/EngineControl_A380X.h +++ b/fbw-a380x/src/wasm/fadec_a380x/src/Fadec/EngineControl_A380X.h @@ -52,7 +52,7 @@ class EngineControl_A380X { double prevThrustLimitType = 0.0; // FLX->CLB thrust limit transition - bool wasFlexActive; + bool wasFlexActive; double transitionStartTime; double transitionFactor; diff --git a/fbw-a380x/src/wasm/fadec_a380x/src/Fadec/Polynomials_A380X.hpp b/fbw-a380x/src/wasm/fadec_a380x/src/Fadec/Polynomials_A380X.hpp index 5733ecb3e4e..fe8c6f4f9c7 100644 --- a/fbw-a380x/src/wasm/fadec_a380x/src/Fadec/Polynomials_A380X.hpp +++ b/fbw-a380x/src/wasm/fadec_a380x/src/Fadec/Polynomials_A380X.hpp @@ -265,8 +265,8 @@ class Polynomial_A380X { // data or a mathematical model of the engine's behavior. // The choice to use different decay rates and steady state temperatures based on the previous // EGT suggests that the engine's shutdown behavior changes at this threshold. - double threshold = ambientTemp + 140; - double decayRate = previousEGT > threshold ? 0.0257743 : 0.00072756; + double threshold = ambientTemp + 140; + double decayRate = previousEGT > threshold ? 0.0257743 : 0.00072756; double steadyStateTemp = previousEGT > threshold ? 135 + ambientTemp : 30 + ambientTemp; return steadyStateTemp + (previousEGT - steadyStateTemp) * exp(-decayRate * deltaTime); } diff --git a/fbw-a380x/src/wasm/fadec_a380x/src/Fadec/Table1502_A380X.hpp b/fbw-a380x/src/wasm/fadec_a380x/src/Fadec/Table1502_A380X.hpp index fb77e660385..707b1eca8d4 100644 --- a/fbw-a380x/src/wasm/fadec_a380x/src/Fadec/Table1502_A380X.hpp +++ b/fbw-a380x/src/wasm/fadec_a380x/src/Fadec/Table1502_A380X.hpp @@ -30,23 +30,22 @@ class Table1502_A380X { * @return A 2D array representing the CN2 - correctedN1 pairs. */ static constexpr double table1502[13][4] = { - {16.012, 0.000, 0.000, 17.000}, // CN3 = 18.20, correctedN1 = [0.00, 0.00] at Mach 0.2, correctedN1 = 17.00 at Mach 0.9 - {19.355, 1.845, 1.845, 17.345}, // CN3 = 22.00, correctedN1 = [1.90, 1.90] at Mach 0.2, correctedN1 = 17.40 at Mach 0.9 - {22.874, 2.427, 2.427, 18.127}, // CN3 = 26.00, correctedN1 = [2.50, 2.50] at Mach 0.2, correctedN1 = 18.20 at Mach 0.9 - {50.147, 12.427, 12.427, 26.627}, // CN3 = 57.00, correctedN1 = [12.80, 12.80] at Mach 0.2, correctedN1 = 27.00 at Mach 0.9 - {60.000, 18.500, 18.500, 33.728}, // CN3 = 68.20, correctedN1 = [19.60, 19.60] at Mach 0.2, correctedN1 = 34.83 at Mach 0.9 - {67.742, 25.243, 25.243, 40.082}, // CN3 = 77.00, correctedN1 = [26.00, 26.00] at Mach 0.2, correctedN1 = 40.84 at Mach 0.9 - {73.021, 30.505, 30.505, 43.854}, // CN3 = 83.00, correctedN1 = [31.42, 31.42] at Mach 0.2, correctedN1 = 44.77 at Mach 0.9 - {78.299, 39.779, 39.779, 48.899}, // CN3 = 89.00, correctedN1 = [40.97, 40.97] at Mach 0.2, correctedN1 = 50.09 at Mach 0.9 - {81.642, 49.515, 49.515, 53.557}, // CN3 = 92.80, correctedN1 = [51.00, 51.00] at Mach 0.2, correctedN1 = 55.04 at Mach 0.9 - {85.337, 63.107, 63.107, 63.107}, // CN3 = 97.00, correctedN1 = [65.00, 65.00] at Mach 0.2, correctedN1 = 65.00 at Mach 0.9 - {87.977, 74.757, 74.757, 74.757}, // CN3 = 100.00, correctedN1 = [77.00, 77.00] at Mach 0.2, correctedN1 = 77.00 at Mach 0.9 - {97.800, 97.200, 97.200, 97.200}, // CN3 = 104.00, correctedN1 = [85.00, 85.00] at Mach 0.2, correctedN1 = 85.50 at Mach 0.9 + {16.012, 0.000, 0.000, 17.000 }, // CN3 = 18.20, correctedN1 = [0.00, 0.00] at Mach 0.2, correctedN1 = 17.00 at Mach 0.9 + {19.355, 1.845, 1.845, 17.345 }, // CN3 = 22.00, correctedN1 = [1.90, 1.90] at Mach 0.2, correctedN1 = 17.40 at Mach 0.9 + {22.874, 2.427, 2.427, 18.127 }, // CN3 = 26.00, correctedN1 = [2.50, 2.50] at Mach 0.2, correctedN1 = 18.20 at Mach 0.9 + {50.147, 12.427, 12.427, 26.627 }, // CN3 = 57.00, correctedN1 = [12.80, 12.80] at Mach 0.2, correctedN1 = 27.00 at Mach 0.9 + {60.000, 18.500, 18.500, 33.728 }, // CN3 = 68.20, correctedN1 = [19.60, 19.60] at Mach 0.2, correctedN1 = 34.83 at Mach 0.9 + {67.742, 25.243, 25.243, 40.082 }, // CN3 = 77.00, correctedN1 = [26.00, 26.00] at Mach 0.2, correctedN1 = 40.84 at Mach 0.9 + {73.021, 30.505, 30.505, 43.854 }, // CN3 = 83.00, correctedN1 = [31.42, 31.42] at Mach 0.2, correctedN1 = 44.77 at Mach 0.9 + {78.299, 39.779, 39.779, 48.899 }, // CN3 = 89.00, correctedN1 = [40.97, 40.97] at Mach 0.2, correctedN1 = 50.09 at Mach 0.9 + {81.642, 49.515, 49.515, 53.557 }, // CN3 = 92.80, correctedN1 = [51.00, 51.00] at Mach 0.2, correctedN1 = 55.04 at Mach 0.9 + {85.337, 63.107, 63.107, 63.107 }, // CN3 = 97.00, correctedN1 = [65.00, 65.00] at Mach 0.2, correctedN1 = 65.00 at Mach 0.9 + {87.977, 74.757, 74.757, 74.757 }, // CN3 = 100.00, correctedN1 = [77.00, 77.00] at Mach 0.2, correctedN1 = 77.00 at Mach 0.9 + {97.800, 97.200, 97.200, 97.200 }, // CN3 = 104.00, correctedN1 = [85.00, 85.00] at Mach 0.2, correctedN1 = 85.50 at Mach 0.9 {118.000, 115.347, 115.347, 115.347} // CN3 = 116.50, correctedN1 = [101.00, 101.00] at Mach 0.2, correctedN1 = 101.00 at Mach 0.9 }; public: - /** * @brief Calculates the expected CN3 at idle. * @@ -79,8 +78,8 @@ class Table1502_A380X { } // Retrieve the lower and upper bounds of the CN3 value and the correctedN1 value at Mach 0.2 and Mach 0.9 - const double cn3lo = table1502[i - 1][0]; - const double cn3hi = table1502[i][0]; + const double cn3lo = table1502[i - 1][0]; + const double cn3hi = table1502[i][0]; const double cn1lolo = table1502[i - 1][1]; const double cn1hilo = table1502[i][1]; const double cn1lohi = table1502[i - 1][3]; diff --git a/fbw-a380x/src/wasm/fadec_a380x/src/Fadec/ThrustLimits_A380X.hpp b/fbw-a380x/src/wasm/fadec_a380x/src/Fadec/ThrustLimits_A380X.hpp index 8cff773f45c..c0632409692 100644 --- a/fbw-a380x/src/wasm/fadec_a380x/src/Fadec/ThrustLimits_A380X.hpp +++ b/fbw-a380x/src/wasm/fadec_a380x/src/Fadec/ThrustLimits_A380X.hpp @@ -37,82 +37,82 @@ class ThrustLimits_A380X { * Climb (CLB), and Maximum Continuous Thrust (MCT). */ static constexpr double limits[72][6] = { - // TO - {-2000, 48.000, 55.000, 81.351, 79.370, 61.535}, // row 0 - {-1000, 46.000, 55.000, 82.605, 80.120, 62.105}, // - {0, 44.000, 55.000, 83.832, 80.776, 62.655}, // - {500, 42.000, 52.000, 84.210, 81.618, 62.655}, // - {1000, 42.000, 52.000, 84.579, 81.712, 62.655}, // - {2000, 40.000, 50.000, 85.594, 82.720, 62.655}, // - {3000, 36.000, 48.000, 86.657, 83.167, 61.960}, // - {4000, 32.000, 46.000, 87.452, 83.332, 61.206}, // - {5000, 29.000, 44.000, 88.833, 84.166, 61.206}, // - {6000, 25.000, 42.000, 90.232, 84.815, 61.206}, // - {7000, 21.000, 40.000, 91.711, 85.565, 61.258}, // - {8000, 17.000, 38.000, 93.247, 86.225, 61.777}, // - {9000, 15.000, 36.000, 94.031, 86.889, 60.968}, // - {10000, 13.000, 34.000, 94.957, 88.044, 60.935}, // - {11000, 12.000, 32.000, 95.295, 88.526, 59.955}, // - {12000, 11.000, 30.000, 95.568, 88.818, 58.677}, // - {13000, 10.000, 28.000, 95.355, 88.819, 59.323}, // - {14000, 10.000, 26.000, 95.372, 89.311, 59.965}, // - {15000, 8.000, 24.000, 95.686, 89.907, 58.723}, // - {16000, 5.000, 22.000, 96.160, 89.816, 57.189}, // - {16600, 5.000, 22.000, 96.560, 89.816, 57.189}, // - {-2000, 47.751, 54.681, 84.117, 81.901, 63.498}, // row 20 - // GA - {-1000, 45.771, 54.681, 85.255, 82.461, 63.920}, // row 21 - {0, 43.791, 54.681, 86.411, 83.021, 64.397}, // - {500, 42.801, 52.701, 86.978, 83.740, 64.401}, // - {1000, 41.811, 52.701, 87.568, 83.928, 64.525}, // - {2000, 38.841, 50.721, 88.753, 84.935, 64.489}, // - {3000, 36.861, 48.741, 89.930, 85.290, 63.364}, // - {4000, 32.901, 46.761, 91.004, 85.836, 62.875}, // - {5000, 28.941, 44.781, 92.198, 86.293, 62.614}, // - {6000, 24.981, 42.801, 93.253, 86.563, 62.290}, // - {7000, 21.022, 40.821, 94.273, 86.835, 61.952}, // - {8000, 17.062, 38.841, 94.919, 87.301, 62.714}, // - {9000, 15.082, 36.861, 95.365, 87.676, 61.692}, // - {10000, 13.102, 34.881, 95.914, 88.150, 60.906}, // - {11000, 12.112, 32.901, 96.392, 88.627, 59.770}, // - {12000, 11.122, 30.921, 96.640, 89.206, 58.933}, // - {13000, 10.132, 28.941, 96.516, 89.789, 60.503}, // - {14000, 9.142, 26.961, 96.516, 90.475, 62.072}, // - {15000, 9.142, 24.981, 96.623, 90.677, 59.333}, // - {16000, 7.162, 23.001, 96.845, 90.783, 58.045}, // - {16600, 5.182, 21.022, 97.366, 91.384, 58.642}, // row 40 - // CLB - {-2000, 30.800, 56.870, 80.280, 72.000, 0.000}, // row 41 - {2000, 20.990, 48.157, 82.580, 74.159, 0.000}, // - {5000, 16.139, 43.216, 84.642, 75.737, 0.000}, // - {8000, 7.342, 38.170, 86.835, 77.338, 0.000}, // - {10000, 4.051, 34.518, 88.183, 77.999, 0.000}, // - {10000.1, 4.051, 34.518, 87.453, 77.353, 0.000}, // - {12000, 0.760, 30.865, 88.303, 78.660, 0.000}, // - {15000, -4.859, 25.039, 89.748, 79.816, 0.000}, // - {17000, -9.934, 19.813, 90.668, 80.895, 0.000}, // - {20000, -15.822, 13.676, 92.106, 81.894, 0.000}, // - {24000, -22.750, 6.371, 93.651, 82.716, 0.000}, // - {27000, -29.105, -0.304, 93.838, 83.260, 0.000}, // - {29314, -32.049, -3.377, 93.502, 82.962, 0.000}, // - {31000, -34.980, -6.452, 95.392, 84.110, 0.000}, // - {35000, -45.679, -17.150, 96.104, 85.248, 0.000}, // - {39000, -45.679, -17.150, 96.205, 84.346, 0.000}, // - {41500, -45.679, -17.150, 95.676, 83.745, 0.000}, // row 58 - // MCT - {-1000, 26.995, 54.356, 82.465, 74.086, 0.000}, // row 59 - {3000, 18.170, 45.437, 86.271, 77.802, 0.000}, // - {7000, 9.230, 40.266, 89.128, 79.604, 0.000}, // - {11000, 4.019, 31.046, 92.194, 82.712, 0.000}, // - {15000, -5.226, 21.649, 95.954, 85.622, 0.000}, // - {17000, -9.913, 20.702, 97.520, 85.816, 0.000}, // - {20000, -15.129, 15.321, 99.263, 86.770, 0.000}, // - {22000, -19.947, 10.382, 98.977, 86.661, 0.000}, // - {25000, -25.397, 4.731, 98.440, 85.765, 0.000}, // - {27000, -30.369, -0.391, 97.279, 85.556, 0.000}, // - {31000, -36.806, -7.165, 98.674, 86.650, 0.000}, // - {35000, -43.628, -14.384, 98.386, 85.747, 0.000}, // - {39000, -47.286, -18.508, 97.278, 85.545, 0.000} // row 71 + // TO + {-2000, 48.000, 55.000, 81.351, 79.370, 61.535}, // row 0 + {-1000, 46.000, 55.000, 82.605, 80.120, 62.105}, // + {0, 44.000, 55.000, 83.832, 80.776, 62.655}, // + {500, 42.000, 52.000, 84.210, 81.618, 62.655}, // + {1000, 42.000, 52.000, 84.579, 81.712, 62.655}, // + {2000, 40.000, 50.000, 85.594, 82.720, 62.655}, // + {3000, 36.000, 48.000, 86.657, 83.167, 61.960}, // + {4000, 32.000, 46.000, 87.452, 83.332, 61.206}, // + {5000, 29.000, 44.000, 88.833, 84.166, 61.206}, // + {6000, 25.000, 42.000, 90.232, 84.815, 61.206}, // + {7000, 21.000, 40.000, 91.711, 85.565, 61.258}, // + {8000, 17.000, 38.000, 93.247, 86.225, 61.777}, // + {9000, 15.000, 36.000, 94.031, 86.889, 60.968}, // + {10000, 13.000, 34.000, 94.957, 88.044, 60.935}, // + {11000, 12.000, 32.000, 95.295, 88.526, 59.955}, // + {12000, 11.000, 30.000, 95.568, 88.818, 58.677}, // + {13000, 10.000, 28.000, 95.355, 88.819, 59.323}, // + {14000, 10.000, 26.000, 95.372, 89.311, 59.965}, // + {15000, 8.000, 24.000, 95.686, 89.907, 58.723}, // + {16000, 5.000, 22.000, 96.160, 89.816, 57.189}, // + {16600, 5.000, 22.000, 96.560, 89.816, 57.189}, // + {-2000, 47.751, 54.681, 84.117, 81.901, 63.498}, // row 20 + // GA + {-1000, 45.771, 54.681, 85.255, 82.461, 63.920}, // row 21 + {0, 43.791, 54.681, 86.411, 83.021, 64.397}, // + {500, 42.801, 52.701, 86.978, 83.740, 64.401}, // + {1000, 41.811, 52.701, 87.568, 83.928, 64.525}, // + {2000, 38.841, 50.721, 88.753, 84.935, 64.489}, // + {3000, 36.861, 48.741, 89.930, 85.290, 63.364}, // + {4000, 32.901, 46.761, 91.004, 85.836, 62.875}, // + {5000, 28.941, 44.781, 92.198, 86.293, 62.614}, // + {6000, 24.981, 42.801, 93.253, 86.563, 62.290}, // + {7000, 21.022, 40.821, 94.273, 86.835, 61.952}, // + {8000, 17.062, 38.841, 94.919, 87.301, 62.714}, // + {9000, 15.082, 36.861, 95.365, 87.676, 61.692}, // + {10000, 13.102, 34.881, 95.914, 88.150, 60.906}, // + {11000, 12.112, 32.901, 96.392, 88.627, 59.770}, // + {12000, 11.122, 30.921, 96.640, 89.206, 58.933}, // + {13000, 10.132, 28.941, 96.516, 89.789, 60.503}, // + {14000, 9.142, 26.961, 96.516, 90.475, 62.072}, // + {15000, 9.142, 24.981, 96.623, 90.677, 59.333}, // + {16000, 7.162, 23.001, 96.845, 90.783, 58.045}, // + {16600, 5.182, 21.022, 97.366, 91.384, 58.642}, // row 40 + // CLB + {-2000, 30.800, 56.870, 80.280, 72.000, 0.000 }, // row 41 + {2000, 20.990, 48.157, 82.580, 74.159, 0.000 }, // + {5000, 16.139, 43.216, 84.642, 75.737, 0.000 }, // + {8000, 7.342, 38.170, 86.835, 77.338, 0.000 }, // + {10000, 4.051, 34.518, 88.183, 77.999, 0.000 }, // + {10000.1, 4.051, 34.518, 87.453, 77.353, 0.000 }, // + {12000, 0.760, 30.865, 88.303, 78.660, 0.000 }, // + {15000, -4.859, 25.039, 89.748, 79.816, 0.000 }, // + {17000, -9.934, 19.813, 90.668, 80.895, 0.000 }, // + {20000, -15.822, 13.676, 92.106, 81.894, 0.000 }, // + {24000, -22.750, 6.371, 93.651, 82.716, 0.000 }, // + {27000, -29.105, -0.304, 93.838, 83.260, 0.000 }, // + {29314, -32.049, -3.377, 93.502, 82.962, 0.000 }, // + {31000, -34.980, -6.452, 95.392, 84.110, 0.000 }, // + {35000, -45.679, -17.150, 96.104, 85.248, 0.000 }, // + {39000, -45.679, -17.150, 96.205, 84.346, 0.000 }, // + {41500, -45.679, -17.150, 95.676, 83.745, 0.000 }, // row 58 + // MCT + {-1000, 26.995, 54.356, 82.465, 74.086, 0.000 }, // row 59 + {3000, 18.170, 45.437, 86.271, 77.802, 0.000 }, // + {7000, 9.230, 40.266, 89.128, 79.604, 0.000 }, // + {11000, 4.019, 31.046, 92.194, 82.712, 0.000 }, // + {15000, -5.226, 21.649, 95.954, 85.622, 0.000 }, // + {17000, -9.913, 20.702, 97.520, 85.816, 0.000 }, // + {20000, -15.129, 15.321, 99.263, 86.770, 0.000 }, // + {22000, -19.947, 10.382, 98.977, 86.661, 0.000 }, // + {25000, -25.397, 4.731, 98.440, 85.765, 0.000 }, // + {27000, -30.369, -0.391, 97.279, 85.556, 0.000 }, // + {31000, -36.806, -7.165, 98.674, 86.650, 0.000 }, // + {35000, -43.628, -14.384, 98.386, 85.747, 0.000 }, // + {39000, -47.286, -18.508, 97.278, 85.545, 0.000 } // row 71 }; public: @@ -145,15 +145,15 @@ class ThrustLimits_A380X { * @param wing The status of the wing anti-ice (0 for off, 1 for on). * @return The total bleed for the engine */ - static double bleedTotal(int type, // + static double bleedTotal(int type, // double altitude, // double oat, // double cp, // double lp, // double flexTemp, // - int packs, // - int nacelle, // - int wing // + int packs, // + int nacelle, // + int wing // ) { if (flexTemp > lp && type <= 1) { return packs * -0.6 + nacelle * -0.7 + wing * -0.7; @@ -169,23 +169,23 @@ class ThrustLimits_A380X { // double - Represents the bleed value for the nacelle anti-ice. // double - Represents the bleed value for the wing anti-ice. std::map, std::tuple> bleedValues = { - {{0, true, true}, {-0.4, -0.6, -0.7}}, // - {{0, true, false}, {-0.5, -0.6, -0.7}}, // - {{0, false, true}, {-0.6, -0.8, -0.8}}, // - {{0, false, false}, {-0.7, -0.8, -0.8}}, // - {{1, true, true}, {-0.4, -0.6, -0.6}}, // - {{1, true, false}, {-0.4, -0.6, -0.6}}, // - {{1, false, true}, {-0.6, -0.7, -0.8}}, // - {{1, false, false}, {-0.6, -0.7, -0.8}}, // - {{2, true, false}, {-0.2, -0.8, -0.4}}, // - {{2, false, false}, {-0.3, -0.8, -0.4}}, // - {{3, true, false}, {-0.6, -0.9, -1.2}}, // - {{3, false, false}, {-0.6, -0.9, -1.2}} // + {{0, true, true}, {-0.4, -0.6, -0.7}}, // + {{0, true, false}, {-0.5, -0.6, -0.7}}, // + {{0, false, true}, {-0.6, -0.8, -0.8}}, // + {{0, false, false}, {-0.7, -0.8, -0.8}}, // + {{1, true, true}, {-0.4, -0.6, -0.6}}, // + {{1, true, false}, {-0.4, -0.6, -0.6}}, // + {{1, false, true}, {-0.6, -0.7, -0.8}}, // + {{1, false, false}, {-0.6, -0.7, -0.8}}, // + {{2, true, false}, {-0.2, -0.8, -0.4}}, // + {{2, false, false}, {-0.3, -0.8, -0.4}}, // + {{3, true, false}, {-0.6, -0.9, -1.2}}, // + {{3, false, false}, {-0.6, -0.9, -1.2}} // }; double n1Packs = 0; - double n1Nai = 0; - double n1Wai = 0; + double n1Nai = 0; + double n1Wai = 0; // Use the map to get the bleed values std::tie(n1Packs, n1Nai, n1Wai) = bleedValues[{type, altitude < 8000, oat < cp}]; @@ -211,7 +211,7 @@ class ThrustLimits_A380X { * @param wing A double representing the wing anti-ice status. * @return The N1 limit as a double. */ - static double limitN1(int type, // + static double limitN1(int type, // double altitude, // double ambientTemp, // double ambientPressure, // @@ -220,25 +220,25 @@ class ThrustLimits_A380X { double nacelle, // double wing // ) { - int rowMin = 0; - int rowMax = 0; - int loAltRow = 0; - int hiAltRow = 0; - double mach = 0; + int rowMin = 0; + int rowMax = 0; + int loAltRow = 0; + int hiAltRow = 0; + double mach = 0; // Set main variables per Limit Type switch (type) { - case 0: // TO + case 0: // TO rowMin = 0; rowMax = 20; - mach = 0; + mach = 0; break; - case 1: // GA + case 1: // GA rowMin = 21; rowMax = 41; - mach = 0.225; + mach = 0.225; break; - case 2: // CLB + case 2: // CLB rowMin = 42; rowMax = 58; if (altitude <= 10000) { @@ -249,10 +249,10 @@ class ThrustLimits_A380X { mach = 0.78; } break; - case 3: // MCT + case 3: // MCT rowMin = 59; rowMax = 71; - mach = Fadec::cas2mach(230, ambientPressure); + mach = Fadec::cas2mach(230, ambientPressure); break; } @@ -269,34 +269,33 @@ class ThrustLimits_A380X { } // Define key table variables and interpolation - const double cp = Fadec::interpolate(altitude, limits[loAltRow][0], limits[hiAltRow][0], limits[loAltRow][1], limits[hiAltRow][1]); - const double lp = Fadec::interpolate(altitude, limits[loAltRow][0], limits[hiAltRow][0], limits[loAltRow][2], limits[hiAltRow][2]); + const double cp = Fadec::interpolate(altitude, limits[loAltRow][0], limits[hiAltRow][0], limits[loAltRow][1], limits[hiAltRow][1]); + const double lp = Fadec::interpolate(altitude, limits[loAltRow][0], limits[hiAltRow][0], limits[loAltRow][2], limits[hiAltRow][2]); const double cn1Flat = Fadec::interpolate(altitude, limits[loAltRow][0], limits[hiAltRow][0], limits[loAltRow][3], limits[hiAltRow][3]); const double cn1Last = Fadec::interpolate(altitude, limits[loAltRow][0], limits[hiAltRow][0], limits[loAltRow][4], limits[hiAltRow][4]); const double cn1Flex = Fadec::interpolate(altitude, limits[loAltRow][0], limits[hiAltRow][0], limits[loAltRow][5], limits[hiAltRow][5]); double cn1 = 0; - double m = 0; - double b = 0; - if (flexTemp > 0 && type <= 1) { // CN1 for Flex Case + double m = 0; + double b = 0; + if (flexTemp > 0 && type <= 1) { // CN1 for Flex Case if (flexTemp <= cp) { cn1 = cn1Flat; } else if (flexTemp > lp) { - m = (cn1Flex - cn1Last) / (100 - lp); - b = cn1Flex - m * 100; + m = (cn1Flex - cn1Last) / (100 - lp); + b = cn1Flex - m * 100; cn1 = (m * flexTemp) + b; } else { - m = (cn1Last - cn1Flat) / (lp - cp); - b = cn1Last - m * lp; + m = (cn1Last - cn1Flat) / (lp - cp); + b = cn1Last - m * lp; cn1 = (m * flexTemp) + b; } - } - else { // CN1 for All other cases + } else { // CN1 for All other cases if (ambientTemp <= cp) { cn1 = cn1Flat; } else { - m = (cn1Last - cn1Flat) / (lp - cp); - b = cn1Last - m * lp; + m = (cn1Last - cn1Flat) / (lp - cp); + b = cn1Last - m * lp; cn1 = (m * ambientTemp) + b; } } diff --git a/fbw-common/src/wasm/cpp-msfs-framework/CMakeLists.txt b/fbw-common/src/wasm/cpp-msfs-framework/CMakeLists.txt index 99ea1e16916..eb45974481f 100644 --- a/fbw-common/src/wasm/cpp-msfs-framework/CMakeLists.txt +++ b/fbw-common/src/wasm/cpp-msfs-framework/CMakeLists.txt @@ -6,7 +6,7 @@ set(SOURCE_FILES MsfsHandler/DataTypes/ClientEvent.cpp MsfsHandler/DataTypes/NamedVariable.cpp MsfsHandler/MsfsHandler.cpp - ) +) set(INCLUDE_FILES MsfsHandler/DataManager.h MsfsHandler/DataTypes/AircraftVariable.h @@ -23,6 +23,7 @@ set(INCLUDE_FILES MsfsHandler/MsfsHandler.h MsfsHandler/SimconnectExceptionStrings.h MsfsHandler/SimUnits.h + lib/arinc429.hpp lib/Callback.h lib/IDGenerator.h lib/fingerprint.hpp @@ -37,7 +38,7 @@ set(INCLUDE_FILES lib/string_utils.hpp lib/quantity.hpp) -# create the targets for all aircrafts +# create the targets for all packages add_library(cpp-msfs-framework-a32nx OBJECT ${SOURCE_FILES} ${INCLUDE_FILES}) target_compile_definitions(cpp-msfs-framework-a32nx PUBLIC A32NX) diff --git a/fbw-common/src/wasm/cpp-msfs-framework/GUIDELINES.md b/fbw-common/src/wasm/cpp-msfs-framework/GUIDELINES.md index 0c9c6eabdcc..fea97c10511 100644 --- a/fbw-common/src/wasm/cpp-msfs-framework/GUIDELINES.md +++ b/fbw-common/src/wasm/cpp-msfs-framework/GUIDELINES.md @@ -1,76 +1,81 @@ # FlyByWire Simulations - C++ WASM Development Guidelines ## Purpose + Reading and troubleshooting other developers code is hard in general. Also, -developers new to the project have a hard time to get started with developing -new features and functionalities in the FlyByWire Simulations code base. +developers new to the project have a hard time to get started with developing +new features and functionalities in the FlyByWire Simulations code base. -This document aims to provide a set of guidelines for the C++ WASM development in +This document aims to provide a set of guidelines for the C++ WASM development in the FlyByWire Simulations code base which aims to readability, maintainability of the code base which is also easily accessible for new developers. ## C++ Code Style -The FlyByWire Cpp code style is based on the clang-format Chromium style -( see`.clang-format`). + +The FlyByWire Cpp code style is based on the clang-format Chromium style +( see`.clang-format`). ## Commenting + Good commenting is a very important part of writing readable and maintainable -software. This is especially true in a multi-developer project with very different -developer backgrounds and level of experience amongst its developers. -The FlyByWire Open-Source project certainly falls into this category. - -As a general rule code should be commented so that other developers should not -have to read the actual code to understand what classes, methods and members do -and why they exist in the first place. - -In C++ in general, it should be sufficient to read the header file to understand +software. This is especially true in a multi-developer project with very different +developer backgrounds and level of experience amongst its developers. +The FlyByWire Open-Source project certainly falls into this category. + +As a general rule code should be commented so that other developers should not +have to read the actual code to understand what classes, methods and members do +and why they exist in the first place. + +In C++ in general, it should be sufficient to read the header file to understand the purpose and usage of a class, method/function or any member. There should be -little need to read the code in the definition files (cpp) to know what a class -or any of its members does or how it should be used. +little need to read the code in the definition files (cpp) to know what a class +or any of its members does or how it should be used. This is especially important for any public members of a class. - + If you write comments think of the following questions: -- What? Why? How to use? +- What? Why? How to use? - What does the code do? - - Give a short general description of what the code does + - Give a short general description of what the code does - What implications / side effects does this code have? - Why does the code do it? - - Explain the purpose of the code - - e.g. why is this method/function needed and where is it used? - - e.g. why is this variable needed and where is it used? + - Explain the purpose of the code + - e.g. why is this method/function needed and where is it used? + - e.g. why is this variable needed and where is it used? - How to use the code? - - Explain how to use the code - - e.g. how to use the method/function? + - Explain how to use the code + - e.g. how to use the method/function? - How does the code actually do it conceptually (optional)? - - Although good code speaks for itself it is helpful to explain in very - broad strokes how the code does it esp. if the code has more complex logic + - Although good code speaks for itself it is helpful to explain in very + broad strokes how the code does it esp. if the code has more complex logic -Modern IDEs like VSCode or JetBrain IDEs provide a lot of features to help -developers by simply hovering over a class, function, variable, etc. to get a +Modern IDEs like VSCode or JetBrain IDEs provide a lot of features to help +developers by simply hovering over a class, function, variable, etc. to get a quick look at the documentation. Have this in mind when writing comments. It is good practice to comment the code as you write it. Often it is easier to -start by writing parts of the documentation first. E.g. writing the header files -first by declaring members and document these often helps to achieve a better -and faster implementation. +start by writing parts of the documentation first. E.g. writing the header files +first by declaring members and document these often helps to achieve a better +and faster implementation. ## Logging -A very simple logging framework is in place in the logging.h header file. +A very simple logging framework is in place in the logging.h header file. + +This logging framework will be improved and extended over time. -This logging framework will be improved and extended over time. - Some notes on logging: -- challenge is to find a logging framework that does not use exceptions or + +- challenge is to find a logging framework that does not use exceptions or threading (which is not supported in MSFS WASM) - MSFS does not easily allow to attach a debugger for C++ and tends to crash if one does - MSFS has no permanent logging to analyse CTDs - Logging should not be excessive but allow to see where the code is at -- Logging should print any warning and errors to the console to make it easier - to find issues later. +- Logging should print any warning and errors to the console to make it easier + to find issues later. ## Unit Testing + Unit testing is a very important part of writing maintainable and readable code. A C++ Unit-testing framework has not yet been chosen or added to the project. diff --git a/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataManager.cpp b/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataManager.cpp index 71509bd900a..4d58bf96186 100644 --- a/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataManager.cpp +++ b/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataManager.cpp @@ -7,7 +7,7 @@ #include "UpdateMode.h" bool DataManager::initialize(HANDLE simConnectHandle) { - hSimConnect = simConnectHandle; + hSimConnect = simConnectHandle; isInitialized = true; return true; } @@ -21,8 +21,8 @@ bool DataManager::preUpdate([[maybe_unused]] sGaugeDrawData* pData) const { } // get current time stamp and tick counter - const FLOAT64 timeStamp = msfsHandlerPtr->getTimeStamp(); - const UINT64 tickCounter = msfsHandlerPtr->getTickCounter(); + const FLOAT64 timeStamp = msfsHandlerPtr->getTimeStamp(); + const UINT64 tickCounter = msfsHandlerPtr->getTickCounter(); // get all variables set to automatically read for (const auto& var : variables) { @@ -94,7 +94,7 @@ bool DataManager::shutdown() { } void DataManager::getRequestedData() const { - DWORD cbData; + DWORD cbData; SIMCONNECT_RECV* ptrData; while (SUCCEEDED(SimConnect_GetNextDispatch(hSimConnect, &ptrData, &cbData))) { processDispatchMessage(ptrData, &cbData); @@ -106,15 +106,19 @@ void DataManager::getRequestedData() const { // ================================================================================================= NamedVariablePtr DataManager::make_named_var(const std::string& varName, - SimUnit unit, - UpdateMode updateMode, - FLOAT64 maxAgeTime, - UINT64 maxAgeTicks) { + SimUnit unit, + UpdateMode updateMode, + FLOAT64 maxAgeTime, + UINT64 maxAgeTicks, + bool noPrefix) { // The uniqueName is used in the map of all named variables and needs to // contain all the information to identify the variable and the expected value // uniquely. This is because the same variable can be used in different places // with different expected values via SimUnits. - const std::string uniqueName{varName + ":" + unit.name}; + // It adds the prefix to the variable name if it is not already present to make sure to really deduplicate + // variables with the same name but with or without prefixes. + const std::string prefixedVarName = noPrefix ? varName : NamedVariable::addPrefixToVarName(varName); + const std::string uniqueName{prefixedVarName + ":" + unit.name}; // Check if variable already exists // Check which update method and frequency to use - if two variables are the same @@ -139,28 +143,29 @@ NamedVariablePtr DataManager::make_named_var(const std::string& varName, } // Create new var and store it in the map - NamedVariablePtr var = NamedVariablePtr(new NamedVariable(varName, unit, updateMode, maxAgeTime, maxAgeTicks)); + // We can set the noPrefix flag to true as we already checked and added the prefix above + NamedVariablePtr var = NamedVariablePtr(new NamedVariable(prefixedVarName, unit, updateMode, maxAgeTime, maxAgeTicks, true)); variables[uniqueName] = var; LOG_DEBUG("DataManager::make_named_var(): created variable " + var->str()); return var; } -AircraftVariablePtr DataManager::make_aircraft_var(const std::string& varName, - int index, - std::string setterEventName, +AircraftVariablePtr DataManager::make_aircraft_var(const std::string& varName, + int index, + std::string setterEventName, const ClientEventPtr& setterEvent, - SimUnit unit, - UpdateMode updateMode, - FLOAT64 maxAgeTime, - UINT64 maxAgeTicks) { + SimUnit unit, + UpdateMode updateMode, + FLOAT64 maxAgeTime, + UINT64 maxAgeTicks) { // The uniqueName is used in the map of all named variables and needs to // contain all the information to identify the variable and the expected value // uniquely. This is because the same variable can be used in different places // with different expected values via Index and SimUnits. const std::string uniqueName{varName + ":" + std::to_string(index) + ":" + unit.name}; - // Check if variable already exists + // Check if variable already exists. // Check which update method and frequency to use - if two variables are the same // use the update method and frequency of the automated one with faster update frequency const auto pair = variables.find(uniqueName); @@ -193,8 +198,8 @@ AircraftVariablePtr DataManager::make_aircraft_var(const std::string& varName, return var; } -ClientEventPtr DataManager::make_client_event(const std::string& clientEventName, - bool registerToSim, +ClientEventPtr DataManager::make_client_event(const std::string& clientEventName, + bool registerToSim, SIMCONNECT_NOTIFICATION_GROUP_ID notificationGroupId) { // find existing event instance for this event for (const auto& event : clientEvents) { @@ -233,7 +238,6 @@ KeyEventCallbackID DataManager::addKeyEventCallback(KeyEventID keyEventId, const return id; } -// FIXME: Double check if this is correct bool DataManager::removeKeyEventCallback(KeyEventID keyEventId, KeyEventCallbackID callbackId) { const auto eventPair = keyEventCallbacks.find(keyEventId); if (eventPair != keyEventCallbacks.end()) { @@ -303,7 +307,7 @@ void DataManager::processDispatchMessage(SIMCONNECT_RECV* pRecv, [[maybe_unused] case SIMCONNECT_RECV_ID_EXCEPTION: { auto* const pException = reinterpret_cast(pRecv); - std::ignore = pException; + std::ignore = pException; LOG_ERROR("DataManager: Exception in SimConnect connection: " + SimconnectExceptionStrings::getSimConnectExceptionString(static_cast(pException->dwException)) + " send_id:" + std::to_string(pException->dwSendID) + " index:" + std::to_string(pException->dwIndex)); @@ -318,7 +322,7 @@ void DataManager::processDispatchMessage(SIMCONNECT_RECV* pRecv, [[maybe_unused] void DataManager::processSimObjectData(SIMCONNECT_RECV* pData) const { const auto pSimobjectData = reinterpret_cast(pData); - const auto pair = simObjects.find(pSimobjectData->dwRequestID); + const auto pair = simObjects.find(pSimobjectData->dwRequestID); if (pair != simObjects.end()) { pair->second->processSimData(pData, msfsHandlerPtr->getTimeStamp(), msfsHandlerPtr->getTickCounter()); return; diff --git a/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataManager.h b/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataManager.h index bc9ffd98b98..9acd0263e5f 100644 --- a/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataManager.h +++ b/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataManager.h @@ -30,13 +30,13 @@ class MsfsHandler; // convenience typedefs using CacheableVariablePtr = std::shared_ptr; -using NamedVariablePtr = std::shared_ptr; -using AircraftVariablePtr = std::shared_ptr; -using SimObjectBasePtr = std::shared_ptr; -using ClientEventPtr = std::shared_ptr; +using NamedVariablePtr = std::shared_ptr; +using AircraftVariablePtr = std::shared_ptr; +using SimObjectBasePtr = std::shared_ptr; +using ClientEventPtr = std::shared_ptr; template using DataDefinitionVariablePtr = std::shared_ptr>; -using DataDefinitionVector = std::vector; +using DataDefinitionVector = std::vector; template using ClientDataAreaVariablePtr = std::shared_ptr>; template @@ -88,7 +88,7 @@ class DataManager { // Map over the event id to quickly find the event - make creating an event a bit less efficient. std::map clientEvents{}; - // Map of callback vectors to be called when a key event is triggered in the sim. + // Map of callback maps to be called when a key event is triggered in the sim. std::map> keyEventCallbacks{}; // Flag to indicate if the data manager is initialized. @@ -107,11 +107,11 @@ class DataManager { */ explicit DataManager(MsfsHandler* msfsHdl) : msfsHandlerPtr(msfsHdl) {} - DataManager() = delete; // no default constructor - DataManager(const DataManager&) = delete; // no copy constructor + DataManager() = delete; // no default constructor + DataManager(const DataManager&) = delete; // no copy constructor DataManager& operator=(const DataManager&) = delete; // no copy assignment - DataManager(DataManager&&) = delete; // no move constructor - DataManager& operator=(DataManager&&) = delete; // no move assignment + DataManager(DataManager&&) = delete; // no move constructor + DataManager& operator=(DataManager&&) = delete; // no move assignment ~DataManager() = default; @@ -177,22 +177,25 @@ class DataManager { * The NamedVariable is a variable which is mapped to a LVAR. It is the simplest variable type and * can be used to store and retrieve custom numeric data from the sim.

* - * OBS: A prefix will be added to the variable name depending on aircraft type. - * E.g. "A32NX_" for the A32NX. Do not add this prefix yourself. + * OBS: If defined at Module creation time a prefix will be added to the variable name depending + * on aircraft type. E.g. "A32NX_" for the A32NX. If the varName already contains the prefix it + * will not be added again.

* * @param varName Name of the variable in the sim * @param unit optional SimUnit of the variable (default=Number) * @param updateMode optional DataManager update mode of the variable (default=UpdateMode::NO_AUTO_UPDATE) * @param maxAgeTime optional maximum age of the variable in seconds (default=0) * @param maxAgeTicks optional maximum age of the variable in ticks (default=0) + * @param noPrefix optional if the aircraft prefix should not be added to the variable name (default=false) * @return A shared pointer to the variable * @see SimUnits.h for available units */ [[nodiscard]] NamedVariablePtr make_named_var(const std::string& varName, - SimUnit unit = UNITS.Number, - UpdateMode updateMode = UpdateMode::NO_AUTO_UPDATE, - FLOAT64 maxAgeTime = 0.0, - UINT64 maxAgeTicks = 0); + SimUnit unit = UNITS.Number, + UpdateMode updateMode = UpdateMode::NO_AUTO_UPDATE, + FLOAT64 maxAgeTime = 0.0, + UINT64 maxAgeTicks = 0, + bool noPrefix = false); /** * @brief Creates a new AircraftVariable and adds it to the list of managed variables.

@@ -214,14 +217,14 @@ class DataManager { * @return A shared pointer to the variable * @see SimUnits.h for available units */ - [[nodiscard]] AircraftVariablePtr make_aircraft_var(const std::string& varName, - int index = 0, - std::string setterEventName = "", - const ClientEventPtr& setterEvent = nullptr, - SimUnit unit = UNITS.Number, - UpdateMode updateMode = UpdateMode::NO_AUTO_UPDATE, - FLOAT64 maxAgeTime = 0.0, - UINT64 maxAgeTicks = 0); + [[nodiscard]] AircraftVariablePtr make_aircraft_var(const std::string& varName, + int index = 0, + std::string setterEventName = "", + const ClientEventPtr& setterEvent = nullptr, + SimUnit unit = UNITS.Number, + UpdateMode updateMode = UpdateMode::NO_AUTO_UPDATE, + FLOAT64 maxAgeTime = 0.0, + UINT64 maxAgeTicks = 0); /** * @brief Creates a new readonly non-indexed AircraftVariable and adds it to the list of managed variables. @@ -237,18 +240,12 @@ class DataManager { * @see SimUnits.h for available units */ [[nodiscard]] AircraftVariablePtr make_simple_aircraft_var(const std::string& varName, - SimUnit unit = UNITS.Number, - bool autoReading = false, - FLOAT64 maxAgeTime = 0.0, - UINT64 maxAgeTicks = 0) { - AircraftVariablePtr var = make_aircraft_var(varName, - 0, - "", - nullptr, - unit, - autoReading ? UpdateMode::AUTO_READ : UpdateMode::NO_AUTO_UPDATE, - maxAgeTime, - maxAgeTicks); + SimUnit unit = UNITS.Number, + bool autoReading = false, + FLOAT64 maxAgeTime = 0.0, + UINT64 maxAgeTicks = 0) { + AircraftVariablePtr var = make_aircraft_var(varName, 0, "", nullptr, unit, + autoReading ? UpdateMode::AUTO_READ : UpdateMode::NO_AUTO_UPDATE, maxAgeTime, maxAgeTicks); LOG_DEBUG("DataManager::make_simple_aircraft_var(): call make_aircraft_var() to create variable " + var->str()); return var; }; @@ -270,11 +267,16 @@ class DataManager { * @return A shared pointer to the variable */ template - [[nodiscard]] DataDefinitionVariablePtr make_datadefinition_var(const std::string& name, + [[nodiscard]] DataDefinitionVariablePtr make_datadefinition_var(const std::string& name, const std::vector& dataDefinitions, - UpdateMode updateMode = UpdateMode::NO_AUTO_UPDATE, - FLOAT64 maxAgeTime = 0.0, - UINT64 maxAgeTicks = 0) { + UpdateMode updateMode = UpdateMode::NO_AUTO_UPDATE, + FLOAT64 maxAgeTime = 0.0, + UINT64 maxAgeTicks = 0) { + if (getDataDefinitionVarByName(name) != nullptr) { + LOG_ERROR("DataManager::make_datadefinition_var(): DataDefinitionVariable with name " + name + " already exists"); + return nullptr; + } + DataDefinitionVariablePtr var = DataDefinitionVariablePtr(new DataDefinitionVariable( hSimConnect, name, dataDefinitions, dataDefIDGen.getNextId(), dataReqIDGen.getNextId(), updateMode, maxAgeTime, maxAgeTicks)); simObjects.insert({var->getRequestId(), var}); @@ -282,6 +284,34 @@ class DataManager { return var; } + /** + * @brief Retrieves a specific DataDefinitionVariable from the DataManager's collection of SimObjects based on the given name. + * + * This function iterates over the DataManager's collection of SimObjects, which includes all registered DataDefinitionVariables. + * It checks each SimObject's name against the provided name. If a match is found, it attempts to cast the SimObject to a + * DataDefinitionVariable of the specified type. If the cast is successful, it returns a shared pointer to the DataDefinitionVariable. + * If no match is found after checking all SimObjects, it returns a null pointer. + * + * @note When reusing a DataDefinitionVariable make sure to know how this DataDefinition is updated and DO NOT CHANGE the update mode + * or periodic update settings of the DataDefinitionVariable. This could lead to unexpected behavior in other modules sharing the + * same DataDefinitionVariable. Especially as the periodic update settings cannot be retrieved from the sim and the + * DataDefinitionVariable does not store the the periodic update settings as these could get easily out of sync (e.g. by using SimConnect + * directly to change them) which would be worse than not having them at all. + * + * @tparam T The type of the DataDefinitionVariable to retrieve. + * @param name The name of the DataDefinitionVariable to retrieve. + * @return A shared pointer to the DataDefinitionVariable if found, otherwise a null pointer. + */ + template + [[nodiscard]] DataDefinitionVariablePtr getDataDefinitionVarByName(const std::string& name) { + for (auto simObject : simObjects) { + if (simObject.second->getName() == name) { + return std::dynamic_pointer_cast>(simObject.second); + } + } + return nullptr; + } + /** * @brief Creates a new client data area variable and adds it to the list of managed variables.

* @@ -304,9 +334,9 @@ class DataManager { */ template [[nodiscard]] ClientDataAreaVariablePtr make_clientdataarea_var(const std::string& clientDataName, - UpdateMode updateMode = UpdateMode::NO_AUTO_UPDATE, - FLOAT64 maxAgeTime = 0.0, - UINT64 maxAgeTicks = 0) { + UpdateMode updateMode = UpdateMode::NO_AUTO_UPDATE, + FLOAT64 maxAgeTime = 0.0, + UINT64 maxAgeTicks = 0) { ClientDataAreaVariablePtr var = ClientDataAreaVariablePtr( new ClientDataAreaVariable(hSimConnect, clientDataName, clientDataIDGen.getNextId(), dataDefIDGen.getNextId(), dataReqIDGen.getNextId(), sizeof(T), updateMode, maxAgeTime, maxAgeTicks)); @@ -348,9 +378,9 @@ class DataManager { template [[nodiscard]] StreamingClientDataAreaVariablePtr make_streamingclientdataarea_var( const std::string& clientDataName, - UpdateMode updateMode = UpdateMode::NO_AUTO_UPDATE, - FLOAT64 maxAgeTime = 0.0, - UINT64 maxAgeTicks = 0) { + UpdateMode updateMode = UpdateMode::NO_AUTO_UPDATE, + FLOAT64 maxAgeTime = 0.0, + UINT64 maxAgeTicks = 0) { StreamingClientDataAreaVariablePtr var = StreamingClientDataAreaVariablePtr(new StreamingClientDataAreaVariable( hSimConnect, clientDataName, clientDataIDGen.getNextId(), dataDefIDGen.getNextId(), dataReqIDGen.getNextId(), updateMode, @@ -400,8 +430,8 @@ class DataManager { * notification group (default=SIMCONNECT_UNUSED). * @return A shared pointer to the ClientEvent */ - [[nodiscard]] ClientEventPtr make_client_event(const std::string& clientEventName, - bool registerToSim, + [[nodiscard]] ClientEventPtr make_client_event(const std::string& clientEventName, + bool registerToSim, SIMCONNECT_NOTIFICATION_GROUP_ID notificationGroupId = SIMCONNECT_UNUSED); /** @@ -414,11 +444,11 @@ class DataManager { * Custom events will only be recognized by another client (and not Microsoft * Flight Simulator) that has been coded to receive such events.

* @param notificationGroupId Specifies the notification group to which the event is added. If no -* entry is made for this parameter, the event is not added to a -* notification group (default=SIMCONNECT_UNUSED). + * entry is made for this parameter, the event is not added to a + * notification group (default=SIMCONNECT_UNUSED). * @return A shared pointer to the custom ClientEvent */ - [[nodiscard]] ClientEventPtr make_custom_event(const std::string& clientEventName, + [[nodiscard]] ClientEventPtr make_custom_event(const std::string& clientEventName, SIMCONNECT_NOTIFICATION_GROUP_ID notificationGroupId = SIMCONNECT_UNUSED) { SIMPLE_ASSERT(clientEventName.find('.') != std::string::npos, "Custom event name must contain a period in the name."); return make_client_event(clientEventName, true, notificationGroupId); @@ -434,7 +464,7 @@ class DataManager { * notification group (default=SIMCONNECT_UNUSED). * @return A shared pointer to the sim ClientEvent */ - [[nodiscard]] ClientEventPtr make_sim_event(const std::string& clientEventName, + [[nodiscard]] ClientEventPtr make_sim_event(const std::string& clientEventName, SIMCONNECT_NOTIFICATION_GROUP_ID notificationGroupId = SIMCONNECT_UNUSED) { SIMPLE_ASSERT(clientEventName.find('.') == std::string::npos, "Sim event name must not contain a period in the name."); return make_client_event(clientEventName, true, notificationGroupId); @@ -450,8 +480,7 @@ class DataManager { * SimConnect will throw an exception error. * @return A shared pointer to the system ClientEvent */ - [[nodiscard]] ClientEventPtr make_system_event(const std::string& clientEventName, - const std::string& systemEventName) { + [[nodiscard]] ClientEventPtr make_system_event(const std::string& clientEventName, const std::string& systemEventName) { SIMPLE_ASSERT(clientEventName.find('.') != std::string::npos, "Client event name for system events must contain a period in the name."); auto event = make_client_event(clientEventName, false, SIMCONNECT_UNUSED); event->subscribeToSimSystemEvent(systemEventName); diff --git a/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/AircraftVariable.h b/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/AircraftVariable.h index c790d71c5a8..beb71a55e72 100644 --- a/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/AircraftVariable.h +++ b/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/AircraftVariable.h @@ -62,12 +62,12 @@ class AircraftVariable : public CacheableVariable { * @param maxAgeTicks The maximum age of an auto updated the variable in sim ticks. */ explicit AircraftVariable(const std::string& varName, - int varIndex = 0, - std::string setterEventName = "", - SimUnit unit = UNITS.Number, - UpdateMode updateMode = UpdateMode::NO_AUTO_UPDATE, - FLOAT64 maxAgeTime = 0.0, - UINT64 maxAgeTicks = 0) + int varIndex = 0, + std::string setterEventName = "", + SimUnit unit = UNITS.Number, + UpdateMode updateMode = UpdateMode::NO_AUTO_UPDATE, + FLOAT64 maxAgeTime = 0.0, + UINT64 maxAgeTicks = 0) : CacheableVariable(varName, unit, updateMode, maxAgeTime, maxAgeTicks), index(varIndex), setterEventName(std::move(setterEventName)), @@ -90,13 +90,13 @@ class AircraftVariable : public CacheableVariable { * @param maxAgeTicks The maximum age of an auto updated the variable in sim ticks. * @param setterEventName The calculator code to write to the variable. */ - explicit AircraftVariable(const std::string& varName, - int varIndex = 0, + explicit AircraftVariable(const std::string& varName, + int varIndex = 0, const std::shared_ptr& setterEvent = nullptr, - SimUnit unit = UNITS.Number, - UpdateMode updateMode = UpdateMode::NO_AUTO_UPDATE, - FLOAT64 maxAgeTime = 0.0, - UINT64 maxAgeTicks = 0) + SimUnit unit = UNITS.Number, + UpdateMode updateMode = UpdateMode::NO_AUTO_UPDATE, + FLOAT64 maxAgeTime = 0.0, + UINT64 maxAgeTicks = 0) : CacheableVariable(varName, unit, updateMode, maxAgeTime, maxAgeTicks), index(varIndex), setterEvent(setterEvent) { dataID = get_aircraft_var_enum(varName.c_str()); if (dataID == -1) { // cannot throw an exception in MSFS @@ -105,16 +105,16 @@ class AircraftVariable : public CacheableVariable { } public: - AircraftVariable() = delete; // no default constructor - AircraftVariable(const AircraftVariable&) = delete; // no copy constructor + AircraftVariable() = delete; // no default constructor + AircraftVariable(const AircraftVariable&) = delete; // no copy constructor AircraftVariable& operator=(const AircraftVariable&) = delete; // no copy assignment - AircraftVariable(AircraftVariable&&) = delete; // move constructor - AircraftVariable& operator=(AircraftVariable&&) = delete; // move assignment + AircraftVariable(AircraftVariable&&) = delete; // move constructor + AircraftVariable& operator=(AircraftVariable&&) = delete; // move assignment [[nodiscard]] FLOAT64 rawReadFromSim() const override; - void rawWriteToSim() override; - void setAutoWrite(bool autoWriting) override; - void set(FLOAT64 value) override; + void rawWriteToSim() override; + void setAutoWrite(bool autoWriting) override; + void set(FLOAT64 value) override; [[nodiscard]] std::string str() const override; diff --git a/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/CacheableVariable.cpp b/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/CacheableVariable.cpp index 28edeea3aa3..68466ef50f7 100644 --- a/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/CacheableVariable.cpp +++ b/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/CacheableVariable.cpp @@ -26,7 +26,6 @@ FLOAT64 CacheableVariable::updateFromSim(FLOAT64 timeStamp, UINT64 tickCounter) return cachedValue.value(); } LOG_TRACE("CacheableVariable::updateFromSim() - read from sim " + this->name + " " + str()); - // update the value from the sim updateStamps(timeStamp, tickCounter); return readFromSim(); } @@ -47,7 +46,7 @@ void CacheableVariable::set(FLOAT64 value) { return; } cachedValue = value; - dirty = true; + dirty = true; setChanged(true); } diff --git a/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/CacheableVariable.h b/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/CacheableVariable.h index e1f964e10cb..50daa73fd6c 100644 --- a/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/CacheableVariable.h +++ b/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/CacheableVariable.h @@ -81,11 +81,11 @@ class CacheableVariable : public ManagedDataObjectBase { : ManagedDataObjectBase(varName, updateMode, maxAgeTime, maxAgeTicks), unit(unit) {} public: - CacheableVariable() = delete; // no default constructor - CacheableVariable(const CacheableVariable&) = delete; // no copy constructor + CacheableVariable() = delete; // no default constructor + CacheableVariable(const CacheableVariable&) = delete; // no copy constructor CacheableVariable& operator=(const CacheableVariable&) = delete; // no copy assignment - CacheableVariable(CacheableVariable&&) = delete; // no move constructor - CacheableVariable& operator=(CacheableVariable&&) = delete; // no move assignment + CacheableVariable(CacheableVariable&&) = delete; // no move constructor + CacheableVariable& operator=(CacheableVariable&&) = delete; // no move assignment /** * Returns the cached value or the default value (FLOAT64{}) if the cache is empty.

@@ -93,14 +93,14 @@ class CacheableVariable : public ManagedDataObjectBase { * Prints an error to std::cerr if the cache is empty.

* * If the value has been set by the set() method since the last read from the sim (is dirty) - * but has not been written to the sim yet an error message is printed to std::cerr. - * (MSFS does not allow exceptions) + * but has not been written to the sim yet an error message is printed to std::cerr if warnIfDirty + * is true. (MSFS does not allow exceptions) * @return cached value or default value */ [[nodiscard]] FLOAT64 get() const; /** - * Reads the value from the sim if the cached value is older than the max age (time and ticks).

+ * Reads the value from the sim if the cached value is older than the max age (time or ticks).

* * If a value has already been read during one tick it will therefore not be read again as the * variable's timeStamp and tickStamp will not be older than the current time and tick.

diff --git a/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/ClientDataAreaVariable.hpp b/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/ClientDataAreaVariable.hpp index 91ec7d1d7b7..df3726a0905 100644 --- a/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/ClientDataAreaVariable.hpp +++ b/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/ClientDataAreaVariable.hpp @@ -88,22 +88,16 @@ class ClientDataAreaVariable : public SimObjectBase { * @param maxAgeTicks The maximum age of the value in ticks before it is updated from the sim by * the requestUpdateFromSim() method. */ - ClientDataAreaVariable(HANDLE hSimConnect, - const std::string& clientDataName, - SIMCONNECT_CLIENT_DATA_ID clientDataId, + ClientDataAreaVariable(HANDLE hSimConnect, + const std::string& clientDataName, + SIMCONNECT_CLIENT_DATA_ID clientDataId, SIMCONNECT_CLIENT_DATA_DEFINITION_ID clientDataDefinitionId, - SIMCONNECT_DATA_REQUEST_ID requestId, - std::size_t dataSize = sizeof(T), - UpdateMode updateMode = UpdateMode::NO_AUTO_UPDATE, - FLOAT64 maxAgeTime = 0.0, - UINT64 maxAgeTicks = 0) - : SimObjectBase(hSimConnect, - clientDataName, - clientDataDefinitionId, - requestId, - updateMode, - maxAgeTime, - maxAgeTicks), + SIMCONNECT_DATA_REQUEST_ID requestId, + std::size_t dataSize = sizeof(T), + UpdateMode updateMode = UpdateMode::NO_AUTO_UPDATE, + FLOAT64 maxAgeTime = 0.0, + UINT64 maxAgeTicks = 0) + : SimObjectBase(hSimConnect, clientDataName, clientDataDefinitionId, requestId, updateMode, maxAgeTime, maxAgeTicks), clientDataId(clientDataId) { // Map the client data area name to the client data area ID HRESULT hresult = SimConnect_MapClientDataNameToID(hSimConnect, name.c_str(), clientDataId); @@ -131,11 +125,11 @@ class ClientDataAreaVariable : public SimObjectBase { } public: - ClientDataAreaVariable() = delete; // no default constructor - ClientDataAreaVariable(const ClientDataAreaVariable&) = delete; // no copy constructor + ClientDataAreaVariable() = delete; // no default constructor + ClientDataAreaVariable(const ClientDataAreaVariable&) = delete; // no copy constructor ClientDataAreaVariable& operator=(const ClientDataAreaVariable&) = delete; // no copy assignment - ClientDataAreaVariable(ClientDataAreaVariable&&) = delete; // no move constructor - ClientDataAreaVariable& operator=(ClientDataAreaVariable&&) = delete; // no move assignment + ClientDataAreaVariable(ClientDataAreaVariable&&) = delete; // no move constructor + ClientDataAreaVariable& operator=(ClientDataAreaVariable&&) = delete; // no move assignment /** * Destructor - clears the client data definition but does not free any sim memory. The sim memory @@ -201,12 +195,11 @@ class ClientDataAreaVariable : public SimObjectBase { * @see * https://docs.flightsimulator.com/html/Programming_Tools/SimConnect/API_Reference/Structures_And_Enumerations/SIMCONNECT_CLIENT_DATA_PERIOD.htm */ - bool requestPeriodicDataFromSim( - SIMCONNECT_CLIENT_DATA_PERIOD period, - SIMCONNECT_CLIENT_DATA_REQUEST_FLAG periodFlags = SIMCONNECT_CLIENT_DATA_REQUEST_FLAG_DEFAULT, - DWORD origin = 0, - DWORD interval = 0, - DWORD limit = 0) const { + bool requestPeriodicDataFromSim(SIMCONNECT_CLIENT_DATA_PERIOD period, + SIMCONNECT_CLIENT_DATA_REQUEST_FLAG periodFlags = SIMCONNECT_CLIENT_DATA_REQUEST_FLAG_DEFAULT, + DWORD origin = 0, + DWORD interval = 0, + DWORD limit = 0) const { if (this->isAutoRead() && period >= SIMCONNECT_CLIENT_DATA_PERIOD_ONCE) { LOG_ERROR("ClientDataAreaVariable: Requested periodic data update from sim is ignored as autoRead is enabled."); return false; diff --git a/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/ClientEvent.cpp b/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/ClientEvent.cpp index c553f19ed80..19e7fee735d 100644 --- a/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/ClientEvent.cpp +++ b/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/ClientEvent.cpp @@ -92,7 +92,7 @@ void ClientEvent::clearNotificationGroup(SIMCONNECT_NOTIFICATION_GROUP_ID notifi } void ClientEvent::setNotificationGroupPriority(SIMCONNECT_NOTIFICATION_GROUP_ID notificationGroupId, - DWORD notificationGroupPriority) const { + DWORD notificationGroupPriority) const { if (!SUCCEEDED(SimConnect_SetNotificationGroupPriority(hSimConnect, notificationGroupId, notificationGroupPriority))) { LOG_ERROR("Failed to set notification group " + std::to_string(notificationGroupId) + " to highest priority"); } @@ -114,7 +114,7 @@ void ClientEvent::trigger(DWORD data0) const { return; } LOG_VERBOSE("Triggered event " + clientEventName + " with client event " + std::to_string(clientEventId) + " with data " + - std::to_string(data0)); + std::to_string(data0)); } void ClientEvent::trigger_ex1(DWORD data0, DWORD data1, DWORD data2, DWORD data3, DWORD data4) const { @@ -129,8 +129,8 @@ void ClientEvent::trigger_ex1(DWORD data0, DWORD data1, DWORD data2, DWORD data3 return; } LOG_VERBOSE("Triggered_ex1 event " + clientEventName + " with client ID " + std::to_string(clientEventId) + " with data " + - std::to_string(data0) + ", " + std::to_string(data1) + ", " + std::to_string(data2) + ", " + std::to_string(data3) + ", " + - std::to_string(data4)); + std::to_string(data0) + ", " + std::to_string(data1) + ", " + std::to_string(data2) + ", " + std::to_string(data3) + ", " + + std::to_string(data4)); } // ================================================================================================= @@ -174,11 +174,11 @@ void ClientEvent::processEvent(DWORD data0, DWORD data1, DWORD data2, DWORD data // Input Events // ================================================================================================= -void ClientEvent::mapInputDownUpEvent(const std::string& inputDefinition, +void ClientEvent::mapInputDownUpEvent(const std::string& inputDefinition, SIMCONNECT_INPUT_GROUP_ID inputGroupId, - DWORD downValue, - DWORD upValue, - bool maskable) { + DWORD downValue, + DWORD upValue, + bool maskable) { if (!SUCCEEDED(SimConnect_MapInputEventToClientEvent(hSimConnect, inputGroupId, inputDefinition.c_str(), getClientEventId(), downValue, getClientEventId(), upValue, maskable))) { LOG_ERROR("Failed to map input down/up event " + inputDefinition + " to client event " + getClientEventName() + " (" + @@ -189,10 +189,10 @@ void ClientEvent::mapInputDownUpEvent(const std::string& inputDefinition, std::to_string(getClientEventId()) + ")"); } -void ClientEvent::mapInputDownEvent(const std::string& inputDefinition, +void ClientEvent::mapInputDownEvent(const std::string& inputDefinition, SIMCONNECT_INPUT_GROUP_ID inputGroupId, - DWORD downValue, - bool maskable) const { + DWORD downValue, + bool maskable) const { SIMCONNECT_CLIENT_EVENT_ID upId = reinterpret_cast(SIMCONNECT_UNUSED); if (!SUCCEEDED(SimConnect_MapInputEventToClientEvent(hSimConnect, inputGroupId, inputDefinition.c_str(), getClientEventId(), downValue, upId, 0, maskable))) { @@ -204,10 +204,10 @@ void ClientEvent::mapInputDownEvent(const std::string& inputDefinition, std::to_string(getClientEventId()) + ")"); } -void ClientEvent::mapInputUpEvent(const std::string& inputDefinition, +void ClientEvent::mapInputUpEvent(const std::string& inputDefinition, SIMCONNECT_INPUT_GROUP_ID inputGroupId, - DWORD upValue, - bool maskable) const { + DWORD upValue, + bool maskable) const { SIMCONNECT_CLIENT_EVENT_ID downId = reinterpret_cast(SIMCONNECT_UNUSED); if (!SUCCEEDED(SimConnect_MapInputEventToClientEvent(hSimConnect, inputGroupId, inputDefinition.c_str(), downId, 0, getClientEventId(), upValue, maskable))) { diff --git a/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/ClientEvent.h b/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/ClientEvent.h index fc031bc6f48..91a84abeec5 100644 --- a/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/ClientEvent.h +++ b/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/ClientEvent.h @@ -89,14 +89,14 @@ class ClientEvent { * @see * https://docs.flightsimulator.com/html/Programming_Tools/SimConnect/API_Reference/Events_And_Data/SimConnect_MapClientEventToSimEvent.htm */ - ClientEvent(HANDLE hSimConnect, SIMCONNECT_CLIENT_EVENT_ID clientEventId, std::string clientEventName); + ClientEvent(HANDLE hSimConnect, SIMCONNECT_CLIENT_EVENT_ID clientEventId, std::string clientEventName); public: - ClientEvent() = delete; // no default constructor - ClientEvent(const ClientEvent&) = delete; // no copy constructor + ClientEvent() = delete; // no default constructor + ClientEvent(const ClientEvent&) = delete; // no copy constructor ClientEvent& operator=(const ClientEvent&) = delete; // no copy assignment - ClientEvent(ClientEvent&&) = delete; // no move constructor - ClientEvent& operator=(ClientEvent&&) = delete; // no move assignment + ClientEvent(ClientEvent&&) = delete; // no move constructor + ClientEvent& operator=(ClientEvent&&) = delete; // no move assignment ~ClientEvent(); // ================================================================================================= @@ -263,11 +263,11 @@ class ClientEvent { * @see * https://docs.flightsimulator.com/html/Programming_Tools/SimConnect/API_Reference/Events_And_Data/SimConnect_MapInputEventToClientEvent.htm */ - void mapInputDownUpEvent(const std::string& inputDefinition, + void mapInputDownUpEvent(const std::string& inputDefinition, SIMCONNECT_INPUT_GROUP_ID inputGroupId = 0, - DWORD downValue = 0, - DWORD upValue = 0, - bool maskable = false); + DWORD downValue = 0, + DWORD upValue = 0, + bool maskable = false); /** * Adds an down input event to this client event and add it to an input group.
@@ -286,10 +286,10 @@ class ClientEvent { * @see * https://docs.flightsimulator.com/html/Programming_Tools/SimConnect/API_Reference/Events_And_Data/SimConnect_MapInputEventToClientEvent.htm */ - void mapInputDownEvent(const std::string& inputDefinition, + void mapInputDownEvent(const std::string& inputDefinition, SIMCONNECT_INPUT_GROUP_ID inputGroupId = 0, - DWORD downValue = 0, - bool maskable = false) const; + DWORD downValue = 0, + bool maskable = false) const; /** * Adds an up input event to this client event and add it to an input group.
@@ -308,10 +308,10 @@ class ClientEvent { * @see * https://docs.flightsimulator.com/html/Programming_Tools/SimConnect/API_Reference/Events_And_Data/SimConnect_MapInputEventToClientEvent.htm */ - void mapInputUpEvent(const std::string& inputDefinition, + void mapInputUpEvent(const std::string& inputDefinition, SIMCONNECT_INPUT_GROUP_ID inputGroupId = 0, - DWORD upValue = 0, - bool maskable = false) const; + DWORD upValue = 0, + bool maskable = false) const; /** * Removes down and up input events from the event input group and unmaps them from the event. diff --git a/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/DataDefinitionVariable.hpp b/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/DataDefinitionVariable.hpp index bf36835848a..91aca3bc62a 100644 --- a/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/DataDefinitionVariable.hpp +++ b/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/DataDefinitionVariable.hpp @@ -31,11 +31,11 @@ class DataManager; * when using the SIMCONNECT_DATA_REQUEST_FLAG_CHANGED flag (default: 0) */ struct DataDefinition { - std::string name; - int index{0}; - SimUnit unit{UNITS.Number}; + std::string name; + int index{0}; + SimUnit unit{UNITS.Number}; SIMCONNECT_DATATYPE dataType{SIMCONNECT_DATATYPE_FLOAT64}; - float epsilon{0.0}; + float epsilon{0.0}; }; /** @@ -105,14 +105,14 @@ class DataDefinitionVariable : public SimObjectBase { * @param maxAgeTime The maximum age of the value in sim time before it is updated from the sim by the requestUpdateFromSim() method. * @param maxAgeTicks The maximum age of the value in ticks before it is updated from the sim by the requestUpdateFromSim() method. */ - DataDefinitionVariable(HANDLE hSimConnect, - const std::string& varName, + DataDefinitionVariable(HANDLE hSimConnect, + const std::string& varName, const std::vector& dataDefinitions, - SIMCONNECT_DATA_DEFINITION_ID dataDefId, - SIMCONNECT_DATA_REQUEST_ID requestId, - UpdateMode updateMode = UpdateMode::NO_AUTO_UPDATE, - FLOAT64 maxAgeTime = 0.0, - UINT64 maxAgeTicks = 0) + SIMCONNECT_DATA_DEFINITION_ID dataDefId, + SIMCONNECT_DATA_REQUEST_ID requestId, + UpdateMode updateMode = UpdateMode::NO_AUTO_UPDATE, + FLOAT64 maxAgeTime = 0.0, + UINT64 maxAgeTicks = 0) : SimObjectBase(hSimConnect, varName, dataDefId, requestId, updateMode, maxAgeTime, maxAgeTicks), dataDefinitions(dataDefinitions), dataStruct{} { @@ -128,11 +128,11 @@ class DataDefinitionVariable : public SimObjectBase { } public: - DataDefinitionVariable() = delete; // no default constructor - DataDefinitionVariable(const DataDefinitionVariable&) = delete; // no copy constructor + DataDefinitionVariable() = delete; // no default constructor + DataDefinitionVariable(const DataDefinitionVariable&) = delete; // no copy constructor DataDefinitionVariable& operator=(const DataDefinitionVariable&) = delete; // no copy assignment - DataDefinitionVariable(DataDefinitionVariable&&) = delete; // no move constructor - DataDefinitionVariable& operator=(DataDefinitionVariable&&) = delete; // no move assignment + DataDefinitionVariable(DataDefinitionVariable&&) = delete; // no move constructor + DataDefinitionVariable& operator=(DataDefinitionVariable&&) = delete; // no move assignment /** * Destructor - clears the client data definition but does not free any sim memory. The sim memory @@ -180,10 +180,10 @@ class DataDefinitionVariable : public SimObjectBase { * @see https://docs.flightsimulator.com/html/Programming_Tools/SimConnect/API_Reference/Structures_And_Enumerations/SIMCONNECT_PERIOD.htm */ bool requestPeriodicDataFromSim(SIMCONNECT_PERIOD period, - DWORD periodFlags = SIMCONNECT_DATA_REQUEST_FLAG_DEFAULT, - DWORD origin = 0, - DWORD interval = 0, - DWORD limit = 0) const { + DWORD periodFlags = SIMCONNECT_DATA_REQUEST_FLAG_DEFAULT, + DWORD origin = 0, + DWORD interval = 0, + DWORD limit = 0) const { if (isAutoRead() && period >= SIMCONNECT_PERIOD_ONCE) { LOG_ERROR("DataDefinitionVariable: Requested periodic data update from sim is ignored as autoRead is enabled."); return false; diff --git a/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/DataObjectBase.hpp b/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/DataObjectBase.hpp index 36508566c6c..06eac87d003 100644 --- a/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/DataObjectBase.hpp +++ b/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/DataObjectBase.hpp @@ -19,11 +19,11 @@ class DataObjectBase { explicit DataObjectBase(std::string varName) : name(std::move(varName)) {} public: - DataObjectBase() = delete; // no default constructor - DataObjectBase(const DataObjectBase&) = delete; // no copy constructor + DataObjectBase() = delete; // no default constructor + DataObjectBase(const DataObjectBase&) = delete; // no copy constructor DataObjectBase& operator=(const DataObjectBase&) = delete; // no copy assignment - DataObjectBase(DataObjectBase&&) = delete; // no move constructor - DataObjectBase& operator=(DataObjectBase&&) = delete; // no move assignment + DataObjectBase(DataObjectBase&&) = delete; // no move constructor + DataObjectBase& operator=(DataObjectBase&&) = delete; // no move assignment /** * @return the name of the variable diff --git a/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/ManagedDataObjectBase.hpp b/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/ManagedDataObjectBase.hpp index 87c43f7bdbe..c42b965b155 100644 --- a/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/ManagedDataObjectBase.hpp +++ b/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/ManagedDataObjectBase.hpp @@ -115,12 +115,12 @@ class ManagedDataObjectBase : public DataObjectBase { } public: - ManagedDataObjectBase() = delete; // no default constructor - ManagedDataObjectBase(const ManagedDataObjectBase&) = delete; // no copy constructor - ManagedDataObjectBase& operator=(const ManagedDataObjectBase&) = delete; // no copy assignment - ManagedDataObjectBase(ManagedDataObjectBase&&) = delete; // no move constructor - ManagedDataObjectBase& operator=(ManagedDataObjectBase&&) = delete; // no move assignment - virtual ~ManagedDataObjectBase() = default; // so derived classes can be destroyed with base class pointer + ManagedDataObjectBase() = delete; // no default constructor + ManagedDataObjectBase(const ManagedDataObjectBase&) = delete; // no copy constructor + ManagedDataObjectBase& operator=(const ManagedDataObjectBase&) = delete; // no copy assignment + ManagedDataObjectBase(ManagedDataObjectBase&&) = delete; // no move constructor + ManagedDataObjectBase& operator=(ManagedDataObjectBase&&) = delete; // no move assignment + virtual ~ManagedDataObjectBase() = default; // so derived classes can be destroyed with base class pointer /** * Adds a callback function to be called when the data object's data changed.

@@ -167,9 +167,9 @@ class ManagedDataObjectBase : public DataObjectBase { * @param tickCounter - current tick counter */ void updateStamps(FLOAT64 timeStamp, UINT64 tickCounter) { - timeStampSimTime = timeStamp; + timeStampSimTime = timeStamp; nextUpdateTimeStamp = timeStamp + maxAgeTime; - tickStamp = tickCounter; + tickStamp = tickCounter; nextUpdateTickStamp = tickCounter + maxAgeTicks; } @@ -197,7 +197,8 @@ class ManagedDataObjectBase : public DataObjectBase { /** * @brief Sets the auto read update mode for the variable. - * @param autoRead if true the variable will be updated from the sim every time the DataManager::preUpdate() method is called, false otherwise + * @param autoRead if true the variable will be updated from the sim every time the DataManager::preUpdate() method is called, false + * otherwise */ virtual void setAutoRead(bool autoRead) { updateMode = static_cast(autoRead ? updateMode | UpdateMode::AUTO_READ : updateMode & ~UpdateMode::AUTO_READ); @@ -211,7 +212,8 @@ class ManagedDataObjectBase : public DataObjectBase { /** * @brief Sets the auto write update mode for the variable. - * @param autoWrite if true the variable will be written to the sim every time the DataManager::postUpdate() method is called, false otherwise + * @param autoWrite if true the variable will be written to the sim every time the DataManager::postUpdate() method is called, false + * otherwise */ virtual void setAutoWrite(bool autoWrite) { updateMode = static_cast(autoWrite ? updateMode | UpdateMode::AUTO_WRITE : updateMode & ~UpdateMode::AUTO_WRITE); diff --git a/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/NamedVariable.cpp b/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/NamedVariable.cpp index 7d60425e962..09856d8bbae 100644 --- a/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/NamedVariable.cpp +++ b/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/NamedVariable.cpp @@ -7,6 +7,17 @@ #include "NamedVariable.h" +std::string NamedVariable::addPrefixToVarName(const std::string& varName) { + // Check if varName already begins with AIRCRAFT_PREFIX + if (varName.compare(0, AIRCRAFT_PREFIX.length(), AIRCRAFT_PREFIX) == 0) { + // If it does, return the varName as it is. + return varName; + } else { + // Otherwise, add the prefix. + return AIRCRAFT_PREFIX + varName; + }; +} + FLOAT64 NamedVariable::rawReadFromSim() const { return get_named_variable_typed_value(dataID, unit.id); } diff --git a/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/NamedVariable.h b/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/NamedVariable.h index 15e6e14fea0..0937dafe8b8 100644 --- a/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/NamedVariable.h +++ b/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/NamedVariable.h @@ -37,48 +37,56 @@ class NamedVariable : public CacheableVariable { * It is recommended to use the DataManager's make_named_var() to create instances of NamedVariable * as it de-duplicates variables and only creates one instance of each name-unit combination. * - * @param varName The varName of the variable in the sim. An aircraft prefix (e.g. A32NX_) will be added automatically. + * @param varName The varName of the variable in the sim. An aircraft prefix (e.g. A32NX_) might be added + * automatically if specified when creating the MsfsHandler and the varName does not already contain it. * @param unit The unit of the variable as per the sim. See SimUnits.h * @param updateMode The DataManager update mode of the variable. (default: UpdateMode::NO_AUTO_UPDATE) * @param maxAgeTime The maximum age of an auto updated variable in seconds. * @param maxAgeTicks The maximum age of an auto updated variable in sim ticks. + * @param noPrefix If true, the aircraft prefix will not be added to the variable name. */ explicit NamedVariable(const std::string& varName, - SimUnit unit = UNITS.Number, - UpdateMode updateMode = UpdateMode::NO_AUTO_UPDATE, - FLOAT64 maxAgeTime = 0.0, - UINT64 maxAgeTicks = 0) - : CacheableVariable(NamedVariable::AIRCRAFT_PREFIX + varName, unit, updateMode, maxAgeTime, maxAgeTicks) { + SimUnit unit = UNITS.Number, + UpdateMode updateMode = UpdateMode::NO_AUTO_UPDATE, + FLOAT64 maxAgeTime = 0.0, + UINT64 maxAgeTicks = 0, + bool noPrefix = false) + : CacheableVariable(noPrefix ? varName : addPrefixToVarName(varName), unit, updateMode, maxAgeTime, maxAgeTicks) { dataID = register_named_variable(name.c_str()); - }; + } public: - NamedVariable() = delete; // no default constructor - NamedVariable(const NamedVariable&) = delete; // no copy constructor - NamedVariable& operator=(const NamedVariable&) = delete; // no copy assignment - NamedVariable(NamedVariable&&) = delete; // move constructor - NamedVariable& operator=(NamedVariable&&) = delete; // move assignment + NamedVariable() = delete; // no default constructor + NamedVariable(const NamedVariable&) = delete; // no copy constructor + NamedVariable& operator=(const NamedVariable&) = delete; // no copy assignment + NamedVariable(NamedVariable&&) = delete; // move constructor + NamedVariable& operator=(NamedVariable&&) = delete; // move assignment [[nodiscard]] FLOAT64 rawReadFromSim() const override; - void rawWriteToSim() override; + void rawWriteToSim() override; [[nodiscard]] std::string str() const override; /** - * Sets the aircraft prefix for all NamedVariables. - * This will usually be set by the MsfsHandler constructor. + * @brief Sets the aircraft prefix as a static class variable for all NamedVariables.

+ * This will usually be set by the MsfsHandler constructor. * @param aircraftPrefix The aircraft prefix to use. */ - static void setAircraftPrefix(const std::string& aircraftPrefix) { - NamedVariable::AIRCRAFT_PREFIX = aircraftPrefix; - } + static void setAircraftPrefix(const std::string& aircraftPrefix) { NamedVariable::AIRCRAFT_PREFIX = aircraftPrefix; } /** - * Returns the aircraft prefix for all NamedVariables. + * @brief Returns the static aircraft prefix for all NamedVariables. * @return The aircraft prefix. */ static const std::string& getAircraftPrefix() { return AIRCRAFT_PREFIX; } + /** + * @brief Adds the aircraft prefix to the variable name if it is not already present. + * @param varName The variable name to prefix. + * @return The prefixed variable name. + */ + static std::string addPrefixToVarName(const std::string& varName); + friend std::ostream& operator<<(std::ostream& os, const NamedVariable& namedVariable); }; diff --git a/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/SimObjectBase.hpp b/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/SimObjectBase.hpp index d81aa9dc17f..e9ab1d2aa84 100644 --- a/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/SimObjectBase.hpp +++ b/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/SimObjectBase.hpp @@ -49,24 +49,24 @@ class SimObjectBase : public ManagedDataObjectBase { * @param maxAgeTime The maximum age of the value in sim time before it is updated from the sim by the requestUpdateFromSim() method. * @param maxAgeTicks The maximum age of the value in ticks before it is updated from the sim by the requestUpdateFromSim() method. */ - SimObjectBase(HANDLE hSimConnect, + SimObjectBase(HANDLE hSimConnect, const std::string& varName, - DWORD dataDefId, - DWORD requestId, - UpdateMode updateMode = UpdateMode::NO_AUTO_UPDATE, - FLOAT64 maxAgeTime = 0.0, - UINT64 maxAgeTicks = 0) + DWORD dataDefId, + DWORD requestId, + UpdateMode updateMode = UpdateMode::NO_AUTO_UPDATE, + FLOAT64 maxAgeTime = 0.0, + UINT64 maxAgeTicks = 0) : ManagedDataObjectBase(varName, updateMode, maxAgeTime, maxAgeTicks), hSimConnect(hSimConnect), dataDefId(dataDefId), requestId(requestId) {} public: - SimObjectBase() = delete; // no default constructor - SimObjectBase(const SimObjectBase&) = delete; // no copy constructor + SimObjectBase() = delete; // no default constructor + SimObjectBase(const SimObjectBase&) = delete; // no copy constructor SimObjectBase& operator=(const SimObjectBase&) = delete; // no copy assignment - SimObjectBase(SimObjectBase&&) = delete; // no move constructor - SimObjectBase& operator=(SimObjectBase&&) = delete; // no move assignment + SimObjectBase(SimObjectBase&&) = delete; // no move constructor + SimObjectBase& operator=(SimObjectBase&&) = delete; // no move assignment /** * Sends a data request to the sim to have the sim prepare the requested data. diff --git a/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/StreamingClientDataAreaVariable.hpp b/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/StreamingClientDataAreaVariable.hpp index 8905a3a5930..4728bc127b3 100644 --- a/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/StreamingClientDataAreaVariable.hpp +++ b/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/DataTypes/StreamingClientDataAreaVariable.hpp @@ -60,14 +60,14 @@ class StreamingClientDataAreaVariable : public ClientDataAreaVariable { * @param maxAgeTicks The maximum age of the value in ticks before it is updated from the sim by * the requestUpdateFromSim() method. */ - StreamingClientDataAreaVariable(HANDLE hSimConnect, - const std::string& clientDataName, - SIMCONNECT_CLIENT_DATA_ID clientDataId, + StreamingClientDataAreaVariable(HANDLE hSimConnect, + const std::string& clientDataName, + SIMCONNECT_CLIENT_DATA_ID clientDataId, SIMCONNECT_CLIENT_DATA_DEFINITION_ID clientDataDefinitionId, - SIMCONNECT_DATA_REQUEST_ID requestId, - UpdateMode updateMode = UpdateMode::NO_AUTO_UPDATE, - FLOAT64 maxAgeTime = 0.0, - UINT64 maxAgeTicks = 0) + SIMCONNECT_DATA_REQUEST_ID requestId, + UpdateMode updateMode = UpdateMode::NO_AUTO_UPDATE, + FLOAT64 maxAgeTime = 0.0, + UINT64 maxAgeTicks = 0) : ClientDataAreaVariable(hSimConnect, clientDataName, clientDataId, @@ -80,7 +80,7 @@ class StreamingClientDataAreaVariable : public ClientDataAreaVariable { content() {} public: - StreamingClientDataAreaVariable() = delete; // no default constructor + StreamingClientDataAreaVariable() = delete; // no default constructor StreamingClientDataAreaVariable(const StreamingClientDataAreaVariable&) = delete; // no copy constructor // no copy assignment StreamingClientDataAreaVariable& operator=(const StreamingClientDataAreaVariable&) = delete; @@ -107,8 +107,8 @@ class StreamingClientDataAreaVariable : public ClientDataAreaVariable { void reserve(std::size_t expectedByteCnt) { this->setChanged(false); this->content.clear(); - this->receivedBytes = 0; - this->receivedChunks = 0; + this->receivedBytes = 0; + this->receivedChunks = 0; this->expectedByteCount = expectedByteCnt; this->content.reserve(expectedByteCnt); } @@ -141,9 +141,9 @@ class StreamingClientDataAreaVariable : public ClientDataAreaVariable { * @return true if successful, false otherwise */ bool writeDataToSim() override { - [[maybe_unused]] int chunkCount = 0; // for debugging output only - std::size_t sentBytes = 0; - std::size_t remainingBytes = this->content.size(); + [[maybe_unused]] int chunkCount = 0; // for debugging output only + std::size_t sentBytes = 0; + std::size_t remainingBytes = this->content.size(); while (sentBytes < this->content.size()) { if (remainingBytes >= ChunkSize) { diff --git a/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/Module.h b/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/Module.h index 732b6784e37..80924e221c1 100644 --- a/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/Module.h +++ b/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/Module.h @@ -34,10 +34,10 @@ class Module { bool _isInitialized = false; public: - Module() = delete; // no default constructor - Module(const Module&) = delete; // no copy constructor + Module() = delete; // no default constructor + Module(const Module&) = delete; // no copy constructor Module& operator=(const Module&) = delete; // no copy assignment - virtual ~Module() = default; + virtual ~Module() = default; /** * Creates a new module and takes a reference to the MsfsHandler instance. diff --git a/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/MsfsHandler.cpp b/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/MsfsHandler.cpp index 77337af7750..323d05fb49f 100644 --- a/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/MsfsHandler.cpp +++ b/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/MsfsHandler.cpp @@ -52,11 +52,13 @@ bool MsfsHandler::initialize() { register_key_event_handler_EX1(keyEventHandlerEx1, nullptr); // base sim data mainly for pause detection - std::vector baseDataDef = {{"SIMULATION TIME", 0, UNITS.Number}, - {"SIMULATION RATE", 0, UNITS.Number}, - {"SIM ON GROUND", 0, UNITS.Bool}, - {"L:" + NamedVariable::getAircraftPrefix() + "IS_READY", 0, UNITS.Number}, - {"L:" + NamedVariable::getAircraftPrefix() + "DEVELOPER_STATE", 0, UNITS.Number}}; + std::vector baseDataDef = { + {"SIMULATION TIME", 0, UNITS.Number}, + {"SIMULATION RATE", 0, UNITS.Number}, + {"SIM ON GROUND", 0, UNITS.Bool }, + {"L:" + NamedVariable::getAircraftPrefix() + "IS_READY", 0, UNITS.Number}, + {"L:" + NamedVariable::getAircraftPrefix() + "DEVELOPER_STATE", 0, UNITS.Number} + }; baseSimData = dataManager.make_datadefinition_var("BASE DATA", baseDataDef); if (!SUCCEEDED(baseSimData->requestPeriodicDataFromSim(SIMCONNECT_PERIOD_VISUAL_FRAME))) { LOG_ERROR(simConnectName + ": Failed to request periodic data for base sim data"); @@ -123,8 +125,8 @@ bool MsfsHandler::update(sGaugeDrawData* pData) { // read and update base data from sim FLOAT64 previousTimeStamp = timeStamp; - timeStamp = baseSimData->data().simulationTime; - simulationDeltaTime = std::max(0., timeStamp - previousTimeStamp); + timeStamp = baseSimData->data().simulationTime; + simulationDeltaTime = std::max(0., timeStamp - previousTimeStamp); tickCounter++; // Call preUpdate(), update() and postUpdate() for all modules @@ -190,4 +192,3 @@ bool MsfsHandler::shutdown() { unregister_all_named_vars(); return result; } - diff --git a/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/MsfsHandler.h b/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/MsfsHandler.h index c6d273d85b1..02889badc84 100644 --- a/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/MsfsHandler.h +++ b/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/MsfsHandler.h @@ -83,14 +83,18 @@ class MsfsHandler { */ // Pause detection NamedVariablePtr a32nxPauseDetected; - ClientEventPtr pauseDetectedEvent; + ClientEventPtr pauseDetectedEvent; /** * Current simulation time used for pause detection and time stamping variable updates */ FLOAT64 timeStamp{}; - /** The difference in sim time (including sim rate) since the last update, in seconds. */ + /** + * The difference in sim time since the last update, in seconds accounting for sim rate. + * As the sim only provides the delta time since the last update, independent of the sim rate, + * this value is calculated by the MsfsHandler. + */ FLOAT64 simulationDeltaTime{}; /** @@ -166,6 +170,9 @@ class MsfsHandler { [[nodiscard]] FLOAT64 getSimulationTime() const { return baseSimData->data().simulationTime; } /** + * @brief The difference in sim time since the last update, in seconds accounting for sim rate. + * As the sim only provides the delta time since the last update, independent of the sim rate, + * this value is calculated by the MsfsHandler. * @return The difference in sim time (accounting for sim rate) since the last update, in seconds. * @note This can return 0, and will return 0 when paused. */ diff --git a/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/SimUnits.h b/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/SimUnits.h index c05f0c7941e..f0ded3609ed 100644 --- a/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/SimUnits.h +++ b/fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/SimUnits.h @@ -16,7 +16,7 @@ struct SimUnit { public: const char* name; - const ENUM id; + const ENUM id; [[maybe_unused]] explicit SimUnit(const char* nameInSim) : name(nameInSim), id(get_units_enum(name)) { // LOG_INFO("SimUnit::SimUnit() " + std::string(name) + " = " + std::to_string(id)); } diff --git a/fbw-common/src/wasm/cpp-msfs-framework/README.md b/fbw-common/src/wasm/cpp-msfs-framework/README.md index 96bf7fb001e..eac94e9dc99 100644 --- a/fbw-common/src/wasm/cpp-msfs-framework/README.md +++ b/fbw-common/src/wasm/cpp-msfs-framework/README.md @@ -3,25 +3,25 @@ A lightweight framework to abstract the most common aspects when developing C++ WASM modules using the MSFS SDK and SimConnect. -See [GUIDELINES.md](https://github.com/flybywiresim/a32nx/blob/cpp-msfs-framework/fbw-common/src/wasm/extra-backend/GUIDELINES.md) +See [GUIDELINES.md](https://github.com/flybywiresim/a32nx/blob/cpp-msfs-framework/fbw-common/src/wasm/extra-backend/GUIDELINES.md) for more information on how to write good C++ code for FlyByWire Simulations. ## Purpose The purpose of this framework is to provide a lightweight abstraction layer -to the MSFS SDK and SimConnect for FlyByWire which encapsulates the most common -aspects of the SDK and SimConnect in C++ objects. This allows developers to focus +to the MSFS SDK and SimConnect for FlyByWire which encapsulates the most common +aspects of the SDK and SimConnect in C++ objects. This allows developers to focus on the implementation of the actual module without having to worry about the boilerplate code required to get the module up and running. It also helps to avoid doubling of code, variables and multiple calls to retrieve the same data from the simulator. -On of the main purposes of this framework is to avoid multiple WASM files which -have to be compiled by MSFS at the start of the flight when files have been +On of the main purposes of this framework is to avoid multiple WASM files which +have to be compiled by MSFS at the start of the flight when files have been updated. Every file adds a significant overhead to the startup time of a flight -in MSFS. Having fewer wasm files is more efficient and allows for faster startup -times. +in MSFS. Having fewer wasm files is more efficient and allows for faster startup +times. ## Goals @@ -35,7 +35,7 @@ aircraft or its systems. This will be done in the actual modules. It helps new developers to get started with C++ WASM development in the FlyByWire Code base without an overwhelming incomprehensible framework. -The framework should be continuously improved to make it easier to use and more +The framework should be continuously improved to make it easier to use and more powerful for additional use cases without making it overly complex. ## Overview and Features @@ -43,24 +43,26 @@ powerful for additional use cases without making it overly complex. The framework is split into two parts: ### Gauge and Modules + These components simplify setting up a C++ WASM module and provide a simple API to implement a module with all necessary boilerplate code. It allows to avoid having multiple WASM files which all add to the startup time -of the flight in MSFS. +of the flight in MSFS. -With this framework it is easy to have multiple gauges and WASM modules in one -WASM file. See details below. +With this framework it is easy to have multiple gauges and WASM modules in one +WASM file. See details below. -This part does not take care of any data or logic from or to the simulator. If -a developer chooses to only use this part of the framework, MSFS SDK and +This part does not take care of any data or logic from or to the simulator. If +a developer chooses to only use this part of the framework, MSFS SDK and SimConnect have to be used directly. -These components live in the aircraft src folders. +These components live in the aircraft src folders. Details see below. -### MsfsHandler and DataManager / Data Objects +### MsfsHandler and DataManager / Data Objects + MsfsHandler and DataManager are the central components which provide a simple API to retrieve and send data from and to the simulator. @@ -69,9 +71,9 @@ modules. It manages the SimConnect connection, all module updates, owns the DataManager and provides some imported core data variables to the modules. The DataManager is a central data store which allows to store and retrieve data -from the simulator. It provides different kind of data objects / variables which abstract the +from the simulator. It provides different kind of data objects / variables which abstract the sim's data types and allows to easily retrieve and send data from the simulator. -One of its main features is de-duplication of variables over all modules and +One of its main features is de-duplication of variables over all modules and to automatically update (read/write) the data to and from the simulator. These components live in the common src folder. @@ -81,9 +83,10 @@ Details see below. ## Components ### Gauge + A gauge is the central entry point for the simulator into the WASM module. -It basically provides a callback function the sim calls with different messages -(service_ids) which will be handled accordingly. +It basically provides a callback function the sim calls with different messages +(service_ids) which will be handled accordingly. In this framework the gauge code can be found in the Gauge_Extra_Backend.cpp file:
/fbw-a32nx/src/wasm/extra-backend-a32nx/src/Gauge_Extra_Backend.cpp
@@ -94,7 +97,7 @@ Gauges need to be configured into the panel.cfg file:
flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/panel/panel.cfg or the corresponding panel.cfg file of the A380X. -The Gauge_Extra_Backend.cpp also instantiates the MsfsHandler and the custom +The Gauge_Extra_Backend.cpp also instantiates the MsfsHandler and the custom modules - this is the only place a new module has to be added. ```cpp @@ -109,24 +112,27 @@ AircraftPresets aircraftPresets(msfsHandler, AircraftPresetProcedures_A32NX::air ... ``` -It is not expected that a Module-developer will have to modify the gauge other +It is not expected that a Module-developer will have to modify the gauge other than adding new Modules. Also see: + - [MSFS SDK Documentation: C/C++ GAUGES](https://docs.flightsimulator.com/html/Content_Configuration/SimObjects/Aircraft_SimO/Instruments/C_C++_Gauges.htm?rhhlterm=_gauge_callback&rhsearch=_gauge_callback) ### MsfsHandler + fbw-common/src/wasm/cpp-msfs-framework/MsfsHandler/MsfsHandler.h -The MsfsHandler is the central component acts as a dispatcher for the custom -modules. It manages the SimConnect connection, all module updates, owns the +The MsfsHandler is the central component acts as a dispatcher for the custom +modules. It manages the SimConnect connection, all module updates, owns the DataManager and provides some imported core data variables to the modules. Each module has to be registered with the MsfsHandler (done automatically in the Module's constructor). The MsfsHandler will then call the update functions of the -module and provides access to the DataManager and the raw sim-data if required. +module and provides access to the DataManager and the raw sim-data if required. It provides the following calls to the module at the appropriate time: + - initialize() - called once at the start of the flight session - preUpdate() - called before the update() call - update() - called every frame @@ -138,36 +144,37 @@ It is not expected that a Module-developer will have to modify the MsfsHandler. ### DataManager The DataManager is a central data store which allows to store and retrieve data -from the simulator. It provides different kinds of variables which abstract the +from the simulator. It provides different kinds of variables which abstract the various sim SDK API elements and data types into C++ objects. It currently provides the following data types: - **AircraftVariable:** a variable which is directly mapped to a simvar. - **NamedVariable**: a variable which is mapped to a LVAR. -- **DataDefinitionVariable**: Custom defined SimObjects base on simvars and custom +- **DataDefinitionVariable**: Custom defined SimObjects base on simvars and custom C++ structs (with SU12 also LVARs can be part of the data definition). -- **ClientDataAreaVariable**: Custom defined SimObjects base on memory mapped data to - exchange arbitrary data between SimConnect clients. +- **ClientDataAreaVariable**: Custom defined SimObjects base on memory mapped data to + exchange arbitrary data between SimConnect clients. - **StreamingClientDataAreaVariable**: Custom defined SimObjects base on memory mapped - which can be larger than the limit of 8k bytes per ClientDataArea by using a + which can be larger than the limit of 8k bytes per ClientDataArea by using a streaming buffer approach to send and retrieve data. - **ClientEvent**: These events are used to either create a custom event or to be mapped to a sim event or sim system event. The main feature of a ClientEvent is that it has a unique ID which can be used to map and recognize the event. Callbacks can then be registered to be called when the event is triggered. - -Also, it allows to register callback functions for KeyEvents. + +Also, it allows to register callback functions for KeyEvents. The below described data types can be created via the DataManager's make_... functions. - + #### DataObjectBase (abstract base class) The base class for all data objects providing the variable's name. #### ManagedDataObjectBase (abstract base class) + MSFS SDK and SimConnect provide different kinds of variables each with different -APIs on how to read and write them to the sim. +APIs on how to read and write them to the sim. The idea of variables in this framework is to provide a relatively consistent interface to the data from the sim. @@ -177,25 +184,26 @@ Each variable has various ways to be updated and written back to the sim: - Manual read/write: The developer can manually read and write the variable from and to the sim at any time - Auto read: The variable can be configured to be automatically read from the sim (preUpdate) via the DataManager - Auto write: The variable can be configured to be automatically written to the sim (postUpdate) via the DataManager -- Max Age in Ticks: The variable can be configured to be automatically read from the sim +- Max Age in Ticks: The variable can be configured to be automatically read from the sim if it is older than a certain number of ticks (preUpdate) -- Max Age in Seconds: The variable can be configured to be automatically read from the sim if +- Max Age in Seconds: The variable can be configured to be automatically read from the sim if it is older than a certain number of seconds (preUpdate) -This base class also provides the means to register and remove callbacks for updates +This base class also provides the means to register and remove callbacks for updates to the variable. Any time the variable is read and has changed the callbacks will be fired. See the documentation of ManagedDataObjectBase for more details. ##### CacheableVariable (abstract base class) + The CacheableVariable is the base class for AircraftVariable and NamedVariable which can be cached to avoid multiple calls to the sim for the same variable. -It is still possible to explicitly read and write the variable from and to the -sim if required. +It is still possible to explicitly read and write the variable from and to the +sim if required. **Reading** - + | method | description | |:-----------------|:---------------------------------------------------------------------------------------------------------| | get() | Returns cached value - never reads directly from sim | @@ -206,7 +214,7 @@ sim if required. See the documentation of CacheableVariable for more details. **Writing** - + | method | description | |--------------------|----------------------------------------------------------------------------------------------------------------------| | set() | Sets cached value - never writes directly to sim - sets dirty flag if set with a different value as the cached value | @@ -214,27 +222,29 @@ See the documentation of CacheableVariable for more details. | writeToSim() | Writes the current cached value to the sim. Clears the dirty flag. | | setAndWriteToSim() | Sets the current value and writes it to the sim. Clears the dirty flag. | | rawWriteToSim() | The raw MSFS SDK call to write the sim. | - + See the documentation of CacheableVariable for more details. ##### NamedVariable + The NamedVariable is a variable which is mapped to a LVAR (Local Variable). It is the simplest -variable type and can be used to store and retrieve custom numeric data from the +variable type and can be used to store and retrieve custom numeric data from the sim. -It is based on the CacheableVariable - see above. +It is based on the CacheableVariable - see above. -OBS: A prefix is added to the variable name to distinguish different aircraft +OBS: A prefix is added to the variable name to distinguish different aircraft (e.g. A32NX_ or A380X_). -The prefix is set via the static variable `AIRCRAFT_PREFIX` in the NamedVariable class. -It is set by the MsfsHandler class' constructor. +The prefix is set via the static variable `AIRCRAFT_PREFIX` in the NamedVariable class. +It is set by the MsfsHandler class' constructor. _Author note: this is done because of a team decision for this convention. The author does not think such a preset should be part of the framework API._ ##### AircraftVariable -The AircraftVariable is a variable which is mapped to an aircraft simvar. As simvars + +The AircraftVariable is a variable which is mapped to an aircraft simvar. As simvars are read-only it is required to use an event to write the variable back to the sim. It allows to specify either an event-name or an instance of an ClientEvent object to @@ -266,13 +276,14 @@ See the documentation of CacheableVariable for more details. **Writing** -| method | description | -|-------------------|---------------------------------------------------| -| writeDataToSim() | Write the current data struct contents to the sim | +| method | description | +|------------------|---------------------------------------------------| +| writeDataToSim() | Write the current data struct contents to the sim | ##### DataDefinitionVariable (Custom SimObjects) -The DataDefinitionVariable is a variable (in fact a data structure) which is mapped -to a custom data struct and a SimObject which can be defined by adding separate + +The DataDefinitionVariable is a variable (in fact a data structure) which is mapped +to a custom data struct and a SimObject which can be defined by adding separate data definitions for single sim variables to a container of data definitions. It requires a local data structure as a template type which is then used to hold the data. @@ -281,33 +292,35 @@ The class is based on ManagedDataObjectBase and therefore supports auto reading the data to the sim. It also supports using the SIMCONNECT_PERIOD flags to update the data by using this method to request the data: requestPeriodicUpdateFromSim().

-As data definition sim objects use memory mapped data between clients they are +As data definition sim objects use memory mapped data between clients they are very efficient but a bit harder to set up and use. A data definition variable consisting of only writable simvars can be used to write data back to the sim without the need to define an event. Writing back a read only simvar will produce a SimConnect exception (visible in the console) -in the next update tick. +in the next update tick. See the DataDefinitionVariable class documentation for more details. A DataDefinitionVariable requires unique IDs for the data definition and the -request. These IDs are used to identify the data definition and the data received -from the sim. The DataManager will create these variables, and it will automatically +request. These IDs are used to identify the data definition and the data received +from the sim. The DataManager will create these variables, and it will automatically assign unique IDs. Also see: + - Example and Pushback modules have examples of custom writable sim objects - [MSFS SDK Documentation: SimConnect Data Definition](https://docs.flightsimulator.com/html/Programming_Tools/SimConnect/API_Reference/Events_And_Data/SimConnect_AddToClientDataDefinition.htm) #### ClientDataAreaVariable (Custom Data Area) -SimConnect also allows to define custom SimObjects using memory mapped data + +SimConnect also allows to define custom SimObjects using memory mapped data between clients to send and receive arbitrary data to and from the sim. It requires a local data struct as a template type which is used to hold the data. -The client owning the data area is responsible for creating and managing the +The client owning the data area is responsible for creating and managing the data area whereas the other clients can only read and write to the data area. As client data areas use memory mapped data between clients they are @@ -315,131 +328,141 @@ very efficient but a bit harder to set up and use. See the ClientDataAreaVariable class documentation for more details. -A ClientDataAreaVariable requires unique IDs for the data area, the data definition -and the request. These IDs are used to identify the data definition and the data -received from the sim. The DataManager will create these variables, and it will automatically +A ClientDataAreaVariable requires unique IDs for the data area, the data definition +and the request. These IDs are used to identify the data definition and the data +received from the sim. The DataManager will create these variables, and it will automatically assign unique IDs. Also see: + - [MSFS SDK Documentation: SimConnect_MapClientDataNameToID](https://docs.flightsimulator.com/html/Programming_Tools/SimConnect/API_Reference/Events_And_Data/SimConnect_MapClientDataNameToID.htm) - + #### StreamingClientDataAreaVariable -The StreamingClientDataAreaVariable class is a special variant of the ClientDataAreaVariable -class which allows to send and receive data larger than the maximum size of a single +The StreamingClientDataAreaVariable class is a special variant of the ClientDataAreaVariable +class which allows to send and receive data larger than the maximum size of a single SimConnect client data area chunk of 8192 bytes. -The data is split into chunks of a fixed size (default 8192 bytes) and sent and +The data is split into chunks of a fixed size (default 8192 bytes) and sent and received in chunks. -The data is stored in a vector of the given type T, which is resized to the number of +The data is stored in a vector of the given type T, which is resized to the number of bytes expected to be received. -Before receiving data the reserve() method must be called to reset the data and set +Before receiving data the reserve() method must be called to reset the data and set the number of bytes to be received. See the StreamingClientDataAreaVariable class documentation for more details. #### ClientEvent + The ClientEvent class represents a client event which can be used to:
+ - create a custom event (between simconnect clients) - be mapped to a sim event - be mapped to a system event - A ClientEvent has a unique id and a name. The name can be used to map the event to a sim event or - to create a custom event. +A ClientEvent has a unique id and a name. The name can be used to map the event to a sim event or +to create a custom event. - Custom events must have a name that contains a period (e.g. "Custom.Event") to the sim recognizes - it as a custom event. +Custom events must have a name that contains a period (e.g. "Custom.Event") to the sim recognizes +it as a custom event. - To map to sim events the name must be identical to the name of the sim event otherwise there will be - a SimConnect exception that the event is unknown. +To map to sim events the name must be identical to the name of the sim event otherwise there will be +a SimConnect exception that the event is unknown. - If the ClientEvent is intended to be used as a system event then it must be constructed with the - registerToSim parameter set to false. This will prevent the event from being registered to the sim. +If the ClientEvent is intended to be used as a system event then it must be constructed with the +registerToSim parameter set to false. This will prevent the event from being registered to the sim. See the DataManager::make_xxx_event() functions for more details. #### Input Event -Input events can be added and mapped to an Event instance to be triggered by the -defined input events. + +Input events can be added and mapped to an Event instance to be triggered by the +defined input events. See [MSFS SDK Documentation: SimConnect_MapInputEventToClientEvent](https://docs.flightsimulator.com/html/Programming_Tools/SimConnect/API_Reference/Events_And_Data/SimConnect_MapInputEventToClientEvent.htm) for how to define input events. -These input events can be clustered in groups to be able to enable and disable a set of multiple +These input events can be clustered in groups to be able to enable and disable a set of multiple input events at once. Use Event::setInputGroupState() to enable or disable a group of input events. -OBS: There are still some inconsistencies in the MSFS SDK regarding input events, esp. when removing -and re-adding input events. It is recommended to only add input events once and not remove them. +OBS: There are still some inconsistencies in the MSFS SDK regarding input events, esp. when removing +and re-adding input events. It is recommended to only add input events once and not remove them. -For details see the ClientEvent class documentation. +For details see the ClientEvent class documentation. #### Key Event + A Key Event is not a data type which can be created. Use the DataManager to register a callback to handle key events (addKeyEventCallback). The callback will be called with the key event data. For details see the DataManager class documentation. #### Mouse Events -Not yet supported. + +Not yet supported. ## Example Code + Good examples of how to use the framework can be found in the modules: - ExampleModule - - Is used to demonstrate various features of the framework and also to debug - and test it. It is not meant to be used as a real module but rather as a - playground to test and learn how to use the framework. - + - Is used to demonstrate various features of the framework and also to debug + and test it. It is not meant to be used as a real module but rather as a + playground to test and learn how to use the framework. + - LightingPresets - - Uses NamedVariable and writeable AircraftVariables - - Uses the one update tick set read a request as set the light levels accordingly. + - Uses NamedVariable and writeable AircraftVariables + - Uses the one update tick set read a request as set the light levels accordingly. - Pushback - - Uses NamedVariable, writeable AircraftVariables and DataDefinitionVariable - - The NamesVariables and AircraftVariables are used to control the pushback process. - - Events and DataDefinitionVariables are used to actually control the pushback - movement + - Uses NamedVariable, writeable AircraftVariables and DataDefinitionVariable + - The NamesVariables and AircraftVariables are used to control the pushback process. + - Events and DataDefinitionVariables are used to actually control the pushback + movement - AircraftPresets - - Uses NamedVariable and writeable AircraftVariables to control the loading of - aircraft presets - - Uses several update ticks to load the preset and set the various variables - accordingly - - Uses the MSFS SDK API call to execute calculator code directly for reading - and setting the state of aircraft systems. - + - Uses NamedVariable and writeable AircraftVariables to control the loading of + aircraft presets + - Uses several update ticks to load the preset and set the various variables + accordingly + - Uses the MSFS SDK API call to execute calculator code directly for reading + and setting the state of aircraft systems. + ## Building + Assuming you are able to build the aircraft as a whole this describes how to add a new module (classes/headers) to the project. The framework code is split into three parts: + - the common c++ framework code which lives in /fbw-common/src/wasm/cpp-msfs-framework - the instance of a coomon backend using the c++ framework is in /fbw-common/src/wasm/extra-backend -- the aircraft specific gauge and modules which live in /fbw-a32nx/src/wasm/extra-backend-a32nx +- the aircraft specific gauge and modules which live in /fbw-a32nx/src/wasm/extra-backend-a32nx and /fbw-a380x/src/wasm/extra-backend-a380x When adding new modules please place them in a new folder in the aircraft's extra-backend folder:
E.g. /fbw-a32nx/src/wasm/extra-backend-a32nx Add it to the following files: + - /fbw-a32nx/src/wasm/extra-backend-a32nx/CMakeLists.txt - /fbw-a32nx/src/wasm/extra-backend-a32nx/src/Gauge_Extra_Backend.cpp -(or the A380X equivalents) + (or the A380X equivalents) To build it separately you can use the following commands: - + ```pwsh .\scripts\dev-env\run.cmd npm run build:cpp-wasm-cmake ``` -or +or ```pwsh .\scripts\dev-env\run.cmd npm run build:cpp-wasm-cmake-clean ``` - + If you want debug information in the build use:
```pwsh diff --git a/fbw-common/src/wasm/extra-backend/Pushback/InertialDampener.hpp b/fbw-common/src/wasm/cpp-msfs-framework/lib/DampingController.hpp similarity index 67% rename from fbw-common/src/wasm/extra-backend/Pushback/InertialDampener.hpp rename to fbw-common/src/wasm/cpp-msfs-framework/lib/DampingController.hpp index 57bd82051fa..6887d33cc00 100644 --- a/fbw-common/src/wasm/extra-backend/Pushback/InertialDampener.hpp +++ b/fbw-common/src/wasm/cpp-msfs-framework/lib/DampingController.hpp @@ -1,16 +1,17 @@ -// Copyright (c) 2023 FlyByWire Simulations +// Copyright (c) 2023-2024 FlyByWire Simulations // SPDX-License-Identifier: GPL-3.0 -#pragma once +#ifndef FLYBYWIRE_PUSHBACK_INERTIALDAMPENER_HPP +#define FLYBYWIRE_PUSHBACK_INERTIALDAMPENER_HPP #include "math_utils.hpp" /** - * The InertialDampener provides a dampened output based on the current input + * The DampingController provides a dampened output based on the current input * and an internal state value. The output value increases or decreases from the * internal state value towards the input value with the given acceleration value. */ -class InertialDampener { +class DampingController { private: double lastValue{}; double accelStepSize{}; @@ -18,7 +19,7 @@ class InertialDampener { public: /** - * Creates a new instance of the InertialDampener + * Creates a new instance of the DampingController * @param startValue initial value to avoid a too large delta for the first usage * @param accelStepSize value which will be added/subtracted to/from the internal * state towards the input value. @@ -26,10 +27,10 @@ class InertialDampener { * state value. If the difference is smaller than epsilon the input value * is returned. */ - InertialDampener(double startValue, double accelStepSize, double epsilon) { - this->lastValue = startValue; + DampingController(double startValue, double accelStepSize, double epsilon) { + this->lastValue = startValue; this->accelStepSize = accelStepSize; - this->epsilon = epsilon; + this->epsilon = epsilon; }; /** @@ -37,9 +38,9 @@ class InertialDampener { * returned value towards the new target value. The value is increased or decreased * by the accelStepSize provided when creating the instance. * @param newTargetValue - * @return new value loser to newTarget value by accelStepSize + * @return new value closer to newTarget value by accelStepSize */ - double updateSpeed(double newTargetValue) { + double updateTargetValue(double newTargetValue) { if (helper::Math::almostEqual(lastValue, newTargetValue, epsilon)) { return newTargetValue; } @@ -47,3 +48,5 @@ class InertialDampener { return lastValue; } }; + +#endif // FLYBYWIRE_PUSHBACK_INERTIALDAMPENER_HPP diff --git a/fbw-common/src/wasm/cpp-msfs-framework/lib/ProfileBuffer.hpp b/fbw-common/src/wasm/cpp-msfs-framework/lib/ProfileBuffer.hpp index 18798c8e6ff..1d59d18cc49 100644 --- a/fbw-common/src/wasm/cpp-msfs-framework/lib/ProfileBuffer.hpp +++ b/fbw-common/src/wasm/cpp-msfs-framework/lib/ProfileBuffer.hpp @@ -5,6 +5,7 @@ #define FLYBYWIRE_AIRCRAFT_PROFILEBUFFER_HPP #include +#include #include #include #include @@ -29,7 +30,7 @@ struct is_numeric> : std::true_type {}; template class ProfileBuffer { private: - std::size_t _capacity; + std::size_t _capacity; std::deque _buffer; public: @@ -37,7 +38,7 @@ class ProfileBuffer { * @brief Construct a new Profile Buffer object * @param capacity the maximum number of values to collect in the buffer */ - explicit ProfileBuffer(std::size_t capacity) : _capacity{capacity}, _buffer{std::deque(capacity)} { + explicit ProfileBuffer(std::size_t capacity) : _capacity{capacity}, _buffer{std::deque()} { static_assert(is_numeric::value || is_duration::value, "T must be numeric or duration type"); } @@ -57,7 +58,13 @@ class ProfileBuffer { * @brief Calculate the sum of all values in the buffer at the time of the call. * @return sum of all values */ - T sum() { return std::reduce(_buffer.begin(), _buffer.end(), T(0)); } + T sum() { +#if __cpp_lib_parallel_algorithm >= 201603 + return std::reduce(_buffer.begin(), _buffer.end(), T(0)); +#else + return std::accumulate(_buffer.begin(), _buffer.end(), T(0)); +#endif + } /** * @brief Calculate the average of all values in the buffer at the time of the call. @@ -76,7 +83,12 @@ class ProfileBuffer { auto sorted = _buffer; std::sort(sorted.begin(), sorted.end()); const std::size_t trimSize = sorted.size() * trimPercent; + +#if __cpp_lib_parallel_algorithm >= 201603 return std::reduce(sorted.begin() + trimSize, sorted.end() - trimSize, T(0)) / (sorted.size() - trimSize * 2); +#else + return std::accumulate(sorted.begin() + trimSize, sorted.end() - trimSize, T(0)) / (sorted.size() - trimSize * 2); +#endif } /** @@ -91,7 +103,11 @@ class ProfileBuffer { auto sorted = _buffer; std::sort(sorted.begin(), sorted.end()); const std::size_t trimSize = sorted.size() * percentile; +#if __cpp_lib_parallel_algorithm >= 201603 return std::reduce(sorted.begin(), sorted.begin() + trimSize, T(0)) / trimSize; +#else + return std::accumulate(sorted.begin(), sorted.begin() + trimSize, T(0)) / trimSize; +#endif } return *std::min_element(_buffer.begin(), _buffer.end()); } diff --git a/fbw-common/src/wasm/cpp-msfs-framework/lib/ScopedTimer.hpp b/fbw-common/src/wasm/cpp-msfs-framework/lib/ScopedTimer.hpp index 1fa3a24b8ee..0f0aac05a94 100644 --- a/fbw-common/src/wasm/cpp-msfs-framework/lib/ScopedTimer.hpp +++ b/fbw-common/src/wasm/cpp-msfs-framework/lib/ScopedTimer.hpp @@ -5,8 +5,8 @@ #define FLYBYWIRE_AIRCRAFT_SCOPEDTIMER_HPP #include -#include #include +#include #include /** @@ -33,7 +33,7 @@ class ScopedTimer { using ClockType = std::chrono::high_resolution_clock; private: - const std::string_view _timerName{}; + const std::string_view _timerName{}; const ClockType::time_point _start{}; public: @@ -49,15 +49,16 @@ class ScopedTimer { */ ~ScopedTimer() { using namespace std::chrono; - const auto stop = ClockType::now(); - const auto duration = (stop - _start); + const auto stop = ClockType::now(); + const auto duration = (stop - _start); const auto duration_micro = duration_cast(duration).count(); - std::cout << "Timer: " << std::setw(10) << std::right << duration_micro << " microseconds" << " for " << _timerName << std::endl; + std::cout << "Timer: " << std::setw(10) << std::right << duration_micro << " microseconds" + << " for " << _timerName << std::endl; } - ScopedTimer(const ScopedTimer&) = delete; - ScopedTimer(ScopedTimer&&) = delete; - auto operator=(const ScopedTimer&) -> ScopedTimer& = delete; + ScopedTimer(const ScopedTimer&) = delete; + ScopedTimer(ScopedTimer&&) = delete; + auto operator=(const ScopedTimer&) -> ScopedTimer& = delete; auto operator=(const ScopedTimer&&) -> ScopedTimer& = delete; }; diff --git a/fbw-common/src/wasm/cpp-msfs-framework/lib/SimpleProfiler.hpp b/fbw-common/src/wasm/cpp-msfs-framework/lib/SimpleProfiler.hpp index 6299f0db1e5..1a4e02c0614 100644 --- a/fbw-common/src/wasm/cpp-msfs-framework/lib/SimpleProfiler.hpp +++ b/fbw-common/src/wasm/cpp-msfs-framework/lib/SimpleProfiler.hpp @@ -36,11 +36,14 @@ class SimpleProfiler { private: const std::string _name; - ProfileBuffer _samples; Clock::time_point _start{}; - bool _started = false; + bool _started = false; + + ProfileBuffer _samples; public: + SimpleProfiler() = delete; + /** * @brief Construct a new Simple Profiler object * @param name Name of the profiler for the output @@ -53,7 +56,7 @@ class SimpleProfiler { */ void start() { _started = true; - _start = Clock::now(); + _start = Clock::now(); } /** @@ -81,7 +84,8 @@ class SimpleProfiler { /** * @brief Return the avg minimum execution time of a percentile of the collected samples at the time of calling this method. * If no percentile is given, the minimum of all samples is returned. - * @param percentile Percentile to return, e.g. 0.05 for the 5% minimum. If no percentile is given, the minimum of all samples is returned. + * @param percentile Percentile to return, e.g. 0.05 for the 5% minimum. If no percentile is given, the minimum of all samples is + * returned. * @return Average execution time of the minimum percentile of the collected samples at the time of calling this method or the minimum of * all samples if no percentile is given */ @@ -89,7 +93,8 @@ class SimpleProfiler { /** * @brief Return the avg maximum execution time of a percentile of the collected samples at the time of calling this method. - * @param percentile Percentile to return, e.g. 0.95 for the 95% maximum. If no percentile is given, the maximum of all samples is returned. + * @param percentile Percentile to return, e.g. 0.95 for the 95% maximum. If no percentile is given, the maximum of all samples is + * returned. * @return Average execution time of the maximum percentile of the collected samples at the time of calling this method or the maximum of * all samples if no percentile is given */ @@ -114,7 +119,7 @@ class SimpleProfiler { * @return String with the average execution time of the collected samples at the time of calling this method */ [[nodiscard]] std::string str() { - auto avg = _samples.avg(); + auto avg = _samples.avg(); std::stringstream os{}; os << "Profiler: " << std::setw(10) << std::right << helper::StringUtils::insertThousandsSeparator(avg.count()) << " (" << std::setw(10) << std::right << helper::StringUtils::insertThousandsSeparator(_samples.minimum().count()) << " / " << std::setw(10) << std::right diff --git a/fbw-common/src/wasm/cpp-msfs-framework/lib/arinc429.hpp b/fbw-common/src/wasm/cpp-msfs-framework/lib/arinc429.hpp new file mode 100644 index 00000000000..1c28ca72dca --- /dev/null +++ b/fbw-common/src/wasm/cpp-msfs-framework/lib/arinc429.hpp @@ -0,0 +1,237 @@ +// Copyright (c) 2023-2024 FlyByWire Simulations +// SPDX-License-Identifier: GPL-3.0 + +#ifndef FLYBYWIRE_AIRCRAFT_ARINC429_HPP +#define FLYBYWIRE_AIRCRAFT_ARINC429_HPP + +#include + +#include "logging.h" + +/** + * @brief Enum for the ARINC429 Sign Status Matrix + */ +enum Arinc429SignStatus { + FailureWarning = 0b00, + NoComputedData = 0b01, + FunctionalTest = 0b10, + NormalOperation = 0b11, +}; + +/** + * @brief ARINC429 like word representation for use in the FBW systems and the simulator. + * It does not implement the full ARINC429 standard but a simplified version of it.

+ * + * An Arinc429Word consists of a 32 bit data word and a 32 bit Sign Status Matrix (SSM). + * The data is stored in a template type T, which can be a 32 bit integer or float. + * The SSM is stored as an unsigned 32 bit integer.

+ * + * As the simulator only supports 64 bit double values, the data and SSM are encoded into a 64 bit unsigned integer and cast to a double or + * decoded from a double to the data and SSM.

+ * + * @tparam T The type of the data (32-bit integer or float) + */ +template +class Arinc429Word { + protected: + Arinc429Word() = default; + + T rawData{}; + uint32_t rawSsm{}; + + public: + /** + * @brief Sets the data and SSM from an arinc429 encoded LVar value (double) + * + * The LVar value is casted to a 64 bit unsigned integer and then split into the data (lower 32 bits) and SSM (upper 32 bits). + * + * @param simVar An arinc429 encoded LVar value + */ + void setFromSimVar(double simVar) { + const auto u64Val = static_cast(simVar); + const uint32_t u32Val = u64Val & 0xffffffff; + rawSsm = u64Val >> 32; + rawData = *reinterpret_cast(&u32Val); + } + + /** + * @brief Sets the data and SSM from a data value and an SSM + * @param data max 32-bit integer or float + * @param ssm The SSM enum value + */ + void setFromData(T data, Arinc429SignStatus ssm) { + // Ensure T is an integer or a float with a maximum size of 32 bits + static_assert((std::is_integral::value || std::is_floating_point::value), "T must be an integer or a float."); + static_assert(sizeof(T) <= 4, "T must be at most 32 bits (4 bytes)."); + + rawSsm = ssm; + rawData = data; + } + + /** + * @brief Converts the data and SSM to an arinc429 encoded LVar value (double) + * @return 64-bit double value representing the arinc429 encoded LVar value + */ + double toSimVar() { + const uint64_t u64Val = *reinterpret_cast(&rawData) | static_cast(rawSsm) << 32; + return static_cast(u64Val); + } + + /** + * @brief Get the SSM enum value + * @return The SSM enum value + */ + Arinc429SignStatus ssm() const { return static_cast(rawSsm); } + + /** + * @brief Set the SSM enum value + * @param ssm + */ + void setSsm(Arinc429SignStatus ssm) { rawSsm = static_cast(ssm); } + + /** + * @brief Set the data value + * @param data max 32-bit integer or float + */ + void setData(T data) { + // Ensure T is an integer or a float with a maximum size of 32 bits + static_assert((std::is_integral::value || std::is_floating_point::value), "T must be an integer or a float."); + static_assert(sizeof(T) <= 4, "T must be at most 32 bits (4 bytes)."); + + rawData = data; + } + + /** + * @brief Check if the SSM is in the Failure Warning state + * @return true if the SSM is in the Failure Warning state + */ + bool isFailureWarning() const { return static_cast(rawSsm) == Arinc429SignStatus::FailureWarning; } + + /** + * @brief Check if the SSM is in the Normal Operation state + * @return true if the SSM is in the Normal Operation state + */ + bool isNormalOperation() const { return static_cast(rawSsm) == Arinc429SignStatus::NormalOperation; } + + /** + * @brief Get the data value + * @return The data value + */ + T value() const { return rawData; } + + /** + * @brief Get the data value or a default value if the SSM is not in Normal Operation or Functional Test + * @param defaultVal The default value to return if the SSM is not in Normal Operation or Functional Test + * @return The data value or the default value + */ + T valueOr(T defaultVal) const { + // Ensure T is an integer or a float with a maximum size of 32 bits + static_assert((std::is_integral::value || std::is_floating_point::value), "T must be an integer or a float."); + static_assert(sizeof(T) <= 4, "T must be at most 32 bits (4 bytes)."); + + if (rawSsm == NormalOperation || rawSsm == FunctionalTest) { + return rawData; + } else { + return defaultVal; + } + } +}; + +/** + * @brief Arinc429DiscreteWord uses bit level encoding of the data. These cannot be used as a numeric value. + */ +class Arinc429DiscreteWord : public Arinc429Word { + public: + /** + * @brief Construct a new Arinc429DiscreteWord object + */ + Arinc429DiscreteWord() = default; + + /** + * @brief Construct a new Arinc429DiscreteWord object + * + * @param simVar An arinc429 encoded LVar value + */ + explicit Arinc429DiscreteWord(double simVar) { setFromSimVar(simVar); } + + /** + * @brief Get the value of a specific bit + * @param bit The bit number (1-32) to get the value from + * @return true if the bit is set, false otherwise + * @throws std::out_of_range if the bit number is out of range if exceptions are enabled. If exceptions are disabled, + * a log message will be printed and the function will return false + */ + bool bitFromValue(int bit) const { + if (bit < 1 || bit > 32) { +#ifdef __cpp_exceptions + throw std::out_of_range("Invalid bit number: " + std::to_string(bit)); +#else + LOG_ERROR("Invalid bit number: " + std::to_string(bit)); + return false; +#endif + } + return (static_cast(rawData) >> (bit - 1)) & 0x01; + } + + /** + * @brief Get the value of a specific bit or a default value if the SSM is not in Normal Operation or Functional Test + * @param bit The bit number (1-32) to get the value from + * @param defaultVal The default value to return if the SSM is not in Normal Operation or Functional Test + * @return true if the bit is set, false otherwise + * @throws std::out_of_range if the bit number is out of range if exceptions are enabled. If exceptions are disabled, + * a log message will be printed and the function will return the default value + */ + bool bitFromValueOr(int bit, bool defaultVal) const { + if (bit < 1 || bit > 32) { +#ifdef __cpp_exceptions + throw std::out_of_range("Invalid bit number: " + std::to_string(bit)); +#else + LOG_ERROR("Invalid bit number: " + std::to_string(bit)); + return defaultVal; +#endif + } + if (rawSsm == NormalOperation || rawSsm == FunctionalTest) { + return bitFromValue(bit); + } else { + return defaultVal; + } + } + + /** + * @brief Set the value of a specific bit + * @param bit The bit number (1-32) to set the value for + * @param value The boolean value to set the bit to + * @throws std::out_of_range if the bit number is out of range if exceptions are enabled. If exceptions are disabled, + * a log message will be printed and the function will return + */ + void setBit(int bit, bool value) { + if (bit < 1 || bit > 32) { +#ifdef __cpp_exceptions + throw std::out_of_range("Invalid bit number: " + std::to_string(bit)); +#else + LOG_ERROR("Invalid bit number: " + std::to_string(bit)); +#endif + } + rawData = static_cast((static_cast(rawData) & ~(1 << (bit - 1))) | (value << (bit - 1))); + } +}; + +/** + * @brief Arinc429NumericWord uses a float value for the data. These can be used as a numeric value. + */ +class Arinc429NumericWord : public Arinc429Word { + public: + /** + * @brief Construct a new Arinc429NumericWord object + */ + Arinc429NumericWord() = default; + + /** + * @brief Construct a new Arinc429NumericWord object based on an arinc429 encoded LVar value + * + * @param simVar An arinc429 encoded LVar value + */ + explicit Arinc429NumericWord(double simVar) { setFromSimVar(simVar); } +}; + +#endif // FLYBYWIRE_AIRCRAFT_ARINC429_HPP diff --git a/fbw-common/src/wasm/cpp-msfs-framework/lib/fingerprint.hpp b/fbw-common/src/wasm/cpp-msfs-framework/lib/fingerprint.hpp index c5c653030ee..feec9faaa51 100644 --- a/fbw-common/src/wasm/cpp-msfs-framework/lib/fingerprint.hpp +++ b/fbw-common/src/wasm/cpp-msfs-framework/lib/fingerprint.hpp @@ -5,16 +5,14 @@ #ifndef FLYBYWIRE_AIRCRAFT_FINGERPRINT_HPP #define FLYBYWIRE_AIRCRAFT_FINGERPRINT_HPP -#include #include +#include /** * This class provides a fingerprint function for vectors of values. */ class Fingerprint { - -public: - + public: /** * Fowler-Noll-Vo hash function * @tparam T the type of the values in the provided vector @@ -24,11 +22,11 @@ class Fingerprint { template static uint64_t fingerPrintFVN(const std::vector& vec) { const uint64_t FNV_OFFSET_BASIS = 0xcbf29ce484222325ULL; - const uint64_t FNV_PRIME = 0x100000001b3ULL; - uint64_t fp = 0; + const uint64_t FNV_PRIME = 0x100000001b3ULL; + uint64_t fp = 0; for (const auto& elem : vec) { - const T& value = elem; - uint64_t hash = FNV_OFFSET_BASIS; + const T& value = elem; + uint64_t hash = FNV_OFFSET_BASIS; const unsigned char* bytes = reinterpret_cast(&value); for (size_t i = 0; i < sizeof(T); i++) { hash ^= static_cast(bytes[i]); @@ -40,8 +38,6 @@ class Fingerprint { } return fp; } - }; - -#endif //FLYBYWIRE_AIRCRAFT_FINGERPRINT_HPP +#endif // FLYBYWIRE_AIRCRAFT_FINGERPRINT_HPP diff --git a/fbw-common/src/wasm/cpp-msfs-framework/lib/logging.h b/fbw-common/src/wasm/cpp-msfs-framework/lib/logging.h index e174b52b947..9ef0afe55ad 100644 --- a/fbw-common/src/wasm/cpp-msfs-framework/lib/logging.h +++ b/fbw-common/src/wasm/cpp-msfs-framework/lib/logging.h @@ -101,9 +101,9 @@ class Logger { public: // disallow copies - Logger(Logger const&) = delete; // copy - Logger& operator=(const Logger&) = delete; // copy assignment - Logger(Logger const&&) = delete; // move + Logger(Logger const&) = delete; // copy + Logger& operator=(const Logger&) = delete; // copy assignment + Logger(Logger const&&) = delete; // move Logger& operator=(const Logger&&) = delete; // move assignment void critical(const std::string& msg) { std::cerr << "critical: " + msg; } diff --git a/fbw-common/src/wasm/cpp-msfs-framework/lib/math_utils.hpp b/fbw-common/src/wasm/cpp-msfs-framework/lib/math_utils.hpp index 1b329321532..98097ba4c35 100644 --- a/fbw-common/src/wasm/cpp-msfs-framework/lib/math_utils.hpp +++ b/fbw-common/src/wasm/cpp-msfs-framework/lib/math_utils.hpp @@ -32,11 +32,11 @@ class Math { * @param a - positive or negative angle * @param b - positive or negative angle */ - static double angleAdd(double a, double b) { - double r = a + b; - r = fmod(fmod(r, 360.0) + 360.0, 360.0); - return r; -} + static double angleAdd(double a, double b) { + double r = a + b; + r = fmod(fmod(r, 360.0) + 360.0, 360.0); + return r; + } /** * Returns the signum (sign) of the given value. @@ -48,7 +48,6 @@ class Math { static inline int sign(T x) { return (x > 0) ? 1 : ((x < 0) ? -1 : 0); } - }; } // namespace helper diff --git a/fbw-common/src/wasm/cpp-msfs-framework/lib/quantity.hpp b/fbw-common/src/wasm/cpp-msfs-framework/lib/quantity.hpp index a4dd6660315..becc705e5bb 100644 --- a/fbw-common/src/wasm/cpp-msfs-framework/lib/quantity.hpp +++ b/fbw-common/src/wasm/cpp-msfs-framework/lib/quantity.hpp @@ -1,7 +1,8 @@ // Copyright (c) 2023 FlyByWire Simulations // SPDX-License-Identifier: GPL-3.0 -#pragma once +#ifndef FBW_COMMON_SRC_WASM_CPP_MSFS_FRAMEWORK_LIB_QUANTITY_HPP +#define FBW_COMMON_SRC_WASM_CPP_MSFS_FRAMEWORK_LIB_QUANTITY_HPP #include #include @@ -34,7 +35,7 @@ class Quantity { } [[nodiscard]] constexpr float value() const { return this->m_value; } - constexpr void setValue(float value) { this->m_value = value; } + constexpr void setValue(float value) { this->m_value = value; } [[nodiscard]] constexpr float convert(const Quantity& rhs) const { return this->m_value / rhs.m_value; } [[nodiscard]] constexpr Quantity>, std::ratio_divide>, @@ -42,7 +43,7 @@ class Quantity { std::ratio_divide>> sqrt() const { return Quantity>, std::ratio_divide>, std::ratio_divide>, - std::ratio_divide>>(std::sqrtf(this->m_value)); + std::ratio_divide>>(std::sqrt(this->m_value)); } [[nodiscard]] constexpr Quantity abs() const { return Quantity(std::abs(this->m_value)); } }; @@ -201,8 +202,8 @@ constexpr Mass operator"" _lbs(unsigned long long int value) { } constexpr Length metre(1.0f); -constexpr Length feet = 0.3048f * metre; -constexpr Length kilometre = 1000.0f * metre; +constexpr Length feet = 0.3048f * metre; +constexpr Length kilometre = 1000.0f * metre; constexpr Length nauticmile = 1852.0f * metre; constexpr Length operator"" _m(long double value) { return Length(static_cast(value)); @@ -231,8 +232,8 @@ constexpr Length operator"" _nm(unsigned long long int value) { constexpr Time second(1.0f); constexpr Time millisecond = second / 1000.0f; -constexpr Time minute = 60.0f * second; -constexpr Time hour = 60.0f * minute; +constexpr Time minute = 60.0f * second; +constexpr Time hour = 60.0f * minute; constexpr Time operator"" _ms(long double value) { return static_cast(value) * millisecond; } @@ -280,7 +281,7 @@ constexpr Angle operator"" _deg(unsigned long long int value) { return static_cast(value) * degree; } -constexpr Velocity knot = 0.51444f * metre / second; +constexpr Velocity knot = 0.51444f * metre / second; constexpr Velocity ftpmin = feet / minute; constexpr Velocity operator"" _mps(long double value) { return Velocity(static_cast(value)); @@ -347,4 +348,4 @@ constexpr AngularAcceleration operator"" _degps2(unsigned long long int value) { return static_cast(value) * degree / (second * second); } -#pragma clang diagnostic pop +#endif // FBW_COMMON_SRC_WASM_CPP_MSFS_FRAMEWORK_LIB_QUANTITY_HPP diff --git a/fbw-common/src/wasm/cpp-msfs-framework/lib/string_utils.hpp b/fbw-common/src/wasm/cpp-msfs-framework/lib/string_utils.hpp index 3f45dfddbf4..925301d8b2e 100644 --- a/fbw-common/src/wasm/cpp-msfs-framework/lib/string_utils.hpp +++ b/fbw-common/src/wasm/cpp-msfs-framework/lib/string_utils.hpp @@ -4,9 +4,12 @@ #ifndef FLYBYWIRE_AIRCRAFT_STRING_UTILS_HPP #define FLYBYWIRE_AIRCRAFT_STRING_UTILS_HPP +#include +#include #include #include #include +#include namespace helper { @@ -29,19 +32,19 @@ class StringUtils { * The function can handle both positive and negative input numbers. */ template - static std::string insertThousandsSeparator(T n, const std::string_view separator = ",") { + static inline std::string insertThousandsSeparator(T n, const std::string_view separator = ",") { static_assert(std::is_integral::value, "T must be an integral type"); // Handle negative numbers bool isNegative = false; if (n < 0) { isNegative = true; - n = -n; // Make the number positive for processing + n = -n; // Make the number positive for processing } - std::string s = std::to_string(n); - const int len = s.length(); - const int numCommas = (len - 1) / 3; + std::string s = std::to_string(n); + const int len = s.length(); + const int numCommas = (len - 1) / 3; s.reserve(len + numCommas); for (int i = len - 4; i >= 0; i -= 3) { s.insert(i + 1, separator); @@ -68,14 +71,207 @@ class StringUtils { * @return A string representation of the number, padded with leading zeros to reach the specified total length. */ template >> - static std::string to_string_with_zero_padding(const T& value, std::size_t total_length) { - std::string str = std::to_string(value); + static inline std::string to_string_with_zero_padding(const T& value, std::size_t total_length) { + bool isNegative = value < 0; + T absValue = isNegative ? -value : value; + + std::string str = std::to_string(absValue); if (str.length() >= total_length) { - return str; + return isNegative ? "-" + str : str; } + std::ostringstream oss; - oss << std::setw(total_length) << std::setfill('0') << value; - return oss.str(); + oss << std::setw(total_length) << std::setfill('0') << absValue; + + return isNegative ? "-" + oss.str() : oss.str(); + } + + /** + * @brief splits a string or string view into a vector of parts at each delimiter + * @tparam StringType + * @param str the string to split + * @param container the container to store the split parts + * @param delim the delimiters to split the string at (default is " ") + */ + template + static inline void splitFast(const StringType& str, std::vector& container, const std::string& delim = " ") { + for (auto first = str.data(), second = str.data(), end = first + str.size(); second != end && first != end; first = second + 1) { + second = std::find_first_of(first, end, std::cbegin(delim), std::cend(delim)); + if (first != second) { + container.emplace_back(first, second - first); + } + } + } + + /** + * @brief splits a string or string view into a vector of parts at each delimiter + * @tparam StringType + * @param str the string to split + * @param container the container to store the split parts + * @param delim the delimiters to split the string at (default is " ") + */ + static inline void splitFast(const char* str, std::vector& container, const char* delim = " ") { + splitFast(std::string(str), container, std::string(delim)); + } + + /** + * @brief Removes whitespace characters from beginning and end of string s
+ * Whitespaces are defined as: ' ', '\\t', '\\n', '\\v', '\\f', '\\r' + * @tparam StringType std::string or std::string_view + * @param s the string to trim + * @return StringType the trimmed string + */ + template + static inline StringType trimFast(const StringType& s) { + const int l = static_cast(s.length()); + int a = 0, b = l - 1; + char c; + while (a < l && ((c = s[a]) == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r')) { + a++; + } + while (b > a && ((c = s[b]) == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r')) { + b--; + } + return s.substr(a, 1 + b - a); + } + + /** + * @brief removes trailing parts of a string after a given commentMarker + * @tparam StringType std::string or std::string_view + * @param s the string to remove trailing comments from + * @param commentMarker the comment marker to search for + * @return StringType the string with trailing comments removed + */ + template + static inline StringType removeTrailingComments(const StringType& s, const std::string& commentMarker) { + const auto pos = s.find(commentMarker); + if (pos != StringType::npos) { + return s.substr(0, pos); + } + return s; + } + + /** + * @brief transforms the given string to lower case + * @param s the string to transform + * @return std::string the transformed string + */ + static inline std::string toLowerCase(const std::string& s) { + std::string str(s); + std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { return char(std::tolower(c)); }); + return str; + } + + /** + * @brief transforms the given string to lower case in place + * @param str the string to transform in place + */ + static inline void toLowerCase(std::string& str) { + std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { return char(std::tolower(c)); }); + } + + /** + * @brief transforms the given string to upper case + * @param s the string to transform + * @return std::string the transformed string + */ + static inline std::string toUpperCase(const std::string& s) { + std::string str(s); + std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { return char(std::toupper(c)); }); + return str; + } + + /** + * @brief transforms the given string to upper case in place + * @param str the string to transform in place + */ + static inline void toUpperCase(std::string& str) { + std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { return char(std::toupper(c)); }); + } + + /** + * @brief Helper function to convert a bit integer to a string showing all bits grouped in bytes + * + * The most significant bit is on the left (bit 63) and the least significant bit is on the right (bit 0). + * + * @tparam T the type of the integer to convert + * @param b the 64 bit integer to convert + * @return std::string the string representation of the bits + */ + template + static std::string strBitsGroupedInteger(const T b) { + // Ensure the template parameter is an integral type + static_assert(std::is_integral::value, "Template parameter must be an integral type."); + + std::ostringstream os; + // Determine the number of bits for the given type + const size_t numBits = sizeof(T) * 8; + T one = 1; // Define `one` as a constant of the same type + + // Loop through the bits and group them by 8 with dots in between + for (size_t i = 0; i < numBits; i++) { + if (i > 0 && i % 8 == 0) { + os << "."; + } + // Check if the corresponding bit is set + os << ((b & (one << (numBits - 1 - i))) ? "1" : "0"); + } + + // Append the integer representation to the output string + os << " (" + std::to_string(b) + ")"; + return os.str(); + } + + /** + * @brief Helper function to convert a floating-point number to a string showing all bits grouped in sign, exponent, and fraction + * @tparam T the type of the floating-point number to convert + * @param value the floating-point number to convert + * @return std::string the string representation of the bits + */ + template + static std::string strBitsGroupedFloatingpoint(const T& value) { + // Ensure the template parameter is an integral type + static_assert(std::is_floating_point::value, "Template parameter must be a floating-point type."); + + std::ostringstream os; + + // Union to reinterpret float/double as raw bits + union { + T float_value; + uint64_t integer_value; // Can hold the bits for both float and double + }; + + float_value = value; + + // Determine the number of bits based on the type (32 bits for float, 64 bits for double) + const size_t numBits = sizeof(T) * 8; + + // Constants for sign, exponent, and fraction bit counts + size_t signBitCount = 1; + size_t exponentBitCount = (numBits == 32) ? 8 : 11; + size_t fractionBitCount = numBits - signBitCount - exponentBitCount; + + // Get the sign bit + os << ((integer_value & (1ULL << (numBits - 1))) ? "1" : "0"); + + os << "."; // Separator for sign and exponent + + // Get the exponent bits + for (size_t i = 0; i < exponentBitCount; i++) { + os << ((integer_value & (1ULL << (numBits - 2 - i))) ? "1" : "0"); + } + + os << "."; // Separator for exponent and fraction + + // Get the fraction bits + for (size_t i = 0; i < fractionBitCount; i++) { + os << ((integer_value & (1ULL << (fractionBitCount - 1 - i))) ? "1" : "0"); + } + + // Add the value in parentheses for context + os << " (" << std::setprecision(17) << float_value << ")"; + + return os.str(); } }; diff --git a/fbw-common/src/wasm/cpp-msfs-framework/test/CMakeLists.txt b/fbw-common/src/wasm/cpp-msfs-framework/test/CMakeLists.txt new file mode 100644 index 00000000000..f5d1a5fa511 --- /dev/null +++ b/fbw-common/src/wasm/cpp-msfs-framework/test/CMakeLists.txt @@ -0,0 +1,69 @@ +message("====================================================================") +message("cpp-framework-test") +message("====================================================================") + +cmake_minimum_required(VERSION 3.25) +project(cpp-framework-tests LANGUAGES CXX) + +# C++ standard +set(CMAKE_CXX_STANDARD 20) +# compiler refinement +set(COMPILER_FLAGS "-g -O0 -Wall -Wextra -Werror -Wshadow -fprofile-arcs -ftest-coverage -pthread") + +# ==================================================================== +# Source files +# ==================================================================== +set(SOURCE_FILES + src/lib/string_utils-tests.cpp + src/lib/math_utils-tests.cpp + src/lib/ProfileBuffer-tests.cpp + src/lib/quantity-tests.cpp + src/lib/fingerprint-tests.cpp + src/lib/arinc429-tests.cpp + src/lib/DampingController-tests.cpp +) + +# ==================================================================== +# Include directories +# ==================================================================== +set(INCLUDE_FILES + ../lib +) + +# ==================================================================== +# GTest Config - do not edit +# ==================================================================== + +# Unit testing enabled +enable_testing() + +set(FETCHCONTENT_QUIET OFF) +set(FETCHCONTENT_UPDATES_DISCONNECTED ON) +include(FetchContent) + +# GOOGLE TEST +message("Downloading/Update Google Test") +FetchContent_Declare( + googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG v1.13.0 +) +FetchContent_Declare(googletest) +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) +option(INSTALL_GMOCK OFF) +option(INSTALL_GTEST OFF) +FetchContent_MakeAvailable(googletest) +include_directories( + ${googletest_SOURCE_DIR}/googletest/include + ${INCLUDE_FILES} +) + +# Google Test executable +set(testExeName cpp-framework-test) +include(GoogleTest) +add_executable(${testExeName} ${SOURCE_FILES} ${INCLUDE_FILES}) +target_link_libraries(${testExeName} PUBLIC gtest gtest_main) + +gtest_discover_tests(${testExeName}) + + diff --git a/fbw-common/src/wasm/cpp-msfs-framework/test/src/lib/DampingController-tests.cpp b/fbw-common/src/wasm/cpp-msfs-framework/test/src/lib/DampingController-tests.cpp new file mode 100644 index 00000000000..9965fca46f2 --- /dev/null +++ b/fbw-common/src/wasm/cpp-msfs-framework/test/src/lib/DampingController-tests.cpp @@ -0,0 +1,32 @@ +// Copyright (c) 2023-2024 FlyByWire Simulations +// SPDX-License-Identifier: GPL-3.0 + +#include "DampingController.hpp" +#include "gtest/gtest.h" + +class DampingControllerTest : public ::testing::Test {}; + +TEST_F(DampingControllerTest, UpdateSpeedIncreasesValueWhenTargetIsHigher) { + DampingController dampener{0.0, 0.1, 0.01}; + double result = dampener.updateTargetValue(1.0); + EXPECT_NEAR(result, 0.1, 0.01); +} + +TEST_F(DampingControllerTest, UpdateSpeedDecreasesValueWhenTargetIsLower) { + DampingController dampener{1.0, 0.1, 0.01}; + double result = dampener.updateTargetValue(0.0); + EXPECT_FLOAT_EQ(result, 0.9); +} + +TEST_F(DampingControllerTest, UpdateSpeedReturnsTargetWhenDifferenceIsLessThanEpsilon) { + DampingController dampener{0.0, 0.1, 0.01}; + double result = dampener.updateTargetValue(0.005); + EXPECT_FLOAT_EQ(result, 0.005); +} + +TEST_F(DampingControllerTest, UpdateSpeedReturnsSameValueForSameTarget) { + DampingController dampener{1.0, 0.1, 0.01}; + double result1 = dampener.updateTargetValue(1.0); + double result2 = dampener.updateTargetValue(1.0); + EXPECT_FLOAT_EQ(result1, result2); +} diff --git a/fbw-common/src/wasm/cpp-msfs-framework/test/src/lib/ProfileBuffer-tests.cpp b/fbw-common/src/wasm/cpp-msfs-framework/test/src/lib/ProfileBuffer-tests.cpp new file mode 100644 index 00000000000..c5b40eac268 --- /dev/null +++ b/fbw-common/src/wasm/cpp-msfs-framework/test/src/lib/ProfileBuffer-tests.cpp @@ -0,0 +1,77 @@ +// Copyright (c) 2023-2024 FlyByWire Simulations +// SPDX-License-Identifier: GPL-3.0 + +#include +#include "ProfileBuffer.hpp" + +class ProfileBufferTest : public ::testing::Test {}; + +TEST(ProfileBufferTest, PushIncreasesSize) { + ProfileBuffer buffer(5); + buffer.push(1); + ASSERT_EQ(buffer.size(), 1); + ASSERT_EQ(buffer.capacity(), 5); +} + +TEST(ProfileBufferTest, PushRemovesOldestValueWhenFull) { + ProfileBuffer buffer(2); + buffer.push(1); + buffer.push(2); + buffer.push(3); + ASSERT_EQ(buffer.size(), 2); + ASSERT_EQ(buffer.minimum(), 2); +} + +TEST(ProfileBufferTest, SumCalculatesCorrectly) { + ProfileBuffer buffer(3); + buffer.push(1); + buffer.push(2); + buffer.push(3); + ASSERT_EQ(buffer.sum(), 6); +} + +TEST(ProfileBufferTest, AverageCalculatesCorrectly) { + ProfileBuffer buffer(3); + buffer.push(1); + buffer.push(2); + buffer.push(3); + ASSERT_EQ(buffer.avg(), 2); +} + +TEST(ProfileBufferTest, TrimmedAverageCalculatesCorrectly) { + ProfileBuffer buffer(5); + buffer.push(1); + buffer.push(2); + buffer.push(3); + buffer.push(4); + buffer.push(5); + ASSERT_EQ(buffer.trimmedAverage(), 3); +} + +TEST(ProfileBufferTest, MinimumCalculatesCorrectly) { + ProfileBuffer buffer(3); + buffer.push(3); + buffer.push(1); + buffer.push(2); + ASSERT_EQ(buffer.minimum(), 1); +} + +TEST(ProfileBufferTest, MaximumCalculatesCorrectly) { + ProfileBuffer buffer(3); + buffer.push(1); + buffer.push(3); + buffer.push(2); + ASSERT_EQ(buffer.maximum(), 3); +} + +TEST(ProfileBufferTest, SizeReturnsCorrectValue) { + ProfileBuffer buffer(3); + buffer.push(1); + buffer.push(2); + ASSERT_EQ(buffer.size(), 2); +} + +TEST(ProfileBufferTest, CapacityReturnsCorrectValue) { + ProfileBuffer buffer(3); + ASSERT_EQ(buffer.capacity(), 3); +} diff --git a/fbw-common/src/wasm/cpp-msfs-framework/test/src/lib/arinc429-tests.cpp b/fbw-common/src/wasm/cpp-msfs-framework/test/src/lib/arinc429-tests.cpp new file mode 100644 index 00000000000..f4e5198b0cb --- /dev/null +++ b/fbw-common/src/wasm/cpp-msfs-framework/test/src/lib/arinc429-tests.cpp @@ -0,0 +1,97 @@ +// Copyright (c) 2023-2024 FlyByWire Simulations +// SPDX-License-Identifier: GPL-3.0 + +#include +#include "arinc429.hpp" + +class Arinc429NumericWordTests : public ::testing::Test {}; + +TEST_F(Arinc429NumericWordTests, SetFromDataCorrectlySetsRawDataAndSsm) { + Arinc429NumericWord word; + word.setFromData(1234.56789, Arinc429SignStatus::FailureWarning); + ASSERT_FLOAT_EQ(word.value(), 1234.56789); + ASSERT_EQ(word.ssm(), Arinc429SignStatus::FailureWarning); +} + +TEST_F(Arinc429NumericWordTests, SetFromSimVarCorrectlySetsRawDataAndSsm) { + Arinc429NumericWord word; + word.setFromData(1234.56789, Arinc429SignStatus::FailureWarning); + Arinc429NumericWord word2; + word2.setFromSimVar(word.toSimVar()); + ASSERT_FLOAT_EQ(word.value(), 1234.56789); + ASSERT_EQ(word.ssm(), Arinc429SignStatus::FailureWarning); +} + +TEST_F(Arinc429NumericWordTests, SetFromDataNegativeValue) { + Arinc429NumericWord word; + word.setFromData(-1234.56789, Arinc429SignStatus::FailureWarning); + ASSERT_FLOAT_EQ(word.value(), -1234.56789); +} + +class Arinc429DiscreteWordTests : public ::testing::Test {}; + +TEST_F(Arinc429DiscreteWordTests, BitFromZeroValueReturnsCorrectBit) { + Arinc429DiscreteWord word; + word.setFromSimVar(0); + ASSERT_EQ(word.bitFromValue(1), 0); + ASSERT_EQ(word.bitFromValue(2), 0); + ASSERT_EQ(word.bitFromValue(16), 0); + ASSERT_EQ(word.bitFromValue(31), 0); + ASSERT_EQ(word.bitFromValue(32), 0); +} + +// Test setting and retrieving a specific bit +TEST_F(Arinc429DiscreteWordTests, SetAndGetBit) { + Arinc429DiscreteWord word; + // Set the 3rd bit to true + word.setBit(3, true); + // Validate if bit is set correctly + ASSERT_TRUE(word.bitFromValue(3)); + // Set the 3rd bit to false + word.setBit(3, false); + // Validate if bit is cleared correctly + ASSERT_FALSE(word.bitFromValue(3)); +} + +// Test default value with 'bitFromValueOr' +TEST_F(Arinc429DiscreteWordTests, BitFromValueOr) { + Arinc429DiscreteWord word; + + // Check default value when SSM is not in NormalOperation or FunctionalTest + word.setSsm(Arinc429SignStatus::FailureWarning); + ASSERT_FALSE(word.bitFromValueOr(2, false)); + ASSERT_TRUE(word.bitFromValueOr(2, true)); + + // When in NormalOperation, should follow bit state + word.setSsm(Arinc429SignStatus::NormalOperation); + word.setBit(2, true); + ASSERT_TRUE(word.bitFromValueOr(2, false)); + + word.setBit(2, false); + ASSERT_FALSE(word.bitFromValueOr(2, true)); +} + +// Test behavior with multiple bits set +TEST_F(Arinc429DiscreteWordTests, MultipleBits) { + Arinc429DiscreteWord word; + + // Set various bits to specific values + word.setBit(1, true); + word.setBit(2, false); + word.setBit(3, true); + + // Validate if the bits are set or cleared correctly + ASSERT_TRUE(word.bitFromValue(1)); + ASSERT_FALSE(word.bitFromValue(2)); + ASSERT_TRUE(word.bitFromValue(3)); +} + +#ifdef __cpp_exceptions +// Test behavior when bit number is out of range +TEST_F(Arinc429DiscreteWordTests, OutOfRangeBit) { + Arinc429DiscreteWord word; + // Trying to access or set bits out of the expected range (1-32) + ASSERT_THROW(word.bitFromValue(33), std::out_of_range); + ASSERT_THROW(word.setBit(33, true), std::out_of_range); +} +#endif diff --git a/fbw-common/src/wasm/cpp-msfs-framework/test/src/lib/fingerprint-tests.cpp b/fbw-common/src/wasm/cpp-msfs-framework/test/src/lib/fingerprint-tests.cpp new file mode 100644 index 00000000000..807626aa38e --- /dev/null +++ b/fbw-common/src/wasm/cpp-msfs-framework/test/src/lib/fingerprint-tests.cpp @@ -0,0 +1,35 @@ +// Copyright (c) 2023-2024 FlyByWire Simulations +// SPDX-License-Identifier: GPL-3.0 + +#include +#include "fingerprint.hpp" + +class FingerprintTest : public ::testing::Test {}; + +TEST(FingerprintTest, FingerprintFVNReturnsConsistentHashForSameInput) { + std::vector testVec = {1, 2, 3, 4, 5}; + uint64_t hash1 = Fingerprint::fingerPrintFVN(testVec); + uint64_t hash2 = Fingerprint::fingerPrintFVN(testVec); + ASSERT_EQ(hash1, hash2); +} + +TEST(FingerprintTest, FingerprintFVNDifferentiatesDifferentInputs) { + std::vector testVec1 = {1, 2, 3, 4, 5}; + std::vector testVec2 = {5, 4, 3, 2, 1}; + ASSERT_NE(Fingerprint::fingerPrintFVN(testVec1), Fingerprint::fingerPrintFVN(testVec2)); +} + +TEST(FingerprintTest, FingerprintFVNHandlesEmptyVector) { + std::vector testVec = {}; + ASSERT_NO_THROW(Fingerprint::fingerPrintFVN(testVec)); +} + +TEST(FingerprintTest, FingerprintFVNHandlesSingleElementVector) { + std::vector testVec = {1}; + ASSERT_NO_THROW(Fingerprint::fingerPrintFVN(testVec)); +} + +TEST(FingerprintTest, FingerprintFVNHandlesLargeVector) { + std::vector testVec(1000000, 1); + ASSERT_NO_THROW(Fingerprint::fingerPrintFVN(testVec)); +} diff --git a/fbw-common/src/wasm/cpp-msfs-framework/test/src/lib/math_utils-tests.cpp b/fbw-common/src/wasm/cpp-msfs-framework/test/src/lib/math_utils-tests.cpp new file mode 100644 index 00000000000..6c436d0a9f6 --- /dev/null +++ b/fbw-common/src/wasm/cpp-msfs-framework/test/src/lib/math_utils-tests.cpp @@ -0,0 +1,29 @@ +// Copyright (c) 2023-2024 FlyByWire Simulations +// SPDX-License-Identifier: GPL-3.0 + +#include "gtest/gtest.h" +#include "math_utils.hpp" + +using helper::Math; + +class MathUtilsTest : public ::testing::Test {}; + +TEST_F(MathUtilsTest, TestAlmostEqual) { + EXPECT_TRUE(Math::almostEqual(1.0f, 1.0f)); + EXPECT_FALSE(Math::almostEqual(1.0f, 2.0f)); + EXPECT_TRUE(Math::almostEqual(1.0f, 1.00001f, 0.0001f)); + EXPECT_FALSE(Math::almostEqual(1.0f, 1.0001f, 0.0001f)); +} + +TEST_F(MathUtilsTest, TestAngleAdd) { + EXPECT_EQ(Math::angleAdd(45.0, 45.0), 90.0); + EXPECT_EQ(Math::angleAdd(360.0, 45.0), 45.0); + EXPECT_EQ(Math::angleAdd(-45.0, 45.0), 0.0); + EXPECT_EQ(Math::angleAdd(-45.0, -45.0), 270.0); +} + +TEST_F(MathUtilsTest, TestSign) { + EXPECT_EQ(Math::sign(10), 1); + EXPECT_EQ(Math::sign(-10), -1); + EXPECT_EQ(Math::sign(0), 0); +} diff --git a/fbw-common/src/wasm/cpp-msfs-framework/test/src/lib/quantity-tests.cpp b/fbw-common/src/wasm/cpp-msfs-framework/test/src/lib/quantity-tests.cpp new file mode 100644 index 00000000000..a1054c47ee8 --- /dev/null +++ b/fbw-common/src/wasm/cpp-msfs-framework/test/src/lib/quantity-tests.cpp @@ -0,0 +1,211 @@ +// Copyright (c) 2023-2024 FlyByWire Simulations +// SPDX-License-Identifier: GPL-3.0 +#include +#include "quantity.hpp" + +class QuantityTest : public ::testing::Test {}; + +// Test default constructor and explicit constructor +TEST(QuantityTest, DefaultAndExplicitConstructor) { + Mass m1; // Default constructor + EXPECT_FLOAT_EQ(m1.value(), 0.0f); + + Mass m2(10.0f); // Explicit constructor + EXPECT_FLOAT_EQ(m2.value(), 10.0f); +} + +// Test addition +TEST(QuantityTest, Addition) { + Mass m1(5.0f); + Mass m2(10.0f); + + Mass m3 = m1 + m2; + EXPECT_FLOAT_EQ(m3.value(), 15.0f); + + m1 += m2; + EXPECT_FLOAT_EQ(m1.value(), 15.0f); +} + +// Test subtraction +TEST(QuantityTest, Subtraction) { + Mass m1(15.0f); + Mass m2(10.0f); + + Mass m3 = m1 - m2; + EXPECT_FLOAT_EQ(m3.value(), 5.0f); + + m1 -= m2; + EXPECT_FLOAT_EQ(m1.value(), 5.0f); +} + +// Test multiplication with and without units +TEST(QuantityTest, Multiplication) { + Mass m1(5.0f); + Mass m2 = m1 * 2.0f; + + EXPECT_FLOAT_EQ(m2.value(), 10.0f); + + Length l1(3.0f); + Velocity v1 = l1 / Time(2.0f); + + EXPECT_FLOAT_EQ(v1.value(), 1.5f); + + v1 = 2.0f * v1; + EXPECT_FLOAT_EQ(v1.value(), 3.0f); +} + +// Test division with and without units +TEST(QuantityTest, Division) { + Mass m1(10.0f); + Mass m2 = m1 / 2.0f; + + EXPECT_FLOAT_EQ(m2.value(), 5.0f); + + Velocity v1(20.0f); + Time t1 = v1 / Acceleration(2.0f); + + EXPECT_FLOAT_EQ(t1.value(), 10.0f); + + v1 = v1 / 2.0f; + EXPECT_FLOAT_EQ(v1.value(), 10.0f); +} + +// Test comparison operators +TEST(QuantityTest, Comparison) { + Mass m1(5.0f); + Mass m2(10.0f); + Mass m3(5.0f); + + EXPECT_TRUE(m1 < m2); + EXPECT_TRUE(m1 <= m2); + EXPECT_TRUE(m1 <= m3); + EXPECT_TRUE(m2 > m1); + EXPECT_TRUE(m2 >= m1); + EXPECT_TRUE(m3 == m1); + EXPECT_TRUE(m2 != m1); +} + +// Test conversion +TEST(QuantityTest, Convert) { + Length l1(1000.0f); // in meters + Length l2(1.0f); // in kilometers + + EXPECT_FLOAT_EQ(l1.convert(l2), 1000.0f); +} + +// Test user-defined literals +TEST(QuantityTest, UserDefinedLiterals) { + Mass m1 = 5.0_kg; + EXPECT_FLOAT_EQ(m1.value(), 5.0f); + + Length l1 = 3.0_m; + EXPECT_FLOAT_EQ(l1.value(), 3.0f); + + Time t1 = 1.0_min; + EXPECT_FLOAT_EQ(t1.value(), 60.0f); + + Velocity v1 = 20.0_kmph; + EXPECT_FLOAT_EQ(v1.value(), 20.0f * 1000.0f / 3600.0f); // Conversion to m/s +} + +// Test absolute value +TEST(QuantityTest, Absolute) { + Mass m1(-10.0f); + Mass m2 = m1.abs(); + + EXPECT_FLOAT_EQ(m2.value(), 10.0f); +} + +TEST(AccelerationTest, DefaultConstructor) { + Acceleration a; + EXPECT_FLOAT_EQ(a.value(), 0.0f); +} + +TEST(AccelerationTest, ValueConstructor) { + Acceleration a(9.8f); + EXPECT_FLOAT_EQ(a.value(), 9.8f); +} + +TEST(AccelerationTest, Addition) { + Acceleration a1(9.8f); + Acceleration a2(1.2f); + a1 += a2; + EXPECT_FLOAT_EQ(a1.value(), 11.0f); +} + +TEST(AccelerationTest, Subtraction) { + Acceleration a1(9.8f); + Acceleration a2(1.2f); + a1 -= a2; + EXPECT_FLOAT_EQ(a1.value(), 8.6f); +} + +TEST(AccelerationTest, MultiplicationWithScalar) { + Acceleration a(9.8f); + a = a * 2.0f; + EXPECT_FLOAT_EQ(a.value(), 19.6f); +} + +TEST(AccelerationTest, DivisionWithScalar) { + Acceleration a(9.8f); + a = a / 2.0f; + EXPECT_FLOAT_EQ(a.value(), 4.9f); +} + +TEST(AccelerationTest, Equality) { + Acceleration a1(9.8f); + Acceleration a2(9.8f); + EXPECT_TRUE(a1 == a2); +} + +TEST(AccelerationTest, Inequality) { + Acceleration a1(9.8f); + Acceleration a2(1.2f); + EXPECT_TRUE(a1 != a2); +} + +TEST(AccelerationTest, LessThan) { + Acceleration a1(9.8f); + Acceleration a2(1.2f); + EXPECT_TRUE(a2 < a1); +} + +TEST(AccelerationTest, GreaterThan) { + Acceleration a1(9.8f); + Acceleration a2(1.2f); + EXPECT_TRUE(a1 > a2); +} + +TEST(AccelerationVelocityTimeRelationTest, VelocityAfterAcceleration) { + // Initial velocity (u) + Velocity u(0.0f); + + // Acceleration (a) + Acceleration a(9.8f); + + // Time (t) + Time t(2.0f); + + // Calculate final velocity (v = u + at) + Velocity v = u + a * t; + + // Check if the final velocity is as expected + EXPECT_FLOAT_EQ(v.value(), 19.6f); +} + +TEST(AccelerationVelocityTimeRelationTest, DistanceTravelledAfterAcceleration) { + // Initial velocity (u) + Velocity u(0.0f); + + // Acceleration (a) + Acceleration a(9.8f); + + // Time (t) + Time t(2.0f); + + // Calculate distance travelled (s = ut + 0.5 * at^2) + Length s = u * t + 0.5f * a * t * t; + + // Check if the distance travelled is as expected + EXPECT_FLOAT_EQ(s.value(), 19.6f); +} diff --git a/fbw-common/src/wasm/cpp-msfs-framework/test/src/lib/string_utils-tests.cpp b/fbw-common/src/wasm/cpp-msfs-framework/test/src/lib/string_utils-tests.cpp new file mode 100644 index 00000000000..84e42853b0b --- /dev/null +++ b/fbw-common/src/wasm/cpp-msfs-framework/test/src/lib/string_utils-tests.cpp @@ -0,0 +1,180 @@ +// Copyright (c) 2023-2024 FlyByWire Simulations +// SPDX-License-Identifier: GPL-3.0 + +#include "gtest/gtest.h" +#include "string_utils.hpp" + +using helper::StringUtils; + +class StringUtilsTest : public ::testing::Test {}; + +TEST_F(StringUtilsTest, TestInsertThousandsSeparator) { + EXPECT_EQ(StringUtils::insertThousandsSeparator(1000), "1,000"); + EXPECT_EQ(StringUtils::insertThousandsSeparator(-1000), "-1,000"); + EXPECT_EQ(StringUtils::insertThousandsSeparator(1234567890, "."), "1.234.567.890"); +} + +TEST_F(StringUtilsTest, TestToStringWithZeroPadding) { + EXPECT_EQ(StringUtils::to_string_with_zero_padding(5, 3), "005"); + EXPECT_EQ(StringUtils::to_string_with_zero_padding(-5, 3), "-005"); +} + +TEST_F(StringUtilsTest, TestSplitFast) { + std::vector result; + StringUtils::splitFast(std::string("Hello World"), result); + EXPECT_EQ(result[0], "Hello"); + EXPECT_EQ(result[1], "World"); + result.clear(); + StringUtils::splitFast(std::string("This;is;a;test!"), result, ";"); + EXPECT_EQ(result[0], "This"); + EXPECT_EQ(result[1], "is"); + EXPECT_EQ(result[2], "a"); + EXPECT_EQ(result[3], "test!"); + result.clear(); + StringUtils::splitFast("This;:is;:a;:test!", result, ";:"); + EXPECT_EQ(result[0], "This"); + EXPECT_EQ(result[1], "is"); + EXPECT_EQ(result[2], "a"); + EXPECT_EQ(result[3], "test!"); +} + +TEST_F(StringUtilsTest, TestTrimFast) { + EXPECT_EQ(StringUtils::trimFast(std::string(" Hello World ")), "Hello World"); + EXPECT_EQ(StringUtils::trimFast(std::string("\tHello World\n\n")), "Hello World"); +} + +TEST_F(StringUtilsTest, TestRemoveTrailingComments) { + EXPECT_EQ(StringUtils::removeTrailingComments(std::string("Hello World // Comment"), "//"), "Hello World "); + EXPECT_EQ(StringUtils::removeTrailingComments(std::string("Hello World // ; Comment"), ";"), "Hello World // "); +} + +TEST_F(StringUtilsTest, TestToLowerCase) { + EXPECT_EQ(StringUtils::toLowerCase("HELLO WORLD"), "hello world"); +} + +TEST_F(StringUtilsTest, TestToUpperCase) { + EXPECT_EQ(StringUtils::toUpperCase("hello world"), "HELLO WORLD"); +} + +TEST(StringUtilsTests, StrBitsGroupedReturnsCorrectStringForZero) { + uint64_t input = 0; + std::string expected = "00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000 (0)"; + ASSERT_EQ(helper::StringUtils::strBitsGroupedInteger(input), expected); +} + +TEST(StringUtilsTests, StrBitsGroupedReturnsCorrectStringForMaxUint64) { + uint64_t input = UINT64_MAX; + std::string expected = "11111111.11111111.11111111.11111111.11111111.11111111.11111111.11111111 (18446744073709551615)"; + ASSERT_EQ(helper::StringUtils::strBitsGroupedInteger(input), expected); +} + +TEST(StringUtilsTests, LeastSignificantBitReturnsCorrectBitForZero) { + uint64_t input = 0b0000000000000000000000000000000000000000000000000000000000000001; + std::string expected = "00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000001 (1)"; + ASSERT_EQ(helper::StringUtils::strBitsGroupedInteger(input), expected); +} + +TEST(StringUtilsTests, MostSignificantBitReturnsCorrectBitForZero) { + uint64_t input = 0b1000000000000000000000000000000000000000000000000000000000000000; + std::string expected = "10000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000 (9223372036854775808)"; + ASSERT_EQ(helper::StringUtils::strBitsGroupedInteger(input), expected); +} + +TEST(StringUtilsTests, Pattern64BitReturnsCorrectBitForZero) { + uint64_t input = 0b1010101010101010101010101010101010101010101010101010101010101010; + std::string expected = "10101010.10101010.10101010.10101010.10101010.10101010.10101010.10101010 (12297829382473034410)"; + ASSERT_EQ(helper::StringUtils::strBitsGroupedInteger(input), expected); +} + +TEST(StringUtilsTests, Pattern32BitReturnsCorrectBitForZero) { + uint32_t input = 0b10101010101010101010101010101010; + std::string expected = "10101010.10101010.10101010.10101010 (2863311530)"; + ASSERT_EQ(helper::StringUtils::strBitsGroupedInteger(input), expected); +} + +TEST(StringUtilsTests, Pattern16BitReturnsCorrectBitForZero) { + uint16_t input = 0b1010101010101010; + std::string expected = "10101010.10101010 (43690)"; + ASSERT_EQ(helper::StringUtils::strBitsGroupedInteger(input), expected); +} + +TEST(StringUtilsTests, Pattern8BitReturnsCorrectBitForZero) { + uint8_t input = 0b10101010; + std::string expected = "10101010 (170)"; + ASSERT_EQ(helper::StringUtils::strBitsGroupedInteger(input), expected); +} + +// Floating point tests + +TEST(StringUtilsTests, StrBitsGroupedFloatingpointReturnsCorrectStringForZero) { + double input = 0.0; + std::string expected = "0.00000000000.0000000000000000000000000000000000000000000000000000 (0)"; + ASSERT_EQ(helper::StringUtils::strBitsGroupedFloatingpoint(input), expected); +} + +TEST(StringUtilsTests, StrBitsGroupedFloatingpointReturnsCorrectStringForOne) { + double input = 1.0; + std::string expected = "0.01111111111.0000000000000000000000000000000000000000000000000000 (1)"; + ASSERT_EQ(helper::StringUtils::strBitsGroupedFloatingpoint(input), expected); +} + +TEST(StringUtilsTests, StrBitsGroupedFloatingpointReturnsCorrectStringForMinusOne) { + double input = -1.0; + std::string expected = "1.01111111111.0000000000000000000000000000000000000000000000000000 (-1)"; + ASSERT_EQ(helper::StringUtils::strBitsGroupedFloatingpoint(input), expected); +} + +TEST(StringUtilsTests, StrBitsGroupedFloatingpointReturnsCorrectStringForHalf) { + double input = 0.5; + std::string expected = "0.01111111110.0000000000000000000000000000000000000000000000000000 (0.5)"; + ASSERT_EQ(helper::StringUtils::strBitsGroupedFloatingpoint(input), expected); +} + +TEST(StringUtilsTests, StrBitsGroupedFloatingpointReturnsCorrectStringForTwo) { + double input = 2.0; + std::string expected = "0.10000000000.0000000000000000000000000000000000000000000000000000 (2)"; + ASSERT_EQ(helper::StringUtils::strBitsGroupedFloatingpoint(input), expected); +} + +TEST(StringUtilsTests, StrBitsGroupedFloatingpointReturnsCorrectStringForSmallNumber) { + double input = 0.1; + std::string expected = "0.01111111011.1001100110011001100110011001100110011001100110011010 (0.10000000000000001)"; + ASSERT_EQ(helper::StringUtils::strBitsGroupedFloatingpoint(input), expected); +} + +// Test cases for floating-point numbers +TEST(StringUtilsTests, StrBitsGroupedFloatingpoint2ReturnsCorrectStringForZero) { + float input = 0.0f; + std::string expected = "0.00000000.00000000000000000000000 (0)"; + ASSERT_EQ(helper::StringUtils::strBitsGroupedFloatingpoint(input), expected); +} + +TEST(StringUtilsTests, StrBitsGroupedFloatingpoint2ReturnsCorrectStringForOne) { + float input = 1.0f; + std::string expected = "0.01111111.00000000000000000000000 (1)"; + ASSERT_EQ(helper::StringUtils::strBitsGroupedFloatingpoint(input), expected); +} + +TEST(StringUtilsTests, StrBitsGroupedFloatingpoint2ReturnsCorrectStringForMinusOne) { + float input = -1.0f; + std::string expected = "1.01111111.00000000000000000000000 (-1)"; + ASSERT_EQ(helper::StringUtils::strBitsGroupedFloatingpoint(input), expected); +} + +TEST(StringUtilsTests, StrBitsGroupedFloatingpoint2ReturnsCorrectStringForHalf) { + float input = 0.5f; + std::string expected = "0.01111110.00000000000000000000000 (0.5)"; + ASSERT_EQ(helper::StringUtils::strBitsGroupedFloatingpoint(input), expected); +} + +TEST(StringUtilsTests, StrBitsGroupedFloatingpoint2ReturnsCorrectStringForTwo) { + float input = 2.0f; + std::string expected = "0.10000000.00000000000000000000000 (2)"; + ASSERT_EQ(helper::StringUtils::strBitsGroupedFloatingpoint(input), expected); +} + +TEST(StringUtilsTests, StrBitsGroupedFloatingpoint2ReturnsCorrectStringForSmallNumber) { + float input = 0.1f; + std::string expected = "0.01111011.10011001100110011001101 (0.10000000149011612)"; + ASSERT_EQ(helper::StringUtils::strBitsGroupedFloatingpoint(input), expected); +} diff --git a/fbw-common/src/wasm/cpp-msfs-framework/test/test-cpp.sh b/fbw-common/src/wasm/cpp-msfs-framework/test/test-cpp.sh new file mode 100755 index 00000000000..09ea21f952b --- /dev/null +++ b/fbw-common/src/wasm/cpp-msfs-framework/test/test-cpp.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +# !!! This file requires LF line endings to be able to run in the docker environment !!! + +# Create a build directory +mkdir -p build +cd build + +# Run CMake with Debug configuration and compile the project +cmake .. +make -j8 + +# Run the tests +ctest + +# Capture the exit status of ctest +exit_status=$? + +# Exit the script with the same status +exit $exit_status diff --git a/fbw-common/src/wasm/extra-backend/AircraftPresets/AircraftPresets.cpp b/fbw-common/src/wasm/extra-backend/AircraftPresets/AircraftPresets.cpp index 0d411d501d0..47683e5fbc7 100644 --- a/fbw-common/src/wasm/extra-backend/AircraftPresets/AircraftPresets.cpp +++ b/fbw-common/src/wasm/extra-backend/AircraftPresets/AircraftPresets.cpp @@ -43,11 +43,11 @@ bool AircraftPresets::initialize() { // LVARs loadAircraftPresetRequest = dataManager->make_named_var("AIRCRAFT_PRESET_LOAD", UNITS.Number, UpdateMode::AUTO_READ_WRITE); - progressAircraftPreset = dataManager->make_named_var("AIRCRAFT_PRESET_LOAD_PROGRESS"); - progressAircraftPresetId = dataManager->make_named_var("AIRCRAFT_PRESET_LOAD_CURRENT_ID"); + progressAircraftPreset = dataManager->make_named_var("AIRCRAFT_PRESET_LOAD_PROGRESS"); + progressAircraftPresetId = dataManager->make_named_var("AIRCRAFT_PRESET_LOAD_CURRENT_ID"); loadAircraftPresetRequest->setAndWriteToSim(0); // reset to 0 on startup - aircraftPresetVerbose = dataManager->make_named_var("AIRCRAFT_PRESET_VERBOSE", UNITS.Bool, UpdateMode::AUTO_READ, 0.250); + aircraftPresetVerbose = dataManager->make_named_var("AIRCRAFT_PRESET_VERBOSE", UNITS.Bool, UpdateMode::AUTO_READ, 0.250); aircraftPresetExpedite = dataManager->make_named_var("AIRCRAFT_PRESET_LOAD_EXPEDITE", UNITS.Bool, UpdateMode::AUTO_READ, 0.250); aircraftPresetExpediteDelay = dataManager->make_named_var("AIRCRAFT_PRESET_LOAD_EXPEDITE_DELAY", UNITS.Number, UpdateMode::AUTO_READ, 0.250); @@ -100,11 +100,11 @@ bool AircraftPresets::update(sGaugeDrawData* pData) { // initialize a new loading process currentProcedureID = loadAircraftPresetRequest->getAsInt64(); - currentProcedure = requestedProcedure.value(); + currentProcedure = requestedProcedure.value(); currentLoadingTime = 0; - currentDelay = 0; - currentStep = 0; - loadingIsActive = true; + currentDelay = 0; + currentStep = 0; + loadingIsActive = true; progressAircraftPreset->setAndWriteToSim(0); progressAircraftPresetId->setAndWriteToSim(0); LOG_INFO("AircraftPresets: Aircraft Preset " + std::to_string(currentProcedureID) + " starting procedure!"); @@ -140,8 +140,8 @@ bool AircraftPresets::update(sGaugeDrawData* pData) { currentDelay = currentLoadingTime + currentStepPtr->delayAfter; // prepare return values for execute_calculator_code - FLOAT64 fvalue = 0.0; - SINT32 ivalue = 0; + FLOAT64 fvalue = 0.0; + SINT32 ivalue = 0; PCSTRINGZ svalue = nullptr; // check if the current step is a condition step and check the condition @@ -224,4 +224,3 @@ void AircraftPresets::updateProgress(const ProcedureStep* currentStepPtr) const std::string buffer = oss.str(); fsCommBusCall("AIRCRAFT_PRESET_WASM_CALLBACK", buffer.c_str(), buffer.size() + 1, FsCommBusBroadcast_JS); } - diff --git a/fbw-common/src/wasm/extra-backend/AircraftPresets/AircraftPresets.h b/fbw-common/src/wasm/extra-backend/AircraftPresets/AircraftPresets.h index 60c0d4ab3f7..13661a9173a 100644 --- a/fbw-common/src/wasm/extra-backend/AircraftPresets/AircraftPresets.h +++ b/fbw-common/src/wasm/extra-backend/AircraftPresets/AircraftPresets.h @@ -20,7 +20,6 @@ class MsfsHandler; */ class AircraftPresets : public Module { private: - // Convenience pointer to the data manager DataManager* dataManager = nullptr; @@ -79,9 +78,9 @@ class AircraftPresets : public Module { : Module(msfsHandler), presetProcedures(PresetProcedures(aircraftProceduresDefinitions)) {} bool initialize() override; - bool preUpdate(sGaugeDrawData*) override { return true; }; // not required for this module + bool preUpdate(sGaugeDrawData*) override { return true; }; // not required for this module bool update(sGaugeDrawData* pData) override; - bool postUpdate(sGaugeDrawData*) override { return true; }; // not required for this module + bool postUpdate(sGaugeDrawData*) override { return true; }; // not required for this module bool shutdown() override; private: diff --git a/fbw-common/src/wasm/extra-backend/AircraftPresets/PresetProcedures.h b/fbw-common/src/wasm/extra-backend/AircraftPresets/PresetProcedures.h index a84886b03bf..17a4a044be9 100644 --- a/fbw-common/src/wasm/extra-backend/AircraftPresets/PresetProcedures.h +++ b/fbw-common/src/wasm/extra-backend/AircraftPresets/PresetProcedures.h @@ -14,7 +14,7 @@ #include #endif -typedef const std::vector ProcedureDefinition; +typedef const std::vector ProcedureDefinition; typedef std::vector Procedure; /** @@ -22,7 +22,6 @@ typedef std::vector Procedure; * and provides the procedures for the different configurations of the aircraft.

*/ class PresetProcedures { - Procedure coldAndDark; Procedure powered; Procedure readyForPushback; @@ -43,7 +42,6 @@ class PresetProcedures { public: PresetProcedures(const PresetProceduresDefinition& proceduresDefinition) { - #ifdef DEBUG // Map the procedure groups // Print to console to add them to the EFB code to display the current step. diff --git a/fbw-common/src/wasm/extra-backend/AircraftPresets/ProcedureStep.h b/fbw-common/src/wasm/extra-backend/AircraftPresets/ProcedureStep.h index 3c817d2ca43..8aea32b64db 100644 --- a/fbw-common/src/wasm/extra-backend/AircraftPresets/ProcedureStep.h +++ b/fbw-common/src/wasm/extra-backend/AircraftPresets/ProcedureStep.h @@ -14,17 +14,18 @@ * @field isConditional True if the procedure step is a pure condition check to wait for a certain state * @field delayAfter Time to delay next step of execution of action - will be skipped if expected state is already set * @field expectedStateCheckCode Check if desired state is already set so the action can be skipped - * @field actionCode Calculator code to achieve the desired state. If it is a conditional this calculator code needs to eval to true or false + * @field actionCode Calculator code to achieve the desired state. If it is a conditional this calculator code needs to eval to true or + * false * @field noExpedite If true, the step will not be expedited even if expedite is set (default: false) */ struct ProcedureStep { std::string description; - int id; - bool isConditional; - double delayAfter; + int id; + bool isConditional; + double delayAfter; std::string expectedStateCheckCode; std::string actionCode; - bool noExpedite = false; + bool noExpedite = false; }; #endif // FLYBYWIRE_AIRCRAFT_PROCEDURESTEP_H diff --git a/fbw-common/src/wasm/extra-backend/LightingPresets/LightingPresets.cpp b/fbw-common/src/wasm/extra-backend/LightingPresets/LightingPresets.cpp index 4e9795dd6bf..a7b92d75566 100644 --- a/fbw-common/src/wasm/extra-backend/LightingPresets/LightingPresets.cpp +++ b/fbw-common/src/wasm/extra-backend/LightingPresets/LightingPresets.cpp @@ -13,7 +13,7 @@ bool LightingPresets::initialize() { // Control LVARs - auto updated with every tick - LOAD/SAVE also auto written to sim loadLightingPresetRequest = dataManager->make_named_var("LIGHTING_PRESET_LOAD", UNITS.Number, UpdateMode::AUTO_READ_WRITE); saveLightingPresetRequest = dataManager->make_named_var("LIGHTING_PRESET_SAVE", UNITS.Number, UpdateMode::AUTO_READ_WRITE); - presetLoadTime = dataManager->make_named_var("LIGHTING_PRESET_LOAD_TIME", UNITS.Number, UpdateMode::AUTO_READ); + presetLoadTime = dataManager->make_named_var("LIGHTING_PRESET_LOAD_TIME", UNITS.Number, UpdateMode::AUTO_READ); // reset to default values loadLightingPresetRequest->setAndWriteToSim(0.0); @@ -83,8 +83,8 @@ bool LightingPresets::loadLightingPreset(INT64 loadPresetRequest) { return false; } const FLOAT64 partialLoad = presetLoadTime->get() / deltaTime; - FLOAT64 stepSize = std::clamp((100 / partialLoad), MIN_STEP_SIZE, MAX_STEP_SIZE); - lastUpdate = msfsHandler.getTimeStamp(); + FLOAT64 stepSize = std::clamp((100 / partialLoad), MIN_STEP_SIZE, MAX_STEP_SIZE); + lastUpdate = msfsHandler.getTimeStamp(); // Read current values to be able to calculate intermediate values which are then applied to the aircraft // Once the intermediate values are identical to the target values then the load is finished @@ -133,9 +133,9 @@ AircraftVariablePtr LightingPresets::createLightPotentiometerVar(int index) cons } FLOAT64 LightingPresets::iniGetOrDefault(const mINI::INIStructure& ini, - const std::string& section, - const std::string& key, - const double defaultValue) { + const std::string& section, + const std::string& key, + const double defaultValue) { if (auto value = ini.get(section).get(key); !value.empty()) { // As MSFS wasm does not support exceptions (try/catch) we can't use // std::stof here. Workaround with std::stringstreams. diff --git a/fbw-common/src/wasm/extra-backend/Pushback/Pushback.cpp b/fbw-common/src/wasm/extra-backend/Pushback/Pushback.cpp index 4ce67923796..76ffdebdf41 100644 --- a/fbw-common/src/wasm/extra-backend/Pushback/Pushback.cpp +++ b/fbw-common/src/wasm/extra-backend/Pushback/Pushback.cpp @@ -35,58 +35,78 @@ bool Pushback::initialize() { dataManager = &msfsHandler.getDataManager(); // LVARs - will be updated every tick if the pushback system is enabled and the tug connected - tugCommandedSpeedFactor = dataManager->make_named_var("PUSHBACK_SPD_FACTOR"); + tugCommandedSpeedFactor = dataManager->make_named_var("PUSHBACK_SPD_FACTOR"); tugCommandedHeadingFactor = dataManager->make_named_var("PUSHBACK_HDG_FACTOR"); // Aircraft configuration // update frequency can be lower as this is only used for tuning and therefore not critical // (e.g. 0.5 Hz or every 30 ticks is enough) - aircraftParkingBrakeFactor = dataManager->make_named_var("PUSHBACK_AIRCRAFT_PARKBRAKE_FACTOR", UNITS.Number, UpdateMode::NO_AUTO_UPDATE, 0.5, 30.0); + aircraftParkingBrakeFactor = + dataManager->make_named_var("PUSHBACK_AIRCRAFT_PARKBRAKE_FACTOR", UNITS.Number, UpdateMode::NO_AUTO_UPDATE, 0.5, 30.0); aircraftSpeedFactor = dataManager->make_named_var("PUSHBACK_AIRCRAFT_SPEED_FACTOR", UNITS.Number, UpdateMode::NO_AUTO_UPDATE, 0.5, 30.0); - aircraftTurnSpeedFactor = dataManager->make_named_var("PUSHBACK_AIRCRAFT_TURN_SPEED_FACTOR", UNITS.Number, UpdateMode::NO_AUTO_UPDATE, 0.5, 30.0); + aircraftTurnSpeedFactor = + dataManager->make_named_var("PUSHBACK_AIRCRAFT_TURN_SPEED_FACTOR", UNITS.Number, UpdateMode::NO_AUTO_UPDATE, 0.5, 30.0); aircraftParkingBrakeFactor->setAndWriteToSim(this->getParkBrakeFactor()); aircraftSpeedFactor->setAndWriteToSim(this->getSpeedFactor()); aircraftTurnSpeedFactor->setAndWriteToSim(this->getTurnSpeedFactor()); // Pushback Base Data // will be updated every visual frame - DataDefinitionVector pushbackBaseDataDef = {{"L:A32NX_PUSHBACK_SYSTEM_ENABLED", 0, UNITS.Bool}, - {"L:A32NX_PARK_BRAKE_LEVER_POS", 0, UNITS.Bool}, - {"PUSHBACK ATTACHED", 0, UNITS.Bool}, - {"PLANE HEADING DEGREES TRUE", 0, UNITS.degrees}, - {"RELATIVE WIND VELOCITY BODY Z", 0, UNITS.FeetSec}}; + DataDefinitionVector pushbackBaseDataDef = { + {"L:A32NX_PUSHBACK_SYSTEM_ENABLED", 0, UNITS.Bool }, + {"L:A32NX_PARK_BRAKE_LEVER_POS", 0, UNITS.Bool }, + {"PUSHBACK ATTACHED", 0, UNITS.Bool }, + {"PLANE HEADING DEGREES TRUE", 0, UNITS.degrees}, + {"RELATIVE WIND VELOCITY BODY Z", 0, UNITS.FeetSec} + }; pushbackBaseInfoPtr = dataManager->make_datadefinition_var("PUSHBACK BASE DATA", pushbackBaseDataDef); + if (pushbackBaseInfoPtr == nullptr) { + LOG_ERROR("Failed to create PushbackBaseInfo data definition"); + return false; + } pushbackBaseInfoPtr->requestPeriodicDataFromSim(SIMCONNECT_PERIOD_VISUAL_FRAME); // Data definitions for PushbackDataID // Will only be written to sim if the pushback system is enabled and the tug connected - DataDefinitionVector pushBackDataDef = {{"PUSHBACK WAIT", 0, UNITS.Bool}, - {"VELOCITY BODY X", 0, UNITS.FeetSec}, - {"VELOCITY BODY Y", 0, UNITS.FeetSec}, - {"VELOCITY BODY Z", 0, UNITS.FeetSec}, - {"ROTATION VELOCITY BODY X", 0, UNITS.FeetSec}, - {"ROTATION VELOCITY BODY Y", 0, UNITS.FeetSec}, - {"ROTATION VELOCITY BODY Z", 0, UNITS.FeetSec}, - {"ROTATION ACCELERATION BODY X", 0, UNITS.FeetSecSquared}, - {"ROTATION ACCELERATION BODY Y", 0, UNITS.FeetSecSquared}, - {"ROTATION ACCELERATION BODY Z", 0, UNITS.FeetSecSquared}}; + DataDefinitionVector pushBackDataDef = { + {"PUSHBACK WAIT", 0, UNITS.Bool }, + {"VELOCITY BODY X", 0, UNITS.FeetSec }, + {"VELOCITY BODY Y", 0, UNITS.FeetSec }, + {"VELOCITY BODY Z", 0, UNITS.FeetSec }, + {"ROTATION VELOCITY BODY X", 0, UNITS.FeetSec }, + {"ROTATION VELOCITY BODY Y", 0, UNITS.FeetSec }, + {"ROTATION VELOCITY BODY Z", 0, UNITS.FeetSec }, + {"ROTATION ACCELERATION BODY X", 0, UNITS.FeetSecSquared}, + {"ROTATION ACCELERATION BODY Y", 0, UNITS.FeetSecSquared}, + {"ROTATION ACCELERATION BODY Z", 0, UNITS.FeetSecSquared} + }; pushbackDataPtr = dataManager->make_datadefinition_var("PUSHBACK DATA", pushBackDataDef); + if (pushbackDataPtr == nullptr) { + LOG_ERROR("Failed to create PushbackData data definition"); + return false; + } // Events // Normally "KEY_..." events can't be treated like normal events, but in this case there is no - // normal event (e.g. TUG_HEADING) that we can use. So we use the "KEY_..." events instead and - // surprisingly the sim accepts them. This seems to be an inconsistency in the sim. + // normal event (e.g., TUG_HEADING) that we can use. So we use the "KEY_..." events instead and + // surprisingly, the sim accepts them. This seems to be an inconsistency in the sim. tugHeadingEvent = dataManager->make_sim_event("KEY_TUG_HEADING", NOTIFICATION_GROUP_1); - tugSpeedEvent = dataManager->make_sim_event("KEY_TUG_SPEED", NOTIFICATION_GROUP_1); + tugSpeedEvent = dataManager->make_sim_event("KEY_TUG_SPEED", NOTIFICATION_GROUP_1); // debug purposes - pushbackDebug = dataManager->make_named_var("PUSHBACK_DEBUG", UNITS.Bool, UpdateMode::AUTO_READ); - DataDefinitionVector pushbackDebugDataDef = {{"L:A32NX_PUSHBACK_UPDT_DELTA", 0, UNITS.Number}, - {"L:A32NX_PUSHBACK_SPD", 0, UNITS.FeetSec}, - {"L:A32NX_PUSHBACK_HDG", 0, UNITS.degrees}, - {"L:A32NX_PUSHBACK_INERTIA_SPD", 0, UNITS.FeetSec}, - {"L:A32NX_PUSHBACK_R_X_OUT", 0, UNITS.FeetSecSquared}}; + pushbackDebug = dataManager->make_named_var("PUSHBACK_DEBUG", UNITS.Bool, UpdateMode::AUTO_READ); + DataDefinitionVector pushbackDebugDataDef = { + {"L:A32NX_PUSHBACK_UPDT_DELTA", 0, UNITS.Number }, + {"L:A32NX_PUSHBACK_SPD", 0, UNITS.FeetSec }, + {"L:A32NX_PUSHBACK_HDG", 0, UNITS.degrees }, + {"L:A32NX_PUSHBACK_INERTIA_SPD", 0, UNITS.FeetSec }, + {"L:A32NX_PUSHBACK_R_X_OUT", 0, UNITS.FeetSecSquared} + }; pushbackDebugPtr = dataManager->make_datadefinition_var("PUSHBACK DEBUG DATA", pushbackDebugDataDef); + if (pushbackDebugPtr == nullptr) { + LOG_ERROR("Failed to create PushbackDebug data definition"); + return false; + } _isInitialized = true; LOG_INFO("Pushback initialized"); @@ -112,8 +132,8 @@ bool Pushback::update(sGaugeDrawData* pData) { // profiler.start(); - const FLOAT64 timeStamp = msfsHandler.getTimeStamp(); - const UINT64 tickCounter = msfsHandler.getTickCounter(); + const FLOAT64 timeStamp = msfsHandler.getTimeStamp(); + const UINT64 tickCounter = msfsHandler.getTickCounter(); // pushbackBaseInfoPtr is updated at every tick, so we can simply use it here const bool parkingBrakeEngaged = static_cast(pushbackBaseInfoPtr->data().parkingBrakeEngaged); @@ -129,15 +149,15 @@ bool Pushback::update(sGaugeDrawData* pData) { // the inertia speed (current actual speed) is calculated in ft/sec. const double speedFactor = parkingBrakeEngaged ? (aircraftSpeedFactor->get() / aircraftParkingBrakeFactor->get()) : aircraftSpeedFactor->get(); - const FLOAT64 tugCmdSpd = tugCommandedSpeedFactor->get() * speedFactor; - const FLOAT64 inertiaSpeed = speedDampener.updateSpeed(tugCmdSpd); + const FLOAT64 tugCmdSpd = tugCommandedSpeedFactor->get() * speedFactor; + const FLOAT64 inertiaSpeed = speedDampener.updateTargetValue(tugCmdSpd); // Based on an aircraft-specific turn speed factor and the user input (0.0-1.0), // the rotation velocity is calculated in ft/sec. const double turnSpeedHdgFactor = parkingBrakeEngaged ? (aircraftTurnSpeedFactor->get() / aircraftParkingBrakeFactor->get()) : aircraftTurnSpeedFactor->get(); - const FLOAT64 computedRotationVelocity = turnDampener.updateSpeed( - (inertiaSpeed / aircraftSpeedFactor->get()) * tugCommandedHeadingFactor->get() * turnSpeedHdgFactor); + const FLOAT64 computedRotationVelocity = + turnDampener.updateTargetValue((inertiaSpeed / aircraftSpeedFactor->get()) * tugCommandedHeadingFactor->get() * turnSpeedHdgFactor); // The heading of the tug is calculated based on the aircraft heading and the user input (0.0-1.0). const FLOAT64 computedTugHdg = @@ -164,13 +184,13 @@ bool Pushback::update(sGaugeDrawData* pData) { // The sim will update these values based on physics like wind, ground friction, weights, inertia, etc. // Therefore, we need to add the "counter rotation acceleration" to the "rotation acceleration" // on the pitch axis to keep the aircraft stable. - pushbackDataPtr->data().pushbackWait = helper::Math::almostEqual(inertiaSpeed, 0.0) ? 1 : 0; - pushbackDataPtr->data().velBodyX = 0; - pushbackDataPtr->data().velBodyY = 0; - pushbackDataPtr->data().velBodyZ = inertiaSpeed; - pushbackDataPtr->data().rotVelBodyX = 0; - pushbackDataPtr->data().rotVelBodyY = computedRotationVelocity; - pushbackDataPtr->data().rotVelBodyZ = 0; + pushbackDataPtr->data().pushbackWait = helper::Math::almostEqual(inertiaSpeed, 0.0) ? 1 : 0; + pushbackDataPtr->data().velBodyX = 0; + pushbackDataPtr->data().velBodyY = 0; + pushbackDataPtr->data().velBodyZ = inertiaSpeed; + pushbackDataPtr->data().rotVelBodyX = 0; + pushbackDataPtr->data().rotVelBodyY = computedRotationVelocity; + pushbackDataPtr->data().rotVelBodyZ = 0; pushbackDataPtr->data().rotAccelBodyX = counterRotationAcceleration; pushbackDataPtr->data().rotAccelBodyY = 0; pushbackDataPtr->data().rotAccelBodyZ = 0; @@ -178,11 +198,11 @@ bool Pushback::update(sGaugeDrawData* pData) { // send as LVARs for debugging in the flyPad if (pushbackDebug->getAsBool()) { - pushbackDebugPtr->data().updateDelta = pData->dt; - pushbackDebugPtr->data().tugCommandedSpeed = tugCmdSpd; + pushbackDebugPtr->data().updateDelta = pData->dt; + pushbackDebugPtr->data().tugCommandedSpeed = tugCmdSpd; pushbackDebugPtr->data().tugCommandedHeading = computedTugHdg; - pushbackDebugPtr->data().tugInertiaSpeed = inertiaSpeed; - pushbackDebugPtr->data().rotXOut = counterRotationAcceleration; + pushbackDebugPtr->data().tugInertiaSpeed = inertiaSpeed; + pushbackDebugPtr->data().rotXOut = counterRotationAcceleration; pushbackDebugPtr->writeDataToSim(); } diff --git a/fbw-common/src/wasm/extra-backend/Pushback/Pushback.h b/fbw-common/src/wasm/extra-backend/Pushback/Pushback.h index 9b4ebc9c7ee..459e79549ec 100644 --- a/fbw-common/src/wasm/extra-backend/Pushback/Pushback.h +++ b/fbw-common/src/wasm/extra-backend/Pushback/Pushback.h @@ -4,9 +4,9 @@ #ifndef FLYBYWIRE_PUSHBACK_H #define FLYBYWIRE_PUSHBACK_H +#include "DampingController.hpp" #include "DataManager.h" #include "Module.h" -#include "Pushback/InertialDampener.hpp" #ifdef __cpp_lib_math_constants #include @@ -38,8 +38,8 @@ class Pushback : public Module { DataManager* dataManager = nullptr; // Used to smoothen acceleration and deceleration - InertialDampener speedDampener{0.0, 0.15, 0.1}; - InertialDampener turnDampener{0.0, 0.01, 0.001}; + DampingController speedDampener{0.0, 0.15, 0.1}; + DampingController turnDampener{0.0, 0.01, 0.001}; // LVARs NamedVariablePtr tugCommandedSpeedFactor; diff --git a/fbw-common/src/wasm/fadec_common/src/EngineRatios.hpp b/fbw-common/src/wasm/fadec_common/src/EngineRatios.hpp index 17f9fd5cc8b..4dba920d966 100644 --- a/fbw-common/src/wasm/fadec_common/src/EngineRatios.hpp +++ b/fbw-common/src/wasm/fadec_common/src/EngineRatios.hpp @@ -4,6 +4,8 @@ #ifndef FLYBYWIRE_AIRCRAFT_ENGINERATIOS_HPP #define FLYBYWIRE_AIRCRAFT_ENGINERATIOS_HPP +#include + #include /** @@ -12,7 +14,6 @@ */ class EngineRatios { public: - /** * @brief Calculates the ratio of the ambient temperature to the standard temperature at sea level. * @@ -23,9 +24,7 @@ class EngineRatios { * @param ambientTemp The ambient temperature in degrees Celsius. * @return The ratio of the ambient temperature to the standard temperature at sea level in degrees Celsius. */ - static FLOAT64 theta(double ambientTemp) { - return (273.15 + ambientTemp) / 288.15; - } + static FLOAT64 theta(double ambientTemp) { return (273.15 + ambientTemp) / 288.15; } /** * @brief Calculates the ratio of the ambient pressure to the standard pressure at sea level. @@ -37,9 +36,7 @@ class EngineRatios { * @param ambientPressure The ambient pressure in hPa. * @return The ratio of the ambient pressure to the standard pressure at sea level in hPa. */ - static FLOAT64 delta(double ambientPressure) { - return ambientPressure / 1013.0; - } + static FLOAT64 delta(double ambientPressure) { return ambientPressure / 1013.0; } /** * @brief Calculates the ratio of the total temperature to the standard temperature at sea level, @@ -55,9 +52,7 @@ class EngineRatios { * @return The ratio of the total temperature to the standard temperature at sea level, accounting * for the effects of Mach number. */ - static FLOAT64 theta2(double mach, double ambientTemp) { - return theta(ambientTemp) * (1 + 0.2 * (std::pow)(mach, 2)); - } + static FLOAT64 theta2(double mach, double ambientTemp) { return theta(ambientTemp) * (1 + 0.2 * (std::pow)(mach, 2)); } /** * @brief Calculates the ratio of the total pressure to the standard pressure at sea level, diff --git a/fbw-common/src/wasm/fadec_common/src/Fadec.cpp b/fbw-common/src/wasm/fadec_common/src/Fadec.cpp index 513ea5c2917..0490dc6529f 100644 --- a/fbw-common/src/wasm/fadec_common/src/Fadec.cpp +++ b/fbw-common/src/wasm/fadec_common/src/Fadec.cpp @@ -4,17 +4,17 @@ #include "Fadec.h" double Fadec::interpolate(double x, double x0, double x1, double y0, double y1) { - if (x0 == x1) - return y0; - if (x < x0) - return y0; - if (x > x1) - return y1; - return ((y0 * (x1 - x)) + (y1 * (x - x0))) / (x1 - x0); + if (x0 == x1) + return y0; + if (x < x0) + return y0; + if (x > x1) + return y1; + return ((y0 * (x1 - x)) + (y1 * (x - x0))) / (x1 - x0); } double Fadec::cas2mach(double cas, double ambientPressure) { - double k = 2188648.141; + double k = 2188648.141; double delta = ambientPressure / 1013; return sqrt((5 * (std::pow)((((std::pow)((((std::pow)(cas, 2) / k) + 1), 3.5) * (1 / delta)) - (1 / delta) + 1), 0.285714286)) - 5); } diff --git a/fbw-common/src/wasm/fadec_common/src/Fadec.h b/fbw-common/src/wasm/fadec_common/src/Fadec.h index f15c52e542f..4a4b6ca389e 100644 --- a/fbw-common/src/wasm/fadec_common/src/Fadec.h +++ b/fbw-common/src/wasm/fadec_common/src/Fadec.h @@ -11,7 +11,6 @@ class MsfsHandler; - class Fadec : public Module { public: static constexpr double LBS_TO_KGS = 0.4535934; @@ -26,14 +25,13 @@ class Fadec : public Module { */ explicit Fadec(MsfsHandler& msfsHandler) : Module(msfsHandler) {} - virtual bool initialize() override = 0; - virtual bool preUpdate(sGaugeDrawData* pData) override = 0; - virtual bool update(sGaugeDrawData* pData) override = 0; + virtual bool initialize() override = 0; + virtual bool preUpdate(sGaugeDrawData* pData) override = 0; + virtual bool update(sGaugeDrawData* pData) override = 0; virtual bool postUpdate(sGaugeDrawData* pData) override = 0; - virtual bool shutdown() override = 0; + virtual bool shutdown() override = 0; public: - /** * @brief Interpolates a value using linear interpolation. * diff --git a/package.json b/package.json index 9c0867b69bb..4f5b7c70746 100644 --- a/package.json +++ b/package.json @@ -6,24 +6,20 @@ "#build-utils": "./build-utils.js" }, "scripts": { - "====== Generic===============": "==========================================", - - "build:cpp-wasm-cmake": "scripts/build-cmake.sh", - "build:cpp-wasm-cmake-clean": "scripts/build-cmake.sh --clean", - "build:cpp-wasm-cmake-debug": "scripts/build-cmake.sh --debug", + "====== Generic===========================================================": "========================================================", + "build:cpp-wasm-cmake": "scripts/build-cmake.sh", + "build:cpp-wasm-cmake-clean": "scripts/build-cmake.sh --clean", + "build:cpp-wasm-cmake-debug": "scripts/build-cmake.sh --debug", "build:cpp-wasm-cmake-debug-clean": "scripts/build-cmake.sh --debug --clean", - - "====== A320 =================": "==========================================", - + "build:cpp-wasm-cmake-test": "cd fbw-common/src/wasm/cpp-msfs-framework/test && ./test-cpp.sh", + "====== A320 =============================================================": "========================================================", "build-a32nx:copy-base-package": "mkdir -p fbw-a32nx/out/flybywire-aircraft-a320-neo && (rsync -a fbw-a32nx/src/base/flybywire-aircraft-a320-neo fbw-a32nx/out/ || cp -a -u fbw-a32nx/src/base/flybywire-aircraft-a320-neo fbw-a32nx/out/)", "build-a32nx:copy-base-lock-highlight-package": "mkdir -p fbw-a32nx/out/flybywire-aircraft-a320-neo-lock-highlight && (rsync -a fbw-a32nx/src/base/flybywire-aircraft-a320-neo-lock-highlight fbw-a32nx/out/ || cp -a -u fbw-a32nx/src/base/flybywire-aircraft-a320-neo-lock-highlight fbw-a32nx/out/)", "build-a32nx:copy-base-files": "npm run build-a32nx:copy-base-package && npm run build-a32nx:copy-base-lock-highlight-package", "build-a32nx:efb-translation": "cd fbw-common/src/systems/instruments/src/EFB/Localization && node build-flypad-translation.js", "build-a32nx:locPak-translation": "cd fbw-a32nx/src/localization && node build-locPak-translation.js", - "build-a32nx:model": "node fbw-a32nx/src/model/buildv2.js && node fbw-a32nx/src/model/build.js", "build-a32nx:behavior": "node fbw-a32nx/src/behavior/build.js", - "build-a32nx:atsu-common": "node fbw-a32nx/src/systems/atsu/common/build.js", "build-a32nx:atsu-fms-client": "node fbw-a32nx/src/systems/atsu/fmsclient/build.js", "build-a32nx:extras-host": "node fbw-a32nx/src/systems/extras-host/build.js", @@ -34,50 +30,36 @@ "build-a32nx:simbridge-client": "node fbw-a32nx/src/systems/simbridge-client/build.js", "build-a32nx:systems-host": "node fbw-a32nx/src/systems/systems-host/build.js", "build-a32nx:tcas": "node fbw-a32nx/src/systems/tcas/build.js", - "build-a32nx:pfd": "cd fbw-a32nx/src/systems/instruments/src/PFD && rollup -c", "build-a32nx:clock": "cd fbw-a32nx/src/systems/instruments/src/Clock && rollup -c", "build-a32nx:ewd": "cd fbw-a32nx/src/systems/instruments/src/EWD && rollup -c", - "build-a32nx:systems": "cargo build -p a320_systems_wasm --target wasm32-wasi --release && wasm-opt -O1 --signext-lowering --enable-bulk-memory -o /external/fbw-a32nx/out/flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/panel/systems.wasm /external/target/wasm32-wasi/release/a320_systems_wasm.wasm", "build-a32nx:fbw": "cd fbw-a32nx/src/wasm/fbw_a320 && ./build.sh && wasm-opt -O1 --signext-lowering -o /external/fbw-a32nx/out/flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/panel/fbw.wasm /external/fbw-a32nx/out/flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/panel/fbw.wasm", "build-a32nx:terronnd": "cd fbw-common/src/wasm/terronnd && ./build.sh && wasm-opt -O1 --signext-lowering -o /external/fbw-a32nx/out/flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/panel/terronnd.wasm /external/fbw-common/src/wasm/terronnd/out/terronnd.wasm", - "build-a32nx:metadata": "node scripts/metadata.js fbw-a32nx/out/flybywire-aircraft-a320-neo a32nx", "build-a32nx:manifest": "node scripts/build_a32nx.js", - "prettier": "prettier --write **/*.json **/*.yml fbw-a32nx/src/systems/instruments/**/*.css", - - "=======deprecated=========": "===========================", + "=======deprecated========================================================": "========================================================", "serve:efb": "cd fbw-a32nx/src/systems/instruments/src/EFB/ && vite --port 9696", "build:instruments": "rollup --max-old-space-size=8192 -c src/systems/instruments/buildSrc/simulatorBuild.mjs", "watch:instruments": "rollup --max-old-space-size=8192 -wc src/systems/instruments/buildSrc/simulatorBuild.mjs", - - "====== A380 =================": "==========================================", - + "====== A380 =============================================================": "========================================================", "build-a380x:copy-base-files": "mkdir -p fbw-a380x/out/flybywire-aircraft-a380-842 && (rsync -a fbw-a380x/src/base/flybywire-aircraft-a380-842 fbw-a380x/out/ || cp -a -u fbw-a380x/src/base/flybywire-aircraft-a380-842 fbw-a380x/out/)", "build-a380x:efb-translation": "cd fbw-common/src/systems/instruments/src/EFB/Localization && node build-flypad-translation.js", "build-a380x:locPak-translation": "cd fbw-a380x/src/localization && node build-locPak-translation.js", - "build-a380x:extras-host": "node fbw-a380x/src/systems/extras-host/build.js", "build-a380x:instruments": "mach build --config fbw-a380x/mach.config.js --work-in-config-dir", "build-a380x:systems-host": "node fbw-a380x/src/systems/systems-host/build.js", - "build-a380x:systems": "cargo build -p a380_systems_wasm --target wasm32-wasi --release && wasm-opt -O1 --signext-lowering --enable-bulk-memory -o /external/fbw-a380x/out/flybywire-aircraft-a380-842/SimObjects/AirPlanes/FlyByWire_A380_842/panel/systems.wasm /external/target/wasm32-wasi/release/a380_systems_wasm.wasm", "build-a380x:fbw": "cd fbw-a380x/src/wasm/fbw_a380 && ./build.sh && wasm-opt -O1 --signext-lowering -o /external/fbw-a380x/out/flybywire-aircraft-a380-842/SimObjects/AirPlanes/FlyByWire_A380_842/panel/fbw.wasm /external/fbw-a380x/out/flybywire-aircraft-a380-842/SimObjects/AirPlanes/FlyByWire_A380_842/panel/fbw.wasm", "build-a380x:terronnd": "cd fbw-common/src/wasm/terronnd && ./build.sh && wasm-opt -O1 --signext-lowering -o /external/fbw-a380x/out/flybywire-aircraft-a380-842/SimObjects/AirPlanes/FlyByWire_A380_842/panel/terronnd.wasm /external/fbw-common/src/wasm/terronnd/out/terronnd.wasm", - "build-a380x:metadata": "node scripts/metadata.js fbw-a380x/out/flybywire-aircraft-a380-842 a380x", "build-a380x:manifest": "node scripts/build_a380x.js flybywire-aircraft-a380-842", - - "====== INGAMEPANELS CHECKLIST FIX ====": "==========================================", - + "====== INGAMEPANELS CHECKLIST FIX =======================================": "========================================================", "build-ingamepanels-checklist-fix:copy-base-package": "mkdir -p fbw-ingamepanels-checklist-fix/out/flybywire-ingamepanels-checklist-fix && (rsync -a fbw-ingamepanels-checklist-fix/src/base/flybywire-ingamepanels-checklist-fix fbw-ingamepanels-checklist-fix/out/ || cp -a -u fbw-ingamepanels-checklist-fix/src/base/flybywire-ingamepanels-checklist-fix fbw-ingamepanels-checklist-fix/out/)", "build-ingamepanels-checklist-fix:copy-base-files": "npm run build-ingamepanels-checklist-fix:copy-base-package", "build-ingamepanels-checklist-fix:manifest": "node scripts/build_ingamepanels_checklist_fix.js", - - "====== COMMON ================": "==========================================", - + "====== COMMON ===========================================================": "========================================================", "lint": "eslint --cache **/*.{js,mjs,jsx,ts,tsx}", "lint-fix": "npm run lint -- --fix", "test": "jest"