2019-11-02 14:52:06 +00:00
# A3XX ADIRS System
# Jonathan Redpath (legoboyvdlp)
# Copyright (c) 2019 Jonathan Redpath (legoboyvdlp)
var _NUMADIRU = 3;
2019-11-04 19:20:56 +00:00
var _selfTestTime = nil;
2020-11-05 20:58:25 +00:00
var ADIRSnodesND = [props.globals.getNode("/instrumentation/efis[0]/nd/ir-1", 1),props.globals.getNode("/instrumentation/efis[1]/nd/ir-2", 1),props.globals.getNode("/instrumentation/efis[0]/nd/ir-3", 1)];
2019-11-06 19:09:42 +00:00
var ADIRU = {
2019-11-04 19:20:56 +00:00
# methods
2019-11-06 19:09:42 +00:00
new: func(n) {
var adiru = { parents:[ADIRU] };
adiru.num = n;
2020-11-22 17:28:08 +00:00
adiru._alignTime = 0;
adiru._pfdTime = 0;
adiru._voltageMain = 0;
adiru._voltageBackup = 0;
adiru._voltageLimitedTime = 0;
adiru._noPowerTime = 0;
adiru._timeVar = 0;
adiru._roll = 0;
adiru._pitch = 0;
adiru._gs = 0;
adiru.aligned = 0;
adiru.operating = 0; # ir operating - used for PFD + fbw failure
adiru.inAlign = 0;
adiru.outputOn = 1; # 0 = disc; 1 = normal
adiru.mode = 0; # 0 = off; 1 = nav; 2 = att
adiru.energised = 0; # 0 = off; 1 = on
adiru.operative = 0; # 0 = off;
adiru.alignTimer = nil;
adiru.input = [];
adiru.output = [];
2019-12-08 19:51:37 +00:00
adiru.alignTimer = maketimer(0.1, adiru, me.alignLoop);
2020-04-18 12:16:47 +00:00
2019-11-06 19:09:42 +00:00
return adiru;
2019-11-02 14:52:06 +00:00
},
2019-12-08 19:51:37 +00:00
setOperative: func(newOperative) {
if (newOperative != me.operative) {
me.operative = newOperative;
if (newOperative) {
me.selfTest();
}
}
},
# Power and state
2019-11-04 19:20:56 +00:00
updateEnergised: func(mode) {
me.energised = mode != 0 ? 1 : 0;
},
updatePower: func(elec) {
me._voltageMain = elec.getValue() or 0;
return me._voltageMain;
},
updateBackupPower: func(elec, isLimited) {
me._voltageBackup = elec.getValue() or 0;
me._voltageLimitedTime = isLimited;
return me._voltageBackup;
},
2019-12-08 19:51:37 +00:00
# BITE
2019-11-04 19:20:56 +00:00
selfTest: func() {
2020-05-01 08:41:39 +00:00
ADIRS._selfTest = 1;
2019-11-04 19:20:56 +00:00
_selfTestTime = pts.Sim.Time.elapsedSec.getValue();
2020-05-01 08:41:39 +00:00
ADIRS.Lights.adrOff[me.num].setValue(1);
ADIRS.Lights.adrFault[me.num].setValue(1);
2019-11-06 19:09:42 +00:00
settimer(func() {
2020-05-01 08:41:39 +00:00
ADIRS.Lights.adrOff[me.num].setValue(0);
ADIRS.Lights.adrFault[me.num].setValue(0);
2019-11-06 19:09:42 +00:00
}, 0.1);
settimer(func() {
2020-05-01 08:41:39 +00:00
ADIRS.Lights.adrOff[me.num].setValue(1);
ADIRS.Lights.adrFault[me.num].setValue(1);
ADIRS.Lights.irFault[me.num].setValue(1);
ADIRS.Lights.irOff[me.num].setValue(1);
2019-11-06 19:09:42 +00:00
}, 1.0);
settimer(func() {
2020-05-01 11:47:53 +00:00
ADIRS.Lights.adrOff[me.num].setValue(!ADIRS.Switches.adrSw[me.num].getValue());
2020-05-01 08:41:39 +00:00
ADIRS.Lights.adrFault[me.num].setValue(0);
ADIRS.Lights.irFault[me.num].setValue(0);
2020-05-01 14:20:21 +00:00
ADIRS.Lights.irOff[me.num].setValue(0);
2019-11-06 19:09:42 +00:00
}, 1.1);
2020-05-01 08:41:39 +00:00
ADIRS.selfTest();
2019-11-04 19:20:56 +00:00
},
2019-12-08 19:51:37 +00:00
# Alignment
align: func(time) {
2020-05-01 08:41:39 +00:00
ADIRS.Lights.irFault[me.num].setBoolValue(0);
if (!ADIRS.skip.getValue()) {
2019-12-08 19:51:37 +00:00
if (time > 0 and me.aligned == 0 and me.inAlign == 0 and me.operative == 1) {
me._alignTime = pts.Sim.Time.elapsedSec.getValue() + time;
2020-11-22 17:28:08 +00:00
me._pfdTime = pts.Sim.Time.elapsedSec.getValue() + 20 + (rand() * 5);
2019-12-08 19:51:37 +00:00
me.inAlign = 1;
if (me.alignTimer != nil) {
me.alignTimer.start();
}
}
} else {
if (me.aligned == 0 and me.inAlign == 0 and me.operative == 1) {
me._alignTime = pts.Sim.Time.elapsedSec.getValue() + 5;
2020-11-22 17:28:08 +00:00
me._pfdTime = pts.Sim.Time.elapsedSec.getValue() + 1;
2019-12-08 19:51:37 +00:00
me.inAlign = 1;
if (me.alignTimer != nil) {
me.alignTimer.start();
}
2019-11-04 19:20:56 +00:00
}
}
},
2019-12-08 19:51:37 +00:00
stopAlignNoAlign: func() {
print("Stopping alignment or setting unaligned state");
me.inAlign = 0;
me.aligned = 0;
2020-11-05 20:58:25 +00:00
ADIRSnodesND[me.num].setValue(0);
2020-05-01 08:42:09 +00:00
ADIRS.Operating.aligned[me.num].setValue(0);
2020-11-22 17:28:08 +00:00
me.operating = 0;
2019-12-08 19:51:37 +00:00
if (me.alignTimer != nil) {
me.alignTimer.stop();
}
2020-11-07 19:07:55 +00:00
foreach (var predicate; keys(canvas_nd.ND_1.NDCpt.predicates)) {
call(canvas_nd.ND_1.NDCpt.predicates[predicate]);
}
foreach (var predicate; keys(canvas_nd.ND_2.NDFo.predicates)) {
call(canvas_nd.ND_2.NDFo.predicates[predicate]);
}
2019-12-08 19:51:37 +00:00
},
2020-11-22 17:28:08 +00:00
irOperating: func() {
me.operating = 1;
},
2019-12-08 19:51:37 +00:00
stopAlignAligned: func() {
me.inAlign = 0;
me.aligned = 1;
2020-11-05 20:58:25 +00:00
ADIRSnodesND[me.num].setValue(1);
2020-05-01 08:42:09 +00:00
ADIRS.Operating.aligned[me.num].setValue(1);
2019-12-08 19:51:37 +00:00
if (me.alignTimer != nil) {
me.alignTimer.stop();
}
2020-11-07 19:07:55 +00:00
foreach (var predicate; keys(canvas_nd.ND_1.NDCpt.predicates)) {
call(canvas_nd.ND_1.NDCpt.predicates[predicate]);
}
foreach (var predicate; keys(canvas_nd.ND_2.NDFo.predicates)) {
call(canvas_nd.ND_2.NDFo.predicates[predicate]);
}
2019-12-08 19:51:37 +00:00
},
2021-01-28 11:14:03 +00:00
_excessMotion: 0,
2019-12-08 19:51:37 +00:00
alignLoop: func() {
me._roll = pts.Orientation.roll.getValue();
me._pitch = pts.Orientation.pitch.getValue();
me._gs = pts.Velocities.groundspeed.getValue();
# todo use IR values
if (me._gs > 5 or abs(me._pitch) > 5 or abs(me._roll) > 10) {
me.stopAlignNoAlign();
2021-01-28 11:14:03 +00:00
me._excessMotion = 1;
2019-12-08 19:51:37 +00:00
print("Excessive motion, restarting");
me.update(); # update operative
me.align(calcAlignTime(pts.Position.latitude.getValue()));
} elsif (me.operative == 0) {
me.stopAlignNoAlign();
2021-01-28 11:14:03 +00:00
me._excessMotion = 0;
2019-12-08 19:51:37 +00:00
} elsif (pts.Sim.Time.elapsedSec.getValue() >= me._alignTime) {
me.stopAlignAligned();
2021-01-28 11:14:03 +00:00
me._excessMotion = 0;
} else {
me._excessMotion = 0;
2019-12-08 19:51:37 +00:00
}
2020-11-22 17:28:08 +00:00
if (!me.operating and pts.Sim.Time.elapsedSec.getValue() >= me._pfdTime) {
me.irOperating();
}
2019-12-08 19:51:37 +00:00
},
instAlign: func() {
me.stopAlignAligned();
2020-11-22 17:28:08 +00:00
me.irOperating();
2019-12-08 19:51:37 +00:00
},
# Update loop
2019-11-04 19:20:56 +00:00
update: func() {
me._timeVar = pts.Sim.Time.elapsedSec.getValue();
if (me.energised and !me._voltageMain and me._voltageLimitedTime and me._noPowerTime == 0) {
me._noPowerTime = me._timeVar;
}
if (me.energised and me.mode) {
if (me._voltageMain) {
me._noPowerTime = 0;
me.setOperative(1);
2020-05-01 08:41:39 +00:00
if (!ADIRS._selfTest) {
ADIRS.Lights.onBat.setBoolValue(0);
2019-11-04 19:20:56 +00:00
}
} elsif (((me._timeVar < me._noPowerTime + 300 and me._voltageLimitedTime) or !me._voltageLimitedTime) and me._voltageBackup) {
me.setOperative(1);
2020-05-01 08:41:39 +00:00
if (!ADIRS._selfTest) {
ADIRS.Lights.onBat.setBoolValue(1);
2019-11-04 19:20:56 +00:00
}
} else {
me._noPowerTime = 0;
me.setOperative(0);
2020-05-01 08:41:39 +00:00
if (!ADIRS._selfTest) {
ADIRS.Lights.onBat.setBoolValue(0);
2019-11-04 19:20:56 +00:00
}
}
} else {
me._noPowerTime = 0;
me.setOperative(0);
2020-05-01 08:41:39 +00:00
if (!ADIRS._selfTest) {
ADIRS.Lights.onBat.setBoolValue(0);
2019-11-04 19:20:56 +00:00
}
}
2019-11-02 14:52:06 +00:00
},
};
var ADIRSControlPanel = {
2019-11-04 19:20:56 +00:00
adrSw: func(n) {
if (n < 0 or n > _NUMADIRU) { return; }
2020-05-01 08:41:39 +00:00
ADIRS._adrSwitchState = ADIRS.Switches.adrSw[n].getValue();
ADIRS.Switches.adrSw[n].setValue(!ADIRS._adrSwitchState);
if (ADIRS.ADIRunits[n] != nil) {
ADIRS.ADIRunits[n].outputOn = !ADIRS._adrSwitchState;
2019-11-04 19:20:56 +00:00
}
2020-05-01 08:41:39 +00:00
ADIRS.Lights.adrOff[n].setValue(ADIRS._adrSwitchState);
2019-11-04 19:20:56 +00:00
},
irSw: func(n) {
if (n < 0 or n > _NUMADIRU) { return; }
2020-05-01 08:41:39 +00:00
ADIRS._irSwitchState = ADIRS.Switches.irSw[n].getValue();
ADIRS.Switches.irSw[n].setValue(!ADIRS._irSwitchState);
if (ADIRS.IRunits[n] != nil) {
ADIRS.IRunits[n].outputOn = !ADIRS._irSwitchState;
2019-11-04 19:20:56 +00:00
}
2020-05-01 08:41:39 +00:00
ADIRS.Lights.irOff[n].setValue(ADIRS._adrSwitchState);
2019-11-04 19:20:56 +00:00
},
irModeSw: func(n, mode) {
if (n < 0 or n > _NUMADIRU) { return; }
if (mode < 0 or mode > 2) { return; }
2020-05-01 08:41:39 +00:00
me._irModeSwitchState = ADIRS.Switches.irModeSw[n].getValue();
if (ADIRS.ADIRunits[n] != nil) {
ADIRS.ADIRunits[n].mode = mode;
ADIRS.ADIRunits[n].updateEnergised(mode);
ADIRS.Switches.irModeSw[n].setValue(mode);
2019-12-08 19:51:37 +00:00
if (mode == 0) {
2020-05-01 08:41:39 +00:00
ADIRS.Lights.irFault[n].setBoolValue(0);
ADIRS.ADIRunits[n].stopAlignNoAlign();
} elsif (ADIRS.ADIRunits[n].aligned == 0) {
ADIRS.ADIRunits[n].update(); # update early so operative is set properly
ADIRS.ADIRunits[n].align(calcAlignTime(pts.Position.latitude.getValue())); # when you set NAV, it first acquires GPS position then acquires GPS. You then use IRS INIT > to set PPOS to align if you wish
2019-12-08 19:51:37 +00:00
}
2019-11-04 19:20:56 +00:00
}
}
};
2020-05-01 08:41:39 +00:00
var ADIRS = {
2019-11-02 14:52:06 +00:00
# local vars
_adrSwitchState: 0,
_irSwitchState: 0,
_irModeSwitchState: 0,
2019-11-04 19:20:56 +00:00
_hasPower: 0,
2019-11-06 19:09:42 +00:00
_cacheOperative: [0, 0, 0],
2020-05-01 16:46:53 +00:00
_cacheOutputOn: [1, 1, 1],
2019-11-04 19:20:56 +00:00
_flapPos: nil,
_slatPos: nil,
_selfTest: 0,
_init: 0,
2019-11-02 14:52:06 +00:00
# ADIRS Units
2019-11-06 19:09:42 +00:00
ADIRunits: [nil, nil, nil],
2019-11-02 14:52:06 +00:00
2019-11-04 19:20:56 +00:00
# Electrical
mainSupply: [systems.ELEC.Bus.acEss, systems.ELEC.Bus.ac2, systems.ELEC.Bus.ac1],
2020-05-03 16:13:49 +00:00
backupSupply: [[systems.ELEC.Source.Bat2.volt, 0], [systems.ELEC.Source.Bat2.volt, 1], [systems.ELEC.Source.Bat1.volt, 1]],
# ADIRS power directly from a separate bus connected to battery (no c.b. unlike main hot bus), as they are so critical
2019-11-04 19:20:56 +00:00
2019-11-02 14:52:06 +00:00
# PTS
Lights: {
2020-05-01 08:42:09 +00:00
adrFault: [props.globals.getNode("/controls/navigation/adirscp/lights/adr-1-fault"), props.globals.getNode("/controls/navigation/adirscp/lights/adr-2-fault"), props.globals.getNode("/controls/navigation/adirscp/lights/adr-3-fault")],
adrOff: [props.globals.getNode("/controls/navigation/adirscp/lights/adr-1-off"), props.globals.getNode("/controls/navigation/adirscp/lights/adr-2-off"), props.globals.getNode("/controls/navigation/adirscp/lights/adr-3-off")],
irFault: [props.globals.getNode("/controls/navigation/adirscp/lights/ir-1-fault"), props.globals.getNode("/controls/navigation/adirscp/lights/ir-2-fault"), props.globals.getNode("/controls/navigation/adirscp/lights/ir-3-fault")],
irOff: [props.globals.getNode("/controls/navigation/adirscp/lights/ir-1-off"), props.globals.getNode("/controls/navigation/adirscp/lights/ir-2-off"), props.globals.getNode("/controls/navigation/adirscp/lights/ir-3-off")],
onBat: props.globals.getNode("/controls/navigation/adirscp/lights/on-bat"),
2019-11-02 14:52:06 +00:00
},
Switches: {
2020-05-01 08:42:09 +00:00
adrSw: [props.globals.getNode("/controls/navigation/adirscp/switches/adr-1"), props.globals.getNode("/controls/navigation/adirscp/switches/adr-2"), props.globals.getNode("/controls/navigation/adirscp/switches/adr-3")],
irModeSw: [props.globals.getNode("/controls/navigation/adirscp/switches/ir-1-mode"), props.globals.getNode("/controls/navigation/adirscp/switches/ir-2-mode"), props.globals.getNode("/controls/navigation/adirscp/switches/ir-3-mode")],
irSw: [props.globals.getNode("/controls/navigation/adirscp/switches/ir-1"), props.globals.getNode("/controls/navigation/adirscp/switches/ir-2"), props.globals.getNode("/controls/navigation/adirscp/switches/ir-3")],
2019-11-02 14:52:06 +00:00
},
2019-11-04 19:20:56 +00:00
Operating: {
2020-05-01 08:42:09 +00:00
adr: [props.globals.getNode("/systems/navigation/adr/operating-1"), props.globals.getNode("/systems/navigation/adr/operating-2"), props.globals.getNode("/systems/navigation/adr/operating-3")],
aligned: [props.globals.getNode("/systems/navigation/aligned-1"), props.globals.getNode("/systems/navigation/aligned-2"), props.globals.getNode("/systems/navigation/aligned-3")],
2019-11-04 19:20:56 +00:00
},
# Nodes
2019-11-02 14:52:06 +00:00
overspeedVFE: props.globals.initNode("/systems/navigation/adr/computation/overspeed-vfe-spd", 0, "INT"),
2019-12-08 19:51:37 +00:00
skip: props.globals.initNode("/controls/adirs/skip", 0, "BOOL"),
mcduControl: props.globals.initNode("/controls/adirs/mcducbtn", 0, "BOOL"),
2019-11-04 19:20:56 +00:00
# System
2019-11-02 14:52:06 +00:00
init: func() {
2019-11-04 19:20:56 +00:00
if (!me._init) {
for (i = 0; i < _NUMADIRU; i = i + 1) {
2019-11-06 19:09:42 +00:00
me.ADIRunits[i] = ADIRU.new(i);
2019-11-04 19:20:56 +00:00
me._init = 1;
}
2019-11-02 14:52:06 +00:00
}
},
update_items: [
props.UpdateManager.FromPropertyHashList(["/fdm/jsbsim/fcs/flap-pos-deg","/fdm/jsbsim/fcs/slat-pos-deg"], 0.1, func(notification)
{
2020-04-27 15:37:43 +00:00
me._flapPos = pts.Fdm.JSBsim.Fcs.flapDeg.getValue();
me._slatPos = pts.Fdm.JSBsim.Fcs.slatDeg.getValue();
2019-11-02 14:52:06 +00:00
if (me._flapPos >= 23 and me._slatPos >= 25) {
2020-05-01 08:41:39 +00:00
ADIRS.overspeedVFE.setValue(181);
2019-11-02 14:52:06 +00:00
} elsif (me._flapPos >= 18) {
2020-05-01 08:41:39 +00:00
ADIRS.overspeedVFE.setValue(189);
2019-11-02 14:52:06 +00:00
} elsif (me._flapPos >= 13 or me._slatPos > 20) {
2020-05-01 08:41:39 +00:00
ADIRS.overspeedVFE.setValue(204);
2019-11-02 14:52:06 +00:00
} elsif (me._slatPos <= 20 and me._flapPos > 2) {
2020-05-01 08:41:39 +00:00
ADIRS.overspeedVFE.setValue(219);
2019-11-02 14:52:06 +00:00
} elsif (me._slatPos >= 2 and me._slatPos <= 20) {
2020-05-01 08:41:39 +00:00
ADIRS.overspeedVFE.setValue(234);
2019-11-02 14:52:06 +00:00
} else {
2020-05-01 08:41:39 +00:00
ADIRS.overspeedVFE.setValue(1024);
2019-11-02 14:52:06 +00:00
}
}
),
],
loop: func() {
2019-11-04 19:20:56 +00:00
if (me._init) {
for (i = 0; i < _NUMADIRU; i = i + 1) {
# update ADR units power
2019-11-06 19:09:42 +00:00
me._hasPower = me.ADIRunits[i].updatePower(me.mainSupply[i]);
2019-11-04 19:20:56 +00:00
if (me._hasPower == 0) {
2019-11-06 19:09:42 +00:00
me.ADIRunits[i].updateBackupPower(me.backupSupply[i][0],me.backupSupply[i][1])
2019-11-04 19:20:56 +00:00
}
# Update ADR units
2019-11-06 19:09:42 +00:00
me.ADIRunits[i].update();
2019-11-04 19:20:56 +00:00
2019-11-06 19:09:42 +00:00
if (me.ADIRunits[i].operative != me._cacheOperative[i] or me.ADIRunits[i].outputOn != me._cacheOutputOn[i]) {
me._cacheOperative[i] = me.ADIRunits[i].operative;
me._cacheOutputOn[i] = me.ADIRunits[i].outputOn;
if (me.ADIRunits[i].outputOn) {
me.Operating.adr[i].setValue(me.ADIRunits[i].operative);
2019-11-04 19:20:56 +00:00
} else {
me.Operating.adr[i].setValue(0);
}
}
}
# Update VFE
notification = nil;
foreach (var update_item; me.update_items) {
update_item.update(notification);
}
2019-11-02 14:52:06 +00:00
}
},
2019-11-04 19:20:56 +00:00
selfTest: func() {
2020-05-01 08:41:39 +00:00
ADIRS.Lights.onBat.setBoolValue(1);
2019-11-04 19:20:56 +00:00
selfTestLoop.start();
},
2019-11-02 14:52:06 +00:00
};
2019-11-04 19:20:56 +00:00
2019-12-08 19:51:37 +00:00
var calcAlignTime = func(latitude) {
return ((0.002 * (latitude * latitude)) + 5) * 60;
};
2019-11-30 13:39:53 +00:00
setlistener("/systems/fmgc/cas-compare/cas-reject-all", func() {
2020-04-27 13:58:38 +00:00
if (pts.FMGC.CasCompare.casRejectAll.getBoolValue()) {
2019-11-30 13:39:53 +00:00
fcu.athrOff("hard");
}
}, 0, 0);
2019-12-08 19:51:37 +00:00
setlistener("/controls/adirs/skip", func() {
2020-05-01 08:41:39 +00:00
if (ADIRS.skip.getBoolValue()) {
2019-12-08 19:51:37 +00:00
for (i = 0; i < 3; i = i + 1) {
2020-05-01 08:41:39 +00:00
if (ADIRS.ADIRunits[i].inAlign == 1) {
ADIRS.ADIRunits[i].stopAlignAligned();
2019-12-08 19:51:37 +00:00
}
}
}
}, 0, 0);
2019-11-04 19:20:56 +00:00
selfTestLoop = maketimer(0.2, func() {
if (pts.Sim.Time.elapsedSec.getValue() > _selfTestTime + 5) {
2020-05-01 08:41:39 +00:00
ADIRS.Lights.onBat.setBoolValue(0);
2019-11-04 19:20:56 +00:00
selfTestLoop.stop();
2020-05-01 08:41:39 +00:00
ADIRS._selfTest = 0;
2019-11-04 19:20:56 +00:00
}
});