A standard CDU framework for FlightGear
IMPORTANT: Some, and possibly most, of the features/ideas discussed here are likely to be affected, and possibly even deprecated, by the ongoing work on providing a property tree-based 2D drawing API accessible from Nasal using the new Canvas system available since FlightGear 2.80 (08/2012). Please see: Canvas MCDU Framework for further information
You are advised not to start working on anything directly related to this without first discussing/coordinating your ideas with other FlightGear contributors using the FlightGear developers mailing list or the Canvas subforum . Anything related to Canvas Core Development should be discussed first of all with TheTom and Zakalawe. Nasal-space frameworks are being maintained by Philosopher and Hooray currently. talk page. |
- Last updated: 01/2012
- Contributors:
Status
04/2011: FlightGear contributor User:awexome is currently working on improving and generalizing the various CDU-related implementations. Status updates (including screen shots) can be found on the forum in the 787 thread.
Make sure to also check out his user page where awexome keeps a progress report on a number of related projects.
Introduction
As of 01/2012, we are unfortunately approaching a situation where we are having too many different CDU implementations with little (or none) reuse and sharing of existing code - at the moment, there are least 4-5 different projects:
- Hcc23's CDU: http://wiki.flightgear.org/Howto:_Development_of_the_CDU
- Gijs' CDU: http://wiki.flightgear.org/Howto:_Coding_a_Boeing_CDU
- Scotth1's CDU: https://gitorious.org/airbus-aircraft/a380?p=airbus-aircraft:a380.git;a=summary
- Skyop's CDU: http://forum.flightgear.org/viewtopic.php?f=4&t=11863&hilit=skyop+crj&start=195#p135105
- Omega95's CDU: http://forum.flightgear.org/viewtopic.php?f=18&t=15082
All of them implemented in Nasal. Now, what we really need is someone to examine all versions and see if/how they could be combined, unified and eventually integrated, so that we end up with a single version that is well understood, can be well documented and well-maintained, usable by all aircraft developers, catering for all different needs.
There's a fair share of common features required for pretty much any CDU/MCDU, especially these SHARED low level requirements are largely identical among these FMS front ends.
For example, this includes instantiating an addressable "screen region" and providing hooks to write alphanumeric text to it, as well as dealing with events, i.e. for key handling.
So, ideally, we could come up with a layered design where generic CDU components could be identified to allow people instantiating and parametrizing CDU-related components. Nasal's OOP support is powerful enough to allow people to override such features easily.
Aircraft specific differences are best addressed by parametrization during CDU-instantiation, rather than by duplicating redundant code.
In real-life, there are only like 3 different FMS/FMC/CDU implementations for airliners:
- Thales
- Honeywell
- Smiths Industries (now GE Aviation)
And the same units from one manufacturer are often used in different aircraft (eg: A320, MD-11, 757 and 767 all use the same Honeywell FMS). The majority of the database format is covered by an ARINC standard.
For smaller aircraft (like biz-jets, turboprops and military trainers) one also has to consider other manufacturers like:
- Barco
- Esterline
- Universal Avionics Systems
It is OK to have different initial implementations, all the versions we have at the moment have different ways of implementing different functionality. We could say this is exploring the problem-space.
But we are getting closer to building up a set of requirements that could be built into a common set of instruments and functions...
We are thinking of one "framework" of sorts for connecting a 3D model of the CDU to the property tree, and another framework for it's internal software, both with provisions for customising.
There are two distinct streams:
- the first is the physical representation of a keypad, screen etc, this is either the traditional LED grid screen, some specialised function keys and general letter/number keypad, the second type of physical representation is the newer LCD monitor type, such as used on 787 and A380 and a few others. This includes page flow, text management and key management.
- The second stream is the back-end processes of the FMS, calculating flight plans, lateral/vertical guidance and interfacing with the route manager and autopilot.
Well, even if you were to find 100 different manufacturers of CDUs, FMCs and FMS there'd still be a great deal of shared functionality and shared requirements, i.e. things that would be identical among ALL implementations, such as addressing a 2D screen region, rendering formatted text at certain coordinates, responding to key events, querying a navigational datatbase, making certain geospatial calculations.
So, yes, the idea is to come up with a list of these shared requirements and find the greatest common denominator for each component so that a set of layered frameworks can be created, to enable users to reuse code as much as possible, while still being able to customize and parametrize functionality as required.
Some things are currently not yet possible/feasible to do from scripting space (i.e. they require new scripting hooks) , but there are many things that are quite possible already and which should eventually be standardized, i.e. by coming up with a dedicated Nasal module that handles all details and which can be reused by aircraft developers easily.
We need to come up with our own module by getting all people to communicate their requirements, so that the existing designs can be reviewed and improved eventually. This is more complex work than coming up with some workaround from scratch, but it's more worthwhile in the long run.
In many aspects, FlightGear follows implicitly the MVC pattern already - simply because of the property tree, which already causes a separation of concerns to a certain degree.
Architecture
Provided below are some design option architectures. This is completely a wishlist on my behalf and very very draft.
Page Definition Markup
The Markup (XML based) for the page definition should encapsulate both the layout of page components, and the flow of actions. Pages can retrieve property values #{property-tree} and call nasal functions ${NasalRef.nasalClass.function()}
<?xml version="1.0"?>
<page>
<title>Page Title</title>
<body>
<group>
<group style="valign:left; width:50%">
<row>
<text style="valign: left; size: 12pt; colour: red">Literal Text</text>
</row>
<row>
<text style="size: 12pt; colour: green">#{/instrumentation/flightdirector/myproperty}</text>
<text style="size: 12pt; colour: red">${NasalRef.nasalClass.function()</text>
</row>
</group>
<group style="valign: right; width: 50%">
<row>
<text style="valign: left; size: 12pt; colour: #1169C0">Destination:</text>
<input value="${/instrumentation/flightdirector/dest-airport}" style="colour: green; width: 150px"/>
</row>
</group>
<group style="halign: bottom">
<row>
<button style="valign: left; background-colour: #E0E0E0" action="NasalModule.nasalObject.function()">Lookup</button>
<button style="valign: right; background-texture: Aircraft/MyAircraft/Tetxtures/button-texture.png" action="page2">Next Page</button>
<row>
</group>
</group>
</body>
</page>
Wishlist of elements;
- title
- body - all child elements are drawable
- group - groups children elements as on layout object
- row - provides a relative row layout object
- text - draws some literal text or text from an expression
- input - draws a clickable hotspot that can receive virtual keyboard input and sets property with value
- button - draws a button object that is also a hotspot, calls nasal function on click
- canvas - create a texture object that we can use OpenGL statements to draw on (pass-through)
- mesh - create a 3D mesh object
Components
MainLoop
pseudo code
init:
KeypadManager keypad = KeypadManager.getQwertyKeypadManager("keyboard-left");
KeypadManager keypad2 = KeypadManager.getThalesCDUKeypad("keypad-right");
me.registerKeypadManager(keypad);
me.registerKeypadManager(keypad2);
Screen cduScreen = ObjectModel.getObjectById("cdu-left");
PageRenderer pgRender = new PageRenderer(cduScreen);
PageLayoutEngine layout = new FreeformLCDLayout(640, 420);
PageLayoutEngine layout2 = new GridLEDLayout(40, 6);
pgRender.setLayoutEngine(layout2);
pgRender.loadPage("ident.xml");
loadPage(page):
Page pg= PageParser.parse(page);
me.calculateBoxLayout(pg);
me.draw();