Howto talk:Development of the CDU
Nasal in XML files (command bindings)
Note that Nasal scripts embedded in XML should be wrapped in <![CDATA[ ... ]]> markup:
<![CDATA[ print("Foo"); ]]>
--Hooray 21:42, 2 December 2010 (UTC)
Thanks for that advice. But shouldn't there be a > somewhere? Could you please correct this example (in a new version below)?
<animation> <type>pick</type> <object-name>Btn.zero</object-name> <action> <button>0</button> <repeatable>false</repeatable> <binding> <command>nasal</command> <script><![CDATA[ setprop("/instrumentation/cdu/input",getprop("/instrumentation/cdu/input")~'0'); ]]></script> </binding> </action> </animation>
--Hcc23 22:16, 2 December 2010 (UTC)
Loading external Nasal files from XML files
There is code to do this in $FG_ROOT/Nasal/io.nas - namely the function "load_nasal(filename, namespace)". io.nas contains some comments. Basically, this allows you to reference/load and run separate Nasal modules, without having to embed all of the code directly in the XML markup. So it's a good practice and makes things easier:
<binding> <command>nasal<command> <script><![CDATA[ io.load_nasal("lsk.nas","lsk"); lsk.hello(); ]]></script> </binding>
with lsk.nas containing:
var hello = func print("Hello from lsk.nas");
--Hooray 23:14, 3 December 2010 (UTC)
Implementing LSK logics
"The most cumbersome buttons are the line select keys. As their function depends on the current state of the CDU, the corresponding XML requires some conditional checks."
I think, we actually talked about this previously on the forums. Instead of using lots of nested XML logics to model a CDU (or any complex instrument), it is actually better to just use the property tree for communicating "events" (e.g. button presses). This would then make it possible for a Nasal script to handle ALL logics (using a registered listener), so that a FSM (finite state machine) can be implemented in Nasal space, this is more flexible than a purely XML-based approach, and could also be more easily reused by other aircraft and developers. My personal suggestion would be to refrain from modeling advanced logics in XML space, while it is certainly possible to do so to a certain degree, the corresponding building blocks are relicts from an era where Nasal scripting was not yet available.--Hooray 22:31, 2 December 2010 (UTC)
Sorry, I just caught up with this discussion. Again in the A380 MCDU, I separate out the two lifecycle stages, there is a action/render stage and a input stage.
For the action/render stage I have a single dispatch("action"); method in my Nasal, this is called when you click on an action button, so it gets all the data ready for the render stage and then changes pages. When you click on a input field, it calls selectField("field") which just sets a property called "current-field". So when you click on the aircraft keyboard it calls a keyPress("key"); function in my mcdu.nas Nasal, this builds the string and sets a property value for whatever the current-field is. In your case, the selectField is done by pressing the LSK, so this needs a little bit of indirection, you could have an array of properties with the name of the field that maps to the index of the LSK. The LSK has two functions, one to select an action (such as "insert") and one to select an input field before you enter some data.
Scotth1 13:16, 4 December 2010 (UTC)
Implementing a finite state machine in Nasal
I think, the right thing to do would be creating a new "fsm.nas" module, so that it can be used by aircraft developers to create their own state machines based on a generic fsm module. This would make it possible to implement all sorts of advanced instruments without using the bloated XML syntax for this.
--Hooray 22:53, 2 December 2010 (UTC)
Generality of the CDU
CDUs differ from aircraft type to aircraft type. Gijs started the CDU for a Boeing 747-400 based upon the documentation he had for that airplane. I personally have access to a B777 FMS PILOT'S GUIDE which I will use to guide me in my decisions.... Hopefully people can live with a "mixed up" CDU for the moment (as compared to no CDU) and interested parties can separate the internal workings later...
--Hcc23 22:32, 2 December 2010 (UTC)
It would be good to consider a component model, where the CDU/FMC implementation is split into different generic components that only need to be parameterized accordingly (e.g. into SCREEN/KEYPAD). This would make it possible for the work to be reusable by different aircraft/CDU implementations.
--Hooray 23:22, 3 December 2010 (UTC)
LCD screen abstraction
My suggestion would be to introduce a new Nasal module here, where people can use a wrapper to create a new alphanumerical screen area and map it to the corresponding osgText animations ($FG_ROOT/Docs/README.osgtext):
var myLCD = lcd.new(lines:14,columns:24);
Next, one could add methods to easily add text to specific lines or columns of this virtual LCD screen, too:
myLCD.add(line:1, text: "INIT/REF INDEX"); myLCD.add(line:2, text: "< IDENT"); myLCD.add(line:3, text: "< POS"); myLCD.add(line:4, text: "< PERF"); myLCD.add(line:5, text: "< TAKEOFF"); myLCD.add(line:6, text: "< APPROACH");
As a third (and optional) argument, one could add support for formatting/styling attributes to change font, font size, font color etc. Once we have such an LCD wrapper, providing a CDU specific wrapper on top of this that handles the LCD transparently would be easy.
The CDU wrapper would then work in terms of "CDU pages" and use the LCD backend internally which addresses the virtual LCD by setting properties, which converts everything to the required osgText animations, so you end up with three wrappers:
- osgText (lowest)
- LCD screen
- CDU (high level)
--Hooray 23:17, 2 December 2010 (UTC)
Using Nasal is exactly what I planned. However, I haven't yet figured out how to use Nasal to achieve the same effects as with XML. THe README.osgtext is very helpfull, but isn't this stuff that lives in the XML scope? How would I achieve a similar effect using nasal?
Any hints for sourcecode where nasal is used to update some text on a screen (I guess in some instrument), based on a property from the property tree? (e.g. like a nasal enabled digital altimeter)?
Any hints are very welcome...
--Hcc23 21:03, 3 December 2010 (UTC)
Most XML files (certainly the PropertyList files) in FlightGear will at some point be read into the property tree, where XML tags become properties. Depending on the subsystem, there is support for "live" properties, so that setting or overwriting a value in the property tree also affects the underlying system. Other properties are polled at framerate in the C++ code, so that modifying them also causes updates. Increasingly, properties are bound to listeners in the C++ code - so that systems can be updated like this, just by setting a property. You can see this in various parts: README.osgtext, for example, mentions support for properties in the form of "text-value" and "number-value" types, where the the value is not literal/hard coded in the XML file, but instead dynamically read from a property in the global property tree. This in itself, would make it possible to define a screen area and then use Nasal and the property tree to change the contents of the "LCD screen". So if you want to update some text on the "screen", this only means setting a property in the property tree by using Nasal (setprop). This way it would for example be possible to define a screen region with 14 lines by using 14 different INPUT properties. You could use a Nasal helper routine to ensure that there are not more than 24 characters written to each property (line), so that you simulate 14 lines X 24 columns. Due to the property tree and Nasal, there are lots of cases in FlightGear where Nasal sort of implicitly follows the MVC pattern already. So the representation and implementation of the screen logics could very well be separated like this. This would also mean that the XML file implementing the screen region, would not need to know about the high level stuff (i.e. CDU implementation), it would just be a "text area" that is populated with text from 14 different properties. Obviously, not everything can currently be implemented directly in Nasal space. But there are usually feasible workarounds available. For example, as far as I know, there is currently no support for also changing other font settings (font, font size, color, reverse) dynamically. But these would be fairly simple C++ modifications. The GUI system implements many of these features already. The general idea really is that the property tree is the mechanism to share data and communicate with other parts of FlightGear. If you really wanted to, you could even dynamically add 3D models by using Nasal.
--Hooray 22:29, 3 December 2010 (UTC)
In reference to the CDU screen description in [1]: You could obviously further partition the screen area into LEFT/RIGHT if you wanted to, so that you could address each region separately by writing to different properties.
--Hooray 23:10, 3 December 2010 (UTC)
This is exactly what I did with the A380 MCDU, as Hcc23 says you need to create the text object in XML, however as Horray says the contents of the text object is taken from the property tree. So in my MCDU where you select the runway, then SID/STAR and then any TRANSITION POINTS, I create 8 osg Text objects in the XML (opt00 - opt08) these are placed on the screen in the XML and are tied to /instrumentation/mcdu/opt[]. Then in my Nasal script (mcdu.nas) I set values to the opt[] properties based on which action you are currently performing. The A380 MCDU is a bit more complex to manage than the 747 or 777 CDU, as it works like a computer monitor, input fields and output text can appear anywhere on the screen, not in LED lines and columns.
A generalised method to manage lines of text is something else I've been thinking about and I like a lot of what you two have been saying here. For example on the E/WD there is a sequence of checklists, these would be perfect for the method you are talking, in particular something like;
var region = TextRegion.new(lines, width, "property-prefix"); region.append("new text"); region.replaceAt(index, "text"); region.clear(); region.appendStyled("text", "style"); region.replaceAtStyled(index, "text", "style"); var nextLine = region.currentLine();
so this would create a child array /lines[lines] under property-prefix and a internal counter (for append). In your animation XML, you just then need to tie the OSG Text object to each property in the array.
Scotth1 12:43, 4 December 2010 (UTC)
- You know what, I wasn't aware of the alignment tag in OSGtext! Now I found this one, it'll be possible to use the property tree for output. Thanks for sharing all your ideas/knowledge, brought me up with some new ideas ;)
- Cheers, Gijs 08:19, 5 December 2010 (UTC)
I've done a proof-of-concept of the text handler and display, there is probably more that could be done with this, but it works quite nicely, just need a way to style each line now?
gitorious/airbus-aircraft/a380/HEAD/Nasal/TextRegion.nas gitorious/airbus-aircraft/a380/HEAD/XML/FlightDeck/FrontPanel/eicas.xml
and in my system.nas (I think from memory) I declare at the beginning (so it's not inside any function and acts like a global var)
ewdChecklist = TextRegion.new(5, 50, "/instrumentation/ewd/checklists");
then I have a update_ewd() function where I can do the following;
if (getprop("/controls/gear/brake-parking") == 1) { ewdChecklist.append("PARK BRAKE ON"); } if (getprop("/instrumentation/ewd/flap-overspeed") == 1) { ewdChecklist.append("FLAP OVERSPEED"); } ewdChecklist.reset();
Scotth1 12:19, 6 December 2010 (UTC)
Bottom up design for virtual screen implementation (params)
Using XML parameters, it would for example be possible to develop a fully property driven virtual screen like this:
- create an osgText animation file for drawing a single character from a property (property-char.xml)
- create an XML file "property-line.xml" for assembling a line of n property-driven XML characters by including and parameterizing the "property-char.xml" file for a given width (24) and a certain offset (spacing) in between characters
- create another XML file "property-screen.xml" for assembling an area of n lines (14) with "property-line.xml" included
So for a 14x24 screen you would end up with 14x24 different properties to address the screen on a character-basis.
The higher level XML files would obviously be able to customize/override any defaults (such as font, font size, color etc) used by the lower level files by using "params".
To display strings on the virtual screen, one would then merely need to set each character property to the corresponding character, this could be done by a Nasal wrapper which takes a whole string as input and writes to the correct character property.
While this would have some restrictions, it would be more flexible than a purely XML based solution: what is getting rendered is not determined by the XML files, these just determine the properties that are used for getting the character data. --Hooray 01:49, 4 December 2010 (UTC)
XML conditions remark
(Hcc23 wonders if the condition on the page could be put somewhere else in order to keep things slightly more organized (by pages that is, and not by buttons...)) CDU Pages
If you really want to pursue this XML-based approach (instead of modeling a FSM in Nasal space), you should know that all PropertyList XML Files support "include" directives that can be specified for each tag in the form an attribute (include="filename.xml"), to include another PropertyList-encoded XML file.
--Hooray 18:00, 3 December 2010 (UTC)
XML "params" tag
Hcc23: I do not yet understand what the <params>...</params> block inside display-text.xml (or any of the other renderers for that matter) actually does. My current assumption is that of a default or fall-back.
"params" is way to parameterize a previously included XML file, so that tags can be overriden with custom values. This is useful to factor out stuff into separate files and then reuse these generic files and just change some values by using "parameters". The "params" tag is briefly explained in $FG_ROOT/Docs/README.xmlpanel. This file contains lots of important things that would actually better be moved to the README.xmlsyntax or README.introduction files (or at least be covered here in the wiki). It also covers aliasing, property indexing and XML file inclusion. So it's definitely worth having a look.
In general, it is a good idea to search the mailing list and forum archives whenever you find something insufficiently documented (first check $FG_ROOT/Docs and the wiki): http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net
I already suggested using the mailing list or the forum to get in touch with other users to answer such and similar questions. However, if you think using the wiki is better, I would suggest to add some "HELP:" markup to all open questions, so that it is easier for people like me to find and answer such questions.
Personally, I am fine with both ways - I actually appreciate that you have so far used all the info that I have provided to directly improve the wiki documentation. So I guess this method could even be more efficient than what we are doing on the forum (i.e. constantly asking users to add new info to the wiki).
--Hooray 23:06, 3 December 2010 (UTC)
Update: almost complete CDU logics moved to Nasal
As of last week, the cdu in Git ($FG_ROOT/Aircraft/Instruments-3d/cdu) is controlled almost completely by Nasal. Latest pieces of XML logics will be moved to Nasal soon. Altough he Nasal script does its work well (much more flexible/clear than XML), I am quite sure there should be a better way. Feedback is welcome of course ;)
Gijs 06:56, 30 January 2011 (EST)