# # C182S Annunciator panel # # (c) 2018 Benedikt Hallinger, public domain # # Described in POH 4-8; the lights will flash for approximately 10 seconds before turning steady on. # This is also true for the test mode toggled by the switch. ################################################################# # Infrastructure code to model the components # Define a basic panel var annunciator_panel = { node: "/instrumentation/annunciator/", volts: "/systems/electrical/outputs/annunciators", svc: "/instrumentation/annunciator/serviceable", test: "/instrumentation/annunciator/testswitch", freq: 0.5, # the blinking interval of annunciators (also used as loop interval) blink: 10, # blink for this many seconds regobj: [], # registered annunciators for main loop init: func() { me.loop = maketimer(annunciator_panel.freq, func(){ # Annunciator panel loop: check annunciator states and trigger blinking/steady lights foreach(annunc_obj; me.regobj) { annunc_obj.update(); }; }); me.loop.simulatedTime = 1; me.loop.start(); print("Annunciator panel: initialized"); }, add: func(annunc_obj) { append(me.regobj, annunc_obj); #print("DBG: Annunciator panel: added new annunciator at: "~annunc_obj.tgt); }, }; # Basic Abstract Annunciator class # modelling the state of a single annunciator that can be activated. # A display blinking value is added to a property appended with "-indicated". # Expects a sublcass that implements isTriggered()! var Annunciator = { # Returns a new Annunciator object writing to a tgt_prop new: func(tgt_prop) { return { parents: [Annunciator], tgt: tgt_prop, triggered_t: -1, }; }, # Updates the state; called by Panel class main loop update: func { var l_volts = getprop(annunciator_panel.volts); var l_svc = getprop(annunciator_panel.svc); #print(" DBG: check annunciator: "~me.tgt~" [l_volts="~l_volts~"; l_svc="~l_svc~"; testSw:"~getprop(annunciator_panel.test)~"; "); if (l_volts and l_svc and (me.isTriggered() or getprop(annunciator_panel.test) == 2)) { # Annunciator test said we are triggeed (or testswitch is engaged)! # initiate flashing or steady light var now = getprop("/sim/time/elapsed-sec"); if (me.triggered_t == -1) { # triggered the first time me.triggered_t = now; setprop(me.tgt, 1); setprop(me.tgt~"-indicated", 1); } else { # already triggered: see if we should blink or light steady var tgt_v = getprop(me.tgt~"-indicated"); if ((me.triggered_t + annunciator_panel.blink) > now) { # blink! setprop(me.tgt~"-indicated", !tgt_v); } else { # light steady! if (tgt_v != 1) { setprop(me.tgt~"-indicated", 1); } } } } else { # reset annunciator to off (cause solved or loss of power) me.triggered_t = -1; setprop(me.tgt, 0); setprop(me.tgt~"-indicated", 0); } }, }; # Annunciator class that triggers if a property value is lower than x # Extends Annunciator base class var AnnunciatorMin = { new: func(tgt_prop, src_prop, v_min) { var m = Annunciator.new(tgt_prop); # call parent constructor append(m.parents, AnnunciatorMin); m.src = src_prop; m.min = v_min; return m; }, # Expected from Annunciator base class: tests if this annunciator was triggered isTriggered: func() { if (getprop(me.src) < me.min ) { var r = 1; } else { var r = 0; } #print(" DBG: check annunciator: "~me.tgt~" ["~me.src~"] < ["~me.min~"]? => "~r); return r; }, }; # Annunciator class that triggers if a property value is higher than x # Extends Annunciator base class var AnnunciatorMax = { new: func(tgt_prop, src_prop, v_max) { var m = Annunciator.new(tgt_prop); # call parent constructor append(m.parents, AnnunciatorMax); m.src = src_prop; m.max = v_max; return m; }, # Expected from Annunciator base class: tests if this annunciator was triggered isTriggered: func() { if (getprop(me.src) > me.max ) { var r = 1; } else { var r = 0; } #print(" DBG: check annunciator: "~me.tgt~" ["~me.src~"] < ["~me.max~"]? => "~r); return r; }, }; # Annunciator class that triggers if one of the properties is true # Extends Annunciator base class var AnnunciatorOR = { new: func(tgt_prop, src_prop_list) { var m = Annunciator.new(tgt_prop); # call parent constructor append(m.parents, AnnunciatorOR); m.src = src_prop_list; return m; }, # Expected from Annunciator base class: tests if this annunciator was triggered isTriggered: func() { var r = 0; foreach(var p; me.src) { if (getprop(p) > 0) { r = 1; break; } #print(" DBG: check annunciator: "~me.tgt~" ["~p~"] > 0? => "~r); } return r; }, }; #################################################################### # Ok, lets go and define the annunciators and add them to the panel! # annunciator_panel.add( AnnunciatorMin.new(annunciator_panel.node~"volts-low", "/systems/electrical/volts", 24.5) ); annunciator_panel.add( AnnunciatorMin.new(annunciator_panel.node~"vac-low-l", "/systems/vacuum[0]/suction-inhg", 3.0) ); annunciator_panel.add( AnnunciatorMin.new(annunciator_panel.node~"vac-low-r", "/systems/vacuum[1]/suction-inhg", 3.0) ); annunciator_panel.add( AnnunciatorMin.new(annunciator_panel.node~"oilpress-low", "/engines/engine/indicated-oil-pressure-psi", 21.0) ); annunciator_panel.add( AnnunciatorMin.new(annunciator_panel.node~"fuel-low-r", "/consumables/fuel/tank[1]/indicated-level-gal_us", 8) ); annunciator_panel.add( AnnunciatorMin.new(annunciator_panel.node~"fuel-low-l", "/consumables/fuel/tank[0]/indicated-level-gal_us", 8) ); annunciator_panel.add( AnnunciatorOR.new(annunciator_panel.node~"fuel-low", ["/instrumentation/annunciator/fuel-low-l", "/instrumentation/annunciator/fuel-low-r"] ) ); annunciator_panel.add( AnnunciatorMax.new(annunciator_panel.node~"pitch-trim", "/instrumentation/annunciator/pitch-trim-trigger", 0) ); #TODO: for mor realism... the fuel detection should probably be modelled finer using a custom class: The POH says, that the annunciator nly fires if the low-condition is met for at least 60 seconds #################################################### # INIT: Start the panel code once FDM is ready setlistener("/sim/signals/fdm-initialized", func { annunciator_panel.init(); # The PITCH-TRIM annunciator needs the previuos AP state. setprop("/autopilot/kap140/panel/state-previous", 0); setprop("/autopilot/kap140/panel/state-previous-memory", 0); setlistener("/autopilot/kap140/panel/state", func(n) { var mem = getprop("/autopilot/kap140/panel/state-previous-memory"); if (getprop("autopilot/kap140/panel/button-ap") and n.getValue() == 5 and mem == 6) { setprop("/autopilot/kap140/panel/state-previous", n.getValue()); } else { setprop("/autopilot/kap140/panel/state-previous", mem); } setprop("/autopilot/kap140/panel/state-previous-memory", n.getValue()); }, 1, 0); });