The generic communication protocol for FlightGear provides a powerful way
of adding a simple ASCII based or binary input/output protocol, just by
defining an XML encoded configuration file and placing it in the
$FG_ROOT/Protocol/ directory.




== file layout ================================================================

A protocol file can contain either or both of <input> and <output>
definition blocks. Which one is used depends on how the protocol
is called  (e.g. --generic=file,out,1,/tmp/data.xml,myproto would
only use the <output> definitions block).

  <?xml version="1.0"?>
  <PropertyList>
      <generic>

          <output>
              <binary_mode>false</binary_mode>
              <line_separator></line_separator>
              <var_separator></var_separator>
              <preamble></preamble>
              <postamble></postamble>

              <chunk>
                      ... first chunk spec ...
              </chunk>

              <chunk>
                      ... another chunk etc. ...
              </chunk>
          </output>

          <input>
              <line_separator></line_separator>
              <var_separator></var_separator>

              <chunk>
                      ... chunk spec ...
              </chunk>
          </input>

      </generic>
  </PropertyList>




== input/output parameters ====================================================

Both <output> and <input> blocks can contain information about
the data mode (ascii/binary) and about separators between fields
and data sets, as well as a list of <chunk>s. Each <chunk> defines
a property that should be written (and how), or a variable and which
property it should be written to.

--- ASCII protocol parameters ---

output only:
  <preamble>        STRING  default: ""    file header put on top of the file
  <postamble>       STRING  default: ""    file footer put at the end of the file

input & output:
  <binary_mode>	    BOOL    default: false (= ASCII mode)
  <var_separator>   STRING  default: ""    field separator
  <line_separator>  STRING  default: ""    separator between data sets


<var_separator> are put between every two output properties, while
<line_separator> is put at the end of each data set. Both can contain
arbitrary strings or one of the following keywords:

  Name             Character

  newline          '\n'
  tab              '\t'
  formfeed         '\f'
  carriagereturn   '\r'
  verticaltab      '\v'


Typical use could be:

  <var_separator>tab</var_separator>
  <line_separator>newline</var_separator>

or

  <var_separator>\t</var_separator>
  <line_separator>\r\n</line_separator>


--- Binary protocol parameters ---

To enable binary mode, simply include a <binary_mode>true</binary_mode> tag in
your XML file. The format of the binary output is tightly packed, with 1 byte
for bool, 4 bytes for int, and 8 bytes for double. At this time, strings are not
supported. A configurable footer at the end of each "line" or packet of binary
output can be added using the <binary_footer> tag. Options include the length
of the packet, a magic number to simplify decoding. Examples:

  <binary_footer>magic,0x12345678</binary_footer>
  <binary_footer>length</binary_footer>
  <binary_footer>none</binary_footer>                 <!-- default -->




== variable parameters (chunk spec) ===========================================

Both <input> and <output> block can contain a list of <chunk> specs,
each of which describes the properties of on variable to write/read.


  <name>        for ease of use (not transferred)
  <node>        the property tree node which provides the data
  <type>        the value type (needed for formatting)
                one of string, float, bool, int (default: int)
  <format>      (ASCII protocol only, not used or needed in binary mode)
                defines the actual piece of text which should be sent.
                it can include "printf" style formatting options like:
                                <type>
                        %s      string
                        %d      integer (default)
                        %f      float

  <factor>      an optional multiplication factor which can be used for
                unit conversion. (for example, radians to degrees).
  <offset>      an optional offset which can be used for unit conversion.
                (for example, degrees Celsius to degrees Fahrenheit).

For input chunks there exist some more options:

  <rel>         optional boolean parameter to enable handling of incoming values
                as relative changes (default: false)
                (Can be eg. used to realize up/down buttons by just sending 1 or
                -1 respectively)

  <min>         an optional minimum limit for the value to be clamped to. This
                limit is always specified as absolute value, also with relative
                changes enabled. (default: 0)
  <max>         an optional upper limit for the input value to be clamped to. If
                <min> equals <max> no limit is applied. (default: 0)
  <wrap>        instead of clamping to minimum and maximum limits, wrap values
                around. Values will be in [min, max] (default: false)
                (Useful for eg. heading selector to start again with 1 for
                values higher than 360)

<rel>, <min>, <max> and <wrap> are only used for numeric data types. <rel> can
additionally be used with type 'bool', where it toggles the value, if the received
value evaluates to 'true', otherwise the value is left unchanged.

Chunks can also consist of a single constant <format>, like in:
  <format>Data Section</format>


== examples ===================================================================

Writes log of this form:

V=16
H=3.590505
P=3.59
V=12
H=3.589020
P=3.59



<?xml version="1.0"?>

<PropertyList>
  <generic>

    <output>
      <line_separator>newline</line_separator>
      <var_separator>newline</var_separator>
      <binary_mode>false</binary_mode>

      <chunk>
        <name>speed</name>
        <format>V=%d</format>
        <node>/velocities/airspeed-kt</node>
      </chunk>

      <chunk>
        <name>heading (rad)</name>
        <format>H=%.6f</format>
        <type>float</type>
        <node>/orientation/heading-deg</node>
        <factor>0.0174532925199433</factor>  <!-- degrees to radians -->
      </chunk>

      <chunk>
        <name>pitch angle (deg)</name>
        <format>P=%03.2f</format>
        <node>/orientation/pitch-deg</node>
      </chunk>
   </output>

 </generic>
</PropertyList>


Control the heading bug by sending relative changes separated by newlines:

<?xml version="1.0"?>

<PropertyList>
  <generic>

    <input>
      <line_separator>newline</line_separator>

       <chunk>
         <name>heading bug</name>
         <type>int</type>
         <node>/autopilot/settings/heading-bug-deg</node>
         <relative>true</relative>
         <min>1</min>
         <max>360</max>
         <wrap>true</wrap>
     </chunk>

   </input>

 </generic>
</PropertyList>

-- writing data in XML syntax -------------------------------------------------

Assuming the file is called $FG_ROOT/Protocol/xmltest.xml, then it could be
used as   $ fgfs --generic=file,out,1,/tmp/data.xml,xmltest


<?xml version="1.0"?>

<PropertyList>
  <generic>
    <output>
      <binary_mode>false</binary_mode>
      <var_separator>\n</var_separator>
      <line_separator>\n</line_separator>
      <preamble>&lt;?xml version="1.0"?&gt;\n\n&lt;data&gt;\n</preamble>
      <postamble>&lt;/data&gt;\n</postamble>

      <chunk>
        <format>\t&lt;set&gt;</format>
      </chunk>

      <chunk>
        <node>/position/altitude-ft</node>
        <type>float</type>
        <format>\t\t&lt;altitude-ft&gt;%.8f&lt;/altitude-ft&gt;</format>
      </chunk>

      <chunk>
        <node>/velocities/airspeed-kt</node>
        <type>float</type>
        <format>\t\t&lt;airspeed-kt&gt;%.8f&lt;/airspeed-kt&gt;</format>
      </chunk>

      <chunk>
        <format>\t&lt;/set&gt;</format>
      </chunk>
    </output>
  </generic>
</PropertyList>


-- Analyzing the resulting binary packet format -------------------------------

A utility called generic-protocol-analyse can be found under
FlightGear/utils/xmlgrep which can be used to analyze the resulting
data packet for the binary protocol.

The output would be something like:

bintest.xml
Generic binary output protocol packet description:

 pos | size |  type  | factor     | description
-----|------|--------|------------|------------------------
   0 |    4 |    int |            | indicated speed (kt)
   4 |    4 |  float |            | pitch att (deg)
   8 |    4 |  float |            | magnetic heading (deg)
  12 |    4 |    int |            | outside air temperature (degF)
  16 |    1 |   bool |            | autocoord

total package size: 17 bytes

