1051 lines
36 KiB
Text
1051 lines
36 KiB
Text
# IT-AUTOFLIGHT System Controller V4.0.5
|
|
# Copyright (c) 2020 Joshua Davidson (Octal450)
|
|
|
|
setprop("/it-autoflight/config/tuning-mode", 0); # Not used by controller
|
|
|
|
# Initialize all used variables and property nodes
|
|
# Sim
|
|
var Controls = {
|
|
aileron: props.globals.getNode("/controls/flight/aileron", 1),
|
|
elevator: props.globals.getNode("/controls/flight/elevator", 1),
|
|
rudder: props.globals.getNode("/controls/flight/rudder", 1),
|
|
};
|
|
|
|
var FPLN = {
|
|
active: props.globals.getNode("/autopilot/route-manager/active", 1),
|
|
activeTemp: 0,
|
|
currentCourse: 0,
|
|
currentWp: props.globals.getNode("/autopilot/route-manager/current-wp", 1),
|
|
currentWpTemp: 0,
|
|
deltaAngle: 0,
|
|
deltaAngleRad: 0,
|
|
distCoeff: 0,
|
|
maxBank: 0,
|
|
maxBankLimit: 0,
|
|
nextCourse: 0,
|
|
num: props.globals.getNode("/autopilot/route-manager/route/num", 1),
|
|
numTemp: 0,
|
|
R: 0,
|
|
radius: 0,
|
|
turnDist: 0,
|
|
wp0Dist: props.globals.getNode("/autopilot/route-manager/wp/dist", 1),
|
|
wpFlyFrom: 0,
|
|
wpFlyTo: 0,
|
|
};
|
|
|
|
var Gear = {
|
|
wow0: props.globals.getNode("/gear/gear[0]/wow", 1),
|
|
wow1: props.globals.getNode("/gear/gear[1]/wow", 1),
|
|
wow1Temp: 1,
|
|
wow2: props.globals.getNode("/gear/gear[2]/wow", 1),
|
|
wow2Temp: 1,
|
|
};
|
|
|
|
var Misc = {
|
|
efis0Trk: props.globals.getNode("/instrumentation/efis[0]/hdg-trk-selected", 1),
|
|
efis1Trk: props.globals.getNode("/instrumentation/efis[1]/hdg-trk-selected", 1),
|
|
flapNorm: props.globals.getNode("/surface-positions/flap-pos-norm", 1),
|
|
};
|
|
|
|
var Position = {
|
|
gearAglFtTemp: 0,
|
|
gearAglFt: props.globals.getNode("/position/gear-agl-ft", 1),
|
|
indicatedAltitudeFt: props.globals.getNode("/instrumentation/altimeter/indicated-altitude-ft", 1),
|
|
indicatedAltitudeFtTemp: 0,
|
|
};
|
|
|
|
var Radio = {
|
|
gsDefl: [props.globals.getNode("/instrumentation/nav[0]/gs-needle-deflection-norm", 1), props.globals.getNode("/instrumentation/nav[1]/gs-needle-deflection-norm", 1)],
|
|
gsDeflTemp: 0,
|
|
inRange: [props.globals.getNode("/instrumentation/nav[0]/in-range", 1), props.globals.getNode("/instrumentation/nav[1]/in-range", 1)],
|
|
inRangeTemp: 0,
|
|
locDefl: [props.globals.getNode("/instrumentation/nav[0]/heading-needle-deflection-norm", 1), props.globals.getNode("/instrumentation/nav[1]/heading-needle-deflection-norm", 1)],
|
|
locDeflTemp: 0,
|
|
radioSel: 0,
|
|
signalQuality: [props.globals.getNode("/instrumentation/nav[0]/signal-quality-norm", 1), props.globals.getNode("/instrumentation/nav[1]/signal-quality-norm", 1)],
|
|
signalQualityTemp: 0,
|
|
};
|
|
|
|
var Velocities = {
|
|
airspeedKt: props.globals.getNode("/velocities/airspeed-kt", 1), # Only used for gain scheduling
|
|
groundspeedKt: props.globals.getNode("/velocities/groundspeed-kt", 1),
|
|
groundspeedMps: 0,
|
|
indicatedAirspeedKt: props.globals.getNode("/instrumentation/airspeed-indicator/indicated-speed-kt", 1),
|
|
indicatedMach: props.globals.getNode("/instrumentation/airspeed-indicator/indicated-mach", 1),
|
|
trueAirspeedKt: props.globals.getNode("/instrumentation/airspeed-indicator/true-speed-kt", 1),
|
|
trueAirspeedKtTemp: 0,
|
|
};
|
|
|
|
# IT-AUTOFLIGHT
|
|
var Input = {
|
|
alt: props.globals.initNode("/it-autoflight/input/alt", 10000, "INT"),
|
|
ap1: props.globals.initNode("/it-autoflight/input/ap1", 0, "BOOL"),
|
|
ap2: props.globals.initNode("/it-autoflight/input/ap2", 0, "BOOL"),
|
|
athr: props.globals.initNode("/it-autoflight/input/athr", 0, "BOOL"),
|
|
altDiff: 0,
|
|
bankLimitSW: props.globals.initNode("/it-autoflight/input/bank-limit-sw", 0, "INT"),
|
|
bankLimitSWTemp: 0,
|
|
fd1: props.globals.initNode("/it-autoflight/input/fd1", 0, "BOOL"),
|
|
fd2: props.globals.initNode("/it-autoflight/input/fd2", 0, "BOOL"),
|
|
fpa: props.globals.initNode("/it-autoflight/input/fpa", 0, "DOUBLE"),
|
|
fpaAbs: props.globals.initNode("/it-autoflight/input/fpa-abs", 0, "DOUBLE"), # Set by property rule
|
|
hdg: props.globals.initNode("/it-autoflight/input/hdg", 0, "INT"),
|
|
hdgCalc: 0,
|
|
kts: props.globals.initNode("/it-autoflight/input/kts", 250, "INT"),
|
|
ktsMach: props.globals.initNode("/it-autoflight/input/kts-mach", 0, "BOOL"),
|
|
lat: props.globals.initNode("/it-autoflight/input/lat", 5, "INT"),
|
|
latTemp: 5,
|
|
mach: props.globals.initNode("/it-autoflight/input/mach", 0.5, "DOUBLE"),
|
|
toga: props.globals.initNode("/it-autoflight/input/toga", 0, "BOOL"),
|
|
trk: props.globals.initNode("/it-autoflight/input/trk", 0, "BOOL"),
|
|
trueCourse: props.globals.initNode("/it-autoflight/input/true-course", 0, "BOOL"),
|
|
useNav2Radio: props.globals.initNode("/it-autoflight/input/use-nav2-radio", 0, "BOOL"),
|
|
vs: props.globals.initNode("/it-autoflight/input/vs", 0, "INT"),
|
|
vsAbs: props.globals.initNode("/it-autoflight/input/vs-abs", 0, "INT"), # Set by property rule
|
|
vert: props.globals.initNode("/it-autoflight/input/vert", 7, "INT"),
|
|
vertTemp: 7,
|
|
};
|
|
|
|
var Internal = {
|
|
alt: props.globals.initNode("/it-autoflight/internal/alt", 10000, "INT"),
|
|
altCaptureActive: 0,
|
|
altDiff: 0,
|
|
altTemp: 0,
|
|
altPredicted: props.globals.initNode("/it-autoflight/internal/altitude-predicted", 0, "DOUBLE"),
|
|
bankLimit: props.globals.initNode("/it-autoflight/internal/bank-limit", 30, "INT"),
|
|
bankLimitAuto: 30,
|
|
bankLimitMax: [30, 5, 10, 15, 20, 25, 30],
|
|
captVs: 0,
|
|
driftAngle: props.globals.initNode("/it-autoflight/internal/drift-angle-deg", 0, "DOUBLE"),
|
|
flchActive: 0,
|
|
fpa: props.globals.initNode("/it-autoflight/internal/fpa", 0, "DOUBLE"),
|
|
hdgErrorDeg: props.globals.initNode("/it-autoflight/internal/heading-error-deg", 0, "DOUBLE"),
|
|
hdgHldValue: 360,
|
|
hdgPredicted: props.globals.initNode("/it-autoflight/internal/heading-predicted", 0, "DOUBLE"),
|
|
lnavAdvanceNm: props.globals.initNode("/it-autoflight/internal/lnav-advance-nm", 0, "DOUBLE"),
|
|
minVs: props.globals.initNode("/it-autoflight/internal/min-vs", -500, "INT"),
|
|
maxVs: props.globals.initNode("/it-autoflight/internal/max-vs", 500, "INT"),
|
|
vs: props.globals.initNode("/it-autoflight/internal/vert-speed-fpm", 0, "DOUBLE"),
|
|
vsTemp: 0,
|
|
};
|
|
|
|
var Output = {
|
|
ap1: props.globals.initNode("/it-autoflight/output/ap1", 0, "BOOL"),
|
|
ap1Temp: 0,
|
|
ap2: props.globals.initNode("/it-autoflight/output/ap2", 0, "BOOL"),
|
|
ap2Temp: 0,
|
|
apprArm: props.globals.initNode("/it-autoflight/output/appr-armed", 0, "BOOL"),
|
|
athr: props.globals.initNode("/it-autoflight/output/athr", 0, "BOOL"),
|
|
athrTemp: 0,
|
|
fd1: props.globals.initNode("/it-autoflight/output/fd1", 0, "BOOL"),
|
|
fd1Temp: 0,
|
|
fd2: props.globals.initNode("/it-autoflight/output/fd2", 0, "BOOL"),
|
|
fd2Temp: 0,
|
|
hdgInHld: props.globals.initNode("/it-autoflight/output/hdg-in-hld", 0, "BOOL"),
|
|
hdgInHldTemp: 0,
|
|
lat: props.globals.initNode("/it-autoflight/output/lat", 5, "INT"),
|
|
latTemp: 5,
|
|
lnavArm: props.globals.initNode("/it-autoflight/output/lnav-armed", 0, "BOOL"),
|
|
locArm: props.globals.initNode("/it-autoflight/output/loc-armed", 0, "BOOL"),
|
|
thrMode: props.globals.initNode("/it-autoflight/output/thr-mode", 2, "INT"),
|
|
vert: props.globals.initNode("/it-autoflight/output/vert", 7, "INT"),
|
|
vertTemp: 7,
|
|
};
|
|
|
|
var Text = {
|
|
arm: props.globals.initNode("/it-autoflight/mode/arm", " ", "STRING"),
|
|
lat: props.globals.initNode("/it-autoflight/mode/lat", "T/O", "STRING"),
|
|
thr: props.globals.initNode("/it-autoflight/mode/thr", "PITCH", "STRING"),
|
|
vert: props.globals.initNode("/it-autoflight/mode/vert", "T/O CLB", "STRING"),
|
|
vertTemp: "T/O CLB",
|
|
};
|
|
|
|
var Settings = {
|
|
autoBankMaxDeg: props.globals.getNode("/it-autoflight/settings/auto-bank-max-deg", 1),
|
|
autolandWithoutAp: props.globals.getNode("/it-autoflight/settings/autoland-without-ap", 1),
|
|
autolandWithoutApTemp: 0,
|
|
customFMA: props.globals.getNode("/it-autoflight/settings/custom-fma", 1),
|
|
disableFinal: props.globals.getNode("/it-autoflight/settings/disable-final", 1),
|
|
latAglFt: props.globals.getNode("/it-autoflight/settings/lat-agl-ft", 1),
|
|
landingFlap: props.globals.getNode("/it-autoflight/settings/land-flap", 1),
|
|
reducAglFt: props.globals.getNode("/it-autoflight/settings/reduc-agl-ft", 1),
|
|
retardAltitude: props.globals.getNode("/it-autoflight/settings/retard-ft", 1),
|
|
retardEnable: props.globals.getNode("/it-autoflight/settings/retard-enable", 1),
|
|
togaSpd: props.globals.getNode("/it-autoflight/settings/togaspd", 1),
|
|
};
|
|
|
|
var Sound = {
|
|
apOff: props.globals.initNode("/it-autoflight/sound/apoffsound", 0, "BOOL"),
|
|
enableApOff: 0,
|
|
};
|
|
|
|
var Gain = {
|
|
altGain: props.globals.getNode("/it-autoflight/config/cmd/alt-gain", 1),
|
|
hdgGain: props.globals.getNode("/it-autoflight/config/cmd/roll", 1),
|
|
pitchKp: props.globals.initNode("/it-autoflight/config/pitch/kp", 0, "DOUBLE"),
|
|
pitchKpCalc: 0,
|
|
pitchKpLow: props.globals.getNode("/it-autoflight/config/pitch/kp-low", 1),
|
|
pitchKpLowTemp: 0,
|
|
pitchKpHigh: props.globals.getNode("/it-autoflight/config/pitch/kp-high", 1),
|
|
pitchKpHighTemp: 0,
|
|
rollCmdKp: props.globals.initNode("/it-autoflight/config/cmd/roll-kp", 0, "DOUBLE"),
|
|
rollCmdKpCalc: 0,
|
|
rollKp: props.globals.initNode("/it-autoflight/config/roll/kp", 0, "DOUBLE"),
|
|
rollKpCalc: 0,
|
|
rollKpLowTemp: 0,
|
|
rollKpLow: props.globals.getNode("/it-autoflight/config/roll/kp-low", 1),
|
|
rollKpHighTemp: 0,
|
|
rollKpHigh: props.globals.getNode("/it-autoflight/config/roll/kp-high", 1),
|
|
};
|
|
|
|
var ITAF = {
|
|
init: func(t = 0) { # Not everything should be reset if the reset is type 1
|
|
if (t != 1) {
|
|
Input.alt.setValue(10000);
|
|
Input.bankLimitSW.setValue(0);
|
|
Input.hdg.setValue(360);
|
|
Input.ktsMach.setBoolValue(0);
|
|
Input.kts.setValue(250);
|
|
Input.mach.setValue(0.5);
|
|
Input.trk.setBoolValue(0);
|
|
Input.trueCourse.setBoolValue(0);
|
|
Input.useNav2Radio.setBoolValue(0);
|
|
}
|
|
Input.ap1.setBoolValue(0);
|
|
Input.ap2.setBoolValue(0);
|
|
Input.athr.setBoolValue(0);
|
|
if (t != 1) {
|
|
Input.fd1.setBoolValue(0);
|
|
Input.fd2.setBoolValue(0);
|
|
}
|
|
Input.vs.setValue(0);
|
|
Input.fpa.setValue(0);
|
|
Input.lat.setValue(5);
|
|
Input.vert.setValue(7);
|
|
Input.toga.setBoolValue(0);
|
|
Output.ap1.setBoolValue(0);
|
|
Output.ap2.setBoolValue(0);
|
|
Output.athr.setBoolValue(0);
|
|
if (t != 1) {
|
|
Output.fd1.setBoolValue(0);
|
|
Output.fd2.setBoolValue(0);
|
|
}
|
|
Output.hdgInHld.setBoolValue(0);
|
|
Output.lnavArm.setBoolValue(0);
|
|
Output.locArm.setBoolValue(0);
|
|
Output.apprArm.setBoolValue(0);
|
|
Output.thrMode.setValue(0);
|
|
Output.lat.setValue(5);
|
|
Output.vert.setValue(7);
|
|
Internal.minVs.setValue(-500);
|
|
Internal.maxVs.setValue(500);
|
|
Internal.alt.setValue(10000);
|
|
Internal.altCaptureActive = 0;
|
|
Text.thr.setValue("PITCH");
|
|
Text.arm.setValue(" ");
|
|
if (Settings.customFMA.getBoolValue()) {
|
|
updateFMA.arm();
|
|
}
|
|
me.updateLatText("T/O");
|
|
me.updateVertText("T/O CLB");
|
|
loopTimer.start();
|
|
slowLoopTimer.start();
|
|
},
|
|
loop: func() {
|
|
Output.latTemp = Output.lat.getValue();
|
|
Output.vertTemp = Output.vert.getValue();
|
|
Output.ap1Temp = Output.ap1.getBoolValue();
|
|
Output.ap2Temp = Output.ap2.getBoolValue();
|
|
Settings.autolandWithoutApTemp = Settings.autolandWithoutAp.getBoolValue();
|
|
|
|
# Kill Autoland if the system should not autoland without AP, and AP is off
|
|
if (Settings.autolandWithoutApTemp) { # Only evaluate the rest if this setting is on
|
|
if (!Output.ap1Temp and !Output.ap2Temp) {
|
|
if (Output.latTemp == 4) {
|
|
me.activateLOC();
|
|
}
|
|
if (Output.vertTemp == 6) {
|
|
me.activateGS();
|
|
}
|
|
}
|
|
}
|
|
|
|
# VOR/ILS Revision
|
|
if (Output.latTemp == 2 or Output.latTemp == 4 or Output.vertTemp == 2 or Output.vertTemp == 6) {
|
|
me.checkRadioRevision(Output.latTemp, Output.vertTemp);
|
|
}
|
|
|
|
Gear.wow1Temp = Gear.wow1.getBoolValue();
|
|
Gear.wow2Temp = Gear.wow2.getBoolValue();
|
|
Output.latTemp = Output.lat.getValue();
|
|
Output.vertTemp = Output.vert.getValue();
|
|
Text.vertTemp = Text.vert.getValue();
|
|
Position.gearAglFtTemp = Position.gearAglFt.getValue();
|
|
Internal.vsTemp = Internal.vs.getValue();
|
|
Position.indicatedAltitudeFtTemp = Position.indicatedAltitudeFt.getValue();
|
|
Output.hdgInHldTemp = Output.hdgInHld.getBoolValue();
|
|
|
|
# HDG HLD logic
|
|
if (Output.latTemp == 0) {
|
|
if (Input.hdg.getValue() == Internal.hdgHldValue and abs(Internal.hdgErrorDeg.getValue()) <= 2.5) {
|
|
if (Output.hdgInHldTemp != 1) {
|
|
Output.hdgInHld.setBoolValue(1);
|
|
}
|
|
} else if (Input.hdg.getValue() != Internal.hdgHldValue) {
|
|
Internal.hdgHldValue = Input.hdg.getValue();
|
|
if (Output.hdgInHldTemp != 0 and abs(Internal.hdgErrorDeg.getValue()) > 2.5) {
|
|
Output.hdgInHld.setBoolValue(0);
|
|
}
|
|
}
|
|
} else {
|
|
if (Output.hdgInHldTemp != 0) {
|
|
Output.hdgInHld.setBoolValue(0);
|
|
}
|
|
}
|
|
|
|
# LNAV Engagement
|
|
if (Output.lnavArm.getBoolValue()) {
|
|
me.checkLNAV(1);
|
|
}
|
|
|
|
# VOR/LOC or ILS/LOC Capture
|
|
if (Output.locArm.getBoolValue()) {
|
|
me.checkLOC(1, 0);
|
|
}
|
|
|
|
# G/S Capture
|
|
if (Output.apprArm.getBoolValue()) {
|
|
me.checkAPPR(1);
|
|
}
|
|
|
|
# Autoland Logic
|
|
if (Output.latTemp == 2) {
|
|
if (Position.gearAglFtTemp <= 150) {
|
|
if (Output.ap1Temp or Output.ap2Temp or Settings.autolandWithoutApTemp) {
|
|
me.setLatMode(4);
|
|
}
|
|
}
|
|
}
|
|
if (Output.vertTemp == 2) {
|
|
if (Position.gearAglFtTemp <= 100 and Position.gearAglFtTemp >= 5) {
|
|
if (Output.ap1Temp or Output.ap2Temp or Settings.autolandWithoutApTemp) {
|
|
me.setVertMode(6);
|
|
}
|
|
}
|
|
} else if (Output.vertTemp == 6) {
|
|
if (!Output.ap1Temp and !Output.ap2Temp and !Settings.autolandWithoutApTemp) {
|
|
me.activateLOC();
|
|
me.activateGS();
|
|
} else {
|
|
if (Position.gearAglFtTemp <= 50 and Position.gearAglFtTemp >= 5 and Text.vert.getValue() != "FLARE") {
|
|
me.updateVertText("FLARE");
|
|
}
|
|
if (Gear.wow1Temp and Gear.wow2Temp and Text.vert.getValue() != "ROLLOUT") {
|
|
me.updateLatText("RLOU");
|
|
me.updateVertText("ROLLOUT");
|
|
}
|
|
}
|
|
}
|
|
|
|
# FLCH Engagement
|
|
if (Text.vertTemp == "T/O CLB") {
|
|
me.checkFLCH(Settings.reducAglFt.getValue());
|
|
}
|
|
|
|
# Altitude Capture/Sync Logic
|
|
if (Output.vertTemp != 0) {
|
|
Internal.alt.setValue(Input.alt.getValue());
|
|
}
|
|
Internal.altTemp = Internal.alt.getValue();
|
|
Internal.altDiff = Internal.altTemp - Position.indicatedAltitudeFtTemp;
|
|
|
|
if (Output.vertTemp != 0 and Output.vertTemp != 2 and Output.vertTemp != 6) {
|
|
Internal.captVs = math.clamp(math.round(abs(Internal.vs.getValue()) / (-1 * Gain.altGain.getValue()), 100), 50, 2500); # Capture limits
|
|
if (abs(Internal.altDiff) <= Internal.captVs and !Gear.wow1Temp and !Gear.wow2Temp) {
|
|
if (Internal.altTemp >= Position.indicatedAltitudeFtTemp and Internal.vsTemp >= -25) { # Don't capture if we are going the wrong way
|
|
me.setVertMode(3);
|
|
} else if (Internal.altTemp < Position.indicatedAltitudeFtTemp and Internal.vsTemp <= 25) { # Don't capture if we are going the wrong way
|
|
me.setVertMode(3);
|
|
}
|
|
}
|
|
}
|
|
|
|
# Altitude Hold Min/Max Reset
|
|
if (Internal.altCaptureActive) {
|
|
if (abs(Internal.altDiff) <= 25 and Text.vert.getValue() != "ALT HLD") {
|
|
me.resetClimbRateLim();
|
|
me.updateVertText("ALT HLD");
|
|
}
|
|
}
|
|
|
|
# Thrust Mode Selector
|
|
if (Output.athr.getBoolValue() and Output.vertTemp != 7 and Settings.retardEnable.getBoolValue() and Position.gearAglFt.getValue() <= Settings.retardAltitude.getValue() and Misc.flapNorm.getValue() >= Settings.landingFlap.getValue() - 0.001) {
|
|
Output.thrMode.setValue(1);
|
|
Text.thr.setValue("RETARD");
|
|
if (Gear.wow1Temp or Gear.wow2Temp) { # Disconnect A/THR on either main gear touch
|
|
me.athrMaster(0);
|
|
setprop("/controls/engines/engine[0]/throttle", 0);
|
|
setprop("/controls/engines/engine[1]/throttle", 0);
|
|
setprop("/controls/engines/engine[2]/throttle", 0);
|
|
setprop("/controls/engines/engine[3]/throttle", 0);
|
|
setprop("/controls/engines/engine[4]/throttle", 0);
|
|
setprop("/controls/engines/engine[5]/throttle", 0);
|
|
setprop("/controls/engines/engine[6]/throttle", 0);
|
|
setprop("/controls/engines/engine[7]/throttle", 0);
|
|
}
|
|
} else if (Output.vertTemp == 4) {
|
|
if (Internal.altTemp >= Position.indicatedAltitudeFtTemp) {
|
|
Output.thrMode.setValue(2);
|
|
Text.thr.setValue("PITCH");
|
|
if (Internal.flchActive and Text.vert.getValue() != "SPD CLB") { # Set before mode change to prevent it from overwriting by mistake
|
|
me.updateVertText("SPD CLB");
|
|
}
|
|
} else {
|
|
Output.thrMode.setValue(1);
|
|
Text.thr.setValue("PITCH");
|
|
if (Internal.flchActive and Text.vert.getValue() != "SPD DES") { # Set before mode change to prevent it from overwriting by mistake
|
|
me.updateVertText("SPD DES");
|
|
}
|
|
}
|
|
} else if (Output.vertTemp == 7) {
|
|
Output.thrMode.setValue(2);
|
|
Text.thr.setValue("PITCH");
|
|
} else {
|
|
Output.thrMode.setValue(0);
|
|
Text.thr.setValue("THRUST");
|
|
}
|
|
},
|
|
slowLoop: func() {
|
|
Input.bankLimitSWTemp = Input.bankLimitSW.getValue();
|
|
Velocities.trueAirspeedKtTemp = Velocities.trueAirspeedKt.getValue();
|
|
FPLN.activeTemp = FPLN.active.getValue();
|
|
FPLN.currentWpTemp = FPLN.currentWp.getValue();
|
|
FPLN.numTemp = FPLN.num.getValue();
|
|
|
|
# Bank Limit
|
|
if (Velocities.trueAirspeedKtTemp >= 420) {
|
|
Internal.bankLimitAuto = 15;
|
|
} else if (Velocities.trueAirspeedKtTemp >= 340) {
|
|
Internal.bankLimitAuto = 20;
|
|
} else {
|
|
Internal.bankLimitAuto = 30;
|
|
}
|
|
|
|
if (Internal.bankLimitAuto > Internal.bankLimitMax[Input.bankLimitSWTemp]) {
|
|
Internal.bankLimit.setValue(Internal.bankLimitMax[Input.bankLimitSWTemp]);
|
|
} else {
|
|
Internal.bankLimit.setValue(Internal.bankLimitAuto);
|
|
}
|
|
|
|
# If in LNAV mode and route is not longer active, switch to HDG HLD
|
|
if (Output.lat.getValue() == 1) { # Only evaulate the rest of the condition if we are in LNAV mode
|
|
if (FPLN.num.getValue() == 0 or !FPLN.active.getBoolValue()) {
|
|
me.setLatMode(3);
|
|
}
|
|
}
|
|
|
|
# Waypoint Advance Logic
|
|
if (FPLN.numTemp > 0 and FPLN.activeTemp == 1) {
|
|
if ((FPLN.currentWpTemp + 1) < FPLN.numTemp) {
|
|
Velocities.groundspeedMps = Velocities.groundspeedKt.getValue() * 0.5144444444444;
|
|
FPLN.wpFlyFrom = FPLN.currentWpTemp;
|
|
if (FPLN.wpFlyFrom < 0) {
|
|
FPLN.wpFlyFrom = 0;
|
|
}
|
|
FPLN.currentCourse = getprop("/autopilot/route-manager/route/wp[" ~ FPLN.wpFlyFrom ~ "]/leg-bearing-true-deg"); # Best left at getprop
|
|
FPLN.wpFlyTo = FPLN.currentWpTemp + 1;
|
|
if (FPLN.wpFlyTo < 0) {
|
|
FPLN.wpFlyTo = 0;
|
|
}
|
|
FPLN.nextCourse = getprop("/autopilot/route-manager/route/wp[" ~ FPLN.wpFlyTo ~ "]/leg-bearing-true-deg"); # Best left at getprop
|
|
FPLN.maxBankLimit = Internal.bankLimit.getValue();
|
|
|
|
FPLN.deltaAngle = math.abs(geo.normdeg180(FPLN.currentCourse - FPLN.nextCourse));
|
|
FPLN.maxBank = FPLN.deltaAngle * 1.5;
|
|
if (FPLN.maxBank > FPLN.maxBankLimit) {
|
|
FPLN.maxBank = FPLN.maxBankLimit;
|
|
}
|
|
FPLN.radius = (Velocities.groundspeedMps * Velocities.groundspeedMps) / (9.81 * math.tan(FPLN.maxBank / 57.2957795131));
|
|
FPLN.deltaAngleRad = (180 - FPLN.deltaAngle) / 114.5915590262;
|
|
FPLN.R = FPLN.radius / math.sin(FPLN.deltaAngleRad);
|
|
FPLN.distCoeff = FPLN.deltaAngle * -0.011111 + 2;
|
|
if (FPLN.distCoeff < 1) {
|
|
FPLN.distCoeff = 1;
|
|
}
|
|
FPLN.turnDist = math.cos(FPLN.deltaAngleRad) * FPLN.R * FPLN.distCoeff / 1852;
|
|
if (Gear.wow0.getBoolValue() and FPLN.turnDist < 1) {
|
|
FPLN.turnDist = 1;
|
|
}
|
|
Internal.lnavAdvanceNm.setValue(FPLN.turnDist);
|
|
|
|
if (FPLN.wp0Dist.getValue() <= FPLN.turnDist and flightplan().getWP(FPLN.currentWp.getValue()).fly_type == "flyBy") { # Don't care unless we are flyBy-ing
|
|
FPLN.currentWp.setValue(FPLN.currentWpTemp + 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
# Reset system once flight complete
|
|
if (!Output.ap1.getBoolValue() and !Output.ap2.getBoolValue() and Gear.wow0.getBoolValue() and Velocities.groundspeedKt.getValue() < 60 and Output.vert.getValue() != 7) { # Not in T/O or G/A
|
|
me.init(1);
|
|
}
|
|
|
|
# Calculate Roll and Pitch Rate Kp
|
|
if (!Settings.disableFinal.getBoolValue()) {
|
|
Gain.rollKpLowTemp = Gain.rollKpLow.getValue();
|
|
Gain.rollKpHighTemp = Gain.rollKpHigh.getValue();
|
|
Gain.pitchKpLowTemp = Gain.pitchKpLow.getValue();
|
|
Gain.pitchKpHighTemp = Gain.pitchKpHigh.getValue();
|
|
|
|
Gain.rollKpCalc = Gain.rollKpLowTemp + (Velocities.airspeedKt.getValue() - 140) * ((Gain.rollKpHighTemp - Gain.rollKpLowTemp) / (360 - 140));
|
|
Gain.pitchKpCalc = Gain.pitchKpLowTemp + (Velocities.airspeedKt.getValue() - 140) * ((Gain.pitchKpHighTemp - Gain.pitchKpLowTemp) / (360 - 140));
|
|
|
|
if (Gain.rollKpLowTemp > Gain.rollKpHighTemp) {
|
|
Gain.rollKpCalc = math.clamp(Gain.rollKpCalc, Gain.rollKpHighTemp, Gain.rollKpLowTemp);
|
|
} else if (Gain.rollKpLowTemp < Gain.rollKpHighTemp) {
|
|
Gain.rollKpCalc = math.clamp(Gain.rollKpCalc, Gain.rollKpLowTemp, Gain.rollKpHighTemp);
|
|
}
|
|
if (Gain.pitchKpLowTemp > Gain.pitchKpHighTemp) {
|
|
Gain.pitchKpCalc = math.clamp(Gain.pitchKpCalc, Gain.pitchKpHighTemp, Gain.pitchKpLowTemp);
|
|
} else if (Gain.pitchKpLowTemp < Gain.pitchKpHighTemp) {
|
|
Gain.pitchKpCalc = math.clamp(Gain.pitchKpCalc, Gain.pitchKpLowTemp, Gain.pitchKpHighTemp);
|
|
}
|
|
|
|
Gain.rollKp.setValue(Gain.rollKpCalc);
|
|
Gain.pitchKp.setValue(Gain.pitchKpCalc);
|
|
}
|
|
|
|
# Calculate Roll Command Kp
|
|
Gain.rollCmdKpCalc = Gain.hdgGain.getValue() + (Velocities.airspeedKt.getValue() - 140) * ((Gain.hdgGain.getValue() + 1.0 - Gain.hdgGain.getValue()) / (360 - 140));
|
|
Gain.rollCmdKpCalc = math.clamp(Gain.rollCmdKpCalc, Gain.hdgGain.getValue(), Gain.hdgGain.getValue() + 1.0);
|
|
|
|
Gain.rollCmdKp.setValue(Gain.rollCmdKpCalc);
|
|
},
|
|
ap1Master: func(s) {
|
|
if (s == 1) {
|
|
if (Output.vert.getValue() != 6 and !Gear.wow1.getBoolValue() and !Gear.wow2.getBoolValue()) {
|
|
Controls.rudder.setValue(0);
|
|
Output.ap1.setBoolValue(1);
|
|
Sound.enableApOff = 1;
|
|
Sound.apOff.setBoolValue(0);
|
|
}
|
|
} else {
|
|
Output.ap1.setBoolValue(0);
|
|
me.apOffFunction();
|
|
}
|
|
Output.ap1Temp = Output.ap1.getBoolValue();
|
|
if (Input.ap1.getBoolValue() != Output.ap1Temp) {
|
|
Input.ap1.setBoolValue(Output.ap1Temp);
|
|
}
|
|
},
|
|
ap2Master: func(s) {
|
|
if (s == 1) {
|
|
if (Output.vert.getValue() != 6 and !Gear.wow1.getBoolValue() and !Gear.wow2.getBoolValue()) {
|
|
Controls.rudder.setValue(0);
|
|
Output.ap2.setBoolValue(1);
|
|
Sound.enableApOff = 1;
|
|
Sound.apOff.setBoolValue(0);
|
|
}
|
|
} else {
|
|
Output.ap2.setBoolValue(0);
|
|
me.apOffFunction();
|
|
}
|
|
Output.ap2Temp = Output.ap2.getBoolValue();
|
|
if (Input.ap2.getBoolValue() != Output.ap2Temp) {
|
|
Input.ap2.setBoolValue(Output.ap2Temp);
|
|
}
|
|
},
|
|
apOffFunction: func() {
|
|
if (!Output.ap1.getBoolValue() and !Output.ap2.getBoolValue()) { # Only do if both APs are off
|
|
if (!Settings.disableFinal.getBoolValue()) {
|
|
Controls.aileron.setValue(0);
|
|
Controls.elevator.setValue(0);
|
|
Controls.rudder.setValue(0);
|
|
}
|
|
if (Text.vert.getValue() == "ROLLOUT") {
|
|
me.init(1);
|
|
}
|
|
if (Sound.enableApOff) {
|
|
Sound.apOff.setBoolValue(1);
|
|
Sound.enableApOff = 0;
|
|
}
|
|
}
|
|
},
|
|
athrMaster: func(s) {
|
|
if (s == 1) {
|
|
Output.athr.setBoolValue(1);
|
|
} else {
|
|
Output.athr.setBoolValue(0);
|
|
}
|
|
Output.athrTemp = Output.athr.getBoolValue();
|
|
if (Input.athr.getBoolValue() != Output.athrTemp) {
|
|
Input.athr.setBoolValue(Output.athrTemp);
|
|
}
|
|
},
|
|
fd1Master: func(s) {
|
|
if (s == 1) {
|
|
Output.fd1.setBoolValue(1);
|
|
} else {
|
|
Output.fd1.setBoolValue(0);
|
|
}
|
|
Output.fd1Temp = Output.fd1.getBoolValue();
|
|
if (Input.fd1.getBoolValue() != Output.fd1Temp) {
|
|
Input.fd1.setBoolValue(Output.fd1Temp);
|
|
}
|
|
},
|
|
fd2Master: func(s) {
|
|
if (s == 1) {
|
|
Output.fd2.setBoolValue(1);
|
|
} else {
|
|
Output.fd2.setBoolValue(0);
|
|
}
|
|
Output.fd2Temp = Output.fd2.getBoolValue();
|
|
if (Input.fd2.getBoolValue() != Output.fd2Temp) {
|
|
Input.fd2.setBoolValue(Output.fd2Temp);
|
|
}
|
|
},
|
|
setLatMode: func(n) {
|
|
Output.vertTemp = Output.vert.getValue();
|
|
if (n == 0) { # HDG SEL
|
|
me.updateLnavArm(0);
|
|
me.updateLocArm(0);
|
|
me.updateApprArm(0);
|
|
Output.lat.setValue(0);
|
|
me.updateLatText("HDG");
|
|
if (Output.vertTemp == 2 or Output.vertTemp == 6) { # Also cancel G/S or FLARE if active
|
|
me.setVertMode(1);
|
|
} else {
|
|
me.armTextCheck();
|
|
}
|
|
} else if (n == 1) { # LNAV
|
|
me.checkLNAV(0);
|
|
} else if (n == 2) { # VOR/LOC
|
|
me.updateLnavArm(0);
|
|
me.armTextCheck();
|
|
me.checkLOC(0, 0);
|
|
} else if (n == 3) { # HDG HLD
|
|
me.updateLnavArm(0);
|
|
me.updateLocArm(0);
|
|
me.updateApprArm(0);
|
|
me.syncHdg();
|
|
Output.lat.setValue(0);
|
|
me.updateLatText("HDG");
|
|
Internal.hdgHldValue = Input.hdg.getValue();
|
|
Output.hdgInHld.setBoolValue(1);
|
|
if (Output.vertTemp == 2 or Output.vertTemp == 6) { # Also cancel G/S or FLARE if active
|
|
me.setVertMode(1);
|
|
} else {
|
|
me.armTextCheck();
|
|
}
|
|
} else if (n == 4) { # ALIGN
|
|
me.updateLnavArm(0);
|
|
me.updateLocArm(0);
|
|
me.updateApprArm(0);
|
|
Output.lat.setValue(4);
|
|
me.updateLatText("ALGN");
|
|
me.armTextCheck();
|
|
} else if (n == 5) { # T/O
|
|
me.updateLnavArm(0);
|
|
me.updateLocArm(0);
|
|
me.updateApprArm(0);
|
|
Output.lat.setValue(5);
|
|
me.updateLatText("T/O");
|
|
me.armTextCheck();
|
|
}
|
|
},
|
|
setLatArm: func(n) {
|
|
if (n == 0) {
|
|
me.updateLnavArm(0);
|
|
me.armTextCheck();
|
|
} else if (n == 1) {
|
|
if (FPLN.num.getValue() > 0 and FPLN.active.getBoolValue()) {
|
|
me.updateLnavArm(1);
|
|
me.armTextCheck();
|
|
}
|
|
} else if (n == 3) {
|
|
me.syncHdg();
|
|
me.updateLnavArm(0);
|
|
me.armTextCheck();
|
|
}
|
|
},
|
|
setVertMode: func(n) {
|
|
Input.altDiff = Input.alt.getValue() - Position.indicatedAltitudeFt.getValue();
|
|
if (n == 0) { # ALT HLD
|
|
Internal.flchActive = 0;
|
|
Internal.altCaptureActive = 0;
|
|
me.updateApprArm(0);
|
|
Output.vert.setValue(0);
|
|
me.resetClimbRateLim();
|
|
me.updateVertText("ALT HLD");
|
|
me.syncAlt();
|
|
me.armTextCheck();
|
|
} else if (n == 1) { # V/S
|
|
if (abs(Input.altDiff) >= 25) {
|
|
Internal.flchActive = 0;
|
|
Internal.altCaptureActive = 0;
|
|
me.updateApprArm(0);
|
|
Output.vert.setValue(1);
|
|
me.updateVertText("V/S");
|
|
me.syncVs();
|
|
me.armTextCheck();
|
|
} else {
|
|
me.updateApprArm(0);
|
|
me.armTextCheck();
|
|
}
|
|
} else if (n == 2) { # G/S
|
|
me.checkLOC(0, 1);
|
|
me.checkAPPR(0);
|
|
} else if (n == 3) { # ALT CAP
|
|
Internal.flchActive = 0;
|
|
Output.vert.setValue(0);
|
|
me.setClimbRateLim();
|
|
Internal.altCaptureActive = 1;
|
|
me.updateVertText("ALT CAP");
|
|
} else if (n == 4) { # FLCH
|
|
me.updateApprArm(0);
|
|
if (abs(Input.altDiff) >= 125) { # SPD CLB or SPD DES
|
|
if (Input.alt.getValue() >= Position.indicatedAltitudeFt.getValue()) { # Usually set Thrust Mode Selector, but we do it now due to timer lag
|
|
me.updateVertText("SPD CLB");
|
|
} else {
|
|
me.updateVertText("SPD DES");
|
|
}
|
|
Internal.altCaptureActive = 0;
|
|
Output.vert.setValue(4);
|
|
Internal.flchActive = 1;
|
|
} else { # ALT CAP
|
|
Internal.flchActive = 0;
|
|
Internal.alt.setValue(Input.alt.getValue());
|
|
Internal.altCaptureActive = 1;
|
|
Output.vert.setValue(0);
|
|
me.updateVertText("ALT CAP");
|
|
}
|
|
me.armTextCheck();
|
|
} else if (n == 5) { # FPA
|
|
if (abs(Input.altDiff) >= 25) {
|
|
Internal.flchActive = 0;
|
|
Internal.altCaptureActive = 0;
|
|
me.updateApprArm(0);
|
|
Output.vert.setValue(5);
|
|
me.updateVertText("FPA");
|
|
me.syncFpa();
|
|
me.armTextCheck();
|
|
} else {
|
|
me.updateApprArm(0);
|
|
me.armTextCheck();
|
|
}
|
|
} else if (n == 6) { # FLARE/ROLLOUT
|
|
Internal.flchActive = 0;
|
|
Internal.altCaptureActive = 0;
|
|
me.updateApprArm(0);
|
|
Output.vert.setValue(6);
|
|
me.updateVertText("G/S");
|
|
me.armTextCheck();
|
|
} else if (n == 7) { # T/O CLB or G/A CLB, text is set by TOGA selector
|
|
Internal.flchActive = 0;
|
|
Internal.altCaptureActive = 0;
|
|
me.updateApprArm(0);
|
|
Output.vert.setValue(7);
|
|
me.armTextCheck();
|
|
}
|
|
},
|
|
activateLNAV: func() {
|
|
if (Output.lat.getValue() != 1) {
|
|
me.updateLnavArm(0);
|
|
me.updateLocArm(0);
|
|
me.updateApprArm(0);
|
|
Output.lat.setValue(1);
|
|
me.updateLatText("LNAV");
|
|
if (Output.vertTemp == 2 or Output.vertTemp == 6) { # Also cancel G/S or FLARE if active
|
|
me.setVertMode(1);
|
|
} else {
|
|
me.armTextCheck();
|
|
}
|
|
}
|
|
},
|
|
activateLOC: func() {
|
|
if (Output.lat.getValue() != 2) {
|
|
me.updateLnavArm(0);
|
|
me.updateLocArm(0);
|
|
Output.lat.setValue(2);
|
|
me.updateLatText("LOC");
|
|
me.armTextCheck();
|
|
}
|
|
},
|
|
activateGS: func() {
|
|
if (Output.vert.getValue() != 2) {
|
|
Internal.flchActive = 0;
|
|
Internal.altCaptureActive = 0;
|
|
me.updateApprArm(0);
|
|
Output.vert.setValue(2);
|
|
me.updateVertText("G/S");
|
|
me.armTextCheck();
|
|
}
|
|
},
|
|
checkLNAV: func(t) {
|
|
if (FPLN.num.getValue() > 0 and FPLN.active.getBoolValue() and Position.gearAglFt.getValue() >= Settings.latAglFt.getValue()) {
|
|
me.activateLNAV();
|
|
} else if (FPLN.active.getBoolValue() and Output.lat.getValue() != 1 and t != 1) {
|
|
me.updateLnavArm(1);
|
|
me.armTextCheck();
|
|
}
|
|
},
|
|
checkFLCH: func(a) {
|
|
if (Position.gearAglFt.getValue() >= a and a != 0) {
|
|
me.setVertMode(4);
|
|
}
|
|
},
|
|
checkLOC: func(t, a) {
|
|
Radio.radioSel = Input.useNav2Radio.getBoolValue();
|
|
if (Radio.inRange[Radio.radioSel].getBoolValue()) { # # Only evaulate the rest of the condition unless we are in range
|
|
Radio.locDeflTemp = Radio.locDefl[Radio.radioSel].getValue();
|
|
Radio.signalQualityTemp = Radio.signalQuality[Radio.radioSel].getValue();
|
|
if (abs(Radio.locDeflTemp) <= 0.95 and Radio.locDeflTemp != 0 and Radio.signalQualityTemp >= 0.99) {
|
|
me.activateLOC();
|
|
} else if (t != 1) { # Do not do this if loop calls it
|
|
if (Output.lat.getValue() != 2) {
|
|
me.updateLnavArm(0);
|
|
me.updateLocArm(1);
|
|
if (a != 1) { # Don't call this if arming with G/S
|
|
me.armTextCheck();
|
|
}
|
|
}
|
|
}
|
|
} else { # Prevent bad behavior due to FG not updating it when not in range
|
|
Radio.signalQuality[Radio.radioSel].setValue(0);
|
|
}
|
|
},
|
|
checkAPPR: func(t) {
|
|
Radio.radioSel = Input.useNav2Radio.getBoolValue();
|
|
if (Radio.inRange[Radio.radioSel].getBoolValue()) { # # Only evaulate the rest of the condition unless we are in range
|
|
Radio.gsDeflTemp = Radio.gsDefl[Radio.radioSel].getValue();
|
|
if (abs(Radio.gsDeflTemp) <= 0.2 and Radio.gsDeflTemp != 0 and Output.lat.getValue() == 2) { # Only capture if LOC is active
|
|
me.activateGS();
|
|
} else if (t != 1) { # Do not do this if loop calls it
|
|
if (Output.vert.getValue() != 2) {
|
|
me.updateApprArm(1);
|
|
}
|
|
me.armTextCheck();
|
|
}
|
|
} else { # Prevent bad behavior due to FG not updating it when not in range
|
|
Radio.signalQuality[Radio.radioSel].setValue(0);
|
|
}
|
|
},
|
|
checkRadioRevision: func(l, v) { # Revert mode if signal lost
|
|
Radio.radioSel = Input.useNav2Radio.getBoolValue();
|
|
Radio.inRangeTemp = Radio.inRange[Radio.radioSel].getBoolValue();
|
|
if (!Radio.inRangeTemp) {
|
|
if (l == 4 or v == 6) {
|
|
me.ap1Master(0);
|
|
me.ap2Master(0);
|
|
me.setLatMode(3);
|
|
me.setVertMode(1);
|
|
} else {
|
|
me.setLatMode(3); # Also cancels G/S if active
|
|
}
|
|
}
|
|
},
|
|
setClimbRateLim: func() {
|
|
Internal.vsTemp = Internal.vs.getValue();
|
|
if (Internal.alt.getValue() >= Position.indicatedAltitudeFt.getValue()) {
|
|
Internal.maxVs.setValue(math.round(Internal.vsTemp));
|
|
Internal.minVs.setValue(-500);
|
|
} else {
|
|
Internal.maxVs.setValue(500);
|
|
Internal.minVs.setValue(math.round(Internal.vsTemp));
|
|
}
|
|
},
|
|
resetClimbRateLim: func() {
|
|
Internal.minVs.setValue(-500);
|
|
Internal.maxVs.setValue(500);
|
|
},
|
|
takeoffGoAround: func() {
|
|
Output.vertTemp = Output.vert.getValue();
|
|
if ((Output.vertTemp == 2 or Output.vertTemp == 6) and Velocities.indicatedAirspeedKt.getValue() >= 80) {
|
|
me.setLatMode(3);
|
|
me.setVertMode(7); # Must be before kicking AP off
|
|
me.updateVertText("G/A CLB");
|
|
Input.ktsMach.setBoolValue(0);
|
|
me.syncKtsGa();
|
|
if (Gear.wow1.getBoolValue() or Gear.wow2.getBoolValue()) {
|
|
me.ap1Master(0);
|
|
me.ap2Master(0);
|
|
}
|
|
} else if (Gear.wow1Temp or Gear.wow2Temp) {
|
|
me.athrMaster(1);
|
|
if (Output.lat.getValue() != 5) { # Don't accidently disarm LNAV
|
|
me.setLatMode(5);
|
|
}
|
|
me.setVertMode(7);
|
|
me.updateVertText("T/O CLB");
|
|
}
|
|
},
|
|
armTextCheck: func() {
|
|
if (Output.apprArm.getBoolValue()) {
|
|
Text.arm.setValue("ILS");
|
|
} else if (Output.locArm.getBoolValue()) {
|
|
Text.arm.setValue("LOC");
|
|
} else if (Output.lnavArm.getBoolValue()) {
|
|
Text.arm.setValue("LNV");
|
|
} else {
|
|
Text.arm.setValue(" ");
|
|
}
|
|
},
|
|
syncKts: func() {
|
|
Input.kts.setValue(math.clamp(math.round(Velocities.indicatedAirspeedKt.getValue()), 100, 350));
|
|
},
|
|
syncKtsGa: func() { # Same as syncKts, except doesn't go below TogaSpd
|
|
Input.kts.setValue(math.clamp(math.round(Velocities.indicatedAirspeedKt.getValue()), Settings.togaSpd.getValue(), 350));
|
|
},
|
|
syncMach: func() {
|
|
Input.mach.setValue(math.clamp(math.round(Velocities.indicatedMach.getValue(), 0.001), 0.5, 0.9));
|
|
},
|
|
syncHdg: func() {
|
|
Input.hdg.setValue(math.round(Internal.hdgPredicted.getValue())); # Switches to track automatically
|
|
},
|
|
syncAlt: func() {
|
|
Input.alt.setValue(math.clamp(math.round(Internal.altPredicted.getValue(), 100), 0, 50000));
|
|
Internal.alt.setValue(math.clamp(math.round(Internal.altPredicted.getValue(), 100), 0, 50000));
|
|
},
|
|
syncVs: func() {
|
|
Input.vs.setValue(math.clamp(math.round(Internal.vs.getValue(), 100), -6000, 6000));
|
|
},
|
|
syncFpa: func() {
|
|
Input.fpa.setValue(math.clamp(math.round(Internal.fpa.getValue(), 0.1), -9.9, 9.9));
|
|
},
|
|
# Allows custom FMA behavior if desired
|
|
updateLatText: func(t) {
|
|
Text.lat.setValue(t);
|
|
if (Settings.customFMA.getBoolValue()) {
|
|
updateFMA.lat();
|
|
}
|
|
},
|
|
updateVertText: func(t) {
|
|
Text.vert.setValue(t);
|
|
if (Settings.customFMA.getBoolValue()) {
|
|
updateFMA.vert();
|
|
}
|
|
},
|
|
updateLnavArm: func(n) {
|
|
Output.lnavArm.setBoolValue(n);
|
|
if (Settings.customFMA.getBoolValue()) {
|
|
updateFMA.arm();
|
|
}
|
|
},
|
|
updateLocArm: func(n) {
|
|
Output.locArm.setBoolValue(n);
|
|
if (Settings.customFMA.getBoolValue()) {
|
|
updateFMA.arm();
|
|
}
|
|
},
|
|
updateApprArm: func(n) {
|
|
Output.apprArm.setBoolValue(n);
|
|
if (Settings.customFMA.getBoolValue()) {
|
|
updateFMA.arm();
|
|
}
|
|
},
|
|
};
|
|
|
|
setlistener("/it-autoflight/input/ap1", func {
|
|
Input.ap1Temp = Input.ap1.getBoolValue();
|
|
if (Input.ap1Temp != Output.ap1.getBoolValue()) {
|
|
ITAF.ap1Master(Input.ap1Temp);
|
|
}
|
|
});
|
|
|
|
setlistener("/it-autoflight/input/ap2", func {
|
|
Input.ap2Temp = Input.ap2.getBoolValue();
|
|
if (Input.ap2Temp != Output.ap2.getBoolValue()) {
|
|
ITAF.ap2Master(Input.ap2Temp);
|
|
}
|
|
});
|
|
|
|
setlistener("/it-autoflight/input/athr", func {
|
|
Input.athrTemp = Input.athr.getBoolValue();
|
|
if (Input.athrTemp != Output.athr.getBoolValue()) {
|
|
ITAF.athrMaster(Input.athrTemp);
|
|
}
|
|
});
|
|
|
|
setlistener("/it-autoflight/input/fd1", func {
|
|
Input.fd1Temp = Input.fd1.getBoolValue();
|
|
if (Input.fd1Temp != Output.fd1.getBoolValue()) {
|
|
ITAF.fd1Master(Input.fd1Temp);
|
|
}
|
|
});
|
|
|
|
setlistener("/it-autoflight/input/fd2", func {
|
|
Input.fd2Temp = Input.fd2.getBoolValue();
|
|
if (Input.fd2Temp != Output.fd2.getBoolValue()) {
|
|
ITAF.fd2Master(Input.fd2Temp);
|
|
}
|
|
});
|
|
|
|
setlistener("/it-autoflight/input/kts-mach", func {
|
|
if (Input.ktsMach.getBoolValue()) {
|
|
ITAF.syncMach();
|
|
} else {
|
|
ITAF.syncKts();
|
|
}
|
|
}, 0, 0);
|
|
|
|
setlistener("/it-autoflight/input/toga", func {
|
|
if (Input.toga.getBoolValue()) {
|
|
ITAF.takeoffGoAround();
|
|
Input.toga.setBoolValue(0);
|
|
}
|
|
});
|
|
|
|
setlistener("/it-autoflight/input/lat", func {
|
|
Input.latTemp = Input.lat.getValue();
|
|
if (!Gear.wow1.getBoolValue() and !Gear.wow2.getBoolValue()) {
|
|
ITAF.setLatMode(Input.latTemp);
|
|
} else {
|
|
ITAF.setLatArm(Input.latTemp);
|
|
}
|
|
});
|
|
|
|
setlistener("/it-autoflight/input/vert", func {
|
|
if (!Gear.wow1.getBoolValue() and !Gear.wow2.getBoolValue()) {
|
|
ITAF.setVertMode(Input.vert.getValue());
|
|
}
|
|
});
|
|
|
|
setlistener("/it-autoflight/input/trk", func {
|
|
Input.trkTemp = Input.trk.getBoolValue();
|
|
if (Input.trkTemp) {
|
|
Input.hdgCalc = Input.hdg.getValue() + math.round(Internal.driftAngle.getValue());
|
|
if (Input.hdgCalc > 360) { # It's rounded, so this is ok. Otherwise do >= 360.5
|
|
Input.hdgCalc = Input.hdgCalc - 360;
|
|
} else if (Input.hdgCalc < 1) { # It's rounded, so this is ok. Otherwise do < 0.5
|
|
Input.hdgCalc = Input.hdgCalc + 360;
|
|
}
|
|
Input.hdg.setValue(Input.hdgCalc);
|
|
Custom.hdgSel.setValue(Input.hdgCalc);
|
|
} else {
|
|
Input.hdgCalc = Input.hdg.getValue() - math.round(Internal.driftAngle.getValue());
|
|
if (Input.hdgCalc > 360) { # It's rounded, so this is ok. Otherwise do >= 360.5
|
|
Input.hdgCalc = Input.hdgCalc - 360;
|
|
} else if (Input.hdgCalc < 1) { # It's rounded, so this is ok. Otherwise do < 0.5
|
|
Input.hdgCalc = Input.hdgCalc + 360;
|
|
}
|
|
Input.hdg.setValue(Input.hdgCalc);
|
|
Custom.hdgSel.setValue(Input.hdgCalc);
|
|
}
|
|
Misc.efis0Trk.setBoolValue(Input.trkTemp); # For Canvas Nav Display.
|
|
Misc.efis1Trk.setBoolValue(Input.trkTemp); # For Canvas Nav Display.
|
|
}, 0, 0);
|
|
|
|
setlistener("/sim/signals/fdm-initialized", func {
|
|
ITAF.init(0);
|
|
});
|
|
|
|
# For Canvas Nav Display.
|
|
setlistener("/it-autoflight/input/hdg", func {
|
|
setprop("/autopilot/settings/heading-bug-deg", getprop("/it-autoflight/input/hdg"));
|
|
});
|
|
|
|
setlistener("/it-autoflight/internal/alt", func {
|
|
setprop("/autopilot/settings/target-altitude-ft", getprop("/it-autoflight/internal/alt"));
|
|
});
|
|
|
|
var loopTimer = maketimer(0.1, ITAF, ITAF.loop);
|
|
var slowLoopTimer = maketimer(1, ITAF, ITAF.slowLoop);
|