]> git.mxchange.org Git - flightgear.git/blobdiff - src/Network/generic.cxx
generic binary protocol: add 'word' datatype
[flightgear.git] / src / Network / generic.cxx
index f31484f166a2b97829873ac85a98edcba56cb142..8372a5e4012a1df1addb10f4809ced426d747f1a 100644 (file)
 
 using simgear::strutils::unescape;
 
-FGGeneric::FGGeneric(vector<string> tokens) : exitOnError(false), initOk(false)
+class FGProtocolWrapper {
+public:
+  virtual ~FGProtocolWrapper() {}
+  virtual int wrap( size_t n, uint8_t * buf ) = 0;
+  virtual int unwrap( size_t n, uint8_t * buf ) = 0;
+};
+
+/**
+ * http://www.ka9q.net/papers/kiss.html
+ */
+class FGKissWrapper : public FGProtocolWrapper {
+public:
+  virtual int wrap( size_t n, uint8_t * buf );
+  virtual int unwrap( size_t n, uint8_t * buf );
+private:
+  static const uint8_t  FEND;
+  static const uint8_t  FESC;
+  static const uint8_t  TFEND;
+  static const uint8_t  TFESC;
+};
+
+const uint8_t  FGKissWrapper::FEND  = 0xC0;
+const uint8_t  FGKissWrapper::FESC  = 0xDB;
+const uint8_t  FGKissWrapper::TFEND = 0xDC;
+const uint8_t  FGKissWrapper::TFESC = 0xDD;
+
+int FGKissWrapper::wrap( size_t n, uint8_t * buf )
+{
+  std::vector<uint8_t> dest;
+  uint8_t *sp = buf;
+
+  dest.push_back(FEND);
+  dest.push_back(0); // command/channel always zero
+  for( size_t i = 0; i < n; i++ ) {
+    uint8_t c = *sp++;
+    switch( c ) {
+      case FESC:
+        dest.push_back(FESC);
+        dest.push_back(TFESC);
+        break;
+
+      case FEND:
+        dest.push_back(FESC);
+        dest.push_back(TFEND);
+        break;
+
+      default:
+        dest.push_back(c);
+        break;
+    }
+  }
+  dest.push_back(FEND);
+
+  memcpy( buf, dest.data(), dest.size() );
+  return dest.size();
+}
+
+int FGKissWrapper::unwrap( size_t n, uint8_t * buf )
+{
+  uint8_t * sp = buf;
+
+  // look for FEND
+  while( 0 < n && FEND != *sp ) {
+    sp++;
+    n--;
+  }
+
+  // ignore all leading FEND
+  while( 0 < n && FEND == *sp ) {
+    sp++;
+    n--;
+  }
+
+  if( 0 == n ) return 0;
+
+  std::vector<uint8_t> dest;
+  {
+    bool escaped = false;
+
+    while( 0 < n ) {
+
+      n--;
+      uint8_t c = *sp++;
+
+      if( escaped ) {
+        switch( c ) {
+
+          case TFESC:
+            dest.push_back( FESC );
+            break;
+
+          case TFEND:
+            dest.push_back( FEND );
+            break;
+
+          default: // this is an error - ignore and continue
+            break;
+        }
+
+        escaped = false;
+
+      } else {
+
+        switch( c ) {
+          case FESC:
+            escaped = true;
+            break;
+
+          case FEND:
+            if( 0 != n ) {
+              SG_LOG(SG_IO, SG_WARN,
+               "KISS frame detected FEND before end of frame. Trailing data dropped." );
+            }
+            n = 0; 
+            break;
+
+          default:
+            dest.push_back( c );
+            break;
+        }
+      }
+    }
+  }
+
+  memcpy( buf, dest.data(), dest.size() );
+  return dest.size();
+}
+
+
+class FGSTXETXWrapper : public FGProtocolWrapper {
+public:
+  virtual int wrap( size_t n, uint8_t * buf );
+  virtual int unwrap( size_t n, uint8_t * buf );
+
+  static const uint8_t  STX;
+  static const uint8_t  ETX;
+  static const uint8_t  DLE;
+};
+
+const uint8_t  FGSTXETXWrapper::STX  = 0x02;
+const uint8_t  FGSTXETXWrapper::ETX  = 0x03;
+const uint8_t  FGSTXETXWrapper::DLE  = 0x00;
+
+int FGSTXETXWrapper::wrap( size_t n, uint8_t * buf )
+{
+  // stuff payload as
+  // <dle><stx>payload<dle><etx>
+  // if payload contains <dle>, stuff <dle> as <dle><dle>
+  std::vector<uint8_t> dest;
+  uint8_t *sp = buf;
+
+  dest.push_back(DLE);
+  dest.push_back(STX);
+
+  while( n > 0 ) {
+    n--;
+
+    if( DLE == *sp )
+      dest.push_back(DLE);
+
+    dest.push_back(*sp++);
+  }
+
+  dest.push_back(DLE);
+  dest.push_back(ETX);
+
+  memcpy( buf, dest.data(), dest.size() ); 
+  return dest.size();
+}
+
+int FGSTXETXWrapper::unwrap( size_t n, uint8_t * buf )
+{
+  return n;
+}
+
+FGGeneric::FGGeneric(vector<string> tokens) : exitOnError(false), initOk(false), wrapper(NULL)
 {
     size_t configToken;
     if (tokens[1] == "socket") {
@@ -77,6 +252,7 @@ FGGeneric::FGGeneric(vector<string> tokens) : exitOnError(false), initOk(false)
 }
 
 FGGeneric::~FGGeneric() {
+  delete wrapper;
 }
 
 union u32 {
@@ -160,6 +336,26 @@ bool FGGeneric::gen_message_binary() {
             break;
         }
 
+        case FG_BYTE:
+        {
+            val = _out_message[i].offset +
+                  _out_message[i].prop->getIntValue() * _out_message[i].factor;
+            int8_t byteVal = val;
+            memcpy(&buf[length], &byteVal, sizeof(int8_t));
+            length += sizeof(int8_t);
+            break;
+        }
+
+        case FG_WORD:
+        {
+            val = _out_message[i].offset +
+                  _out_message[i].prop->getIntValue() * _out_message[i].factor;
+            int16_t wordVal = val;
+            memcpy(&buf[length], &wordVal, sizeof(int16_t));
+            length += sizeof(int16_t);
+            break;
+        }
+
         default: // SG_STRING
             const char *strdata = _out_message[i].prop->getStringValue();
             int32_t strlength = strlen(strdata);
@@ -182,6 +378,7 @@ bool FGGeneric::gen_message_binary() {
              * length += (strlength % 4 > 0 ? sizeof(int32_t) - strlength % 4 : 0;
              */
             break;
+
         }
     }
 
@@ -205,6 +402,8 @@ bool FGGeneric::gen_message_binary() {
         length += sizeof(int32_t);
     }
 
+    if( wrapper ) length = wrapper->wrap( length, reinterpret_cast<uint8_t*>(buf) );
+
     return true;
 }
 
@@ -219,39 +418,43 @@ bool FGGeneric::gen_message_ascii() {
         if (i > 0) {
             generic_sentence += var_separator;
         }
+        
+        string format = simgear::strutils::sanitizePrintfFormat(_out_message[i].format);
 
         switch (_out_message[i].type) {
+        case FG_BYTE:
+        case FG_WORD:
         case FG_INT:
             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);
+            snprintf(tmp, 255, format.c_str(), (int)val);
             break;
 
         case FG_BOOL:
-            snprintf(tmp, 255, _out_message[i].format.c_str(),
+            snprintf(tmp, 255, 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);
+            snprintf(tmp, 255, 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);
+            snprintf(tmp, 255, format.c_str(), (float)val);
             break;
 
         case FG_DOUBLE:
             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);
+            snprintf(tmp, 255, format.c_str(), (double)val);
             break;
 
         default: // SG_STRING
-            snprintf(tmp, 255, _out_message[i].format.c_str(),
+            snprintf(tmp, 255, format.c_str(),
                                    _out_message[i].prop->getStringValue());
         }
 
@@ -333,6 +536,22 @@ bool FGGeneric::parse_message_binary(int length) {
             p1 += sizeof(int64_t);
             break;
 
+        case FG_BYTE:
+            tmp32 = *(int8_t *)p1;
+            updateValue(_in_message[i], (int)tmp32);
+            p1 += sizeof(int8_t);
+            break;
+
+        case FG_WORD:
+            if (binary_byte_order == BYTE_ORDER_NEEDS_CONVERSION) {
+                tmp32 = sg_bswap_16(*(int16_t *)p1);
+            } else {
+                tmp32 = *(int16_t *)p1;
+            }
+            updateValue(_in_message[i], (int)tmp32);
+            p1 += sizeof(int16_t);
+            break;
+
         default: // SG_STRING
             SG_LOG( SG_IO, SG_ALERT, "Generic protocol: "
                     "Ignoring unsupported binary input chunk type.");
@@ -372,6 +591,8 @@ bool FGGeneric::parse_message_ascii(int length) {
         }
 
         switch (_in_message[i].type) {
+        case FG_BYTE:
+        case FG_WORD:
         case FG_INT:
             updateValue(_in_message[i], atoi(p1));
             break;
@@ -567,7 +788,7 @@ FGGeneric::reinit()
                 // bad configuration
                 return;
             }
-            if (!binary_mode && (line_separator.size() == 0 ||
+            if (!binary_mode && (line_separator.empty() ||
                 *line_separator.rbegin() != '\n')) {
 
                 SG_LOG(SG_IO, SG_WARN,
@@ -677,6 +898,14 @@ FGGeneric::read_config(SGPropertyNode *root, vector<_serial_prot> &msg)
                        "byte order, using HOST byte order.");
             }
         }
+
+        if( root->hasValue( "wrapper" ) ) {
+            string w = root->getStringValue( "wrapper" );
+            if( w == "kiss" )  wrapper = new FGKissWrapper();
+            else if( w == "stxetx" )  wrapper = new FGSTXETXWrapper();
+            else SG_LOG(SG_IO, SG_ALERT,
+                       "generic protocol: Undefined binary protocol wrapper '" + w + "' ignored" );
+        }
     }
 
     int record_length = 0; // Only used for binary protocols.
@@ -695,8 +924,13 @@ FGGeneric::read_config(SGPropertyNode *root, vector<_serial_prot> &msg)
         chunk.wrap = chunks[i]->getBoolValue("wrap");
         chunk.rel = chunks[i]->getBoolValue("relative");
 
-        string node = chunks[i]->getStringValue("node", "/null");
-        chunk.prop = fgGetNode(node.c_str(), true);
+        if( chunks[i]->hasChild("const") ) {
+            chunk.prop = new SGPropertyNode();
+            chunk.prop->setStringValue( chunks[i]->getStringValue("const", "" ) );
+        } else {
+            string node = chunks[i]->getStringValue("node", "/null");
+            chunk.prop = fgGetNode(node.c_str(), true);
+        }
 
         string type = chunks[i]->getStringValue("type");
 
@@ -714,9 +948,15 @@ FGGeneric::read_config(SGPropertyNode *root, vector<_serial_prot> &msg)
         } else if (type == "fixed") {
             chunk.type = FG_FIXED;
             record_length += sizeof(int32_t);
-        } else if (type == "string")
+        } else if (type == "string") {
             chunk.type = FG_STRING;
-        else {
+        } else if (type == "byte") {
+            chunk.type = FG_BYTE;
+            record_length += sizeof(int8_t);
+        } else if (type == "word") {
+            chunk.type = FG_WORD;
+            record_length += sizeof(int16_t);
+        } else {
             chunk.type = FG_INT;
             record_length += sizeof(int32_t);
         }