1
0
Fork 0
fgdata/Nasal/FailureMgr/public.nas
Anton Gomez Alvedro 5df7a784e5 Failure Management Framework (1st milestone)
Replaces existing Nasal/failures.nas script with a programmable failure
manager. The failure manager allows dynammic creation and removal of
failure modes, on demand activation and a flexible set of triggers.
The public interface can be found in Nasal/FailureMgr/public.nas

Aircraft/Generic/Systems/failures.nas provides a library of triggers and
failure actuators ready to use for programming the failure manager.

A compatibility layer is included under
Aircraft/Generic/Systems/compat_failure_modes.nas.
This compatibility layer is currently loaded on startup and programs the
FailureMgr to emulate the former behavior (same set of failure modes and
compatible interface through the property tree).

This first milestone is only intended to replace the failure management
engine underneeth with minimum visible changes, and hopefully no aircraft
breakages. Future milestones will build upon this to add a Canvas based
procedural GUI and example integration on aircrafts.
2014-06-06 21:41:11 -05:00

229 lines
6.4 KiB
Text

# Failure Manager public interface
#
# Copyright (C) 2014 Anton Gomez Alvedro
#
# 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.
var proproot = "sim/failure-manager/";
##
# Subscribe a new failure mode to the system.
#
# id: Unique identifier for this failure mode.
# eg: "engine/carburetor-ice"
#
# description: Short text description, suitable for printing to the user.
# eg: "Ice in the carburetor"
#
# actuator: Object implementing the FailureActuator interface.
# Used by the failure manager to apply a certain level of
# failure to the failure mode.
var add_failure_mode = func(id, description, actuator) {
_failmgr.add_failure_mode(
FailureMode.new(id, description, actuator));
}
##
# Remove a failure mode from the system.
# id: FailureMode id string, e.g. "systems/pitot"
var remove_failure_mode = func(id) {
_failmgr.remove_failure_mode(id);
}
##
# Removes all failure modes from the failure manager.
var remove_all = func {
_failmgr.remove_all();
}
##
# Attaches a trigger to the given failure mode. Discards the current trigger
# if any.
#
# mode_id: FailureMode id string, e.g. "systems/pitot"
# trigger: Trigger object or nil. Nil will just detach the current trigger
var set_trigger = func(mode_id, trigger) {
_failmgr.set_trigger(mode_id, trigger);
}
##
# Returns the trigger object attached to the given failure mode.
# mode_id: FailureMode id string, e.g. "systems/pitot"
var get_trigger = func(mode_id) {
_failmgr.get_trigger(mode_id);
}
##
# Applies a certain level of failure to this failure mode.
#
# mode_id: Failure mode id string.
# level: Floating point number in the range [0, 1]
# Zero represents no failure and one means total failure.
var set_failure_level = func (mode_id, level) {
setprop(proproot ~ mode_id ~ "/failure-level", level);
}
##
# Allows applications to disable the failure manager and restore it later on.
# While disabled, no failure modes will be activated from the failure manager.
var enable = func setprop(proproot ~ "enabled", 1);
var disable = func setprop(proproot ~ "enabled", 0);
##
# Encapsulates a condition that when met, will make the failure manager to
# apply a certain level of failure to the failure mode it is bound to.
#
# Two types of triggers are supported: pollable and asynchronous.
#
# Pollable triggers require periodic check for trigger conditions. For example,
# an altitude trigger will need to poll current altitude until the fire
# condition is reached.
#
# Asynchronous trigger do not require periodic updates. They can detect
# the firing condition by themselves by using timers or listeners.
# Async triggers must call the inherited method on_fire() to let the Failure
# Manager know about the fired condition.
#
# See Aircraft/Generic/Systems/failures.nas for concrete examples of triggers.
var Trigger = {
# 1 for pollable triggers, 0 for async triggers.
requires_polling: 0,
new: func {
return {
parents: [Trigger],
params: {},
fired: 0,
##
# Async triggers shall call the on_fire() callback when their fire
# conditions are met to notify the failure manager.
on_fire: func 0,
_path: nil
};
},
##
# Enables/disables the trigger. While a trigger is disabled, any timer
# or listener that could potentially own shall be disabled.
enable: func,
disable: func,
##
# Forces a check of the firing conditions. Returns 1 if the trigger fired,
# 0 otherwise.
update: func 0,
##
# Returns a printable string describing the trigger condition.
to_str: func "undefined trigger",
##
# Modify a trigger parameter. Parameters will take effect after the next
# call to reset()
set_param: func(param, value) {
contains(me.params, param) or
die("Trigger.set_param: undefined param: " ~ param);
me._path != nil or
die("Trigger.set_param: Unbound trigger");
setprop(sprintf("%s/%s",me._path, param), value);
},
##
# Reload trigger parameters and reset internal state, i.e. start from
# scratch. If the trigger was fired, the trigger is set to not fired.
reset: func {
me._path or die("Trigger.reset: unbound trigger");
foreach (var p; keys(me.params))
me.params[p] = getprop(sprintf("%s/%s", me._path, p));
me.fired = 0;
me._path != nil and setprop(me._path ~ "/reset", 0);
},
##
# Creates an interface for the trigger in the property tree.
# Every parameter in the params hash will be exposed, in addition to
# a path/reset property for resetting the trigger from the prop tree.
bind: func(path) {
me._path == nil or
die("Trigger.bind(): attempt to bind an already bound trigger");
me._path = path;
props.globals.getNode(path) != nil or props.globals.initNode(path);
props.globals.getNode(path).setValues(me.params);
var reset_prop = path ~ "/reset";
props.globals.initNode(reset_prop, 0, "BOOL");
setlistener(reset_prop, func me.reset(), 0, 0);
},
##
# Removes this trigger's interface from the property tree.
unbind: func {
props.globals.getNode(me._path ~ "/reset").remove();
foreach (var p; keys(me.params))
props.globals.getNode(me._path ~ "/" ~ p).remove();
me._path = nil;
}
};
##
# FailureActuators encapsulate the actions required for activating the actual
# failure simulation.
#
# Traditionally this action was just manipulating a "serviceable" property
# somewhere, but the FailureActuator gives you more flexibility, allowing you
# to touch several properties at once or call other Nasal scripts, for example.
#
# See Aircraft/Generic/Systems/failure.nas and
# Aircraft/Generic/Systems/compat_failures.nas for some examples of actuators.
var FailureActuator = {
##
# Called from the failure manager to activate a certain level of failure.
# level: Target level of failure [0 to 1].
set_failure_level: func(level) 0,
##
# Returns the level of failure that is currently being simulated.
get_failure_level: func 0,
};