]> git.mxchange.org Git - flightgear.git/blobdiff - src/Network/generic.cxx
Merge branch 'jmt/track-bug' into next
[flightgear.git] / src / Network / generic.cxx
index 7df1220d90dfd3596258e78c63cc9492a74bad2d..423d2be189b28ffec2de641415dc99ab3b1bdcfb 100644 (file)
@@ -2,7 +2,7 @@
 //
 // Written by Curtis Olson, started November 1999.
 //
-// Copyright (C) 1999  Curtis L. Olson - curt@flightgear.org
+// Copyright (C) 1999  Curtis L. Olson - http://www.flightgear.org/~curt
 //
 // This program is free software; you can redistribute it and/or
 // modify it under the terms of the GNU General Public License as
 //
 // You should have received a copy of the GNU General Public License
 // along with this program; if not, write to the Free Software
-// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 //
 // $Id$
 
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <string.h>                // strstr()
+#include <stdlib.h>                // strtod(), atoi()
 
 #include <simgear/debug/logstream.hxx>
 #include <simgear/io/iochannel.hxx>
-#include <simgear/misc/exception.hxx>
+#include <simgear/structure/exception.hxx>
 #include <simgear/misc/sg_path.hxx>
+#include <simgear/misc/stdint.hxx>
 #include <simgear/props/props.hxx>
 #include <simgear/props/props_io.hxx>
 
 #include <Main/globals.hxx>
 #include <Main/fg_props.hxx>
+#include <Main/util.hxx>
 
 #include "generic.hxx"
 
 
-FGGeneric::FGGeneric(string& config) {
 
-    string file = config+".xml";
+FGGeneric::FGGeneric(vector<string> tokens) : exitOnError(false)
+{
+    size_t configToken;
+    if (tokens[1] == "socket") {
+        configToken = 7;
+    } else if (tokens[1] == "file") {
+        configToken = 5;
+    } else {
+        configToken = 6; 
+    }
 
-    SGPath path( globals->get_fg_root() );
-    path.append("Protocol");
-    path.append(file.c_str());
-    SG_LOG(SG_GENERAL, SG_INFO, "Reading communication protocol from "
-                                << path.str());
+    if (configToken >= tokens.size()) {
+       SG_LOG(SG_GENERAL, SG_ALERT,
+              "Not enough tokens passed for generic protocol");
+       return;
+    }
 
-    SGPropertyNode root;
-    try {
-        readProperties(path.str(), &root);
-     } catch (const sg_exception &e) {
-        SG_LOG(SG_GENERAL, SG_ALERT,
-         "Unable to load the protocol configuration file");
-         return;
+    string config = tokens[ configToken ];
+    file_name = config+".xml";
+    direction = tokens[2];
+
+    if (direction != "in" && direction != "out") {
+        SG_LOG(SG_GENERAL, SG_ALERT, "Unsuported protocol direction: "
+               << direction);
     }
 
-    SGPropertyNode *output = root.getNode("generic/output");
+    reinit();
+}
 
-        /* These variables specified in the fgfsbase/Properties/xxxx.xml file for each format
-         * var_sep_string = the string/charachter to place between variables
-         * line_sep_string = the string/charachter to place at the end of each lot of variables
-         */
-    var_sep_string = output->getStringValue("var_separator");
-    line_sep_string = output->getStringValue("line_separator");
-
-        if ( var_sep_string == "newline" )
-                var_separator = '\n';
-        else if ( var_sep_string == "tab" )
-                var_separator = '\t';
-        else if ( var_sep_string == "space" )
-                var_separator = ' ';
-        else if ( var_sep_string == "formfeed" )
-                var_separator = '\f';
-        else if ( var_sep_string == "carriagereturn" )
-                var_sep_string = '\r';
-        else if ( var_sep_string == "verticaltab" )
-                var_separator = '\v';
-        else
-                var_separator = var_sep_string;
-
-        if ( line_sep_string == "newline" )
-                line_separator = '\n';
-        if ( line_sep_string == "tab" )
-                line_separator = '\t';
-        if ( line_sep_string == "space" )
-                line_separator = ' ';
-        else if ( line_sep_string == "formfeed" )
-                line_separator = '\f';
-        else if ( line_sep_string == "carriagereturn" )
-                line_separator = '\r';
-        else if ( line_sep_string == "verticaltab" )
-                line_separator = '\v';
-        else
-                line_separator = line_sep_string;
-
-
-    vector<SGPropertyNode_ptr> chunks = output->getChildren("chunk");
-    for (unsigned int i = 0; i < chunks.size(); i++) {
+FGGeneric::~FGGeneric() {
+}
 
-        _serial_prot chunk;
+union u32 {
+    uint32_t intVal;
+    float floatVal;
+};
 
-     // chunk.name = chunks[i]->getStringValue("name");
-        chunk.format = chunks[i]->getStringValue("format", "%d");
-        chunk.offset = chunks[i]->getDoubleValue("offset");
-        chunk.factor = chunks[i]->getDoubleValue("offset", 1.0);
+union u64 {
+    uint64_t longVal;
+    double doubleVal;
+};
 
-        string node = chunks[i]->getStringValue("node");
-        chunk.prop = fgGetNode(node.c_str(), true);
+// generate the message
+bool FGGeneric::gen_message_binary() {
+    string generic_sentence;
+    length = 0;
 
-        string type = chunks[i]->getStringValue("type");
-        if (type == "bool")
-            chunk.type = FG_BOOL;
-        else if (type == "float")
-            chunk.type = FG_DOUBLE;
-        else if (type == "string")
-            chunk.type = FG_STRING;
-        else
-            chunk.type = FG_INT;
+    double val;
+    for (unsigned int i = 0; i < _out_message.size(); i++) {
+
+        switch (_out_message[i].type) {
+        case FG_INT:
+            val = _out_message[i].offset +
+                  _out_message[i].prop->getIntValue() * _out_message[i].factor;
+
+            if (binary_byte_order == BYTE_ORDER_MATCHES_NETWORK_ORDER) {
+                *((int32_t*)&buf[length]) = (int32_t)val;
+            } else {
+                *((uint32_t*)&buf[length]) = sg_bswap_32((uint32_t)val);
+            }
+            length += sizeof(int32_t);
+            break;
+
+        case FG_BOOL:
+            *((int8_t*)&buf[length])
+                      = _out_message[i].prop->getBoolValue() ? true : false;
+            length += 1;
+            break;
 
-        _message.push_back(chunk);
-        
+        case FG_FIXED:
+        {
+            val = _out_message[i].offset +
+                 _out_message[i].prop->getFloatValue() * _out_message[i].factor;
+
+            int fixed = (int)(val * 65536.0f); 
+            if (binary_byte_order == BYTE_ORDER_MATCHES_NETWORK_ORDER) {
+                *((int32_t*)&buf[length]) = (int32_t)fixed;
+            } else {
+                *((uint32_t*)&buf[length]) = sg_bswap_32((uint32_t)fixed);
+            } 
+            length += sizeof(int32_t);
+            break;
+        }
+        case FG_FLOAT:
+            val = _out_message[i].offset +
+                 _out_message[i].prop->getFloatValue() * _out_message[i].factor;
+
+            if (binary_byte_order == BYTE_ORDER_MATCHES_NETWORK_ORDER) {
+                *((float*)&buf[length]) = val;
+            } else {
+                u32 tmpun32;
+                tmpun32.floatVal = static_cast<float>(val);
+                *((uint32_t*)&buf[length]) = sg_bswap_32(tmpun32.intVal);
+            }
+            length += sizeof(uint32_t);
+            break;
+
+        case FG_DOUBLE:
+            val = _out_message[i].offset +
+                 _out_message[i].prop->getFloatValue() * _out_message[i].factor;
+
+            if (binary_byte_order == BYTE_ORDER_MATCHES_NETWORK_ORDER) {
+                *((double*)&buf[length]) = val;
+            } else {
+                u64 tmpun64;
+                tmpun64.doubleVal = val;
+                *((uint64_t*)&buf[length]) = sg_bswap_64(tmpun64.longVal);
+            }
+            length += sizeof(int64_t);
+            break;
+
+        default: // SG_STRING
+            const char *strdata = _out_message[i].prop->getStringValue();
+            int strlength = strlen(strdata);
+
+            if (binary_byte_order == BYTE_ORDER_NEEDS_CONVERSION) {
+                SG_LOG( SG_IO, SG_ALERT, "Generic protocol: "
+                        "FG_STRING will be written in host byte order.");
+            }
+            /* Format for strings is 
+             * [length as int, 4 bytes][ASCII data, length bytes]
+             */
+            if (binary_byte_order == BYTE_ORDER_MATCHES_NETWORK_ORDER) {
+                *((int32_t*)&buf[length]) = strlength;
+            } else {
+                *((int32_t*)&buf[length]) = sg_bswap_32(strlength);
+            }
+            length += sizeof(int32_t);
+            strncpy(&buf[length], strdata, strlength);
+            length += strlength; 
+            /* FIXME padding for alignment? Something like: 
+             * length += (strlength % 4 > 0 ? sizeof(int32_t) - strlength % 4 : 0;
+             */
+        }
     }
 
-}
+    // add the footer to the packet ("line")
+    switch (binary_footer_type) {
+        case FOOTER_LENGTH:
+            binary_footer_value = length;
+            break;
 
-FGGeneric::~FGGeneric() {
-    _message.clear();
-}
+        case FOOTER_MAGIC:
+        case FOOTER_NONE:
+            break;
+    }
 
+    if (binary_footer_type != FOOTER_NONE) {
+        if (binary_byte_order == BYTE_ORDER_MATCHES_NETWORK_ORDER) {
+            *((int32_t*)&buf[length]) = binary_footer_value;
+        } else {
+            *((int32_t*)&buf[length]) = sg_bswap_32(binary_footer_value);
+        }
+        length += sizeof(int32_t);
+    }
 
-// generate the message
-bool FGGeneric::gen_message() {
+    return true;
+}
 
+bool FGGeneric::gen_message_ascii() {
     string generic_sentence;
     char tmp[255];
+    length = 0;
 
-    int v;
-    double d;
+    double val;
+    for (unsigned int i = 0; i < _out_message.size(); i++) {
 
-    for (unsigned int i = 0; i < _message.size(); i++) {
-
-        if (i > 0)
-           generic_sentence += var_separator;
+        if (i > 0) {
+            generic_sentence += var_separator;
+        }
 
-        switch (_message[i].type) {
+        switch (_out_message[i].type) {
         case FG_INT:
-            v = _message[i].offset +
-                    _message[i].prop->getIntValue() * _message[i].factor;
-            snprintf(tmp, 255, _message[i].format.c_str(), v);
+            val = _out_message[i].offset +
+                  _out_message[i].prop->getIntValue() * _out_message[i].factor;
+            snprintf(tmp, 255, _out_message[i].format.c_str(), (int)val);
             break;
 
         case FG_BOOL:
-            snprintf(tmp, 255, _message[i].format.c_str(),
-                               _message[i].prop->getBoolValue());
+            snprintf(tmp, 255, _out_message[i].format.c_str(),
+                               _out_message[i].prop->getBoolValue());
+            break;
+
+        case FG_FIXED:
+            val = _out_message[i].offset +
+                _out_message[i].prop->getFloatValue() * _out_message[i].factor;
+            snprintf(tmp, 255, _out_message[i].format.c_str(), (float)val);
+            break;
+
+        case FG_FLOAT:
+            val = _out_message[i].offset +
+                _out_message[i].prop->getFloatValue() * _out_message[i].factor;
+            snprintf(tmp, 255, _out_message[i].format.c_str(), (float)val);
             break;
 
         case FG_DOUBLE:
-            d = _message[i].offset +
-                       _message[i].prop->getDoubleValue() * _message[i].factor;
-            snprintf(tmp, 255, _message[i].format.c_str(), d);
+            val = _out_message[i].offset +
+                _out_message[i].prop->getDoubleValue() * _out_message[i].factor;
+            snprintf(tmp, 255, _out_message[i].format.c_str(), (double)val);
             break;
 
         default: // SG_STRING
-             snprintf(tmp, 255, _message[i].format.c_str(),
-                               _message[i].prop->getStringValue());
+            snprintf(tmp, 255, _out_message[i].format.c_str(),
+                                   _out_message[i].prop->getStringValue());
         }
 
         generic_sentence += tmp;
     }
 
-    /* After each lot of variables has been added, put the line separator char/string */
+    /* After each lot of variables has been added, put the line separator
+     * char/string
+     */
     generic_sentence += line_separator;
-            
+
     length =  generic_sentence.length();
     strncpy( buf, generic_sentence.c_str(), length );
 
     return true;
 }
 
-bool FGGeneric::parse_message() {
-        return true;
+bool FGGeneric::gen_message() {
+    if (binary_mode) {
+        return gen_message_binary();
+    } else {
+        return gen_message_ascii();
+    }
+}
+
+bool FGGeneric::parse_message_binary() {
+    char *p2, *p1 = buf;
+    int32_t tmp32;
+    double val;
+    int i = -1;
+
+    p2 = p1 + FG_MAX_MSG_SIZE;
+    while ((++i < (int)_in_message.size()) && (p1  < p2)) {
+
+        switch (_in_message[i].type) {
+        case FG_INT:
+            if (binary_byte_order == BYTE_ORDER_NEEDS_CONVERSION) {
+                tmp32 = sg_bswap_32(*(int32_t *)p1);
+            } else {
+                tmp32 = *(int32_t *)p1;
+            }
+
+            val = _in_message[i].offset + (double)tmp32 * _in_message[i].factor;
+
+            _in_message[i].prop->setIntValue((int)val);
+            p1 += sizeof(int32_t);
+            break;
+
+        case FG_BOOL:
+            _in_message[i].prop->setBoolValue( p1[0] != 0 );
+            p1 += 1;
+            break;
+
+        case FG_FIXED:
+            if (binary_byte_order == BYTE_ORDER_NEEDS_CONVERSION) {
+                tmp32 = sg_bswap_32(*(int32_t *)p1);
+            } else {
+                tmp32 = *(int32_t *)p1;
+            }
+
+            val = _in_message[i].offset +
+                  ((double)tmp32 / 65536.0f) * _in_message[i].factor;
+
+            _in_message[i].prop->setFloatValue(val);
+            p1 += sizeof(int32_t);
+            break;
+
+        case FG_FLOAT:
+            u32 tmpun32;
+            if (binary_byte_order == BYTE_ORDER_NEEDS_CONVERSION) {
+                tmpun32.intVal = sg_bswap_32(*(uint32_t *)p1);
+            } else {
+                tmpun32.floatVal = *(float *)p1;
+            }
+
+            val = _in_message[i].offset +
+                  tmpun32.floatVal * _in_message[i].factor;
+
+            _in_message[i].prop->setFloatValue(val);
+            p1 += sizeof(int32_t);
+            break;
+
+        case FG_DOUBLE:
+            u64 tmpun64;
+            if (binary_byte_order == BYTE_ORDER_NEEDS_CONVERSION) {
+                tmpun64.longVal = sg_bswap_64(*(uint64_t *)p1);
+            } else {
+                tmpun64.doubleVal = *(double *)p1;
+            }
+
+            val = _in_message[i].offset +
+                   tmpun64.doubleVal * _in_message[i].factor;
+
+            _in_message[i].prop->setDoubleValue(val);
+            p1 += sizeof(int64_t);
+            break;
+
+        default: // SG_STRING
+            SG_LOG( SG_IO, SG_ALERT, "Generic protocol: "
+                    "Ignoring unsupported binary input chunk type.");
+        }
+    }
+    
+    return true;
+}
+
+bool FGGeneric::parse_message_ascii() {
+    char *p2, *p1 = buf;
+    double val;
+    int i = -1;
+
+    while ((++i < (int)_in_message.size()) &&
+           p1 && strcmp(p1, line_separator.c_str())) {
+
+        p2 = strstr(p1, var_separator.c_str());
+        if (p2) {
+            *p2 = 0;
+            p2 += var_separator.length();
+        }
+
+        switch (_in_message[i].type) {
+        case FG_INT:
+            val = _in_message[i].offset + atoi(p1) * _in_message[i].factor;
+            _in_message[i].prop->setIntValue((int)val);
+            break;
+
+        case FG_BOOL:
+            _in_message[i].prop->setBoolValue( atof(p1) != 0.0 );
+            break;
+
+        case FG_FIXED:
+        case FG_FLOAT:
+            val = _in_message[i].offset + strtod(p1, 0) * _in_message[i].factor;
+            _in_message[i].prop->setFloatValue((float)val);
+            break;
+
+        case FG_DOUBLE:
+            val = _in_message[i].offset + strtod(p1, 0) * _in_message[i].factor;
+            _in_message[i].prop->setDoubleValue(val);
+            break;
+
+        default: // SG_STRING
+            _in_message[i].prop->setStringValue(p1);
+        }
+
+        p1 = p2;
+    }
+
+    return true;
 }
 
+bool FGGeneric::parse_message() {
+    if (binary_mode) {
+        return parse_message_binary(); 
+    } else {
+        return parse_message_ascii();
+    }
+}
 
 
 // open hailing frequencies
@@ -200,6 +423,13 @@ bool FGGeneric::open() {
 
     set_enabled( true );
 
+    if ( get_direction() == SG_IO_OUT && ! preamble.empty() ) {
+        if ( ! io->write( preamble.c_str(), preamble.size() ) ) {
+            SG_LOG( SG_IO, SG_WARN, "Error writing preamble." );
+            return false;
+        }
+    }
+
     return true;
 }
 
@@ -211,20 +441,59 @@ bool FGGeneric::process() {
     if ( get_direction() == SG_IO_OUT ) {
         gen_message();
         if ( ! io->write( buf, length ) ) {
-            SG_LOG( SG_IO, SG_ALERT, "Error writing data." );
-            return false;
+            SG_LOG( SG_IO, SG_WARN, "Error writing data." );
+            goto error_out;
         }
     } else if ( get_direction() == SG_IO_IN ) {
-        // Temporarliy disable this as output only!
-        //if ( (length = io->readline( buf, FG_MAX_MSG_SIZE )) > 0 ) {
-        //    parse_message();
-        //} else {
-        //    SG_LOG( SG_IO, SG_ALERT, "Error reading data." );
-        //    return false;
-        //}
+        if ( io->get_type() == sgFileType ) {
+            if (!binary_mode) {
+                length = io->readline( buf, FG_MAX_MSG_SIZE );
+                if ( length > 0 ) {
+                    parse_message();
+                } else {
+                    SG_LOG( SG_IO, SG_ALERT, "Error reading data." );
+                    return false;
+                }
+            } else {
+                length = io->read( buf, binary_record_length );
+                if ( length == binary_record_length ) {
+                    parse_message();
+                } else {
+                    SG_LOG( SG_IO, SG_ALERT,
+                            "Generic protocol: Received binary "
+                            "record of unexpected size, expected: "
+                            << binary_record_length << " but received: "
+                            << length);
+                }
+            }
+        } else {
+            if (!binary_mode) {
+                while ((length = io->readline( buf, FG_MAX_MSG_SIZE )) > 0 ) {
+                    parse_message();
+                }
+            } else {
+                while ((length = io->read( buf, binary_record_length )) 
+                          == binary_record_length ) {
+                    parse_message();
+                }
+
+                if ( length > 0 ) {
+                    SG_LOG( SG_IO, SG_ALERT,
+                        "Generic protocol: Received binary "
+                        "record of unexpected size, expected: "
+                        << binary_record_length << " but received: "
+                        << length);
+                }
+            }
+        }
     }
-
     return true;
+error_out:
+    if (exitOnError) {
+        fgExit(1);
+        return true; // should not get there, but please the compiler
+    } else
+        return false;
 }
 
 
@@ -232,6 +501,13 @@ bool FGGeneric::process() {
 bool FGGeneric::close() {
     SGIOChannel *io = get_io_channel();
 
+    if ( get_direction() == SG_IO_OUT && ! postamble.empty() ) {
+        if ( ! io->write( postamble.c_str(), postamble.size() ) ) {
+            SG_LOG( SG_IO, SG_ALERT, "Error writing postamble." );
+            return false;
+        }
+    }
+
     set_enabled( false );
 
     if ( ! io->close() ) {
@@ -240,3 +516,189 @@ bool FGGeneric::close() {
 
     return true;
 }
+
+
+void
+FGGeneric::reinit()
+{
+    SGPath path( globals->get_fg_root() );
+    path.append("Protocol");
+    path.append(file_name.c_str());
+
+    SG_LOG(SG_GENERAL, SG_INFO, "Reading communication protocol from "
+                                << path.str());
+
+    SGPropertyNode root;
+    try {
+        readProperties(path.str(), &root);
+    } catch (const sg_exception &) {
+        SG_LOG(SG_GENERAL, SG_ALERT,
+         "Unable to load the protocol configuration file");
+         return;
+    }
+
+    if (direction == "out") {
+        SGPropertyNode *output = root.getNode("generic/output");
+        if (output) {
+            _out_message.clear();
+            read_config(output, _out_message);
+        }
+    } else if (direction == "in") {
+        SGPropertyNode *input = root.getNode("generic/input");
+        if (input) {
+            _in_message.clear();
+            read_config(input, _in_message);
+        }
+    }
+}
+
+
+void
+FGGeneric::read_config(SGPropertyNode *root, vector<_serial_prot> &msg)
+{
+    binary_mode = root->getBoolValue("binary_mode");
+
+    if (!binary_mode) {
+        /* These variables specified in the $FG_ROOT/data/Protocol/xxx.xml
+         * file for each format
+         *
+         * var_sep_string  = the string/charachter to place between variables
+         * line_sep_string = the string/charachter to place at the end of each
+         *                   lot of variables
+         */
+        preamble = fgUnescape(root->getStringValue("preamble"));
+        postamble = fgUnescape(root->getStringValue("postamble"));
+        var_sep_string = fgUnescape(root->getStringValue("var_separator"));
+        line_sep_string = fgUnescape(root->getStringValue("line_separator"));
+
+        if ( var_sep_string == "newline" ) {
+            var_separator = '\n';
+        } else if ( var_sep_string == "tab" ) {
+            var_separator = '\t';
+        } else if ( var_sep_string == "space" ) {
+            var_separator = ' ';
+        } else if ( var_sep_string == "formfeed" ) {
+            var_separator = '\f';
+        } else if ( var_sep_string == "carriagereturn" ) {
+            var_sep_string = '\r';
+        } else if ( var_sep_string == "verticaltab" ) {
+            var_separator = '\v';
+        } else {
+            var_separator = var_sep_string;
+        }
+
+        if ( line_sep_string == "newline" ) {
+            line_separator = '\n';
+        } else if ( line_sep_string == "tab" ) {
+            line_separator = '\t';
+        } else if ( line_sep_string == "space" ) {
+            line_separator = ' ';
+        } else if ( line_sep_string == "formfeed" ) {
+            line_separator = '\f';
+        } else if ( line_sep_string == "carriagereturn" ) {
+            line_separator = '\r';
+        } else if ( line_sep_string == "verticaltab" ) {
+            line_separator = '\v';
+        } else {
+            line_separator = line_sep_string;
+        }
+    } else {
+        // default values: no footer and record_length = sizeof(representation)
+        binary_footer_type = FOOTER_NONE;
+        binary_record_length = -1;
+
+        // default choice is network byte order (big endian)
+        if (sgIsLittleEndian()) {
+           binary_byte_order = BYTE_ORDER_NEEDS_CONVERSION;
+        } else {
+           binary_byte_order = BYTE_ORDER_MATCHES_NETWORK_ORDER;
+        }
+
+        if ( root->hasValue("binary_footer") ) {
+            string footer_type = root->getStringValue("binary_footer");
+            if ( footer_type == "length" ) {
+                binary_footer_type = FOOTER_LENGTH;
+            } else if ( footer_type.substr(0, 5) == "magic" ) {
+                binary_footer_type = FOOTER_MAGIC;
+                binary_footer_value = strtol(footer_type.substr(6, 
+                            footer_type.length() - 6).c_str(), (char**)0, 0);
+            } else if ( footer_type != "none" ) {
+                SG_LOG(SG_IO, SG_ALERT,
+                       "generic protocol: Unknown generic binary protocol "
+                       "footer '" << footer_type << "', using no footer.");
+            }
+        }
+
+        if ( root->hasValue("record_length") ) {
+            binary_record_length = root->getIntValue("record_length");
+        }
+
+        if ( root->hasValue("byte_order") ) {
+            string byte_order = root->getStringValue("byte_order");
+            if (byte_order == "network" ) {
+                if ( sgIsLittleEndian() ) {
+                    binary_byte_order = BYTE_ORDER_NEEDS_CONVERSION;
+                } else {
+                    binary_byte_order = BYTE_ORDER_MATCHES_NETWORK_ORDER;
+                }
+            } else if ( byte_order == "host" ) {
+                binary_byte_order = BYTE_ORDER_MATCHES_NETWORK_ORDER;
+            } else {
+                SG_LOG(SG_IO, SG_ALERT,
+                       "generic protocol: Undefined generic binary protocol"
+                       "byte order, using HOST byte order.");
+            }
+        }
+    }
+
+    int record_length = 0; // Only used for binary protocols.
+    vector<SGPropertyNode_ptr> chunks = root->getChildren("chunk");
+    for (unsigned int i = 0; i < chunks.size(); i++) {
+
+        _serial_prot chunk;
+
+        // chunk.name = chunks[i]->getStringValue("name");
+        chunk.format = fgUnescape(chunks[i]->getStringValue("format", "%d"));
+        chunk.offset = chunks[i]->getDoubleValue("offset");
+        chunk.factor = chunks[i]->getDoubleValue("factor", 1.0);
+
+        string node = chunks[i]->getStringValue("node", "/null");
+        chunk.prop = fgGetNode(node.c_str(), true);
+
+        string type = chunks[i]->getStringValue("type");
+
+        // Note: officially the type is called 'bool' but for backward
+        //       compatibility 'boolean' will also be supported.
+        if (type == "bool" || type == "boolean") {
+            chunk.type = FG_BOOL;
+            record_length += 1;
+        } else if (type == "float") {
+            chunk.type = FG_FLOAT;
+            record_length += sizeof(int32_t);
+        } else if (type == "double") {
+            chunk.type = FG_DOUBLE;
+            record_length += sizeof(int64_t);
+        } else if (type == "fixed") {
+            chunk.type = FG_FIXED;
+            record_length += sizeof(int32_t);
+        } else if (type == "string")
+            chunk.type = FG_STRING;
+        else {
+            chunk.type = FG_INT;
+            record_length += sizeof(int32_t);
+        }
+        msg.push_back(chunk);
+
+    }
+
+    if( binary_mode ) {
+        if (binary_record_length == -1) {
+            binary_record_length = record_length;
+        } else if (binary_record_length < record_length) {
+            SG_LOG(SG_IO, SG_ALERT,
+                   "generic protocol: Requested binary record length shorter than "
+                   " requested record representation.");
+            binary_record_length = record_length;
+        }
+    }
+}