# A3XX FADEC/Throttle Control System # Copyright (c) 2020 Josh Davidson (Octal450) if (getprop("options/eng") == "IAE") { io.include("fadec-iae.nas"); } else { io.include("fadec-cfm.nas"); } var Output = { limFlex: props.globals.getNode("/systems/thrust/lim-flex"), }; var thr1 = 0; var thr2 = 0; var state1 = 0; var state2 = 0; var engstate1 = 0; var engstate2 = 0; var eprtoga = 0; var eprmct = 0; var eprflx = 0; var eprclb = 0; var n1toga = 0; var n1mct = 0; var n1flx = 0; var n1clb = 0; var alpha = 0; var flaps = 0; var alphaProt = 0; var togaLock = 0; var gs = 0; setprop("systems/thrust/alpha-floor", 0); setprop("systems/thrust/toga-lk", 0); setprop("systems/thrust/epr/toga-lim", 0.0); setprop("systems/thrust/epr/mct-lim", 0.0); setprop("systems/thrust/epr/flx-lim", 0.0); setprop("systems/thrust/epr/clb-lim", 0.0); setprop("systems/thrust/n1/toga-lim", 0.0); setprop("systems/thrust/n1/mct-lim", 0.0); setprop("systems/thrust/n1/flx-lim", 0.0); setprop("systems/thrust/n1/clb-lim", 0.0); setprop("engines/flx-thr", 0.0); setprop("controls/engines/thrust-limit", "TOGA"); setprop("controls/engines/epr-limit", 0.0); setprop("controls/engines/n1-limit", 0.0); setprop("systems/thrust/state1", "IDLE"); setprop("systems/thrust/state2", "IDLE"); setprop("systems/thrust/lvrclb", 0); setprop("systems/thrust/clbreduc-ft", "1500"); setprop("systems/thrust/toga-lim", 0.0); setprop("systems/thrust/mct-lim", 0.0); setprop("systems/thrust/clb-lim", 0.0); setprop("systems/thrust/lim-flex", 0); setprop("engines/flex-derate", 0); setprop("systems/thrust/eng-out", 0); setprop("systems/thrust/thr-locked", 0); setprop("systems/thrust/thr-locked-alert", 0); setprop("systems/thrust/thr-locked-flash", 0); setprop("systems/thrust/thr-lock-time", 0); setprop("systems/thrust/thr-lock-cmd[0]", 0); setprop("systems/thrust/thr-lock-cmd[1]", 0); setlistener("/sim/signals/fdm-initialized", func { thrust_loop.start(); thrust_flash.start(); }); setlistener("/controls/engines/engine[0]/throttle-pos", func { engstate1 = getprop("engines/engine[0]/state"); engstate2 = getprop("engines/engine[1]/state"); thr1 = getprop("controls/engines/engine[0]/throttle-pos"); if (getprop("systems/thrust/alpha-floor") == 0 and getprop("systems/thrust/toga-lk") == 0) { if (thr1 < 0.01) { setprop("systems/thrust/state1", "IDLE"); unflex(); atoff_request(); } else if (thr1 >= 0.01 and thr1 < 0.60) { setprop("systems/thrust/state1", "MAN"); unflex(); } else if (thr1 >= 0.60 and thr1 < 0.65) { setprop("systems/thrust/state1", "CL"); unflex(); } else if (thr1 >= 0.65 and thr1 < 0.78) { setprop("systems/thrust/state1", "MAN THR"); unflex(); } else if (thr1 >= 0.78 and thr1 < 0.83) { if (getprop("systems/thrust/eng-out") != 1) { if (getprop("controls/engines/thrust-limit") == "FLX") { if (getprop("gear/gear[0]/wow") == 1 and (engstate1 == 3 or engstate2 == 3)) { setprop("it-autoflight/input/athr", 1); } setprop("controls/engines/engine[0]/throttle-fdm", 0.99); } else { setprop("controls/engines/engine[0]/throttle-fdm", 0.95); } } setprop("systems/thrust/state1", "MCT"); } else if (thr1 >= 0.83 and thr1 < 0.95) { setprop("systems/thrust/state1", "MAN THR"); unflex(); } else if (thr1 >= 0.95) { if (getprop("gear/gear[0]/wow") == 1 and (engstate1 == 3 or engstate2 == 3)) { setprop("it-autoflight/input/athr", 1); } setprop("controls/engines/engine[0]/throttle-fdm", 0.99); setprop("systems/thrust/state1", "TOGA"); unflex(); } } else { if (thr1 < 0.01) { setprop("systems/thrust/state1", "IDLE"); } else if (thr1 >= 0.01 and thr1 < 0.60) { setprop("systems/thrust/state1", "MAN"); } else if (thr1 >= 0.60 and thr1 < 0.65) { setprop("systems/thrust/state1", "CL"); } else if (thr1 >= 0.65 and thr1 < 0.78) { setprop("systems/thrust/state1", "MAN THR"); } else if (thr1 >= 0.78 and thr1 < 0.83) { setprop("systems/thrust/state1", "MCT"); } else if (thr1 >= 0.83 and thr1 < 0.95) { setprop("systems/thrust/state1", "MAN THR"); } else if (thr1 >= 0.95) { setprop("systems/thrust/state1", "TOGA"); } setprop("controls/engines/engine[0]/throttle-fdm", 0.99); } }, 0, 0); setlistener("/controls/engines/engine[1]/throttle-pos", func { engstate1 = getprop("engines/engine[0]/state"); engstate2 = getprop("engines/engine[1]/state"); thr2 = getprop("controls/engines/engine[1]/throttle-pos"); if (getprop("systems/thrust/alpha-floor") == 0 and getprop("systems/thrust/toga-lk") == 0) { if (thr2 < 0.01) { setprop("systems/thrust/state2", "IDLE"); unflex(); atoff_request(); } else if (thr2 >= 0.01 and thr2 < 0.60) { setprop("systems/thrust/state2", "MAN"); unflex(); } else if (thr2 >= 0.60 and thr2 < 0.65) { setprop("systems/thrust/state2", "CL"); unflex(); } else if (thr2 >= 0.65 and thr2 < 0.78) { setprop("systems/thrust/state2", "MAN THR"); unflex(); } else if (thr2 >= 0.78 and thr2 < 0.83) { if (getprop("systems/thrust/eng-out") != 1) { if (getprop("controls/engines/thrust-limit") == "FLX") { if (getprop("gear/gear[0]/wow") == 1 and (engstate1 == 3 or engstate2 == 3)) { setprop("it-autoflight/input/athr", 1); } setprop("controls/engines/engine[1]/throttle-fdm", 0.99); } else { setprop("controls/engines/engine[1]/throttle-fdm", 0.95); } } setprop("systems/thrust/state2", "MCT"); } else if (thr2 >= 0.83 and thr2 < 0.95) { setprop("systems/thrust/state2", "MAN THR"); unflex(); } else if (thr2 >= 0.95) { if (getprop("gear/gear[0]/wow") == 1 and (engstate1 == 3 or engstate2 == 3)) { setprop("it-autoflight/input/athr", 1); } setprop("controls/engines/engine[1]/throttle-fdm", 0.99); setprop("systems/thrust/state2", "TOGA"); unflex(); } } else { if (thr2 < 0.01) { setprop("systems/thrust/state2", "IDLE"); } else if (thr2 >= 0.01 and thr2 < 0.60) { setprop("systems/thrust/state2", "MAN"); } else if (thr2 >= 0.60 and thr2 < 0.65) { setprop("systems/thrust/state2", "CL"); } else if (thr2 >= 0.65 and thr2 < 0.78) { setprop("systems/thrust/state2", "MAN THR"); } else if (thr2 >= 0.78 and thr2 < 0.83) { setprop("systems/thrust/state2", "MCT"); } else if (thr2 >= 0.83 and thr2 < 0.95) { setprop("systems/thrust/state2", "MAN THR"); } else if (thr2 >= 0.95) { setprop("systems/thrust/state2", "TOGA"); } setprop("controls/engines/engine[1]/throttle-fdm", 0.99); } }, 0, 0); # Alpha Floor and Toga Lock setlistener("/it-autoflight/input/athr", func { if (getprop("systems/thrust/alpha-floor") == 1) { setprop("it-autoflight/input/athr", 1); } else { setprop("systems/thrust/toga-lk", 0); } }); # Checks if all throttles are in the IDLE position, before tuning off the A/THR. var atoff_request = func { state1 = getprop("systems/thrust/state1"); state2 = getprop("systems/thrust/state2"); if ((state1 == "IDLE") and (state2 == "IDLE") and (getprop("systems/thrust/alpha-floor") == 0) and (getprop("systems/thrust/toga-lk") == 0)) { if (getprop("it-autoflight/input/athr") == 1 and pts.Position.gearAglFt.getValue() > 50) { fcu.athrOff("soft"); } elsif (pts.Position.gearAglFt.getValue() < 50) { fcu.athrOff("none"); } } } var thrust_loop = maketimer(0.04, func { state1 = getprop("systems/thrust/state1"); state2 = getprop("systems/thrust/state2"); engstate1 = getprop("engines/engine[0]/state"); engstate2 = getprop("engines/engine[1]/state"); thr1 = getprop("controls/engines/engine[0]/throttle-pos"); thr2 = getprop("controls/engines/engine[1]/throttle-pos"); eprtoga = getprop("systems/thrust/epr/toga-lim"); eprmct = getprop("systems/thrust/epr/mct-lim"); eprflx = getprop("systems/thrust/epr/flx-lim"); eprclb = getprop("systems/thrust/epr/clb-lim"); n1toga = getprop("systems/thrust/n1/toga-lim"); n1mct = getprop("systems/thrust/n1/mct-lim"); n1flx = getprop("systems/thrust/n1/flx-lim"); n1clb = getprop("systems/thrust/n1/clb-lim"); gs = getprop("velocities/groundspeed-kt"); if (getprop("FMGC/internal/flex-set") == 1 and getprop("systems/fadec/n1mode1") == 0 and getprop("systems/fadec/n1mode2") == 0 and getprop("gear/gear[1]/wow") == 1 and getprop("gear/gear[2]/wow") == 1 and gs < 40) { setprop("systems/thrust/lim-flex", 1); } else if (getprop("FMGC/internal/flex-set") == 0 or engstate1 != 3 or engstate2 != 3) { setprop("systems/thrust/lim-flex", 0); } if (getprop("controls/engines/engine[0]/reverser") == "1" or getprop("controls/engines/engine[1]/reverser") == "1") { setprop("controls/engines/thrust-limit", "MREV"); setprop("controls/engines/epr-limit", 1.000); setprop("controls/engines/n1-limit", 0.0); } else if (getprop("gear/gear[1]/wow") == 0 or getprop("gear/gear[2]/wow") == 0 or (engstate1 != 3 and engstate2 != 3)) { if ((state1 == "TOGA" or state2 == "TOGA" or (state1 == "MAN THR" and thr1 >= 0.83) or (state2 == "MAN THR" and thr2 >= 0.83)) or getprop("systems/thrust/alpha-floor") == 1 or getprop("systems/thrust/toga-lk") == 1) { setprop("controls/engines/thrust-limit", "TOGA"); setprop("controls/engines/epr-limit", eprtoga); setprop("controls/engines/n1-limit", n1toga); } else if ((state1 == "MCT" or state2 == "MCT" or (state1 == "MAN THR" and thr1 < 0.83) or (state2 == "MAN THR" and thr2 < 0.83)) and getprop("systems/thrust/lim-flex") == 0) { setprop("controls/engines/thrust-limit", "MCT"); setprop("controls/engines/epr-limit", eprmct); setprop("controls/engines/n1-limit", n1mct); } else if ((state1 == "MCT" or state2 == "MCT" or (state1 == "MAN THR" and thr1 < 0.83) or (state2 == "MAN THR" and thr2 < 0.83)) and getprop("systems/thrust/lim-flex") == 1) { setprop("controls/engines/thrust-limit", "FLX"); setprop("controls/engines/epr-limit", eprflx); setprop("controls/engines/n1-limit", n1flx); } else if (state1 == "CL" or state2 == "CL" or state1 == "MAN" or state2 == "MAN" or state1 == "IDLE" or state2 == "IDLE") { setprop("controls/engines/thrust-limit", "CLB"); setprop("controls/engines/epr-limit", eprclb); setprop("controls/engines/n1-limit", n1clb); } } else if (getprop("FMGC/internal/flex-set") == 1 and getprop("systems/fadec/n1mode1") == 0 and getprop("systems/fadec/n1mode2") == 0) { if ((state1 == "TOGA" or state2 == "TOGA" or (state1 == "MAN THR" and thr1 >= 0.83) or (state2 == "MAN THR" and thr2 >= 0.83)) or getprop("systems/thrust/alpha-floor") == 1 or getprop("systems/thrust/toga-lk") == 1) { setprop("controls/engines/thrust-limit", "TOGA"); setprop("controls/engines/epr-limit", eprtoga); setprop("controls/engines/n1-limit", n1toga); } else { setprop("controls/engines/thrust-limit", "FLX"); setprop("controls/engines/epr-limit", eprflx); setprop("controls/engines/n1-limit", n1flx); } } else { setprop("controls/engines/thrust-limit", "TOGA"); setprop("controls/engines/epr-limit", eprtoga); setprop("controls/engines/n1-limit", n1toga); } alpha = getprop("fdm/jsbsim/aero/alpha-deg"); flaps = getprop("controls/flight/flap-pos"); if (flaps == 0) { alphaProt = 9.5; } else if (flaps == 1 or flaps == 2 or flaps == 3) { alphaProt = 15.0; } else if (flaps == 4) { alphaProt = 14.0; } else if (flaps == 5) { alphaProt = 13.0; } togaLock = alphaProt - 1; if (getprop("gear/gear[1]/wow") == 0 and getprop("gear/gear[2]/wow") == 0 and getprop("it-fbw/law") == 0 and (getprop("systems/thrust/eng-out") == 0 or (getprop("systems/thrust/eng-out") == 1 and flaps == 0)) and getprop("systems/fadec/n1mode1") == 0 and getprop("systems/fadec/n1mode2") == 0) { if (alpha > alphaProt and pts.Position.gearAglFt.getValue() >= 100) { setprop("systems/thrust/alpha-floor", 1); setprop("systems/thrust/toga-lk", 0); setprop("it-autoflight/input/athr", 1); setprop("controls/engines/engine[0]/throttle-fdm", 0.99); setprop("controls/engines/engine[1]/throttle-fdm", 0.99); } else if (getprop("systems/thrust/alpha-floor") == 1 and alpha < togaLock) { setprop("systems/thrust/alpha-floor", 0); setprop("it-autoflight/input/athr", 1); setprop("systems/thrust/toga-lk", 1); setprop("controls/engines/engine[0]/throttle-fdm", 0.99); setprop("controls/engines/engine[1]/throttle-fdm", 0.99); } } else { setprop("systems/thrust/alpha-floor", 0); setprop("systems/thrust/toga-lk", 0); } }); var unflex = func { state1 = getprop("systems/thrust/state1"); state2 = getprop("systems/thrust/state2"); if (state1 != "MCT" and state2 != "MCT" and getprop("gear/gear[1]/wow") == 0 and getprop("gear/gear[2]/wow") == 0) { setprop("systems/thrust/lim-flex", 0); } } var thrust_flash = maketimer(0.5, func { state1 = getprop("systems/thrust/state1"); state2 = getprop("systems/thrust/state2"); if (getprop("gear/gear[1]/wow") == 0 and getprop("gear/gear[2]/wow") == 0 and (getprop("engines/engine[0]/state") != 3 or getprop("engines/engine[1]/state") != 3)) { setprop("systems/thrust/eng-out", 1); } else { setprop("systems/thrust/eng-out", 0); } if (state1 == "CL" and state2 == "CL" and getprop("systems/thrust/eng-out") != 1) { setprop("systems/thrust/lvrclb", 0); } else if (state1 == "MCT" and state2 == "MCT" and getprop("systems/thrust/lim-flex") != 1 and getprop("systems/thrust/eng-out") == 1) { setprop("systems/thrust/lvrclb", 0); } else { var status = getprop("systems/thrust/lvrclb"); if (status == 0) { if (getprop("gear/gear[0]/wow") == 0) { if (getprop("systems/thrust/state1") == "MAN" or getprop("systems/thrust/state2") == "MAN") { setprop("systems/thrust/lvrclb", 1); } else { if (getprop("instrumentation/altimeter/indicated-altitude-ft") >= getprop("systems/thrust/clbreduc-ft") and getprop("gear/gear[1]/wow") == 0 and getprop("gear/gear[2]/wow") == 0) { setprop("systems/thrust/lvrclb", 1); } else if ((state1 == "CL" and state2 != "CL") or (state1 != "CL" and state2 == "CL") and getprop("systems/thrust/eng-out") != 1) { setprop("systems/thrust/lvrclb", 1); } else { setprop("systems/thrust/lvrclb", 0); } } } } else if (status == 1) { setprop("systems/thrust/lvrclb", 0); } } }); var lockThr = func() { state1 = getprop("systems/thrust/state1"); state2 = getprop("systems/thrust/state2"); if ((state1 == "CL" and state2 == "CL" and getprop("systems/thrust/eng-out") == 0) or (state1 == "MCT" and state2 == "MCT" and getprop("systems/thrust/eng-out") == 1)) { setprop("systems/thrust/thr-lock-time", getprop("sim/time/elapsed-sec")); setprop("systems/thrust/thr-locked", 1); lockTimer.start(); } } var checkLockThr = func() { if (getprop("systems/thrust/thr-lock-time") + 5 > getprop("sim/time/elapsed-sec")) { return; } if (fmgc.Output.athr.getBoolValue()) { lockTimer.stop(); setprop("systems/thrust/thr-locked", 0); setprop("systems/thrust/thr-locked-alert", 0); setprop("systems/thrust/thr-lock-time", 0); setprop("systems/thrust/thr-locked-flash", 0); return; } if (getprop("systems/thrust/thr-locked") == 0) { lockTimer.stop(); setprop("systems/thrust/thr-locked", 0); setprop("systems/thrust/thr-locked-alert", 0); setprop("systems/thrust/thr-lock-time", 0); setprop("systems/thrust/thr-locked-flash", 0); return; } state1 = getprop("systems/thrust/state1"); state2 = getprop("systems/thrust/state2"); if ((state1 != "CL" and state2 != "CL" and getprop("systems/thrust/eng-out") == 0) or (state1 != "MCT" and state2 != "MCT" and getprop("systems/thrust/eng-out") == 1)) { lockTimer.stop(); setprop("systems/thrust/thr-locked", 0); setprop("systems/thrust/thr-locked-alert", 0); setprop("systems/thrust/thr-lock-time", 0); setprop("systems/thrust/thr-locked-flash", 0); } elsif ((state1 == "CL" and state2 == "CL" and getprop("systems/thrust/eng-out") == 0) or (state1 == "MCT" and state2 == "MCT" and getprop("systems/thrust/eng-out") == 1)) { setprop("systems/thrust/thr-locked-alert", 1); setprop("systems/thrust/thr-lock-time", getprop("sim/time/elapsed-sec")); setprop("systems/thrust/thr-locked-flash", 1); lockTimer.stop(); lockTimer2.start(); } } var checkLockThr2 = func() { if (fmgc.Output.athr.getBoolValue()) { lockTimer2.stop(); setprop("systems/thrust/thr-locked", 0); setprop("systems/thrust/thr-locked-alert", 0); setprop("systems/thrust/thr-lock-time", 0); setprop("systems/thrust/thr-locked-flash", 0); return; } if (getprop("systems/thrust/thr-locked") == 0) { lockTimer2.stop(); setprop("systems/thrust/thr-locked", 0); setprop("systems/thrust/thr-locked-alert", 0); setprop("systems/thrust/thr-lock-time", 0); setprop("systems/thrust/thr-locked-flash", 0); return; } if (getprop("systems/thrust/thr-lock-time") + 5 < getprop("sim/time/elapsed-sec")) { setprop("systems/thrust/thr-locked-flash", 0); settimer(func() { setprop("systems/thrust/thr-locked-flash", 1); setprop("systems/thrust/thr-lock-time", getprop("sim/time/elapsed-sec")); ecam.athr_lock.noRepeat = 0; ecam.athr_lock.noRepeat2 = 0; }, 0.2); } state1 = getprop("systems/thrust/state1"); state2 = getprop("systems/thrust/state2"); if ((state1 != "CL" and state2 != "CL" and getprop("systems/thrust/eng-out") == 0) or (state1 != "MCT" and state2 != "MCT" and getprop("systems/thrust/eng-out") == 1)) { lockTimer2.stop(); setprop("systems/thrust/thr-locked", 0); setprop("systems/thrust/thr-locked-alert", 0); setprop("systems/thrust/thr-lock-time", 0); setprop("systems/thrust/thr-locked-flash", 0); } } setlistener("/systems/thrust/thr-locked", func { if (getprop("systems/thrust/thr-locked") == 1) { setprop("systems/thrust/thr-lock-cmd[0]", getprop("controls/engines/engine[0]/throttle-output")); setprop("systems/thrust/thr-lock-cmd[1]", getprop("controls/engines/engine[1]/throttle-output")); } }, 0, 0); var lockTimer = maketimer(0.1, checkLockThr); var lockTimer2 = maketimer(0.1, checkLockThr2);