diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md
index 741d4e69d2b9..7b02db9f3c34 100644
--- a/.github/CHANGELOG.md
+++ b/.github/CHANGELOG.md
@@ -71,6 +71,7 @@
1. [FMGC] Fix inbound leg time for holds - @tracernz (Mike)
1. [MCDU] Improved visuals of Init-A and Init-B page - @derl30n (Leon)
1. [MODEL] Added new animated gear gravity extension handle- @tyler58546 (tyler58546), @MoreRightRudder (Mike), @Crocket63 (crocket), @Lantarius
+1. [HYD] Custom Lvar for gear lever to fix ground collision bug - @Crocket63 (crocket)
1. [HYD] Randomised per actuator flow restrictions at plane init - @Crocket63 (crocket)
1. [MCDU] Hide stored elements on A/C Status when there are none - @tracernz (Mike)
1. [FMGC] Fix ident for CD legs - @tracernz (Mike)
diff --git a/docs/a320-simvars.md b/docs/a320-simvars.md
index dc0b9fd71549..6e794f4df553 100644
--- a/docs/a320-simvars.md
+++ b/docs/a320-simvars.md
@@ -3240,6 +3240,18 @@ In the variables below, {number} should be replaced with one item in the set: {
- Indicates the position of the gear emergency extension crank handle from 0 to 300 (3 turns)
- Percent
+- A32NX_GEAR_LEVER_POSITION_REQUEST
+ - Indicates that the pilot tries to move the gear lever (1=down)
+ - Boolean
+
+- A32NX_GEAR_HANDLE_POSITION
+ - Indicates the actual position of the gear handle
+ - Percent over 100
+
+- A32NX_GEAR_HANDLE_HITS_LOCK_SOUND
+ - Indicates that gear lever just hit the baulk lock mechanism
+ - Boolean
+
## ATC (ATA 34)
- A32NX_TRANSPONDER_MODE
diff --git a/flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/Checklist/Library.xml b/flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/Checklist/Library.xml
index 0fcc7777f0aa..fea5b3479fcb 100644
--- a/flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/Checklist/Library.xml
+++ b/flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/Checklist/Library.xml
@@ -65,7 +65,7 @@
-
+
@@ -1150,7 +1150,7 @@
-
+
@@ -1641,7 +1641,7 @@
-
+
@@ -1841,7 +1841,7 @@
-
+
@@ -2381,7 +2381,7 @@
-
+
diff --git a/flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/Climb.flt b/flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/Climb.flt
index fcba78061fdf..db8f8a0d8cfe 100644
--- a/flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/Climb.flt
+++ b/flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/Climb.flt
@@ -153,6 +153,7 @@ A32NX_SEC_2_PUSHBUTTON_PRESSED=1
A32NX_SEC_3_PUSHBUTTON_PRESSED=1
A32NX_FAC_1_PUSHBUTTON_PRESSED=1
A32NX_FAC_2_PUSHBUTTON_PRESSED=1
+A32NX_GEAR_LEVER_POSITION_REQUEST = 0
[Gauges.0]
KollsmanSetting=29.921342849731445313
diff --git a/flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/approach.FLT b/flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/approach.FLT
index d427ec43102c..79c59a385ac1 100644
--- a/flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/approach.FLT
+++ b/flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/approach.FLT
@@ -264,6 +264,7 @@ A32NX_OVHD_PRESS_MODE_SEL_PB_IS_AUTO = 1
A32NX_OVHD_PRESS_MAN_VS_CTL_SWITCH = 1
A32NX_TRANSPONDER_MODE = 1
A32NX_SWITCH_ATC_ALT = 1
+A32NX_GEAR_LEVER_POSITION_REQUEST = 0
[Gauges.0]
KollsmanSetting=29.921342849731445313
diff --git a/flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/apron.FLT b/flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/apron.FLT
index 6887dcdf6678..d19ef1cb9e15 100644
--- a/flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/apron.FLT
+++ b/flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/apron.FLT
@@ -272,6 +272,7 @@ A32NX_SWITCH_ATC_ALT = 1
A32NX_GEAR_CENTER_POSITION = 100
A32NX_GEAR_LEFT_POSITION = 100
A32NX_GEAR_RIGHT_POSITION = 100
+A32NX_GEAR_LEVER_POSITION_REQUEST = 1
[Gauges.0]
KollsmanSetting=29.921342849731445313
diff --git a/flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/cruise.FLT b/flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/cruise.FLT
index 684182ff2f54..20127bdb3d22 100644
--- a/flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/cruise.FLT
+++ b/flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/cruise.FLT
@@ -264,6 +264,7 @@ A32NX_OVHD_PRESS_MODE_SEL_PB_IS_AUTO = 1
A32NX_OVHD_PRESS_MAN_VS_CTL_SWITCH = 1
A32NX_TRANSPONDER_MODE = 1
A32NX_SWITCH_ATC_ALT = 1
+A32NX_GEAR_LEVER_POSITION_REQUEST = 0
[Gauges.0]
KollsmanSetting=29.921342849731445313
diff --git a/flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/final.FLT b/flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/final.FLT
index 7381cdba7d23..6fd82ea5fe10 100644
--- a/flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/final.FLT
+++ b/flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/final.FLT
@@ -266,6 +266,7 @@ A32NX_SWITCH_ATC_ALT = 1
A32NX_GEAR_CENTER_POSITION = 100
A32NX_GEAR_LEFT_POSITION = 100
A32NX_GEAR_RIGHT_POSITION = 100
+A32NX_GEAR_LEVER_POSITION_REQUEST = 1
[Gauges.0]
KollsmanSetting=29.921342849731445313
diff --git a/flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/hangar.flt b/flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/hangar.flt
index 95c1f41f7d74..47cf00778881 100644
--- a/flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/hangar.flt
+++ b/flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/hangar.flt
@@ -246,6 +246,7 @@ XMLVAR_A320_WeatherRadar_Sys=1
A32NX_GEAR_CENTER_POSITION = 100
A32NX_GEAR_LEFT_POSITION = 100
A32NX_GEAR_RIGHT_POSITION = 100
+A32NX_GEAR_LEVER_POSITION_REQUEST = 1
[Gauges.0]
KollsmanSetting=29.921342849731445313
diff --git a/flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/model/A320_NEO_INTERIOR.xml b/flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/model/A320_NEO_INTERIOR.xml
index 7b68f0dff022..f41259f2fd78 100644
--- a/flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/model/A320_NEO_INTERIOR.xml
+++ b/flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/model/A320_NEO_INTERIOR.xml
@@ -840,12 +840,12 @@
%((L:A32NX_BRAKE_FAN_BTN_PRESSED, Bool))%{if}Turn OFF brake fan%{else}Turn ON brake fan%{end}
-
+
lever_landing_gear
LEVER_LANDINGGEAR
- gearleverclick
-
+ 3
+
PUSH_AUTOBKR_LDGGEAR_1
1
@@ -1777,7 +1777,7 @@
5
- (A:GEAR HANDLE POSITION, Bool) (A:GEAR POSITION, percent) 99.9 > and (>O:_ShouldBeConnectedToPowerGrid)
+ (L:A32NX_LGCIU_2_NOSE_GEAR_DOWNLOCKED, Bool) 1 == (>O:_ShouldBeConnectedToPowerGrid)
(O:_ShouldBeConnectedToPowerGrid) sp0
2 (>A:BUS LOOKUP INDEX, Number)
(A:CIRCUIT CONNECTION ON:17, Bool) l0 != if{ 17 2 (>K:2:ELECTRICAL_BUS_TO_CIRCUIT_CONNECTION_TOGGLE) }
@@ -1833,7 +1833,7 @@
- (A:GEAR CENTER POSITION, Percent over 100) 1 == (L:A32NX_PARK_BRAKE_LEVER_POS, bool) 1 == and
+ (L:A32NX_GEAR_CENTER_POSITION, Percent over 100) 1 == (L:A32NX_PARK_BRAKE_LEVER_POS, bool) 1 == and
(L:A32NX_ELEC_DC_GND_FLT_SVC_BUS_IS_POWERED, Bool)
99
diff --git a/flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/runway.FLT b/flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/runway.FLT
index cd993124da1c..77863930792d 100644
--- a/flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/runway.FLT
+++ b/flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/runway.FLT
@@ -274,6 +274,7 @@ A32NX_SWITCH_ATC_ALT = 1
A32NX_GEAR_CENTER_POSITION = 100
A32NX_GEAR_LEFT_POSITION = 100
A32NX_GEAR_RIGHT_POSITION = 100
+A32NX_GEAR_LEVER_POSITION_REQUEST = 1
[Gauges.0]
KollsmanSetting=29.921342849731445313
diff --git a/flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/sound/sound.xml b/flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/sound/sound.xml
index 986244a93018..815094c56237 100644
--- a/flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/sound/sound.xml
+++ b/flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/sound/sound.xml
@@ -642,11 +642,11 @@
-
+
-
+
diff --git a/flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/taxi.flt b/flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/taxi.flt
index cc5788288a6a..76bf3570d5ee 100644
--- a/flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/taxi.flt
+++ b/flybywire-aircraft-a320-neo/SimObjects/AirPlanes/FlyByWire_A320_NEO/taxi.flt
@@ -257,6 +257,7 @@ A32NX_SWITCH_ATC_ALT = 1
A32NX_GEAR_CENTER_POSITION = 100
A32NX_GEAR_LEFT_POSITION = 100
A32NX_GEAR_RIGHT_POSITION = 100
+A32NX_GEAR_LEVER_POSITION_REQUEST = 1
[Gauges.0]
KollsmanSetting=29.921342849731445313
diff --git a/flybywire-aircraft-a320-neo/html_ui/Pages/A32NX_Core/A32NX_BrakeTemp.js b/flybywire-aircraft-a320-neo/html_ui/Pages/A32NX_Core/A32NX_BrakeTemp.js
index 8e8aca62c1a0..3dc049e4d036 100644
--- a/flybywire-aircraft-a320-neo/html_ui/Pages/A32NX_Core/A32NX_BrakeTemp.js
+++ b/flybywire-aircraft-a320-neo/html_ui/Pages/A32NX_Core/A32NX_BrakeTemp.js
@@ -82,13 +82,13 @@ class A32NX_BrakeTemp {
SimVar.GetSimVarValue("L:A32NX_REPORTED_BRAKE_TEMPERATURE_4", "celsius")
];
}
- const GearLeftPosition = SimVar.GetSimVarValue("GEAR LEFT POSITION", "Percent Over 100");
+ const GearLeftPosition = SimVar.GetSimVarValue("L:A32NX_GEAR_LEFT_POSITION", "Percent Over 100");
const GearLeftExtended = GearLeftPosition >= 0.25;
- const GearRightExtended = SimVar.GetSimVarValue("GEAR RIGHT POSITION", "Percent Over 100") >= 0.25;
+ const GearRightExtended = SimVar.GetSimVarValue("L:A32NX_GEAR_RIGHT_POSITION", "Percent Over 100") >= 0.25;
const currentBrakeFanState = SimVar.GetSimVarValue("L:A32NX_BRAKE_FAN", "Bool");
const brakeFanButtonIsPressed = SimVar.GetSimVarValue("L:A32NX_BRAKE_FAN_BTN_PRESSED", "Bool");
// if the fan button is pressed down and the left main gear is down and locked, the fan is on
- const brakeFanIsOn = brakeFanButtonIsPressed && (GearLeftPosition == 1);
+ const brakeFanIsOn = brakeFanButtonIsPressed && (GearLeftPosition == 100);
let fanMultiplier = 1;
let fanDifferentialFactor = 1;
if (brakeFanIsOn) {
diff --git a/flybywire-aircraft-a320-neo/html_ui/Pages/A32NX_Core/A32NX_FWC.js b/flybywire-aircraft-a320-neo/html_ui/Pages/A32NX_Core/A32NX_FWC.js
index 975e444ac031..ddb8b2fe63a2 100644
--- a/flybywire-aircraft-a320-neo/html_ui/Pages/A32NX_Core/A32NX_FWC.js
+++ b/flybywire-aircraft-a320-neo/html_ui/Pages/A32NX_Core/A32NX_FWC.js
@@ -367,7 +367,7 @@ class A32NX_FWC {
// - Glide slope captured
// - Landing locked down
- const landingGearIsDown = SimVar.GetSimVarValue("L:A32NX_FLAPS_HANDLE_INDEX", "Enum") >= 1 && SimVar.GetSimVarValue("GEAR HANDLE POSITION", "Boolean");
+ const landingGearIsDown = SimVar.GetSimVarValue("L:A32NX_FLAPS_HANDLE_INDEX", "Enum") >= 1 && SimVar.GetSimVarValue("L:A32NX_GEAR_HANDLE_POSITION", "Percent over 100") > 0.5;
const verticalMode = SimVar.GetSimVarValue("L:A32NX_FMA_VERTICAL_MODE", "Number");
const glideSlopeCaptured = verticalMode >= 30 && verticalMode <= 34;
const landingGearIsLockedDown = SimVar.GetSimVarValue("GEAR POSITION:0", "Enum") > 0.9;
diff --git a/flybywire-aircraft-a320-neo/html_ui/Pages/A32NX_Core/A32NX_LocalVarUpdater.js b/flybywire-aircraft-a320-neo/html_ui/Pages/A32NX_Core/A32NX_LocalVarUpdater.js
index 7be23073f2bb..c3386c7ab73d 100644
--- a/flybywire-aircraft-a320-neo/html_ui/Pages/A32NX_Core/A32NX_LocalVarUpdater.js
+++ b/flybywire-aircraft-a320-neo/html_ui/Pages/A32NX_Core/A32NX_LocalVarUpdater.js
@@ -65,7 +65,7 @@ class A32NX_LocalVarUpdater {
}
_noSmokingMemoSelector() {
- const gearPercent = SimVar.GetSimVarValue("GEAR CENTER POSITION", "Percent");
+ const gearPercent = SimVar.GetSimVarValue("L:A32NX_GEAR_CENTER_POSITION", "Percent");
const noSmokingSwitch = SimVar.GetSimVarValue("L:XMLVAR_SWITCH_OVHD_INTLT_NOSMOKING_Position", "Position");
// Switch is ON
diff --git a/flybywire-aircraft-a320-neo/html_ui/Pages/VCockpit/Instruments/NavSystems/A320_Neo/A32NX_NavSystem.js b/flybywire-aircraft-a320-neo/html_ui/Pages/VCockpit/Instruments/NavSystems/A320_Neo/A32NX_NavSystem.js
index 93bca47db7e4..73e07f550a5e 100644
--- a/flybywire-aircraft-a320-neo/html_ui/Pages/VCockpit/Instruments/NavSystems/A320_Neo/A32NX_NavSystem.js
+++ b/flybywire-aircraft-a320-neo/html_ui/Pages/VCockpit/Instruments/NavSystems/A320_Neo/A32NX_NavSystem.js
@@ -2824,7 +2824,7 @@ class Warnings extends NavSystemElement {
return this.linearMultiPointsEvaluation(this.pullUp_sinkRate_Points, descentRate, height) == 2;
}
landingGearCallback() {
- const gear = !SimVar.GetSimVarValue("IS GEAR RETRACTABLE", "Boolean") || SimVar.GetSimVarValue("GEAR HANDLE POSITION", "Boolean");
+ const gear = !SimVar.GetSimVarValue("IS GEAR RETRACTABLE", "Boolean") || SimVar.GetSimVarValue("L:A32NX_GEAR_HANDLE_POSITION", "Percent over 100") > 0.5;
const throttle = SimVar.GetSimVarValue("L:A32NX_AUTOTHRUST_TLA:1", "number");
const flaps = SimVar.GetSimVarValue("L:A32NX_FLAPS_HANDLE_INDEX", "number");
return !gear && (flaps > 1 || (throttle == 0));
diff --git a/src/behavior/src/A32NX_Interior_Handling.xml b/src/behavior/src/A32NX_Interior_Handling.xml
index 59f425998359..004d54bf8eaa 100644
--- a/src/behavior/src/A32NX_Interior_Handling.xml
+++ b/src/behavior/src/A32NX_Interior_Handling.xml
@@ -542,6 +542,47 @@
+
+
+ TT_Package.LANDING_GEAR_LEVER_GEAR_TITLE
+ lever_landing_gear
+ LEVER_LANDINGGEAR
+ LEVER_LANDINGGEAR
+ 0
+ 0
+ 100
+ 0.001
+ 0.03
+
+ (L:A32NX_GEAR_HANDLE_POSITION, Number) 0.95 > if{
+ (>K:GEAR_UP)
+ } els{
+ (>K:GEAR_DOWN)
+ }
+
+
+ (L:A32NX_GEAR_LEVER_LOCKED, Boolean) 1 == if{
+ (>K:GEAR_DOWN)
+ }
+
+
+
+
+
+
+
+
+ 3
+
+ (L:A32NX_GEAR_HANDLE_POSITION, Percent) 3 *
+
+ (>K:GEAR_UP)
+ (>K:GEAR_DOWN)
+
+
+
+
+
HANDLING_Indicator_ElevatorTrim
diff --git a/src/behavior/src/A32NX_Interior_Misc.xml b/src/behavior/src/A32NX_Interior_Misc.xml
index a18eb4c12ed0..7dc7fa2bdc6c 100644
--- a/src/behavior/src/A32NX_Interior_Misc.xml
+++ b/src/behavior/src/A32NX_Interior_Misc.xml
@@ -188,52 +188,6 @@
-
-
-
- LANDING_GEAR_Lever_Gear
- LANDING_GEAR_Lever_Gear
- LANDING_GEAR_Lever_Gear
- LANDING_GEAR_Lever_GearLight
- 400
- 10
- @TT_Package.LANDING_GEAR_LEVER_GEAR_TITLE
- gear_lever
- gear_lever_on
- gear_lever_off
- True
-
-
- #TOOLTIP_LANDING_GEAR_TITLE#
- LANDING_GEAR_Gear
- (>B:LANDING_GEAR_Gear_Inc)
- (>B:LANDING_GEAR_Gear_Dec)
-
-
-
-
- (L:A32NX_GEAR_LEVER_LOCKED, Bool) ! if{ #UP_CODE# }
-
-
-
-
-
-
- 1
-
-
- (B:LANDING_GEAR_Gear) 100 *
-
-
-
-
-
-
- #LIGHT_NODE_ID#
-
-
-
-
diff --git a/src/instruments/src/EWD/elements/PseudoFWC.tsx b/src/instruments/src/EWD/elements/PseudoFWC.tsx
index c70d63a7eed9..e1434f6c3fa2 100644
--- a/src/instruments/src/EWD/elements/PseudoFWC.tsx
+++ b/src/instruments/src/EWD/elements/PseudoFWC.tsx
@@ -300,7 +300,7 @@ const PseudoFWC: React.FC = () => {
// const aircraftOnGround = left1LandingGear === 1 || right1LandingGear === 1;
// FIXME The landing gear triggers the dual engine failure on loading
const aircraftOnGround = SimVar.GetSimVarValue('SIM ON GROUND', 'Bool');
- const [landingGearLeverDown] = useSimVar('GEAR HANDLE POSITION', 'bool', 500);
+ const [landingGearLeverDown] = useSimVar('L:A32NX_GEAR_HANDLE_POSITION', 'bool', 500);
const [landingLight2Retracted] = useSimVar('L:LANDING_2_Retracted', 'bool', 500);
const [landingLight3Retracted] = useSimVar('L:LANDING_3_Retracted', 'bool', 500);
const [autoBrakesArmedMode] = useSimVar('L:A32NX_AUTOBRAKES_ARMED_MODE', 'enum', 500);
diff --git a/src/systems/a320_systems/src/hydraulic/mod.rs b/src/systems/a320_systems/src/hydraulic/mod.rs
index 5c3f3518c9a8..b0c1e38f0939 100644
--- a/src/systems/a320_systems/src/hydraulic/mod.rs
+++ b/src/systems/a320_systems/src/hydraulic/mod.rs
@@ -8036,6 +8036,7 @@ mod tests {
let mut test_bed = test_bed_on_ground_with()
.on_the_ground()
.set_cold_dark_inputs()
+ .with_worst_case_ptu()
.set_park_brake(false)
.start_eng2(Ratio::new::(80.))
.run_one_tick();
@@ -8048,7 +8049,7 @@ mod tests {
// Yellow pressurised by engine2, green presurised from ptu we expect fault LOW press on EDP1
assert!(test_bed.is_yellow_pressure_switch_pressurised());
- assert!(test_bed.yellow_pressure() > Pressure::new::(2800.));
+ assert!(test_bed.yellow_pressure() > Pressure::new::(2500.));
assert!(test_bed.is_green_pressure_switch_pressurised());
assert!(test_bed.green_pressure() > Pressure::new::(2300.));
assert!(test_bed.is_green_edp_press_low());
diff --git a/src/systems/a320_systems_wasm/src/gear.rs b/src/systems/a320_systems_wasm/src/gear.rs
index cebf2865ccc2..8f8a5b3a3bc7 100644
--- a/src/systems/a320_systems_wasm/src/gear.rs
+++ b/src/systems/a320_systems_wasm/src/gear.rs
@@ -4,17 +4,16 @@ use msfs::sim_connect;
use msfs::{sim_connect::SimConnect, sim_connect::SIMCONNECT_OBJECT_ID_USER};
use systems_wasm::aspects::{
- EventToVariableMapping, MsfsAspectBuilder, ObjectWrite, VariableToEventMapping,
- VariableToEventWriteOn, VariablesToObject,
+ EventToVariableMapping, MsfsAspectBuilder, ObjectWrite, VariablesToObject,
};
use systems_wasm::{set_data_on_sim_object, Variable};
pub(super) fn gear(builder: &mut MsfsAspectBuilder) -> Result<(), Box> {
// Read gear demand from all sim sim events and mask them
- let gear_set_set_event_id = builder.event_to_variable(
+ builder.event_to_variable(
"GEAR_SET",
EventToVariableMapping::EventDataRaw,
- Variable::aspect("GEAR_LEVER_POSITION_REQUEST"),
+ Variable::named("GEAR_LEVER_POSITION_REQUEST"),
|options| options.mask(),
)?;
@@ -29,37 +28,30 @@ pub(super) fn gear(builder: &mut MsfsAspectBuilder) -> Result<(), Box
}
},
),
- Variable::aspect("GEAR_LEVER_POSITION_REQUEST"),
+ Variable::named("GEAR_LEVER_POSITION_REQUEST"),
|options| options.mask(),
)?;
builder.event_to_variable(
"GEAR_UP",
EventToVariableMapping::Value(0.),
- Variable::aspect("GEAR_LEVER_POSITION_REQUEST"),
+ Variable::named("GEAR_LEVER_POSITION_REQUEST"),
|options| options.mask(),
)?;
builder.event_to_variable(
"GEAR_DOWN",
EventToVariableMapping::Value(1.),
- Variable::aspect("GEAR_LEVER_POSITION_REQUEST"),
+ Variable::named("GEAR_LEVER_POSITION_REQUEST"),
|options| options.mask(),
)?;
- // Feedback the gear event to the sim
- builder.variable_to_event_id(
- Variable::aspect("GEAR_HANDLE_POSITION"),
- VariableToEventMapping::EventDataRaw,
- VariableToEventWriteOn::Change,
- gear_set_set_event_id,
- );
-
// GEAR POSITION FEEDBACK TO SIM
builder.variables_to_object(Box::new(GearPosition {
nose_position: 1.,
left_position: 1.,
right_position: 1.,
+ gear_handle_position: 1.,
}));
Ok(())
@@ -78,6 +70,10 @@ struct GearPosition {
#[name = "GEAR RIGHT POSITION"]
#[unit = "Percent over 100"]
right_position: f64,
+
+ #[name = "GEAR HANDLE POSITION"]
+ #[unit = "Percent over 100"]
+ gear_handle_position: f64,
}
impl VariablesToObject for GearPosition {
@@ -86,13 +82,30 @@ impl VariablesToObject for GearPosition {
Variable::named("GEAR_CENTER_POSITION"),
Variable::named("GEAR_LEFT_POSITION"),
Variable::named("GEAR_RIGHT_POSITION"),
+ Variable::named("GEAR_DOOR_CENTER_POSITION"),
+ Variable::named("GEAR_DOOR_LEFT_POSITION"),
+ Variable::named("GEAR_DOOR_RIGHT_POSITION"),
]
}
fn write(&mut self, values: Vec) -> ObjectWrite {
- self.nose_position = values[0] / 100.;
- self.left_position = values[1] / 100.;
- self.right_position = values[2] / 100.;
+ const GEAR_POSITION_FOR_FAKE_DOOR_DRAG: f64 = 0.10;
+
+ let gear_deployed = values[0] > 5. || values[1] > 5. || values[2] > 5.;
+ let door_opened = values[3] > 10. || values[4] > 10. || values[5] > 10.;
+
+ // If doors are deployed we fake gear going down a bit to get some door drag effect from the sim
+ if door_opened && !gear_deployed {
+ self.nose_position = (values[3] / 100.).min(GEAR_POSITION_FOR_FAKE_DOOR_DRAG);
+ self.left_position = (values[4] / 100.).min(GEAR_POSITION_FOR_FAKE_DOOR_DRAG);
+ self.right_position = (values[5] / 100.).min(GEAR_POSITION_FOR_FAKE_DOOR_DRAG);
+ } else {
+ self.nose_position = values[0] / 100.;
+ self.left_position = values[1] / 100.;
+ self.right_position = values[2] / 100.;
+ }
+
+ self.gear_handle_position = if gear_deployed { 1. } else { 0. };
ObjectWrite::default()
}
diff --git a/src/systems/systems/src/landing_gear/mod.rs b/src/systems/systems/src/landing_gear/mod.rs
index 0d91791d07ab..1861009574a8 100644
--- a/src/systems/systems/src/landing_gear/mod.rs
+++ b/src/systems/systems/src/landing_gear/mod.rs
@@ -422,10 +422,10 @@ struct LandingGearControlCoordinator {
previous_gear_handle_is_down: bool,
}
impl LandingGearControlCoordinator {
- fn new() -> Self {
+ fn new(context: &mut InitContext) -> Self {
Self {
active_lgciu_id: LgciuId::Lgciu1,
- previous_gear_handle_is_down: true,
+ previous_gear_handle_is_down: context.start_gear_down(),
}
}
@@ -488,7 +488,7 @@ impl LandingGearControlInterfaceUnitSet {
) -> Self {
Self {
gear_handle_baulk_lock_id: context.get_identifier("GEAR_LEVER_LOCKED".to_owned()),
- coordinator: LandingGearControlCoordinator::new(),
+ coordinator: LandingGearControlCoordinator::new(context),
lgcius: [
LandingGearControlInterfaceUnit::new(context, LgciuId::Lgciu1, lgciu1_powered_by),
LandingGearControlInterfaceUnit::new(context, LgciuId::Lgciu2, lgciu2_powered_by),
@@ -530,6 +530,7 @@ impl LandingGearControlInterfaceUnitSet {
);
self.gear_handle_unit.update(
+ context,
&self.lgcius[LgciuId::Lgciu1 as usize],
&self.lgcius[LgciuId::Lgciu2 as usize],
);
@@ -585,11 +586,22 @@ impl LandingGearHandle for LandingGearControlInterfaceUnitSet {
struct LandingGearHandleUnit {
gear_handle_real_position_id: VariableIdentifier,
gear_handle_position_requested_id: VariableIdentifier,
+ gear_handle_hits_lock_sound_id: VariableIdentifier,
- is_lever_down: bool,
lever_should_lock_down: bool,
+
+ lever_position: Ratio,
+ lever_commanded_down: bool,
+
+ lever_just_hit_lock_sound: bool,
}
impl LandingGearHandleUnit {
+ const GEAR_LEVER_SPEED_PERCENT_PER_S: f64 = 180.;
+
+ const GEAR_LEVER_MAX_LOCK_POSITION: f64 = 0.95;
+
+ const GEAR_LEVER_UP_DOWN_DETECTION_POSITION: f64 = 0.5;
+
fn new(context: &mut InitContext) -> Self {
let init_gear_down = context.start_gear_down();
@@ -597,20 +609,71 @@ impl LandingGearHandleUnit {
gear_handle_real_position_id: context.get_identifier("GEAR_HANDLE_POSITION".to_owned()),
gear_handle_position_requested_id: context
.get_identifier("GEAR_LEVER_POSITION_REQUEST".to_owned()),
+ gear_handle_hits_lock_sound_id: context
+ .get_identifier("GEAR_HANDLE_HITS_LOCK_SOUND".to_owned()),
- is_lever_down: init_gear_down,
lever_should_lock_down: init_gear_down,
+
+ lever_position: if init_gear_down {
+ Ratio::new::(1.)
+ } else {
+ Ratio::new::(0.)
+ },
+
+ lever_commanded_down: init_gear_down,
+
+ lever_just_hit_lock_sound: false,
}
}
- fn update(&mut self, lgciu1: &impl LandingGearHandle, lgciu2: &impl LandingGearHandle) {
+ fn update(
+ &mut self,
+ context: &UpdateContext,
+ lgciu1: &impl LandingGearHandle,
+ lgciu2: &impl LandingGearHandle,
+ ) {
self.lever_should_lock_down =
- lgciu1.gear_handle_baulk_locked() && lgciu2.gear_handle_baulk_locked()
+ lgciu1.gear_handle_baulk_locked() && lgciu2.gear_handle_baulk_locked();
+
+ self.update_position(context);
+ }
+
+ fn update_position(&mut self, context: &UpdateContext) {
+ let previous_position = self.lever_position;
+
+ if self.lever_commanded_down {
+ self.lever_position += Ratio::new::(
+ Self::GEAR_LEVER_SPEED_PERCENT_PER_S * context.delta_as_secs_f64(),
+ );
+ } else {
+ let could_hit_lock_mechanism_after_update = self.lever_position.get::()
+ >= Self::GEAR_LEVER_MAX_LOCK_POSITION
+ && self.lever_should_lock_down;
+
+ self.lever_position -= Ratio::new::(
+ Self::GEAR_LEVER_SPEED_PERCENT_PER_S * context.delta_as_secs_f64(),
+ );
+
+ if could_hit_lock_mechanism_after_update {
+ self.lever_position = self
+ .lever_position
+ .max(Ratio::new::(Self::GEAR_LEVER_MAX_LOCK_POSITION));
+ }
+ }
+
+ self.lever_position = self
+ .lever_position
+ .max(Ratio::new::(0.))
+ .min(Ratio::new::(1.));
+
+ self.lever_just_hit_lock_sound = previous_position.get::()
+ > Self::GEAR_LEVER_MAX_LOCK_POSITION
+ && self.lever_position == Ratio::new::(Self::GEAR_LEVER_MAX_LOCK_POSITION);
}
}
impl LandingGearHandle for LandingGearHandleUnit {
fn gear_handle_is_down(&self) -> bool {
- self.is_lever_down
+ self.lever_position.get::() >= Self::GEAR_LEVER_UP_DOWN_DETECTION_POSITION
}
fn gear_handle_baulk_locked(&self) -> bool {
@@ -619,16 +682,20 @@ impl LandingGearHandle for LandingGearHandleUnit {
}
impl SimulationElement for LandingGearHandleUnit {
fn read(&mut self, reader: &mut SimulatorReader) {
- let lever_down_raw: bool = reader.read(&self.gear_handle_position_requested_id);
-
- self.is_lever_down = lever_down_raw || (self.lever_should_lock_down && self.is_lever_down);
+ let lever_down_req_raw: bool = reader.read(&self.gear_handle_position_requested_id);
+ self.lever_commanded_down = lever_down_req_raw;
}
fn write(&self, writer: &mut SimulatorWriter) {
- writer.write(&self.gear_handle_real_position_id, self.is_lever_down);
+ writer.write(
+ &self.gear_handle_real_position_id,
+ self.lever_position.get::(),
+ );
- // Aligning request on demand so in sim position is always consistent with system state
- writer.write(&self.gear_handle_position_requested_id, self.is_lever_down);
+ writer.write(
+ &self.gear_handle_hits_lock_sound_id,
+ self.lever_just_hit_lock_sound,
+ );
}
}
@@ -1385,21 +1452,25 @@ mod tests {
fn in_flight(mut self) -> Self {
self.set_on_ground(false);
+ self = self.set_gear_handle_up();
self
}
fn on_the_ground(mut self) -> Self {
self.set_on_ground(true);
+ self = self.set_gear_handle_down();
self
}
fn set_gear_handle_up(mut self) -> Self {
self.write_by_name("GEAR_LEVER_POSITION_REQUEST", 0.);
+ self.run_with_delta(Duration::from_millis(1000));
self
}
fn set_gear_handle_down(mut self) -> Self {
self.write_by_name("GEAR_LEVER_POSITION_REQUEST", 1.);
+ self.run_with_delta(Duration::from_millis(1000));
self
}
@@ -1408,7 +1479,12 @@ mod tests {
}
fn is_gear_handle_down(&mut self) -> bool {
- self.read_by_name("GEAR_HANDLE_POSITION")
+ let lever_pos: f64 = self.read_by_name("GEAR_HANDLE_POSITION");
+ lever_pos >= 0.90
+ }
+
+ fn is_gear_lever_lock_makes_sound(&mut self) -> bool {
+ self.read_by_name("GEAR_HANDLE_HITS_LOCK_SOUND")
}
fn fail_hyd_pressure(&mut self) {
@@ -1488,28 +1564,38 @@ mod tests {
}
#[test]
- fn gear_lever_up_and_locked_can_go_down_but_not_up() {
- let mut test_bed = test_bed_in_flight_with().in_flight().run_one_tick();
+ fn gear_lever_locked_makes_locked_sound_once_when_trying_up() {
+ let mut test_bed = test_bed_on_ground_with().on_the_ground().run_one_tick();
- test_bed = test_bed.set_gear_handle_up().run_one_tick();
+ assert!(test_bed.is_gear_handle_lock_down_active());
+ assert!(test_bed.is_gear_handle_down());
+ assert!(!test_bed.is_gear_lever_lock_makes_sound());
- assert!(!test_bed.is_gear_handle_lock_down_active());
- assert!(!test_bed.is_gear_handle_down());
+ test_bed = test_bed.on_the_ground().set_gear_handle_up();
- test_bed = test_bed.on_the_ground().set_gear_handle_up().run_one_tick();
+ assert!(test_bed.is_gear_lever_lock_makes_sound());
- assert!(test_bed.is_gear_handle_lock_down_active());
+ // Make sure next ticks sound doesn't play anymore
+ test_bed = test_bed.run_one_tick();
+ assert!(!test_bed.is_gear_lever_lock_makes_sound());
+
+ test_bed = test_bed.run_one_tick();
+ assert!(!test_bed.is_gear_lever_lock_makes_sound());
+ }
+
+ #[test]
+ fn gear_lever_up_and_locked_can_go_down_but_not_up() {
+ let mut test_bed = test_bed_in_flight_with().in_flight().run_one_tick();
+
+ assert!(!test_bed.is_gear_handle_lock_down_active());
assert!(!test_bed.is_gear_handle_down());
- test_bed = test_bed
- .on_the_ground()
- .set_gear_handle_down()
- .run_one_tick();
+ test_bed = test_bed.on_the_ground().set_gear_handle_down();
assert!(test_bed.is_gear_handle_lock_down_active());
assert!(test_bed.is_gear_handle_down());
- test_bed = test_bed.on_the_ground().set_gear_handle_up().run_one_tick();
+ test_bed = test_bed.on_the_ground().set_gear_handle_up();
assert!(test_bed.is_gear_handle_lock_down_active());
assert!(test_bed.is_gear_handle_down());
@@ -1522,8 +1608,6 @@ mod tests {
.set_gear_handle_down()
.run_one_tick();
- test_bed = test_bed.run_one_tick();
-
assert!(!test_bed.is_gear_handle_lock_down_active());
assert!(test_bed.is_gear_handle_down());
}
@@ -1537,7 +1621,10 @@ mod tests {
#[test]
fn gear_up_when_lever_up_down_when_lever_down() {
- let mut test_bed = test_bed_in_flight_with().in_flight().set_gear_handle_down();
+ let mut test_bed = test_bed_in_flight_with()
+ .in_flight()
+ .set_gear_handle_down()
+ .run_one_tick();
for _ in 0..2 {
test_bed.run_without_delta();
@@ -1546,7 +1633,7 @@ mod tests {
assert!(test_bed.query(|a| a.lgcius.gear_system_state()) == GearSystemState::AllDownLocked);
println!("GEAR UP!!");
- test_bed = test_bed.set_gear_handle_up();
+ test_bed = test_bed.set_gear_handle_up().run_one_tick();
for _ in 0..30 {
test_bed.run_without_delta();
@@ -1555,7 +1642,8 @@ mod tests {
assert!(test_bed.query(|a| a.lgcius.gear_system_state()) == GearSystemState::AllUpLocked);
// Gear DOWN
- test_bed = test_bed.set_gear_handle_down();
+ test_bed = test_bed.set_gear_handle_down().run_one_tick();
+
for _ in 0..30 {
test_bed.run_without_delta();
}
@@ -1573,12 +1661,15 @@ mod tests {
assert!(test_bed.query(|a| a.lgcius.active_lgciu_id()) == LgciuId::Lgciu1);
test_bed = test_bed.set_gear_handle_up().run_one_tick();
+
assert!(test_bed.query(|a| a.lgcius.active_lgciu_id()) == LgciuId::Lgciu2);
test_bed = test_bed.set_gear_handle_down().run_one_tick();
+
assert!(test_bed.query(|a| a.lgcius.active_lgciu_id()) == LgciuId::Lgciu2);
test_bed = test_bed.set_gear_handle_up().run_one_tick();
+
assert!(test_bed.query(|a| a.lgcius.active_lgciu_id()) == LgciuId::Lgciu1);
}