Merge requests #12
This commit is contained in:
commit
d3dc9b013c
1 changed files with 277 additions and 0 deletions
277
Aircraft/Generic/autochecklist.nas
Normal file
277
Aircraft/Generic/autochecklist.nas
Normal file
|
@ -0,0 +1,277 @@
|
|||
################################################################################
|
||||
#
|
||||
# Automated Checklists
|
||||
#
|
||||
# Copyright (c) 2015, Richard Senior
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
# MA 02110-1301, USA.
|
||||
#
|
||||
################################################################################
|
||||
#
|
||||
# This script runs the bindings in a sequence of checklists. Typically used
|
||||
# to implement autostart or shutdown but can run any checklist sequence at any
|
||||
# time. Checklist execution runs each binding where the condition is not yet
|
||||
# satisfied and waits until the condition becomes true before moving on. If
|
||||
# the condition does not become true within a timeout period, the checklist
|
||||
# execution fails.
|
||||
#
|
||||
# Can also run in no wait mode where items are run in order without waiting
|
||||
# for the previous condition to become true. Checklists never timeout or fail
|
||||
# in no wait mode but some conditions may remain false.
|
||||
#
|
||||
# Typical usage:
|
||||
#
|
||||
# 1. Add this script to <Aircraft>-set.xml:
|
||||
#
|
||||
# <nasal>
|
||||
# ... other scripts here
|
||||
# <autochecklist>
|
||||
# <file>Aircraft/Generic/autochecklist.nas</file>
|
||||
# </autochecklist>
|
||||
# </nasal>
|
||||
#
|
||||
# 2. In the <Aircraft>-set.xml, define a list of checklist indexes to run
|
||||
# as a named sequence.
|
||||
#
|
||||
# For example, to run checklists with indexes 0 and 1 for startup and
|
||||
# checklist 9 for shutdown:
|
||||
#
|
||||
# <checklists>
|
||||
# <checklist include="Checklists/before-starting-engines.xml"/>
|
||||
# <checklist include="Checklists/start-engines.xml"/>
|
||||
# ... more checklists here
|
||||
# <checklist include="Checklists/parking.xml"/>
|
||||
# <startup>
|
||||
# <index n="0">0</index> <!-- Before starting engines -->
|
||||
# <index n="1">1</index> <!-- Start engines -->
|
||||
# </startup>
|
||||
# <shutdown>
|
||||
# <index n="0">9</index> <!-- Parking -->
|
||||
# </startup>
|
||||
# </checklists>
|
||||
#
|
||||
# 3. Define a menu item that calls the complete_checklists function with
|
||||
# the name of the checklist sequence you would like to run.
|
||||
#
|
||||
# For example:
|
||||
#
|
||||
# <item>
|
||||
# <label>Autostart</label>
|
||||
# <binding>
|
||||
# <command>nasal</command>
|
||||
# <script>autochecklist.complete_checklists("startup");</script>
|
||||
# </binding>
|
||||
# </item>
|
||||
#
|
||||
# For a no wait checklist execution (which will never fail), pass zero (0)
|
||||
# as the second argument:
|
||||
#
|
||||
# autochecklist.complete_checklists(sequence:"startup", wait:0);
|
||||
#
|
||||
# 4. Optionally, configure automated execution using the following properties.
|
||||
# See comments within the autochecklist_init function for a description.
|
||||
#
|
||||
# <checklists>
|
||||
# ...
|
||||
# <auto>
|
||||
# <completed-message>Checklists complete</completed-message>
|
||||
# <startup-message>Running checklists, please wait ...</startup-message>
|
||||
# <timeout-message>Some checks failed.</timeout-message>
|
||||
# <timeout-sec>10</timeout-sec>
|
||||
# <wait-sec>3</wait-sec>
|
||||
# <auto>
|
||||
# </checklists>
|
||||
#
|
||||
# Note that messages are not displayed for no wait execution.
|
||||
#
|
||||
################################################################################
|
||||
|
||||
var checklists = nil;
|
||||
var auto = nil;
|
||||
var active = nil;
|
||||
var timeout_sec = nil;
|
||||
var timeout_start = nil;
|
||||
var wait_sec = nil;
|
||||
var completed_message = nil;
|
||||
var startup_message = nil;
|
||||
var timeout_message = nil;
|
||||
|
||||
var autochecklist_init = func()
|
||||
{
|
||||
# Root property tree path for checklists
|
||||
#
|
||||
checklists = props.globals.getNode("sim/checklists");
|
||||
|
||||
# Root property tree path for auto checklists
|
||||
#
|
||||
auto = checklists.initNode("auto");
|
||||
|
||||
# Flag to indicate that checklists are being completed automatically.
|
||||
# This can be used in Nasal bindings in the checklists to suppress a
|
||||
# binding when automated execution is in progress, e.g. for checklist
|
||||
# items that display dialogs.
|
||||
#
|
||||
active = auto.initNode("active", 0, "BOOL");
|
||||
|
||||
# Timeout for completion of a checklist item. If the previous condition
|
||||
# is still not satisifed after this timeout, the checklist fails.
|
||||
#
|
||||
timeout_sec = auto.initNode("timeout-sec", 10, "INT");
|
||||
timeout_start = auto.initNode("timeout-start", 0.0, "DOUBLE");
|
||||
|
||||
# If the previous checklist item is not complete, the process waits
|
||||
# this number of seconds before trying again.
|
||||
#
|
||||
wait_sec = auto.initNode("wait-sec", 3, "INT");
|
||||
|
||||
# Messages
|
||||
#
|
||||
completed_message = auto.initNode("completed-message",
|
||||
"Checklists complete."
|
||||
);
|
||||
|
||||
startup_message = auto.initNode("startup-message",
|
||||
"Running checklists, please wait ..."
|
||||
);
|
||||
|
||||
timeout_message = auto.initNode("timeout-message",
|
||||
"Some checks failed. Try completing checklist manually."
|
||||
);
|
||||
}
|
||||
|
||||
################################################################################
|
||||
|
||||
# Announces a message to the pilot
|
||||
#
|
||||
# @param message: the message to display
|
||||
#
|
||||
var announce = func(message)
|
||||
{
|
||||
setprop("sim/messages/copilot", message);
|
||||
logprint(3, message);
|
||||
}
|
||||
|
||||
# Resets the timestamp used for checking timeouts
|
||||
#
|
||||
var reset_timeout = func()
|
||||
{
|
||||
timeout_start.setValue(0.0);
|
||||
}
|
||||
|
||||
# Return true if the timeout period has been exceeded
|
||||
#
|
||||
var timed_out = func()
|
||||
{
|
||||
var elapsed = getprop("sim/time/elapsed-sec") - timeout_start.getValue();
|
||||
return timeout_start.getValue() and elapsed > timeout_sec.getValue();
|
||||
}
|
||||
|
||||
# Waits for the completion of an item, setting a timestamp for timeouts
|
||||
#
|
||||
# @param node: the node containing the list of checklist indexes to run
|
||||
# @param from: the checklist item node from which to start
|
||||
#
|
||||
var wait_for_completion = func(node, from)
|
||||
{
|
||||
var t = maketimer(wait_sec.getValue(), func {
|
||||
complete(node, 1, from);
|
||||
});
|
||||
t.singleShot = 1;
|
||||
t.start();
|
||||
|
||||
if (!timeout_start.getValue()) {
|
||||
timeout_start.setValue(getprop("sim/time/elapsed-sec"));
|
||||
}
|
||||
}
|
||||
|
||||
# Automatically complete a set of checklists defined by a series of indexes
|
||||
# listed under the node argument. Not intended to be called from outside this
|
||||
# script.
|
||||
#
|
||||
# @param node: the node containing the list of checklist indexes to run
|
||||
# @param wait: whether to wait for the preceding binding to complete
|
||||
# @param from: the checklist item node from which to start, default nil
|
||||
#
|
||||
var complete = func(node, wait, from = nil)
|
||||
{
|
||||
var previous_condition = nil;
|
||||
var skipping = from != nil;
|
||||
|
||||
foreach (var index; node.getChildren("index")) {
|
||||
var checklist = checklists.getChild("checklist", index.getValue());
|
||||
foreach (var item; checklist.getChildren("item")) {
|
||||
var condition = item.getNode("condition");
|
||||
if (skipping) {
|
||||
if (!item.equals(from)) {
|
||||
previous_condition = condition;
|
||||
continue;
|
||||
}
|
||||
skipping = 0;
|
||||
}
|
||||
if (wait) {
|
||||
if (props.condition(previous_condition)) {
|
||||
reset_timeout();
|
||||
} else {
|
||||
if (timed_out()) {
|
||||
var title = checklist.getNode("title").getValue();
|
||||
announce(title~": "~timeout_message.getValue());
|
||||
} else {
|
||||
wait_for_completion(node: node, from: item);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!props.condition(condition)) {
|
||||
foreach (var binding; item.getChildren("binding")) {
|
||||
active.setValue(1);
|
||||
props.runBinding(binding);
|
||||
active.setValue(0);
|
||||
}
|
||||
}
|
||||
previous_condition = condition;
|
||||
}
|
||||
}
|
||||
if (wait) {
|
||||
announce(completed_message.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
################################################################################
|
||||
|
||||
# Complete a checklist sequence, typically called from a Nasal binding in a
|
||||
# menu, e.g. Autostart, but could be assigned to a controller button or even
|
||||
# called from a listener.
|
||||
#
|
||||
# @param sequence: the name of the checklist sequence to run
|
||||
# @param wait: whether to wait for the preceding binding, default 1 (true)
|
||||
#
|
||||
var complete_checklists = func(sequence, wait = 1)
|
||||
{
|
||||
var node = checklists.getNode(sequence);
|
||||
if (node != nil) {
|
||||
if (wait) {
|
||||
announce(startup_message.getValue());
|
||||
}
|
||||
complete(node, wait);
|
||||
} else {
|
||||
announce("Could not find checklist sequence called '"~sequence~"'");
|
||||
}
|
||||
}
|
||||
|
||||
setlistener("/sim/signals/fdm-initialized", func() {
|
||||
autochecklist_init();
|
||||
});
|
||||
|
Loading…
Reference in a new issue