Skip to content

Commit

Permalink
to squash: remove flight phase computation from Javascript
Browse files Browse the repository at this point in the history
  • Loading branch information
beheh committed Dec 2, 2021
1 parent 52a1715 commit 3b27dd4
Showing 1 changed file with 7 additions and 213 deletions.
220 changes: 7 additions & 213 deletions flybywire-aircraft-a320-neo/html_ui/Pages/A32NX_Core/A32NX_FWC.js
Original file line number Diff line number Diff line change
@@ -1,62 +1,24 @@
class A32NX_FWC {
constructor() {
// momentary
this.toConfigTest = null; // WTOCT
this.flightPhaseEndedPulse = false; // ESLD 1.0.155
this.toConfigTest = null;
this.flightPhaseEndedPulse = false;

// persistent
this.flightPhase = null;
this.ldgMemo = null;
this.toMemo = null;

// ESDL 1. 0. 60
this.gndMemo = new NXLogic_ConfirmNode(1); // outptuts ZGND

// ESDL 1. 0. 60
this.eng1OrTwoRunningConf = new NXLogic_ConfirmNode(30);

// ESDL 1. 0. 73
this.speedAbove80KtsMemo = new NXLogic_MemoryNode(true);

// ESDL 1. 0. 79 / ESDL 1. 0. 80
this.mctMemo = new NXLogic_ConfirmNode(60, false);

// ESDL 1. 0.100
this.firePBOutConf = new NXLogic_ConfirmNode(0.2); // CONF01
this.firePBOutMemo = new NXLogic_TriggeredMonostableNode(2); // MTRIG 05
this.firePBClear10 = new NXLogic_MemoryNode(false);
this.phase110Memo = new NXLogic_TriggeredMonostableNode(300); // MTRIG 03
this.phase8GroundMemo = new NXLogic_TriggeredMonostableNode(2); // MTRIG 06
this.ac80KtsMemo = new NXLogic_TriggeredMonostableNode(2); // MTRIG 04
this.prevPhase9InvertMemo = new NXLogic_TriggeredMonostableNode(3, false); // MTRIG 02
this.eng1Or2TOPowerInvertMemo = new NXLogic_TriggeredMonostableNode(1, false); // MTRIG 01
this.phase9Nvm = new NXLogic_MemoryNode(true, true);
this.prevPhase9 = false;

// ESDL 1. 0.110
this.groundImmediateMemo = new NXLogic_TriggeredMonostableNode(2); // MTRIG 03
this.phase5Memo = new NXLogic_TriggeredMonostableNode(120); // MTRIG 01
this.phase67Memo = new NXLogic_TriggeredMonostableNode(180); // MTRIG 02

// ESDL 1. 0.115
this.memoFlightPhaseInhibOvrd_memo = new NXLogic_MemoryNode(false);

// ESDL 1. 0.180
this.memoTo_conf01 = new NXLogic_ConfirmNode(120, true); // CONF 01
this.memoTo_conf01 = new NXLogic_ConfirmNode(120, true);
this.memoTo_memo = new NXLogic_MemoryNode(false);

// ESDL 1. 0.190
this.memoLdgMemo_conf01 = new NXLogic_ConfirmNode(1, true); // CONF 01
this.memoLdgMemo_conf01 = new NXLogic_ConfirmNode(1, true);
this.memoLdgMemo_memory1 = new NXLogic_MemoryNode(false);
this.memoLdgMemo_conf02 = new NXLogic_ConfirmNode(10, true); // CONF 01
this.memoLdgMemo_conf02 = new NXLogic_ConfirmNode(10, true);
this.memoLdgMemo_below2000ft = new NXLogic_MemoryNode(true);

// ESDL 1. 0.310
this.memoToInhibit_conf01 = new NXLogic_ConfirmNode(3, true); // CONF 01

// ESDL 1. 0.320
this.memoLdgInhibit_conf01 = new NXLogic_ConfirmNode(3, true); // CONF 01

// master warning & caution buttons
this.warningPressed = false;
this.cautionPressed = false;
Expand All @@ -72,7 +34,8 @@ class A32NX_FWC {
update(_deltaTime, _core) {
this._resetPulses();

this._updateFlightPhase(_deltaTime);
this.flightPhase = SimVar.GetSimVarValue("L:A32NX_FWC_FLIGHT_PHASE", "Enum");

this._updateButtons(_deltaTime);
this._updateTakeoffMemo(_deltaTime);
this._updateLandingMemo(_deltaTime);
Expand Down Expand Up @@ -114,175 +77,7 @@ class A32NX_FWC {
}
}

_updateFlightPhase(_deltaTime) {
const radioHeight = SimVar.GetSimVarValue("RADIO HEIGHT", "Feet");
const eng1N1 = SimVar.GetSimVarValue("ENG N1 RPM:1", "Percent");
const eng2N1 = SimVar.GetSimVarValue("ENG N1 RPM:2", "Percent");
// TODO find a better source for the following value ("core speed at or above idle")
// Note that N1 starts below idle on spawn on the runway, so this should be below 16 to not jump back to phase 1
const oneEngRunning = (
eng1N1 > 15 || eng2N1 > 15
);
const eng1Or2Running = this.eng1OrTwoRunningConf.write(oneEngRunning, _deltaTime);
const engOneAndTwoNotRunning = !eng1Or2Running;
const hFail = false;
const adcTestInhib = false;

// ESLD 1.0.60
const groundImmediate = Simplane.getIsGrounded();
const ground = this.gndMemo.write(groundImmediate, _deltaTime);

// ESLD 1.0.73
const ias = SimVar.GetSimVarValue("AIRSPEED INDICATED", "knots");
const acSpeedAbove80kts = this.speedAbove80KtsMemo.write(ias > 83, ias < 77);

// ESLD 1.0.90
const hAbv1500 = radioHeight > 1500;
const hAbv800 = radioHeight > 800;

// ESLD 1.0.79 + 1.0.80
const eng1TLA = SimVar.GetSimVarValue("L:A32NX_AUTOTHRUST_TLA:1", "number");
const eng1TLAFTO = SimVar.GetSimVarValue("L:AIRLINER_TO_FLEX_TEMP", "number") !== 0; // is a flex temp is set?
const eng1MCT = eng1TLA > 33.3 && eng1TLA < 36.7;
const eng1TLAFullPwr = eng1TLA > 43.3;
const eng2TLA = SimVar.GetSimVarValue("L:A32NX_AUTOTHRUST_TLA:2", "number");
const eng2TLAFTO = eng1TLAFTO; // until we have proper FADECs
const eng2MCT = eng2TLA > 33.3 && eng2TLA < 36.7;
const eng2TLAFullPwr = eng2TLA > 43.3;
const eng1OrEng2SupMCT = !(eng1TLA < 36.7) || !(eng2TLA < 36.7);
const eng1AndEng2MCL = eng1TLA > 22.9 && eng2TLA > 22.9;
const eng1Or2TOPowerSignal = (
(eng1TLAFTO && eng1MCT) ||
(eng2TLAFTO && eng2MCT) ||
(eng1OrEng2SupMCT || eng1OrEng2SupMCT) ||
(eng1TLAFullPwr || eng2TLAFullPwr)
);
const eng1Or2TOPower = (
eng1Or2TOPowerSignal ||
(this.mctMemo.write(eng1Or2TOPowerSignal, _deltaTime) && !hAbv1500 && eng1AndEng2MCL)
);

// ESLD 1.0.100
const eng1FirePbOut = SimVar.GetSimVarValue("L:A32NX_FIRE_BUTTON_ENG1", "Bool");
const eng1FirePbMemo = this.firePBOutMemo.write(
this.firePBOutConf.write(eng1FirePbOut, _deltaTime),
_deltaTime
);
const resetFirePbClear10 = eng1FirePbMemo && ground;

const phase8 = (
(this.phase8GroundMemo.write(groundImmediate, _deltaTime) || groundImmediate) &&
!eng1Or2TOPower &&
acSpeedAbove80kts
);

const phase34Cond = ground && eng1Or2TOPower;
const phase3 = !acSpeedAbove80kts && eng1Or2Running && phase34Cond;
const phase4 = acSpeedAbove80kts && phase34Cond;

const setPhase9Nvm = phase3 || phase8;
const resetPhase9Nvm = (
(
!this.ac80KtsMemo.write(!acSpeedAbove80kts, _deltaTime) &&
(
(ground && this.prevPhase9InvertMemo.write(this.prevPhase9, _deltaTime)) ||
resetFirePbClear10 ||
(ground && this.eng1Or2TOPowerInvertMemo.write(eng1Or2TOPower, _deltaTime))
) &&
!this.prevPhase9
) || adcTestInhib
);
const phase9Nvm = this.phase9Nvm.write(setPhase9Nvm, resetPhase9Nvm); // S* / R (NVM)
const phase29Cond = ground && !eng1Or2TOPower && !acSpeedAbove80kts;
const phase9 = oneEngRunning && phase9Nvm && phase29Cond;
const phase2 = phase29Cond && !phase9Nvm && eng1Or2Running;

const phase110MemoA = this.firePBClear10.write(phase9, resetFirePbClear10); // S / R*
const phase110Cond = !phase9 && engOneAndTwoNotRunning && groundImmediate;
const phase110Memo = this.phase110Memo.write(phase110MemoA && phase110Cond, _deltaTime); // MTRIG 03
const phase1 = phase110Cond && !phase110Memo;
const phase10 = phase110Cond && phase110Memo;

this.prevPhase9 = phase9;

// ESLD 1.0.110
const ground2sMemorized = this.groundImmediateMemo.write(groundImmediate, _deltaTime) || groundImmediate;
const phase5Cond = !hAbv1500 && eng1Or2TOPower && !hFail && !ground2sMemorized;
const phase5 = this.phase5Memo.write(phase5Cond, _deltaTime) && phase5Cond;

const phase67Cond = (
!ground2sMemorized &&
!hFail &&
!eng1Or2TOPower &&
!hAbv1500 &&
!hAbv800
);
const phase67Memo = this.phase67Memo.write(phase67Cond, _deltaTime) && phase67Cond;

const phase6 = !phase5 && !ground2sMemorized && !phase67Memo;
const phase7 = phase67Memo && !phase8;

/*** End of ESLD logic ***/

// consolidate into single variable (just to be safe)
const phases = [phase1, phase2, phase3, phase4, phase5, phase6, phase7, phase8, phase9, phase10];

if (this.flightPhase === null && phases.indexOf(true) !== -1) {
// if we aren't initialized, just grab the first one that is valid
this._setFlightPhase(phases.indexOf(true) + 1);
console.log(`FWC flight phase: ${this.flightPhase}`);
return;
}

const activePhases = phases.map((x, i) => [x, i + 1]).filter(y => !!y[0]).map(z => z[1]);

// the usual and easy case: only one flight phase is valid
if (activePhases.length === 1) {
if (activePhases[0] !== this.flightPhase) {
console.log(`FWC flight phase: ${this.flightPhase} => ${activePhases[0]}`);
this._setFlightPhase(activePhases[0]);
}
return;
}

// the mixed case => warn
if (activePhases.length > 1) {
console.warn(`Multiple FWC flight phases are valid: ${activePhases.join(", ")}`);
if (activePhases.indexOf(this.flightPhase) !== -1) {
// if the currently active one is present, keep it
console.warn(`Remaining in FWC flight phase ${this.flightPhase}`);
return;
}
// pick the earliest one
this._setFlightPhase(activePhases[0]);
console.log(`Resolving by switching FWC flight phase: ${this.flightPhase} => ${activePhases[0]}`);
return;
}

// otherwise, no flight phase is valid => warn
console.warn("No valid FWC flight phase");
if (this.flightPhase === null) {
this._setFlightPhase(null);
}
}

_setFlightPhase(flightPhase) {
if (flightPhase === this.flightPhase) {
return;
}

// ESDL 1.0.115
if (this.flightPhase !== null) {
this.flightPhaseEndedPulse = true;
}

// update flight phase
this.flightPhase = flightPhase;
SimVar.SetSimVarValue("L:A32NX_FWC_FLIGHT_PHASE", "Enum", this.flightPhase || 0);
}

_updateTakeoffMemo(_deltaTime) {
/// FWC ESLD 1.0.180
const setFlightPhaseMemo = this.flightPhase === 2 && this.toConfigTest;
const resetFlightPhaseMemo = (
this.flightPhase === 10 ||
Expand All @@ -305,7 +100,6 @@ class A32NX_FWC {
const radioHeightInvalid = false;
const gearDownlocked = SimVar.GetSimVarValue("GEAR TOTAL PCT EXTENDED", "percent") > 0.95;

// FWC ESLD 1.0.190
const setBelow2000ft = radioHeight < 2000;
const resetBelow2000ft = radioHeight > 2200;
const memo2 = this.memoLdgMemo_below2000ft.write(setBelow2000ft, resetBelow2000ft);
Expand Down

0 comments on commit 3b27dd4

Please sign in to comment.