From f196c8418d11846ac7b5e3a24e80d615d64a2cf0 Mon Sep 17 00:00:00 2001
From: Erik Hofman <erik@ehofman.com>
Date: Thu, 15 Apr 2021 10:11:42 +0200
Subject: [PATCH] Update the props sample description: remove an unnecessary
 type specifier (the union already holds it), add a sample version number and
 a mode to indicate reading from, or writing to, a property. The option to set
 a property value is reserved for future use and not yet implemented.

---
 src/Network/DDS/dds_props.c     |  9 ++--
 src/Network/DDS/dds_props.h     |  8 ++-
 src/Network/DDS/dds_props.idl   | 41 ++++++++-------
 src/Network/DDS/fg_dds_log.cpp  |  8 ++-
 src/Network/DDS/fg_dds_prop.cpp | 91 ++++++++++++++++++---------------
 src/Network/dds_props.cxx       | 20 ++++----
 6 files changed, 99 insertions(+), 78 deletions(-)

diff --git a/src/Network/DDS/dds_props.c b/src/Network/DDS/dds_props.c
index 413c5f67e..7d4297763 100644
--- a/src/Network/DDS/dds_props.c
+++ b/src/Network/DDS/dds_props.c
@@ -17,8 +17,8 @@ static const dds_key_descriptor_t FG_DDS_PROP_keys[1] =
 static const uint32_t FG_DDS_PROP_ops [] =
 {
   DDS_OP_ADR | DDS_OP_TYPE_4BY | DDS_OP_FLAG_SGN | DDS_OP_FLAG_KEY, offsetof (FG_DDS_PROP, id),
-  DDS_OP_ADR | DDS_OP_TYPE_ARR | DDS_OP_SUBTYPE_1BY, offsetof (FG_DDS_PROP, guid), 16,
-  DDS_OP_ADR | DDS_OP_TYPE_4BY | DDS_OP_FLAG_SGN, offsetof (FG_DDS_PROP, type),
+  DDS_OP_ADR | DDS_OP_TYPE_1BY, offsetof (FG_DDS_PROP, version),
+  DDS_OP_ADR | DDS_OP_TYPE_BOO, offsetof (FG_DDS_PROP, mode),
   DDS_OP_ADR | DDS_OP_TYPE_UNI | DDS_OP_SUBTYPE_4BY | DDS_OP_FLAG_SGN, offsetof (FG_DDS_PROP, val._d), 9u, (31u << 16) + 4u,
   DDS_OP_JEQ | DDS_OP_TYPE_BOO | 0, FG_DDS_BOOL, offsetof (FG_DDS_PROP, val._u.Bool),
   DDS_OP_JEQ | DDS_OP_TYPE_4BY | DDS_OP_FLAG_SGN | 0, FG_DDS_NONE, offsetof (FG_DDS_PROP, val._u.Int32),
@@ -29,6 +29,7 @@ static const uint32_t FG_DDS_PROP_ops [] =
   DDS_OP_JEQ | DDS_OP_TYPE_STR | 0, FG_DDS_ALIAS, offsetof (FG_DDS_PROP, val._u.String),
   DDS_OP_JEQ | DDS_OP_TYPE_STR | 0, FG_DDS_STRING, offsetof (FG_DDS_PROP, val._u.String),
   DDS_OP_JEQ | DDS_OP_TYPE_STR | 0, FG_DDS_UNSPECIFIED, offsetof (FG_DDS_PROP, val._u.String),
+  DDS_OP_ADR | DDS_OP_TYPE_ARR | DDS_OP_SUBTYPE_1BY, offsetof (FG_DDS_PROP, guid), 16,
   DDS_OP_RTS
 };
 
@@ -40,7 +41,7 @@ const dds_topic_descriptor_t FG_DDS_PROP_desc =
   1u,
   "FG::DDS_PROP",
   FG_DDS_PROP_keys,
-  14,
+  15,
   FG_DDS_PROP_ops,
-  "<MetaData version=\"1.0.0\"><Module name=\"FG\"><Enum name=\"propType\"><Element name=\"DDS_NONE\" value=\"0\"/><Element name=\"DDS_ALIAS\" value=\"1\"/><Element name=\"DDS_BOOL\" value=\"2\"/><Element name=\"DDS_INT\" value=\"3\"/><Element name=\"DDS_LONG\" value=\"4\"/><Element name=\"DDS_FLOAT\" value=\"5\"/><Element name=\"DDS_DOUBLE\" value=\"6\"/><Element name=\"DDS_STRING\" value=\"7\"/><Element name=\"DDS_UNSPECIFIED\" value=\"8\"/></Enum><Union name=\"propValue\"><SwitchType><Type name=\"propType\"/></SwitchType><Case name=\"Bool\"><Boolean/><Label value=\"DDS_BOOL\"/></Case><Case name=\"Int32\"><Long/><Label value=\"DDS_NONE\"/><Label value=\"DDS_INT\"/></Case><Case name=\"Int64\"><LongLong/><Label value=\"DDS_LONG\"/></Case><Case name=\"Float32\"><Float/><Label value=\"DDS_FLOAT\"/></Case><Case name=\"Float64\"><Double/><Label value=\"DDS_DOUBLE\"/></Case><Case name=\"String\"><String/><Label value=\"DDS_ALIAS\"/><Label value=\"DDS_STRING\"/><Label value=\"DDS_UNSPECIFIED\"/></Case></Union><Struct name=\"DDS_PROP\"><Member name=\"id\"><Long/></Member><Member name=\"guid\"><Array size=\"16\"><Octet/></Array></Member><Member name=\"type\"><Type name=\"propType\"/></Member><Member name=\"val\"><Type name=\"propValue\"/></Member></Struct></Module></MetaData>"
+  "<MetaData version=\"1.0.0\"><Module name=\"FG\"><Enum name=\"propType\"><Element name=\"DDS_NONE\" value=\"0\"/><Element name=\"DDS_ALIAS\" value=\"1\"/><Element name=\"DDS_BOOL\" value=\"2\"/><Element name=\"DDS_INT\" value=\"3\"/><Element name=\"DDS_LONG\" value=\"4\"/><Element name=\"DDS_FLOAT\" value=\"5\"/><Element name=\"DDS_DOUBLE\" value=\"6\"/><Element name=\"DDS_STRING\" value=\"7\"/><Element name=\"DDS_UNSPECIFIED\" value=\"8\"/></Enum><Union name=\"propValue\"><SwitchType><Type name=\"propType\"/></SwitchType><Case name=\"Bool\"><Boolean/><Label value=\"DDS_BOOL\"/></Case><Case name=\"Int32\"><Long/><Label value=\"DDS_NONE\"/><Label value=\"DDS_INT\"/></Case><Case name=\"Int64\"><LongLong/><Label value=\"DDS_LONG\"/></Case><Case name=\"Float32\"><Float/><Label value=\"DDS_FLOAT\"/></Case><Case name=\"Float64\"><Double/><Label value=\"DDS_DOUBLE\"/></Case><Case name=\"String\"><String/><Label value=\"DDS_ALIAS\"/><Label value=\"DDS_STRING\"/><Label value=\"DDS_UNSPECIFIED\"/></Case></Union><Struct name=\"DDS_PROP\"><Member name=\"id\"><Long/></Member><Member name=\"version\"><Octet/></Member><Member name=\"mode\"><Boolean/></Member><Member name=\"val\"><Type name=\"propValue\"/></Member><Member name=\"guid\"><Array size=\"16\"><Octet/></Array></Member></Struct></Module></MetaData>"
 };
diff --git a/src/Network/DDS/dds_props.h b/src/Network/DDS/dds_props.h
index 5985daf1f..38a240299 100644
--- a/src/Network/DDS/dds_props.h
+++ b/src/Network/DDS/dds_props.h
@@ -17,7 +17,10 @@
 extern "C" {
 #endif
 
+#define FG_DDS_PROP_VERSION 0
 #define FG_DDS_PROP_REQUEST -1
+#define FG_DDS_MODE_READ (0)
+#define FG_DDS_MODE_WRITE (1)
 typedef enum FG_propType
 {
   FG_DDS_NONE,
@@ -56,9 +59,10 @@ typedef struct FG_propValue
 typedef struct FG_DDS_PROP
 {
   int32_t id;
-  uint8_t guid[16];
-  FG_propType type;
+  uint8_t version;
+  bool mode;
   FG_propValue val;
+  uint8_t guid[16];
 } FG_DDS_PROP;
 
 extern const dds_topic_descriptor_t FG_DDS_PROP_desc;
diff --git a/src/Network/DDS/dds_props.idl b/src/Network/DDS/dds_props.idl
index dd59a3e18..0b8ac6bf8 100644
--- a/src/Network/DDS/dds_props.idl
+++ b/src/Network/DDS/dds_props.idl
@@ -5,7 +5,10 @@ module FG
 {
 
 // defining it this way also generates accompanying #defines in the header file.
+const octet DDS_PROP_VERSION = 0;
 const short DDS_PROP_REQUEST = -1;
+const boolean DDS_MODE_READ = 0;
+const boolean DDS_MODE_WRITE = 1;
 
 enum propType
 {
@@ -47,38 +50,40 @@ union propValue switch ( propType )
 // Initial property request sequence
 // for properties where the id is not yet known:
 // 1. Set id to FG_DDS_PROP_REQUEST
-// 2. set guid to the 16-byte participants GUID
-// 3. Set type to STRING
-// 4. Set val.String to the propery path
-// 5. Send the package.
+// 2. Set version to FG_DDS_PROP_VERSION
+// 3. Set mode to FG_DDS_MODE_READ
+// 4. set guid to the 16-byte participants GUID
+// 5. Set val type to STRING
+// 6. Set val String to the propery path
+// 7. Send the package.
 //
-// 6. wait for an answer
+// 8. Wait for an answer
 //    * Check whether guid matches the participants GUID.
 //    * The index of the requested propery path is stored in the id variable
 //      which should be used by successive request as the id for that property.
-//    * The type variable indicates the type of the value of the property.
 //    * The val union holds the value of the propery.
 //
 // Successive property request sequence:
-// 1. Set id to the id of the requested property
-// 2. Send the package.
+// 1. Make sure id is to the id of the requested property
+// 2. Make sure version is to FG_DDS_PROP_VERSION
+// 3. Set mode to FG_DDS_MODE_READ or FG_DDS_MODE_WRITE
+// 3a. Optionally set the val union to match the property to overwrite.
+// 4. Send the package.
 //
-// 3. wait for an answer
+// 5. Wait for an answer
 //    * Check whether id matches the requested property id.
-//    * The type variable indicates the type of the value of the property.
 //    * The val union holds the value of the propery.
-//
-// guid is not defined as an array of 16 unsigned characters to keep the
-// sample small for successive requests. This way only a FG_DDS_PROP_REQUEST
-// sample will reserve the full 16-bytes.
 struct DDS_PROP
 {
-    long id;		// property index and DDS id
+    long id;		// 32-bit property index and DDS id.
+    octet version;	// 8-bit sample-type version number.
 
+    boolean mode;	// FG_DDS_MODE_READ or FG_DDS_MODE_WRITE
+    propValue val;	// property value or path.
+
+    // A sequence could be used here but unfortunatelly it's initializer
+    // already is 10-bytes in size.
     octet guid[16];
-
-    propType type;
-    propValue val;
 };
 #pragma keylist DDS_PROP id
 
diff --git a/src/Network/DDS/fg_dds_log.cpp b/src/Network/DDS/fg_dds_log.cpp
index 0102a05a8..8fe28e17a 100644
--- a/src/Network/DDS/fg_dds_log.cpp
+++ b/src/Network/DDS/fg_dds_log.cpp
@@ -111,11 +111,15 @@ int main()
       printf("     rudder: %lf\n", ctrls.rudder);
     }
 
-    if (topics["prop"]->read()) {
+    if (topics["prop"]->read() &&
+         prop.version == FG_DDS_PROP_VERSION )
+    {
       printf("=== [fg_dds_log] Received : ");
       printf("Prop Message:\n");
+      printf(" version: %i\n", prop.version);
+      printf(" mode: %s\n", prop.mode ? "write" : "read");
       if (prop.id == FG_DDS_PROP_REQUEST) {
-        printf(" request: %s\n", prop.val._u.String);
+        printf(" path: %s\n", prop.val._u.String);
         printf("GUID: ");
         for(int i=0; i<16; ++i)
           printf("%X ", prop.guid[i]);
diff --git a/src/Network/DDS/fg_dds_prop.cpp b/src/Network/DDS/fg_dds_prop.cpp
index 947b3e328..5720463ac 100644
--- a/src/Network/DDS/fg_dds_prop.cpp
+++ b/src/Network/DDS/fg_dds_prop.cpp
@@ -16,7 +16,7 @@ int main()
   FG_DDS_PROP prop;
   SG_DDS_Topic *topic = new SG_DDS_Topic(prop, &FG_DDS_PROP_desc);
 
-  participant.add(topic, SG_IO_OUT);
+  participant.add(topic, SG_IO_BI);
 
   dds_guid_t guid = topic->get_guid();
   memcpy(prop.guid, guid.v, 16);
@@ -25,6 +25,9 @@ int main()
     printf("%X ", prop.guid[i]);
   printf("\n");
 
+  prop.version = FG_DDS_PROP_VERSION;
+  prop.mode = FG_DDS_MODE_READ;
+
   char path[256];
   printf("\nType 'q' to quit\n");
   do
@@ -33,7 +36,7 @@ int main()
     int len = scanf("%255s", path);
     if (len == EOF) continue;
 
-    if (*path == 'q')  break;
+    if (*path == 'q') break;
 
     prop.id = FG_DDS_PROP_REQUEST;
     prop.val._d = FG_DDS_STRING;
@@ -42,47 +45,51 @@ int main()
     topic->write();
 
     participant.wait();
-
-    topic->read();
-    switch(prop.val._d)
+    if (topic->read() &&
+         prop.version == FG_DDS_PROP_VERSION &&
+         prop.id != FG_DDS_PROP_REQUEST)
     {
-    case FG_DDS_NONE:
-      printf("       type: none");
-      break;
-    case FG_DDS_ALIAS:
-      printf("       type: alias");
-      printf("      value: %s\n", prop.val._u.String);
-      break;
-    case FG_DDS_BOOL:
-      printf("       type: bool");
-      printf("      value: %i\n", prop.val._u.Bool);
-      break;
-    case FG_DDS_INT:
-      printf("       type: int");
-      printf("      value: %i\n", prop.val._u.Int32);
-      break;
-    case FG_DDS_LONG:
-      printf("       type: long");
-      printf("      value: %li\n", prop.val._u.Int64);
-      break;
-    case FG_DDS_FLOAT:
-      printf("       type: float");
-      printf("      value: %f\n", prop.val._u.Float32);
-      break;
-    case FG_DDS_DOUBLE:
-      printf("       type: double");
-      printf("      value: %lf\n", prop.val._u.Float64);
-      break;
-    case FG_DDS_STRING:
-      printf("       type: string");
-      printf("      value: %s\n", prop.val._u.String);
-      break;
-    case FG_DDS_UNSPECIFIED:
-      printf("       type: unspecified");
-      printf("      value: %s\n", prop.val._u.String);
-      break;
-    default:
-      break;
+      printf("\nReceived:\n");
+      switch(prop.val._d)
+      {
+      case FG_DDS_NONE:
+        printf("       type: none");
+        break;
+      case FG_DDS_ALIAS:
+        printf("       type: alias");
+        printf("      value: %s\n", prop.val._u.String);
+        break;
+      case FG_DDS_BOOL:
+        printf("       type: bool");
+        printf("      value: %i\n", prop.val._u.Bool);
+        break;
+      case FG_DDS_INT:
+        printf("       type: int");
+        printf("      value: %i\n", prop.val._u.Int32);
+        break;
+      case FG_DDS_LONG:
+        printf("       type: long");
+        printf("      value: %li\n", prop.val._u.Int64);
+        break;
+      case FG_DDS_FLOAT:
+        printf("       type: float");
+        printf("      value: %f\n", prop.val._u.Float32);
+        break;
+      case FG_DDS_DOUBLE:
+        printf("       type: double");
+        printf("      value: %lf\n", prop.val._u.Float64);
+        break;
+      case FG_DDS_STRING:
+        printf("       type: string");
+        printf("      value: %s\n", prop.val._u.String);
+        break;
+      case FG_DDS_UNSPECIFIED:
+        printf("       type: unspecified");
+        printf("      value: %s\n", prop.val._u.String);
+        break;
+      default:
+        break;
+      }
     }
   } while(true);
 
diff --git a/src/Network/dds_props.cxx b/src/Network/dds_props.cxx
index 72513f825..aacb2ba7b 100644
--- a/src/Network/dds_props.cxx
+++ b/src/Network/dds_props.cxx
@@ -81,7 +81,7 @@ bool FGDDSProps::process() {
         {
             if (prop.id == FG_DDS_PROP_REQUEST)
             {
-                if (prop.type == FG_DDS_STRING)
+                if (prop.val._d == FG_DDS_STRING)
                 {
                     const char *path = prop.val._u.String;
                     auto it = path_list.find(path);
@@ -148,31 +148,31 @@ void FGDDSProps::setProp(FG_DDS_PROP& prop, SGPropertyNode_ptr p)
     {
         simgear::props::Type type = p->getType();
         if (type == simgear::props::BOOL) {
-            prop.type = FG_DDS_BOOL;
+            prop.val._d = FG_DDS_BOOL;
             prop.val._u.Bool = p->getBoolValue();
         } else if (type == simgear::props::INT) {
-            prop.type = FG_DDS_INT;
+            prop.val._d = FG_DDS_INT;
             prop.val._u.Int32 = p->getIntValue();
         } else if (type == simgear::props::LONG) {
-            prop.type = FG_DDS_LONG;
+            prop.val._d = FG_DDS_LONG;
             prop.val._u.Int64 = p->getLongValue();
         } else if (type == simgear::props::FLOAT) {
-            prop.type = FG_DDS_FLOAT;
+            prop.val._d = FG_DDS_FLOAT;
             prop.val._u.Float32 = p->getFloatValue();
         } else if (type == simgear::props::DOUBLE) {
-            prop.type = FG_DDS_DOUBLE;
+            prop.val._d = FG_DDS_DOUBLE;
             prop.val._u.Float64 = p->getDoubleValue();
         } else if (type == simgear::props::ALIAS) {
-            prop.type = FG_DDS_ALIAS;
+            prop.val._d = FG_DDS_ALIAS;
             prop.val._u.String = const_cast<char*>(p->getStringValue());
         } else if (type == simgear::props::STRING) {
-            prop.type = FG_DDS_STRING;
+            prop.val._d = FG_DDS_STRING;
             prop.val._u.String = const_cast<char*>(p->getStringValue());
         } else if (type == simgear::props::UNSPECIFIED) {
-            prop.type = FG_DDS_UNSPECIFIED;
+            prop.val._d = FG_DDS_UNSPECIFIED;
             prop.val._u.String = const_cast<char*>(p->getStringValue());
         } else {
-            prop.type = FG_DDS_NONE;
+            prop.val._d = FG_DDS_NONE;
             prop.val._u.Int32 = 0;
         }
     }