Nasal CDU Framework
This page is a rather technical description of the Nasal code for the framework used to implement a Boeing style CDU.
Work in progress This article or section will be worked on in the upcoming hours or days. Note: Hcc23 is working on this. Find him in the FG IRC channel to discuss this page. See history for the latest developments. |
Note: Although this is meant as a documentation for the code, it obviously will (always) be (slightly) outdated. However, after reading through this page, the actual source code at https://gitorious.org/fg/fgdata/trees/master/Aircraft/Instruments-3d/cdu should not present any major surprises. Hcc23 10:07, 7 May 2011 (EDT)
Basic Classes
Line
The line class represents data to be shown on a row of the CDU's display matrix. This does not mean that a line has to span a complete row of the CDU's display matrix.
var Line = {
# "Static"
vector byID,
func registerInPropTree(path),
func formatOutput(input_data),
func getScreenTextVector(),
func new(line_data,ptp),
# "Public"
scalar me.id,
scalar me.ptp,
vector me.used_properties,
vector me.line_data,
scalar me.line_string_length,
func me.enable(),
func me.disable(),
# "Private"
scalar me.active,
};
Field
A field holds two lines, the label and the data line, as well as information about what the associated line select key does.
var Field = {
# "Static"
vector byID,
func registerInPropTree(path=nil),
func new(label,data,key_action=nil,ptp=nil),
# "Public"
scalar me.id,
scalar me.ptp,
func me.get_label_line(),
func me.get_label_line(),
func me.used_properties(),
func me.lsk_binding(),
func me.enable_lsk(),
func me.disable_lsk(),
# "Private"
(Line) me.label_line,
(Line) me.data_line,
scalar me.lsk_active,
};
SubPage
A SubPage is actually the main element in the CDU framework. It holds the content via its fields and manages the updating of the CDU screen.
var SubPage = {
# "Static"
vector byID,
(Field) blankField,
func registerInPropTree(path=nil),
func updateField(field, side, lsk_index),
func displayFields(field_vector, side),
func displayPage(),
func new(parent_base_page,name=nil,ptp=nil),
# "Public"
scalar me.id,
scalar me.separator,
scalar me.ptp,
func me.register_field(field_pos,field),
func me.activate(),
(Field) me.home
# "Private"
scalar me.parent,
scalar me.title,
scalar me.status,
vector me.left_field,
vector me.right_field,
};
BasePage
A BasePage is exactly that: a base to hold sub pages. A base page most closely represents the concept of a page in a CDU.
var BasePage = {
# "Static"
vector byID,
func displayPage(),
func regiserInPropTree(path)
func new(name,ptp=nil),
# "Public"
scalar me.id,
scalar me.active_sub_page_id,
func me.activate(),
(Field) me.home,
scalar me.ptp,
# "Private"
vector me.sub_pages,
scalar me.title,
scalar me.status,
};
CDU
The CDU is the main class for the instrument. Each simulated CDU should have one and only one CDU instance associated to it. This is intended to support multiple CDUs showing different content in the future.
var CDU = {
# "STATIC"
func M_ERROR(message_string),
func M_WARNING(message_string),
func M_NOTE(message_string),
func M_HINT(message_string),
func updateDisplay(),
scalar activeBasePageID,
(ScratchPad) scratchPad,
(Timer) timer,
(ListenerCollection) listOfListeners,
};
Additional Infrastructure
The previous section was more concerned with the conceptually necessary pieces for a/the CDU. This section introduces the other elements the framework introduces in order to code a functional CDU.
ScratchPad
The ScratchPad is the input/output line in the CDU(s). The scratch pas as such is kind of different from the rest of the CDU(s) as the scratch pad messages are truly static, i.e. they happen to be displayed on all CDUs in the cockpit, no matter what the individual CDU is otherwise showing.
var ScratchPad = {
# "STATIC"
vector messages,
scalar deleteString, # "DELETE"~""
func displayScratchPad(),
func new(),
# "PUBLIC"
scalar me.input_string,
func me.erase,
# "PRIVATE"
scalar me.pm_trigger,
func me.plusminus(),
func me.clear(pressedTime),
func me.erase(),
};
ListenerCollection
In order to update fields that are tied to a (potentially changing) property, fields that need a (potentially changing) property to compute their data can (and automatically will) register a property listener on the relevant properties whenever the relevant field is displayed. In order to unregister the listener for pages that are no longer displayed, the class CDU keeps a collection of the currently active listeners, such allowing the unregisterling for unneeded listeners.
var ListenerCollection = {
# "STATIC"
func registerInPropTree(path),
func add(prop, field_id, subpage_id, side, lsk_index),
func clearAll(),
func new(ptp=nil),
# "PRIVATE"
scalar me.ptp,
vector me.listener_list,
vector me.property_list,
};