Property Tree/Explained

From wiki.flightgear.org

Jump to: navigation, search
Property Tree


Contents

An abstract View

The Property Tree System in FlightGear is generally spoken, used by pretty much all FlightGear subsystems that are basically tied together by it, in other words: it is the property tree that is the enabling mechanism to "share" important runtime data between different components of FlightGear.

While this doesn't necessarily apply to all internal FlightGear data structures, it does mostly apply to those variables that may need to be modified at runtime, be it for customization purposes or other uses. In addition, it is made very straightforward to publish/expose new variables from C++ space to the property tree. In addition, new property tree variables can be easily created using XML files or Nasal scripts.

But the Property Tree is also used by other FlightGear-related software (such as Atlas), where the Property Tree's purpose is extended to being that of an network-based "Inter Process Communications (IPC)"-mechanism/enabler, so that other software (open source or or not) can easily interface with and "look into" FlightGear, and inspect/modify runtime state variables (in a peek/poke manner).

This makes it for example possible, to basically "remote control" FlightGear, but also to modify environmental settings easily at runtime, from a different process, computer, network or even continent! eg

//*** example to slave one copy of fgfs to another ***

// This instructs the first instance of fgfs to send UDP packets in the native format to a machine called seattle.com on port 5500.
fgfs1:  --native=socket,out,30,seattle.com,5500,udp

// The second instance of fgfs will accept UDP packets (from anywhere) on port 5500.  
// Note the additional --fdm=external option which tells the second instance of fgfs to not run the normal flight model,
// but instead set the FDM values based on an external source (the network in this case.)
fgfs2:  --native=socket,in,30,toulouse.net,5500,udp --fdm=external

Inside FlightGear, code may be triggered by modifying properties using so called "listeners", similar to the signal/slots mechanism supported by QT. Listeners are code routines that are bound to specific properties and which are automatically invoked by FlightGear once a property is modified. Listeners can be implemented as native C/C++ code or Nasal scripts.

//* Example Nasal script listening to a switch
setlistener("/some/switch", func {
    if (cmdarg().getBoolValue()) {
       print("turned on");
     } else {
        print("turned off");
     }
 });

Access to the Property Tree is provided via well-defined means, such as C++ APIs, network protocols, XML files and scripting interfaces (via Nasal).

Furthermore, the Property Tree has been designed to directly map to XML files, specifically to "PropertyList-encoded" XML files, these follow a key/value structure that can be directly translated to the hierarchy used in the Property Tree.

In fact, most of the contents of the FlightGear Property Tree that you get to see at runtime is dynamically composed from such PropertyList-encoded XML files, that are directly loaded into the property tree.

Property Tree: Step by Step

A dump space for your data

For starters, it's probably sufficient to imagine the property tree as a very powerful global (process-wide) "dump space" for simple variables, such as numbers and strings (in its current form, the property tree doesn't contain binary blobs such as actual file contents like images, audio files etc), instead properties usually such data as references to plain text file paths.

Key/Value pairs

The property tree stores variables as "key/value" pairs, so that you can easily refer to a variable by using its "key" (such as for example "altitude") and query the property tree for the value that it has stored for this key (variable).

aircraft-dir =	'/home/flight-sim/flight-gear-9/data/Aircraft/A380'
description = 'Airbus A380-House'
longitude-deg = '-122.3576543'
altitude-ft = '28.24378768'
altitude-agl-ft = '22.46997954'

Hierarchical Storage / where the tree part comes in

To provide support for hierarchically/logically grouped variable storage, the property tree is implemented as a tree-like structure of nested key/value pairs, this can be imagined pretty much like a virtual file system where you have folders (locations) and files (data).

/position/
/position/longitude-deg =	'-122.3576835'	(double)
/position/latitude-deg =	'37.61373348'	(double)
/position/altitude-agl-ft =	'22.47111218'	(double)

/velocities/
/velocities/uBody-fps =	'0.01999366548'	(double)
/velocities/airspeed-kt =	'0.01184097074'	(double)
/velocities/mach =	'1.808156878e-05'	(double)
/velocities/vertical-speed-fps =	'-3.065542307e-05'	(double)
/velocities/groundspeed-kt =	'0.01195743728'	(double)

/engine/
/engine[n]/thrust = 0.9

/cabin/back/light/

Categories for your data

This approach is powerful because it supports the concept of "categories" for data storage, so that you can place -by convention- certain "data" in a specific place (think "drawer"), pretty much like storing work-related stuff in a "work" folder on your computer, or storing your media files (video/audio) in a distinct "media" folder, too.

So, this system allows for logical groups or "categories" of data items, so that you know where to search for certain data. On the other hand, this is based purely on conventions - there's nothing that enforces things to be placed in a certain location.

Property Tree Paths

In fact, the file system analogy previously used pretty much also applies to accessing (writing/reading) values: Values (or data items) in the property tree can be referred to via a "path" which acts as the "key" to the data, this path pretty much looks like a conventional file system path, for example something like "/private/settings/foo" could be an imaginary path/key to access a property tree variable stored at that place. So, from a syntactic point of view this is pretty much similar to file system paths, like they are used on Linux/Unix computers (i.e. no drive letters or backslashes are used).

Naming Properties

In addition, some naming restrictions apply as well. In general, you should

  • use lower-case, alphanumeric ASCII characters in these paths
  • and only use the hyphen to separate words or append a suffix.
  • these conventions simplify working with properties and make them more intuitive.
cool:
   foo-bar
not cool:
   Foo-bar
   foo_bar 
   fo0Bar

Naming Conventions

To ensure that keys (paths) to variables are not simply named arbitrarily, some naming conventions apply, these can be mostly deduced from existing properties, such as for example appending a suffix to make properties more self-explanatory by indicating what unit the properties is provided in (e.g. "deg", "rad", "hz", "ft", "nm").

Identically named properties

Multiple identically named properties, for example inside an XML file, will map to an array-like representation inside the property tree. Consider for example:

<PropertyList>
 <foo/>
 <foo/>
 <foo/>
 <foo/>
</PropertyList>

When read into the property tree, the four different foo nodes will be converted into nodes named foo[0] - foo[3] respectively.

Typing

In general, the property tree is pretty much untyped, that is it can easily work with untyped properties (generally represented as strings) that can be dynamically converted to different representations, such as numbers like int, float, double or boolean values at runtime.

For example from a telnet session or a socket the values returned could be:

 gear_up = 1             / bool (gear_up)
 elevator = -1.0 to +1.0 / long(-0.56)
 callsign = "AC234"      / str(callsign)
 throttle = 55           / int(throttle)

When creating your own properties, it is generally considered good practice to chose the most suitable data type, as well.

It is important to keep in mind that storing a property without its type (i.e. untyped), will inevitably result in a conversion being performed somewhere to convert the data to a non-string representation.

So, to avoid unnecessary performance penalties it's always a good idea to also define valid types for your properties.

Likewise, using the proper access means to avoid unnecessary conversions, is also important.

Personal tools