Browse Source

feat(pubsub) extended PubSub RT level example, added testcase for PubSub RT levels, fixed memory leaks, moved offset calculation into DSM and NM binary size calculation (signature changed)

Andreas Ebner 4 years ago
parent
commit
a1cd155875

+ 60 - 22
examples/pubsub/server_pubsub_publisher_rt_level.c

@@ -10,20 +10,25 @@
 #include <stdlib.h>
 #include <open62541/server_pubsub.h>
 
+/* possible options: PUBSUB_CONFIG_FASTPATH_NONE, PUBSUB_CONFIG_FASTPATH_FIXED_OFFSETS, PUBSUB_CONFIG_FASTPATH_STATIC_VALUES */
+#define PUBSUB_CONFIG_FASTPATH_FIXED_OFFSETS
 #define PUBSUB_CONFIG_PUBLISH_CYCLE_MS 100
 #define PUBSUB_CONFIG_PUBLISH_CYCLES 100
-/* possible values: PUBSUB_CONFIG_FASTPATH_NONE (WIP not implemented), PUBSUB_CONFIG_FASTPATH_FIXED_OFFSETS, PUBSUB_CONFIG_FASTPATH_STATIC_VALUES (WIP  not implemented)*/
-#define PUBSUB_CONFIG_FASTPATH_FIXED_OFFSETS
 #define PUBSUB_CONFIG_FIELD_COUNT 10
 
 /**
- * The PubSub RT level example points out the configuration of different PubSub RT levels. These levels will be later
- * used for deterministic message generation. The main target is to reduce the time spread and effort during the publish cycle.
- * Most of the RT levels are based on a pre-generated and buffered DataSetMesseges and
- * NetworkMessages. Since changes in the PubSub-configuration will invalidate the buffered frames, the PubSub
- * configuration can be frozen after the configuration phase.
+ * The PubSub RT level example points out the configuration of different PubSub RT-levels. These levels will be
+ * used together with an RT capable OS for deterministic message generation. The main target is to reduce the time
+ * spread and effort during the publish cycle. Most of the RT levels are based on pre-generated and buffered
+ * DataSetMesseges and NetworkMessages. Since changes in the PubSub-configuration will invalidate the buffered
+ * frames, the PubSub configuration must be frozen after the configuration phase.
  *
- * This example can be configured to compare and measure the different PubSub options.
+ * This example can be configured to compare and measure the different PubSub options by the following define options:
+ * PUBSUB_CONFIG_FASTPATH_NONE -> The published fields are added to the information model and published in the default non-RT mode
+ * PUBSUB_CONFIG_FASTPATH_STATIC_VALUES -> The published fields are not visible in the information model. The publish cycle is improved
+ * by prevent the value lookup within the information model.
+ * PUBSUB_CONFIG_FASTPATH_FIXED_OFFSETS -> The published fields are not visible in the information model. After the PubSub-configuration
+ * freeze, the NetworkMessages and DataSetMessages will be calculated and buffered. During the publish cycle these buffers will only be updated.
  */
 
 UA_NodeId publishedDataSetIdent, dataSetFieldIdent, writerGroupIdent, connectionIdentifier;
@@ -59,10 +64,31 @@ addMinimalPubSubConfiguration(UA_Server * server){
 
 static void
 valueUpdateCallback(UA_Server *server, void *data) {
+#if defined PUBSUB_CONFIG_FASTPATH_FIXED_OFFSETS || defined PUBSUB_CONFIG_FASTPATH_STATIC_VALUES
     for (int i = 0; i < PUBSUB_CONFIG_FIELD_COUNT; ++i)
-        *valueStore[i] = *valueStore[i]+1;
+        *valueStore[i] = *valueStore[i] + 1;
     if(*valueStore[0] > PUBSUB_CONFIG_PUBLISH_CYCLES)
         running = false;
+#endif
+#if defined PUBSUB_CONFIG_FASTPATH_NONE
+    for(size_t i = 0; i < PUBSUB_CONFIG_FIELD_COUNT; i++){
+        UA_Variant value;
+        UA_Variant_init(&value);
+        if(UA_Server_readValue(server, UA_NODEID_NUMERIC(1, 1000 + (UA_UInt32) i), &value) != UA_STATUSCODE_GOOD) {
+            UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Failed to read publish value. Node number: %zu", i);
+            continue;
+        }
+        UA_UInt32 *intValue = (UA_UInt32 *) value.data;
+        *intValue = *intValue + 1;
+        if(UA_Server_writeValue(server, UA_NODEID_NUMERIC(1, 1000 + (UA_UInt32) i), value) != UA_STATUSCODE_GOOD){
+            UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Failed to update publish value. Node number: %zu", i);
+            continue;
+        }
+        if(i == 0 && *intValue  > PUBSUB_CONFIG_PUBLISH_CYCLES)
+            running = false;
+        UA_Variant_deleteMembers(&value);
+    }
+#endif
 }
 
 int main(void) {
@@ -84,8 +110,6 @@ int main(void) {
     /*Add standard PubSub configuration (no difference to the std. configuration)*/
     addMinimalPubSubConfiguration(server);
 
-    /* Add one WriterGroup with PubSub RT Level 0. If any rtLevel != UA_PUBSUB_RT_NONE is set, the
-     * writerGroup does not start the publishing interval automatically.*/
     UA_WriterGroupConfig writerGroupConfig;
     memset(&writerGroupConfig, 0, sizeof(UA_WriterGroupConfig));
     writerGroupConfig.name = UA_STRING("Demo WriterGroup");
@@ -95,7 +119,6 @@ int main(void) {
     writerGroupConfig.encodingMimeType = UA_PUBSUB_ENCODING_UADP;
     writerGroupConfig.messageSettings.encoding             = UA_EXTENSIONOBJECT_DECODED;
     writerGroupConfig.messageSettings.content.decoded.type = &UA_TYPES[UA_TYPES_UADPWRITERGROUPMESSAGEDATATYPE];
-    /* RT Level 0 setup */
     UA_UadpWriterGroupMessageDataType writerGroupMessage;
     UA_UadpWriterGroupMessageDataType_init(&writerGroupMessage);
     /* Change message settings of writerGroup to send PublisherId,
@@ -106,8 +129,10 @@ int main(void) {
                                                     (UA_UadpNetworkMessageContentMask) UA_UADPNETWORKMESSAGECONTENTMASK_WRITERGROUPID |
                                                     (UA_UadpNetworkMessageContentMask) UA_UADPNETWORKMESSAGECONTENTMASK_PAYLOADHEADER);
     writerGroupConfig.messageSettings.content.decoded.data = &writerGroupMessage;
-#if defined PUBSUB_CONFIG_FASTPATH_FIXED_OFFSETS
+#ifdef PUBSUB_CONFIG_FASTPATH_FIXED_OFFSETS
     writerGroupConfig.rtLevel = UA_PUBSUB_RT_FIXED_SIZE;
+#elif defined PUBSUB_CONFIG_FASTPATH_STATIC_VALUES
+    writerGroupConfig.rtLevel = UA_PUBSUB_RT_DIRECT_VALUE_ACCESS;
 #endif
     UA_Server_addWriterGroup(server, connectionIdentifier, &writerGroupConfig, &writerGroupIdent);
     /* Add one DataSetWriter */
@@ -138,6 +163,28 @@ int main(void) {
         dsfConfig.field.variable.staticValueSource.value = variant;
         UA_Server_addDataSetField(server, publishedDataSetIdent, &dsfConfig, &dataSetFieldIdent);
     }
+#endif
+#if defined PUBSUB_CONFIG_FASTPATH_NONE
+    UA_DataSetFieldConfig dsfConfig;
+    memset(&dsfConfig, 0, sizeof(UA_DataSetFieldConfig));
+    for(size_t i = 0; i < PUBSUB_CONFIG_FIELD_COUNT; i++){
+        UA_VariableAttributes attributes = UA_VariableAttributes_default;
+        UA_Variant value;
+        UA_Variant_init(&value);
+        UA_UInt32 intValue = (UA_UInt32) i * 1000;
+        UA_Variant_setScalar(&value, &intValue, &UA_TYPES[UA_TYPES_UINT32]);
+        attributes.value = value;
+        if(UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1,  1000 + (UA_UInt32) i),
+                UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
+                UA_QUALIFIEDNAME(1, "variable"), UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
+                 attributes, NULL, NULL) != UA_STATUSCODE_GOOD){
+            UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Failed to add Publish-Node to the server. Node number: %zu", i);
+            continue;
+        }
+        dsfConfig.field.variable.publishParameters.publishedVariable = UA_NODEID_NUMERIC(1, 1000 + (UA_UInt32) i);
+        dsfConfig.field.variable.publishParameters.attributeId = UA_ATTRIBUTEID_VALUE;
+        UA_Server_addDataSetField(server, publishedDataSetIdent, &dsfConfig, &dataSetFieldIdent);
+    }
 #endif
     /* The PubSub configuration is currently editable and the publish callback is not running */
     writerGroupConfig.publishingInterval = PUBSUB_CONFIG_PUBLISH_CYCLE_MS;
@@ -147,15 +194,6 @@ int main(void) {
     UA_Server_freezeWriterGroupConfiguration(server, writerGroupIdent);
     UA_Server_setWriterGroupOperational(server, writerGroupIdent);
 
-    /* Changes of the PubSub configuration is restricted after freeze */
-    UA_StatusCode retVal = UA_Server_updateWriterGroupConfig(server, writerGroupIdent, &writerGroupConfig);
-    if(retVal != UA_STATUSCODE_BADCONFIGURATIONERROR)
-        return EXIT_FAILURE;
-
-    /* Unfreeze the PubSub configuration (and stop implicitly the publish callback) */
-    //UA_Server_setWriterGroupDisabled(server, writerGroupIdent);
-    //UA_Server_unfreezeWriterGroupConfiguration(server, writerGroupIdent);
-
     UA_UInt64 callbackId;
     UA_Server_addRepeatedCallback(server, valueUpdateCallback, NULL, PUBSUB_CONFIG_PUBLISH_CYCLE_MS, &callbackId);
 

+ 3 - 9
src/pubsub/ua_pubsub_manager.c

@@ -2,7 +2,7 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  *
- * Copyright (c) 2017-2018 Fraunhofer IOSB (Author: Andreas Ebner)
+ * Copyright (c) 2017-2019 Fraunhofer IOSB (Author: Andreas Ebner)
  * Copyright (c) 2018 Fraunhofer IOSB (Author: Julius Pfrommer)
  */
 
@@ -100,10 +100,7 @@ UA_Server_addPubSubConnection(UA_Server *server,
     for(size_t i = 0; i < server->pubSubManager.connectionsSize; i++){
         UA_WriterGroup *wg;
         LIST_FOREACH(wg, &server->pubSubManager.connections[i].writerGroups, listEntry){
-            UA_PubSubConnection *connection = UA_PubSubConnection_findConnectionbyId(server, wg->linkedConnection);
-            /* TODO Check if the value is null -> how can we ensure consistency in this case? */
-            if(connection)
-                wg->linkedConnectionPtr = connection;
+            wg->linkedConnectionPtr = UA_PubSubConnection_findConnectionbyId(server, wg->linkedConnection);
         }
     }
 #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
@@ -158,10 +155,7 @@ UA_Server_removePubSubConnection(UA_Server *server, const UA_NodeId connection)
         for(size_t i = 0; i < server->pubSubManager.connectionsSize; i++){
             UA_WriterGroup *wg;
             LIST_FOREACH(wg, &server->pubSubManager.connections[i].writerGroups, listEntry){
-                UA_PubSubConnection *tmp_connection = UA_PubSubConnection_findConnectionbyId(server, wg->linkedConnection);
-                /* TODO Check if the value is null -> how can we ensure consistency in this case? */
-                if(tmp_connection)
-                    wg->linkedConnectionPtr = tmp_connection;
+                wg->linkedConnectionPtr = UA_PubSubConnection_findConnectionbyId(server, wg->linkedConnection);
             }
         }
     }

+ 1 - 1
src/pubsub/ua_pubsub_manager.h

@@ -2,7 +2,7 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  *
- * Copyright (c) 2017-2018 Fraunhofer IOSB (Author: Andreas Ebner)
+ * Copyright (c) 2017-2019 Fraunhofer IOSB (Author: Andreas Ebner)
  */
 
 #ifndef UA_PUBSUB_MANAGER_H_

+ 126 - 258
src/pubsub/ua_pubsub_networkmessage.c

@@ -3,6 +3,7 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  *
  * Copyright (c) 2017 - 2018 Fraunhofer IOSB (Author: Tino Bischoff)
+ * Copyright (c) 2019 Fraunhofer IOSB (Author: Andreas Ebner)
  */
 
 #include <open62541/types_generated_encoding_binary.h>
@@ -51,231 +52,6 @@ static UA_Boolean UA_NetworkMessage_ExtendedFlags1Enabled(const UA_NetworkMessag
 static UA_Boolean UA_NetworkMessage_ExtendedFlags2Enabled(const UA_NetworkMessage* src);
 static UA_Boolean UA_DataSetMessageHeader_DataSetFlags2Enabled(const UA_DataSetMessageHeader* src);
 
-size_t
-UA_DataSetMessage_generateOffsetBuffer(UA_NetworkMessageOffsetBuffer *offsetBuffer,
-                                       UA_DataSetMessage* p, size_t currentOffset) {
-    size_t size = currentOffset;
-    UA_Byte byte;
-    size += UA_Byte_calcSizeBinary(&byte); // DataSetMessage Type + Flags
-    if(UA_DataSetMessageHeader_DataSetFlags2Enabled(&p->header))
-        size += UA_Byte_calcSizeBinary(&byte);
-
-    if(p->header.dataSetMessageSequenceNrEnabled) {
-        offsetBuffer->offsets = (UA_NetworkMessageOffset *) UA_realloc(offsetBuffer->offsets,
-                                                                       sizeof(UA_NetworkMessageOffsetBuffer) * (offsetBuffer->offsetsSize + 1));
-        offsetBuffer->offsets[offsetBuffer->offsetsSize].offset = size;
-        offsetBuffer->offsets[offsetBuffer->offsetsSize].offsetData.value.value = UA_DataValue_new();
-        UA_DataValue_init(offsetBuffer->offsets[offsetBuffer->offsetsSize].offsetData.value.value);
-        UA_Variant_setScalar(&offsetBuffer->offsets[offsetBuffer->offsetsSize].offsetData.value.value->value,
-                             &p->header.dataSetMessageSequenceNr, &UA_TYPES[UA_TYPES_UINT16]);
-        offsetBuffer->offsets[offsetBuffer->offsetsSize++].contentType = UA_PUBSUB_OFFSETTYPE_DATASETMESSAGE_SEQUENCENUMBER;
-        size += UA_UInt16_calcSizeBinary(&p->header.dataSetMessageSequenceNr);
-    }
-
-    if(p->header.timestampEnabled)
-        size += UA_DateTime_calcSizeBinary(&p->header.timestamp); /* UtcTime */
-
-    if(p->header.picoSecondsIncluded)
-        size += UA_UInt16_calcSizeBinary(&p->header.picoSeconds);
-
-    if(p->header.statusEnabled)
-        size += UA_UInt16_calcSizeBinary(&p->header.status);
-
-    if(p->header.configVersionMajorVersionEnabled)
-        size += UA_UInt32_calcSizeBinary(&p->header.configVersionMajorVersion);
-
-    if(p->header.configVersionMinorVersionEnabled)
-        size += UA_UInt32_calcSizeBinary(&p->header.configVersionMinorVersion);
-
-    if(p->header.dataSetMessageType == UA_DATASETMESSAGE_DATAKEYFRAME) {
-        if(p->header.fieldEncoding != UA_FIELDENCODING_RAWDATA){
-            //TODO clarify RT and Rawdata behavior
-            size += UA_calcSizeBinary(&p->data.keyFrameData.fieldCount, &UA_TYPES[UA_TYPES_UINT16]);
-        }
-
-        if(p->header.fieldEncoding == UA_FIELDENCODING_VARIANT) {
-            for (UA_UInt16 i = 0; i < p->data.keyFrameData.fieldCount; i++){
-                offsetBuffer->offsets = (UA_NetworkMessageOffset *) UA_realloc(offsetBuffer->offsets, sizeof(UA_NetworkMessageOffsetBuffer) * (offsetBuffer->offsetsSize + 1));
-                offsetBuffer->offsets[offsetBuffer->offsetsSize].offset = size;
-                offsetBuffer->offsets[offsetBuffer->offsetsSize].contentType = UA_PUBSUB_OFFSETTYPE_PAYLOAD_VARIANT;
-                //TODO check value source and alloc!
-                offsetBuffer->offsets[offsetBuffer->offsetsSize].offsetData.value.value = UA_DataValue_new();
-                UA_Variant_setScalar(&offsetBuffer->offsets[offsetBuffer->offsetsSize++].offsetData.value.value->value,
-                        p->data.keyFrameData.dataSetFields[i].value.data, p->data.keyFrameData.dataSetFields[i].value.type);
-                //offsetBuffer->offsets[offsetBuffer->offsetsSize++].offsetData.value.value->value = p->data.keyFrameData.dataSetFields->value;
-                size += UA_calcSizeBinary(&p->data.keyFrameData.dataSetFields[i].value, &UA_TYPES[UA_TYPES_VARIANT]);
-            }
-        } else if(p->header.fieldEncoding == UA_FIELDENCODING_RAWDATA) {
-            // not implemented
-        } else if(p->header.fieldEncoding == UA_FIELDENCODING_DATAVALUE) {
-            for (UA_UInt16 i = 0; i < p->data.keyFrameData.fieldCount; i++) {
-                offsetBuffer->offsets = (UA_NetworkMessageOffset *) UA_realloc(offsetBuffer->offsets, sizeof(UA_NetworkMessageOffsetBuffer) * (offsetBuffer->offsetsSize + 1));
-                offsetBuffer->offsets[offsetBuffer->offsetsSize].offset = size;
-                offsetBuffer->offsets[offsetBuffer->offsetsSize].contentType = UA_PUBSUB_OFFSETTYPE_PAYLOAD_DATAVALUE;
-                //TODO check value source, change implementation to 'variant'
-                offsetBuffer->offsets[offsetBuffer->offsetsSize++].offsetData.value.value = p->data.keyFrameData.dataSetFields;
-                size += UA_calcSizeBinary(&p->data.keyFrameData.dataSetFields[i], &UA_TYPES[UA_TYPES_DATAVALUE]);
-            }
-        }
-    } else if(p->header.dataSetMessageType == UA_DATASETMESSAGE_DATADELTAFRAME) {
-        //TODO clarify how to handle DATADELTAFRAME messages with RT
-        if(p->header.fieldEncoding != UA_FIELDENCODING_RAWDATA)
-            size += UA_calcSizeBinary(&p->data.deltaFrameData.fieldCount, &UA_TYPES[UA_TYPES_UINT16]);
-
-        if(p->header.fieldEncoding == UA_FIELDENCODING_VARIANT) {
-            for (UA_UInt16 i = 0; i < p->data.deltaFrameData.fieldCount; i++) {
-                size += UA_calcSizeBinary(&p->data.deltaFrameData.deltaFrameFields[i].fieldIndex, &UA_TYPES[UA_TYPES_UINT16]);
-                size += UA_calcSizeBinary(&p->data.deltaFrameData.deltaFrameFields[i].fieldValue.value, &UA_TYPES[UA_TYPES_VARIANT]);
-            }
-        } else if(p->header.fieldEncoding == UA_FIELDENCODING_RAWDATA) {
-            // not implemented
-        } else if(p->header.fieldEncoding == UA_FIELDENCODING_DATAVALUE) {
-            for (UA_UInt16 i = 0; i < p->data.deltaFrameData.fieldCount; i++) {
-                size += UA_calcSizeBinary(&p->data.deltaFrameData.deltaFrameFields[i].fieldIndex, &UA_TYPES[UA_TYPES_UINT16]);
-                size += UA_calcSizeBinary(&p->data.deltaFrameData.deltaFrameFields[i].fieldValue, &UA_TYPES[UA_TYPES_DATAVALUE]);
-            }
-        }
-    }
-    /* KeepAlive-Message contains no Payload Data */
-    return size;
-}
-
-size_t
-UA_NetworkMessage_generateOffsetBuffer(UA_NetworkMessageOffsetBuffer *offsetBuffer,
-        UA_NetworkMessage* p) {
-    size_t retval = 0;
-    UA_Byte byte;
-    size_t size = UA_Byte_calcSizeBinary(&byte); // UADPVersion + UADPFlags
-    if(UA_NetworkMessage_ExtendedFlags1Enabled(p)) {
-        size += UA_Byte_calcSizeBinary(&byte);
-        if(UA_NetworkMessage_ExtendedFlags2Enabled(p))
-            size += UA_Byte_calcSizeBinary(&byte);
-    }
-
-    if(p->publisherIdEnabled) {
-        switch (p->publisherIdType) {
-            case UA_PUBLISHERDATATYPE_BYTE:
-                size += UA_Byte_calcSizeBinary(&p->publisherId.publisherIdByte);
-                break;
-
-            case UA_PUBLISHERDATATYPE_UINT16:
-                size += UA_UInt16_calcSizeBinary(&p->publisherId.publisherIdUInt16);
-                break;
-
-            case UA_PUBLISHERDATATYPE_UINT32:
-                size += UA_UInt32_calcSizeBinary(&p->publisherId.publisherIdUInt32);
-                break;
-
-            case UA_PUBLISHERDATATYPE_UINT64:
-                size += UA_UInt64_calcSizeBinary(&p->publisherId.publisherIdUInt64);
-                break;
-
-            case UA_PUBLISHERDATATYPE_STRING:
-                size += UA_String_calcSizeBinary(&p->publisherId.publisherIdString);
-                break;
-        }
-    }
-
-    if(p->dataSetClassIdEnabled)
-        size += UA_Guid_calcSizeBinary(&p->dataSetClassId);
-
-    // Group Header
-    if(p->groupHeaderEnabled) {
-        size += UA_Byte_calcSizeBinary(&byte);
-
-        if(p->groupHeader.writerGroupIdEnabled)
-            size += UA_UInt16_calcSizeBinary(&p->groupHeader.writerGroupId);
-
-        if(p->groupHeader.groupVersionEnabled)
-            size += UA_UInt32_calcSizeBinary(&p->groupHeader.groupVersion);
-
-        if(p->groupHeader.networkMessageNumberEnabled) {
-            offsetBuffer->offsets = (UA_NetworkMessageOffset *) UA_realloc(offsetBuffer->offsets, sizeof(UA_NetworkMessageOffsetBuffer) * (offsetBuffer->offsetsSize + 1));
-            offsetBuffer->offsets[offsetBuffer->offsetsSize].offset = size;
-            offsetBuffer->offsets[offsetBuffer->offsetsSize].offsetData.value.value = UA_DataValue_new();
-            UA_DataValue_init(offsetBuffer->offsets[offsetBuffer->offsetsSize].offsetData.value.value);
-            UA_Variant_setScalar(&offsetBuffer->offsets[offsetBuffer->offsetsSize].offsetData.value.value->value,
-                                 &p->groupHeader.sequenceNumber, &UA_TYPES[UA_TYPES_UINT16]);
-            offsetBuffer->offsets[offsetBuffer->offsetsSize++].contentType = UA_PUBSUB_OFFSETTYPE_NETWORKMESSAGE_SEQUENCENUMBER;
-            size += UA_UInt16_calcSizeBinary(&p->groupHeader.networkMessageNumber);
-        }
-
-        if(p->groupHeader.sequenceNumberEnabled){
-            size += UA_UInt16_calcSizeBinary(&p->groupHeader.sequenceNumber);
-        }
-    }
-
-    // Payload Header
-    if(p->payloadHeaderEnabled) {
-        if(p->networkMessageType == UA_NETWORKMESSAGE_DATASET) {
-            size += UA_Byte_calcSizeBinary(&p->payloadHeader.dataSetPayloadHeader.count);
-            if(p->payloadHeader.dataSetPayloadHeader.dataSetWriterIds != NULL) {
-                size += UA_UInt16_calcSizeBinary(&p->payloadHeader.dataSetPayloadHeader.dataSetWriterIds[0]) *
-                        p->payloadHeader.dataSetPayloadHeader.count;
-            } else {
-                return 0; /* no dataSetWriterIds given! */
-            }
-        } else {
-            // not implemented
-        }
-    }
-
-    if(p->timestampEnabled) {
-        offsetBuffer->offsets = (UA_NetworkMessageOffset *) UA_realloc(offsetBuffer->offsets, sizeof(UA_NetworkMessageOffsetBuffer) * (offsetBuffer->offsetsSize + 1));
-        offsetBuffer->offsets[offsetBuffer->offsetsSize].offset = size;
-        offsetBuffer->offsets[offsetBuffer->offsetsSize++].contentType = UA_PUBSUB_OFFSETTYPE_TIMESTAMP;
-        size += UA_DateTime_calcSizeBinary(&p->timestamp);
-    }
-
-    if(p->picosecondsEnabled){
-        offsetBuffer->offsets = (UA_NetworkMessageOffset *) UA_realloc(offsetBuffer->offsets, sizeof(UA_NetworkMessageOffsetBuffer) * (offsetBuffer->offsetsSize + 1));
-        offsetBuffer->offsets[offsetBuffer->offsetsSize].offset = size;
-        offsetBuffer->offsets[offsetBuffer->offsetsSize++].contentType = UA_PUBSUB_OFFSETTYPE_TIMESTAMP_PICOSECONDS;
-        size += UA_UInt16_calcSizeBinary(&p->picoseconds);
-    }
-
-    if(p->promotedFieldsEnabled) {
-        size += UA_UInt16_calcSizeBinary(&p->promotedFieldsSize);
-        for (UA_UInt16 i = 0; i < p->promotedFieldsSize; i++)
-            size += UA_Variant_calcSizeBinary(&p->promotedFields[i]);
-    }
-
-    if(p->securityEnabled) {
-        size += UA_Byte_calcSizeBinary(&byte);
-        size += UA_UInt32_calcSizeBinary(&p->securityHeader.securityTokenId);
-        size += UA_Byte_calcSizeBinary(&p->securityHeader.nonceLength);
-        if(p->securityHeader.nonceLength > 0)
-            size += (UA_Byte_calcSizeBinary(&p->securityHeader.messageNonce.data[0]) * p->securityHeader.nonceLength);
-        if(p->securityHeader.securityFooterEnabled)
-            size += UA_UInt16_calcSizeBinary(&p->securityHeader.securityFooterSize);
-    }
-
-    if(p->networkMessageType == UA_NETWORKMESSAGE_DATASET) {
-        UA_Byte count = 1;
-        if(p->payloadHeaderEnabled) {
-            count = p->payloadHeader.dataSetPayloadHeader.count;
-            if(count > 1)
-                size += UA_UInt16_calcSizeBinary(&(p->payload.dataSetPayload.sizes[0])) * count;
-        }
-
-        for (size_t i = 0; i < count; i++) {
-            UA_DataSetMessage_generateOffsetBuffer(offsetBuffer, &(p->payload.dataSetPayload.dataSetMessages[i]), size);
-            size += UA_DataSetMessage_calcSizeBinary(&(p->payload.dataSetPayload.dataSetMessages[i]));
-        }
-    }
-
-    if (p->securityEnabled) {
-        if (p->securityHeader.securityFooterEnabled)
-            size += p->securityHeader.securityFooterSize;
-
-        if (p->securityHeader.networkMessageSigned)
-            size += UA_ByteString_calcSizeBinary(&p->signature);
-    }
-
-    retval = size;
-    return retval;
-}
-
 UA_StatusCode
 UA_NetworkMessage_updateBufferedMessage(UA_NetworkMessageOffsetBuffer *buffer){
     UA_StatusCode rv = UA_STATUSCODE_GOOD;
@@ -547,7 +323,8 @@ UA_NetworkMessage_encodeBinary(const UA_NetworkMessage* src, UA_Byte **bufPos,
                    (src->payload.dataSetPayload.sizes[i] != 0)) {
                     sz = src->payload.dataSetPayload.sizes[i];
                 } else {
-                    sz = (UA_UInt16)UA_DataSetMessage_calcSizeBinary(&src->payload.dataSetPayload.dataSetMessages[i]);
+                    sz = (UA_UInt16) UA_DataSetMessage_calcSizeBinary(&src->payload.dataSetPayload.dataSetMessages[i],
+                                                                      NULL, 0);
                 }
 
                 rv = UA_UInt16_encodeBinary(&sz, bufPos, bufEnd);
@@ -907,7 +684,8 @@ UA_NetworkMessage_decodeBinary(const UA_ByteString *src, size_t *offset, UA_Netw
     return retval;
 }
 
-size_t UA_NetworkMessage_calcSizeBinary(const UA_NetworkMessage* p) {
+size_t
+UA_NetworkMessage_calcSizeBinary(UA_NetworkMessage *p, UA_NetworkMessageOffsetBuffer *offsetBuffer) {
     size_t retval = 0;
     UA_Byte byte;
     size_t size = UA_Byte_calcSizeBinary(&byte); // UADPVersion + UADPFlags
@@ -919,32 +697,32 @@ size_t UA_NetworkMessage_calcSizeBinary(const UA_NetworkMessage* p) {
 
     if(p->publisherIdEnabled) {
         switch (p->publisherIdType) {
-        case UA_PUBLISHERDATATYPE_BYTE:
-            size += UA_Byte_calcSizeBinary(&p->publisherId.publisherIdByte);
-            break;
+            case UA_PUBLISHERDATATYPE_BYTE:
+                size += UA_Byte_calcSizeBinary(&p->publisherId.publisherIdByte);
+                break;
 
-        case UA_PUBLISHERDATATYPE_UINT16:
-            size += UA_UInt16_calcSizeBinary(&p->publisherId.publisherIdUInt16);
-            break;
+            case UA_PUBLISHERDATATYPE_UINT16:
+                size += UA_UInt16_calcSizeBinary(&p->publisherId.publisherIdUInt16);
+                break;
 
-        case UA_PUBLISHERDATATYPE_UINT32:
-            size += UA_UInt32_calcSizeBinary(&p->publisherId.publisherIdUInt32);
-            break;
+            case UA_PUBLISHERDATATYPE_UINT32:
+                size += UA_UInt32_calcSizeBinary(&p->publisherId.publisherIdUInt32);
+                break;
 
-        case UA_PUBLISHERDATATYPE_UINT64:
-            size += UA_UInt64_calcSizeBinary(&p->publisherId.publisherIdUInt64);
-            break;
+            case UA_PUBLISHERDATATYPE_UINT64:
+                size += UA_UInt64_calcSizeBinary(&p->publisherId.publisherIdUInt64);
+                break;
 
-        case UA_PUBLISHERDATATYPE_STRING:
-            size += UA_String_calcSizeBinary(&p->publisherId.publisherIdString);
-            break;
+            case UA_PUBLISHERDATATYPE_STRING:
+                size += UA_String_calcSizeBinary(&p->publisherId.publisherIdString);
+                break;
         }
     }
 
     if(p->dataSetClassIdEnabled)
         size += UA_Guid_calcSizeBinary(&p->dataSetClassId);
 
-    // Group Header 
+    // Group Header
     if(p->groupHeaderEnabled) {
         size += UA_Byte_calcSizeBinary(&byte);
 
@@ -954,11 +732,22 @@ size_t UA_NetworkMessage_calcSizeBinary(const UA_NetworkMessage* p) {
         if(p->groupHeader.groupVersionEnabled)
             size += UA_UInt32_calcSizeBinary(&p->groupHeader.groupVersion);
 
-        if(p->groupHeader.networkMessageNumberEnabled)
+        if(p->groupHeader.networkMessageNumberEnabled) {
+            if(offsetBuffer){
+                offsetBuffer->offsets = (UA_NetworkMessageOffset *) UA_realloc(offsetBuffer->offsets, sizeof(UA_NetworkMessageOffset) * (offsetBuffer->offsetsSize + (size_t)1));
+                offsetBuffer->offsets[offsetBuffer->offsetsSize].offset = size;
+                offsetBuffer->offsets[offsetBuffer->offsetsSize].offsetData.value.value = UA_DataValue_new();
+                UA_DataValue_init(offsetBuffer->offsets[offsetBuffer->offsetsSize].offsetData.value.value);
+                UA_Variant_setScalar(&offsetBuffer->offsets[offsetBuffer->offsetsSize].offsetData.value.value->value,
+                                     &p->groupHeader.sequenceNumber, &UA_TYPES[UA_TYPES_UINT16]);
+                offsetBuffer->offsets[offsetBuffer->offsetsSize++].contentType = UA_PUBSUB_OFFSETTYPE_NETWORKMESSAGE_SEQUENCENUMBER;
+            }
             size += UA_UInt16_calcSizeBinary(&p->groupHeader.networkMessageNumber);
+        }
 
-        if(p->groupHeader.sequenceNumberEnabled)
+        if(p->groupHeader.sequenceNumberEnabled){
             size += UA_UInt16_calcSizeBinary(&p->groupHeader.sequenceNumber);
+        }
     }
 
     // Payload Header
@@ -967,7 +756,7 @@ size_t UA_NetworkMessage_calcSizeBinary(const UA_NetworkMessage* p) {
             size += UA_Byte_calcSizeBinary(&p->payloadHeader.dataSetPayloadHeader.count);
             if(p->payloadHeader.dataSetPayloadHeader.dataSetWriterIds != NULL) {
                 size += UA_UInt16_calcSizeBinary(&p->payloadHeader.dataSetPayloadHeader.dataSetWriterIds[0]) *
-                    p->payloadHeader.dataSetPayloadHeader.count;
+                        p->payloadHeader.dataSetPayloadHeader.count;
             } else {
                 return 0; /* no dataSetWriterIds given! */
             }
@@ -976,13 +765,27 @@ size_t UA_NetworkMessage_calcSizeBinary(const UA_NetworkMessage* p) {
         }
     }
 
-    if(p->timestampEnabled)
+    if(p->timestampEnabled) {
+        if(offsetBuffer){
+            offsetBuffer->offsets = (UA_NetworkMessageOffset *) UA_realloc(offsetBuffer->offsets, sizeof(UA_NetworkMessageOffset) * (offsetBuffer->offsetsSize + 1));
+            offsetBuffer->offsets[offsetBuffer->offsetsSize].offset = size;
+            offsetBuffer->offsets[offsetBuffer->offsetsSize++].contentType = UA_PUBSUB_OFFSETTYPE_TIMESTAMP;
+        }
         size += UA_DateTime_calcSizeBinary(&p->timestamp);
+    }
 
-    if(p->picosecondsEnabled)
+    if(p->picosecondsEnabled){
+        if (offsetBuffer) {
+            offsetBuffer->offsets = (UA_NetworkMessageOffset *) UA_realloc(offsetBuffer->offsets,
+                                                                           sizeof(UA_NetworkMessageOffset) *
+                                                                           (offsetBuffer->offsetsSize + 1));
+            offsetBuffer->offsets[offsetBuffer->offsetsSize].offset = size;
+            offsetBuffer->offsets[offsetBuffer->offsetsSize++].contentType = UA_PUBSUB_OFFSETTYPE_TIMESTAMP_PICOSECONDS;
+        }
         size += UA_UInt16_calcSizeBinary(&p->picoseconds);
+    }
 
-    if(p->promotedFieldsEnabled) { 
+    if(p->promotedFieldsEnabled) {
         size += UA_UInt16_calcSizeBinary(&p->promotedFieldsSize);
         for (UA_UInt16 i = 0; i < p->promotedFieldsSize; i++)
             size += UA_Variant_calcSizeBinary(&p->promotedFields[i]);
@@ -997,7 +800,7 @@ size_t UA_NetworkMessage_calcSizeBinary(const UA_NetworkMessage* p) {
         if(p->securityHeader.securityFooterEnabled)
             size += UA_UInt16_calcSizeBinary(&p->securityHeader.securityFooterSize);
     }
-    
+
     if(p->networkMessageType == UA_NETWORKMESSAGE_DATASET) {
         UA_Byte count = 1;
         if(p->payloadHeaderEnabled) {
@@ -1006,8 +809,12 @@ size_t UA_NetworkMessage_calcSizeBinary(const UA_NetworkMessage* p) {
                 size += UA_UInt16_calcSizeBinary(&(p->payload.dataSetPayload.sizes[0])) * count;
         }
 
-        for (size_t i = 0; i < count; i++)
-            size += UA_DataSetMessage_calcSizeBinary(&(p->payload.dataSetPayload.dataSetMessages[i]));
+        for (size_t i = 0; i < count; i++) {
+            if (offsetBuffer)
+                UA_DataSetMessage_calcSizeBinary(&(p->payload.dataSetPayload.dataSetMessages[i]), offsetBuffer,
+                                                 size);
+            size += UA_DataSetMessage_calcSizeBinary(&(p->payload.dataSetPayload.dataSetMessages[i]), NULL, 0);
+        }
     }
 
     if (p->securityEnabled) {
@@ -1470,23 +1277,85 @@ UA_DataSetMessage_decodeBinary(const UA_ByteString *src, size_t *offset, UA_Data
 }
 
 size_t
-UA_DataSetMessage_calcSizeBinary(const UA_DataSetMessage* p) {
-    size_t size = UA_DataSetMessageHeader_calcSizeBinary(&p->header);
+UA_DataSetMessage_calcSizeBinary(UA_DataSetMessage* p, UA_NetworkMessageOffsetBuffer *offsetBuffer, size_t currentOffset) {
+    size_t size = currentOffset;
+    UA_Byte byte;
+    size += UA_Byte_calcSizeBinary(&byte); // DataSetMessage Type + Flags
+    if(UA_DataSetMessageHeader_DataSetFlags2Enabled(&p->header))
+        size += UA_Byte_calcSizeBinary(&byte);
+
+    if(p->header.dataSetMessageSequenceNrEnabled) {
+        if (offsetBuffer) {
+            offsetBuffer->offsets = (UA_NetworkMessageOffset *) UA_realloc(offsetBuffer->offsets,
+                                                                           sizeof(UA_NetworkMessageOffset) *
+                                                                           (offsetBuffer->offsetsSize + 1));
+            offsetBuffer->offsets[offsetBuffer->offsetsSize].offset = size;
+            offsetBuffer->offsets[offsetBuffer->offsetsSize].offsetData.value.value = UA_DataValue_new();
+            UA_DataValue_init(offsetBuffer->offsets[offsetBuffer->offsetsSize].offsetData.value.value);
+            UA_Variant_setScalar(&offsetBuffer->offsets[offsetBuffer->offsetsSize].offsetData.value.value->value,
+                                 &p->header.dataSetMessageSequenceNr, &UA_TYPES[UA_TYPES_UINT16]);
+            offsetBuffer->offsets[offsetBuffer->offsetsSize++].contentType = UA_PUBSUB_OFFSETTYPE_DATASETMESSAGE_SEQUENCENUMBER;
+        }
+        size += UA_UInt16_calcSizeBinary(&p->header.dataSetMessageSequenceNr);
+    }
+
+    if(p->header.timestampEnabled)
+        size += UA_DateTime_calcSizeBinary(&p->header.timestamp); /* UtcTime */
+
+    if(p->header.picoSecondsIncluded)
+        size += UA_UInt16_calcSizeBinary(&p->header.picoSeconds);
+
+    if(p->header.statusEnabled)
+        size += UA_UInt16_calcSizeBinary(&p->header.status);
+
+    if(p->header.configVersionMajorVersionEnabled)
+        size += UA_UInt32_calcSizeBinary(&p->header.configVersionMajorVersion);
+
+    if(p->header.configVersionMinorVersionEnabled)
+        size += UA_UInt32_calcSizeBinary(&p->header.configVersionMinorVersion);
 
     if(p->header.dataSetMessageType == UA_DATASETMESSAGE_DATAKEYFRAME) {
-        if(p->header.fieldEncoding != UA_FIELDENCODING_RAWDATA)
+        if(p->header.fieldEncoding != UA_FIELDENCODING_RAWDATA){
+            //TODO clarify RT and Rawdata behavior
             size += UA_calcSizeBinary(&p->data.keyFrameData.fieldCount, &UA_TYPES[UA_TYPES_UINT16]);
+        }
 
         if(p->header.fieldEncoding == UA_FIELDENCODING_VARIANT) {
-            for (UA_UInt16 i = 0; i < p->data.keyFrameData.fieldCount; i++)
+            for (UA_UInt16 i = 0; i < p->data.keyFrameData.fieldCount; i++){
+                if (offsetBuffer) {
+                    offsetBuffer->offsets = (UA_NetworkMessageOffset *) UA_realloc(offsetBuffer->offsets,
+                                                                                   sizeof(UA_NetworkMessageOffset) *
+                                                                                   (offsetBuffer->offsetsSize + 1));
+                    offsetBuffer->offsets[offsetBuffer->offsetsSize].offset = size;
+                    offsetBuffer->offsets[offsetBuffer->offsetsSize].contentType = UA_PUBSUB_OFFSETTYPE_PAYLOAD_VARIANT;
+                    //TODO check value source and alloc!
+                    offsetBuffer->offsets[offsetBuffer->offsetsSize].offsetData.value.value = UA_DataValue_new();
+                    UA_Variant_setScalar(
+                            &offsetBuffer->offsets[offsetBuffer->offsetsSize++].offsetData.value.value->value,
+                            p->data.keyFrameData.dataSetFields[i].value.data,
+                            p->data.keyFrameData.dataSetFields[i].value.type);
+                    //offsetBuffer->offsets[offsetBuffer->offsetsSize++].offsetData.value.value->value = p->data.keyFrameData.dataSetFields->value;
+                }
                 size += UA_calcSizeBinary(&p->data.keyFrameData.dataSetFields[i].value, &UA_TYPES[UA_TYPES_VARIANT]);
+            }
         } else if(p->header.fieldEncoding == UA_FIELDENCODING_RAWDATA) {
             // not implemented
         } else if(p->header.fieldEncoding == UA_FIELDENCODING_DATAVALUE) {
-            for (UA_UInt16 i = 0; i < p->data.keyFrameData.fieldCount; i++)
+            for (UA_UInt16 i = 0; i < p->data.keyFrameData.fieldCount; i++) {
+                if (offsetBuffer) {
+                    offsetBuffer->offsets = (UA_NetworkMessageOffset *) UA_realloc(offsetBuffer->offsets,
+                                                                                   sizeof(UA_NetworkMessageOffset) *
+                                                                                   (offsetBuffer->offsetsSize + 1));
+                    offsetBuffer->offsets[offsetBuffer->offsetsSize].offset = size;
+                    offsetBuffer->offsets[offsetBuffer->offsetsSize].contentType = UA_PUBSUB_OFFSETTYPE_PAYLOAD_DATAVALUE;
+                    //TODO check value source, change implementation to 'variant'
+                    offsetBuffer->offsets[offsetBuffer->offsetsSize++].offsetData.value.value = p->data.keyFrameData.dataSetFields;
+                }
                 size += UA_calcSizeBinary(&p->data.keyFrameData.dataSetFields[i], &UA_TYPES[UA_TYPES_DATAVALUE]);
+            }
         }
     } else if(p->header.dataSetMessageType == UA_DATASETMESSAGE_DATADELTAFRAME) {
+        //TODO clarify how to handle DATADELTAFRAME messages with RT
         if(p->header.fieldEncoding != UA_FIELDENCODING_RAWDATA)
             size += UA_calcSizeBinary(&p->data.deltaFrameData.fieldCount, &UA_TYPES[UA_TYPES_UINT16]);
 
@@ -1504,7 +1373,6 @@ UA_DataSetMessage_calcSizeBinary(const UA_DataSetMessage* p) {
             }
         }
     }
-
     /* KeepAlive-Message contains no Payload Data */
     return size;
 }

+ 5 - 11
src/pubsub/ua_pubsub_networkmessage.h

@@ -3,6 +3,7 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  *
  * Copyright (c) 2017 - 2018 Fraunhofer IOSB (Author: Tino Bischoff)
+ * Copyright (c) 2017-2019 Fraunhofer IOSB (Author: Andreas Ebner)
  */
 
 #ifndef UA_PUBSUB_NETWORKMESSAGE_H_
@@ -64,8 +65,7 @@ UA_DataSetMessageHeader_decodeBinary(const UA_ByteString *src, size_t *offset,
 size_t
 UA_DataSetMessageHeader_calcSizeBinary(const UA_DataSetMessageHeader* p);
 
-/* Offsets for buffered messages in the PubSub fast path.
- * TODO: Implement the generation of the offsets */
+/* Offsets for buffered messages in the PubSub fast path. */
 typedef enum {
     UA_PUBSUB_OFFSETTYPE_DATASETMESSAGE_SEQUENCENUMBER,
     UA_PUBSUB_OFFSETTYPE_NETWORKMESSAGE_SEQUENCENUMBER,
@@ -134,7 +134,8 @@ UA_DataSetMessage_decodeBinary(const UA_ByteString *src, size_t *offset,
                                UA_DataSetMessage* dst);
 
 size_t
-UA_DataSetMessage_calcSizeBinary(const UA_DataSetMessage* p);
+UA_DataSetMessage_calcSizeBinary(UA_DataSetMessage *p, UA_NetworkMessageOffsetBuffer *offsetBuffer,
+                                 size_t currentOffset);
 
 void UA_DataSetMessage_free(const UA_DataSetMessage* p);
 
@@ -234,13 +235,6 @@ typedef struct {
     UA_ByteString signature;
 } UA_NetworkMessage;
 
-size_t
-UA_NetworkMessage_generateOffsetBuffer(UA_NetworkMessageOffsetBuffer *offsetBuffer,
-                                       UA_NetworkMessage* p);
-
-size_t
-UA_DataSetMessage_generateOffsetBuffer(UA_NetworkMessageOffsetBuffer *offsetBuffer,
-                                       UA_DataSetMessage* p, size_t currentOffset);
 UA_StatusCode
 UA_NetworkMessage_updateBufferedMessage(UA_NetworkMessageOffsetBuffer *buffer);
 
@@ -253,7 +247,7 @@ UA_NetworkMessage_decodeBinary(const UA_ByteString *src, size_t *offset,
                                UA_NetworkMessage* dst);
 
 size_t
-UA_NetworkMessage_calcSizeBinary(const UA_NetworkMessage* p);
+UA_NetworkMessage_calcSizeBinary(UA_NetworkMessage *p, UA_NetworkMessageOffsetBuffer *offsetBuffer);
 
 void
 UA_NetworkMessage_deleteMembers(UA_NetworkMessage* p);

+ 39 - 12
src/pubsub/ua_pubsub_writer.c

@@ -2,7 +2,7 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  *
- * Copyright (c) 2017-2018 Fraunhofer IOSB (Author: Andreas Ebner)
+ * Copyright (c) 2017-2019 Fraunhofer IOSB (Author: Andreas Ebner)
  * Copyright (c) 2019 Fraunhofer IOSB (Author: Julius Pfrommer)
  * Copyright (c) 2019 Kalycito Infotech Private Limited
  */
@@ -13,6 +13,7 @@
 #ifdef UA_ENABLE_PUBSUB /* conditional compilation */
 
 #include "ua_pubsub.h"
+#include "ua_pubsub_networkmessage.h"
 
 #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
 #include "ua_pubsub_ns0.h"
@@ -244,7 +245,6 @@ UA_Server_freezeWriterGroupConfiguration(UA_Server *server, const UA_NodeId writ
     //WriterGroup freeze
     wg->config.configurationFrozen = UA_TRUE;
     //DataSetWriter freeze
-    size_t dsmCount = 0;
     UA_DataSetWriter *dataSetWriter;
     LIST_FOREACH(dataSetWriter, &wg->writers, listEntry){
         dataSetWriter->config.configurationFrozen = UA_TRUE;
@@ -259,6 +259,7 @@ UA_Server_freezeWriterGroupConfiguration(UA_Server *server, const UA_NodeId writ
         }
     }
     if(wg->config.rtLevel == UA_PUBSUB_RT_FIXED_SIZE){
+        size_t dsmCount = 0;
         if(wg->config.encodingMimeType != UA_PUBSUB_ENCODING_UADP) {
             UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
                            "PubSub-RT configuration fail: Non-RT capable encoding.");
@@ -315,14 +316,15 @@ UA_Server_freezeWriterGroupConfiguration(UA_Server *server, const UA_NodeId writ
             dsmCount++;
         }
         UA_NetworkMessage networkMessage;
+        memset(&networkMessage, 0, sizeof(networkMessage));
         UA_StatusCode  res = generateNetworkMessage(pubSubConnection, wg, dsmStore, dsWriterIds, (UA_Byte) dsmCount,
                                 &wg->config.messageSettings, &wg->config.transportSettings, &networkMessage);
         if(res != UA_STATUSCODE_GOOD)
             return UA_STATUSCODE_BADINTERNALERROR;
-        UA_NetworkMessage_generateOffsetBuffer(&wg->bufferedMessage, &networkMessage);
+        UA_NetworkMessage_calcSizeBinary(&networkMessage, &wg->bufferedMessage);
         /* Allocate the buffer. Allocate on the stack if the buffer is small. */
         UA_ByteString buf;
-        size_t msgSize = UA_NetworkMessage_calcSizeBinary(&networkMessage);
+        size_t msgSize = UA_NetworkMessage_calcSizeBinary(&networkMessage, NULL);
         res = UA_ByteString_allocBuffer(&buf, msgSize);
         if(res != UA_STATUSCODE_GOOD)
             return UA_STATUSCODE_BADOUTOFMEMORY;
@@ -331,8 +333,13 @@ UA_Server_freezeWriterGroupConfiguration(UA_Server *server, const UA_NodeId writ
         UA_Byte *bufPos = wg->bufferedMessage.buffer.data;
         UA_NetworkMessage_encodeBinary(&networkMessage, &bufPos, bufEnd);
         /* Clean up DSM */
-        for(size_t i = 0; i < dsmCount; i++)
+        for(size_t i = 0; i < dsmCount; i++){
             UA_free(dsmStore[i].data.keyFrameData.dataSetFields);
+#ifdef UA_ENABLE_JSON_ENCODING
+            UA_free(dsmStore[i].data.keyFrameData.fieldNames);
+#endif
+        }
+
             //UA_DataSetMessage_free(&dsmStore[i]);
     }
     return UA_STATUSCODE_GOOD;
@@ -711,7 +718,6 @@ UA_Server_removeDataSetField(UA_Server *server, const UA_NodeId dsf) {
         UA_free(parentPublishedDataSet->dataSetMetaData.fields);
         UA_FieldMetaData *fieldMetaData = (UA_FieldMetaData *) UA_calloc(parentPublishedDataSet->dataSetMetaData.fieldsSize,
                                                                          sizeof(UA_FieldMetaData));
-
         if(!fieldMetaData){
             result.result =  UA_STATUSCODE_BADOUTOFMEMORY;
             return result;
@@ -1144,6 +1150,17 @@ UA_Server_addDataSetWriter(UA_Server *server,
         return UA_STATUSCODE_BADCONFIGURATIONERROR;
     }
 
+    if(wg->config.rtLevel != UA_PUBSUB_RT_NONE){
+        UA_DataSetField *tmpDSF;
+        TAILQ_FOREACH(tmpDSF, &currentDataSetContext->fields, listEntry){
+            if(tmpDSF->config.field.variable.staticValueSourceEnabled != UA_TRUE){
+                UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
+                               "Adding DataSetWriter failed. Fields in PDS are not RT capable.");
+                return UA_STATUSCODE_BADCONFIGURATIONERROR;
+            }
+        }
+    }
+
     UA_DataSetWriter *newDataSetWriter = (UA_DataSetWriter *) UA_calloc(1, sizeof(UA_DataSetWriter));
     if(!newDataSetWriter)
         return UA_STATUSCODE_BADOUTOFMEMORY;
@@ -1357,7 +1374,6 @@ UA_PubSubDataSetField_sampleValue(UA_Server *server, UA_DataSetField *field,
         value->value.storageType = UA_VARIANT_DATA_NODELETE;
         *value = field->config.field.variable.staticValueSource;
     }
-
 }
 
 static UA_StatusCode
@@ -1767,7 +1783,6 @@ generateNetworkMessage(UA_PubSubConnection *connection, UA_WriterGroup *wg,
         return UA_STATUSCODE_BADINTERNALERROR;
     UA_UadpWriterGroupMessageDataType *wgm = (UA_UadpWriterGroupMessageDataType*)
             messageSettings->content.decoded.data;
-    memset(networkMessage, 0, sizeof(UA_NetworkMessage));
 
     networkMessage->publisherIdEnabled =
             ((u64)wgm->networkMessageContentMask & (u64)UA_UADPNETWORKMESSAGECONTENTMASK_PUBLISHERID) != 0;
@@ -1805,7 +1820,7 @@ generateNetworkMessage(UA_PubSubConnection *connection, UA_WriterGroup *wg,
     /* Compute the length of the dsm separately for the header */
     UA_STACKARRAY(UA_UInt16, dsmLengths, dsmCount);
     for(UA_Byte i = 0; i < dsmCount; i++)
-        dsmLengths[i] = (UA_UInt16)UA_DataSetMessage_calcSizeBinary(&dsm[i]);
+        dsmLengths[i] = (UA_UInt16) UA_DataSetMessage_calcSizeBinary(&dsm[i], NULL, 0);
 
     networkMessage->payloadHeader.dataSetPayloadHeader.count = dsmCount;
     networkMessage->payloadHeader.dataSetPayloadHeader.dataSetWriterIds = writerIds;
@@ -1833,11 +1848,12 @@ sendNetworkMessage(UA_PubSubConnection *connection, UA_WriterGroup *wg,
                    UA_ExtensionObject *transportSettings) {
 
     UA_NetworkMessage nm;
+    memset(&nm, 0, sizeof(UA_NetworkMessage));
     generateNetworkMessage(connection, wg, dsm, writerIds, dsmCount, messageSettings, transportSettings, &nm);
 
     /* Allocate the buffer. Allocate on the stack if the buffer is small. */
     UA_ByteString buf;
-    size_t msgSize = UA_NetworkMessage_calcSizeBinary(&nm);
+    size_t msgSize = UA_NetworkMessage_calcSizeBinary(&nm, NULL);
     size_t stackSize = 1;
     if(msgSize <= UA_MAX_STACKBUF)
         stackSize = msgSize;
@@ -1885,6 +1901,12 @@ UA_WriterGroup_publishCallback(UA_Server *server, UA_WriterGroup *writerGroup) {
     if(writerGroup->writersCount <= 0)
         return;
 
+    if(!writerGroup->linkedConnectionPtr){
+        UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
+                       "Publish failed: Invalid reference to PubSubConnection");
+        return;
+    }
+
     /* Binary or Json encoding?  */
     if(writerGroup->config.encodingMimeType != UA_PUBSUB_ENCODING_UADP &&
        writerGroup->config.encodingMimeType != UA_PUBSUB_ENCODING_JSON) {
@@ -1957,8 +1979,13 @@ UA_WriterGroup_publishCallback(UA_Server *server, UA_WriterGroup *writerGroup) {
            if(res != UA_STATUSCODE_GOOD)
                 UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
                                "PubSub Publish: Could not send a NetworkMessage");
-            UA_DataSetMessage_free(&dsmStore[dsmCount]);
-            continue;
+           if(writerGroup->config.rtLevel == UA_PUBSUB_RT_DIRECT_VALUE_ACCESS){
+               for (size_t i = 0; i < dsmStore[dsmCount].data.keyFrameData.fieldCount; ++i) {
+                   dsmStore[dsmCount].data.keyFrameData.dataSetFields[i].value.data = NULL;
+               }
+           }
+           UA_DataSetMessage_free(&dsmStore[dsmCount]);
+           continue;
         }
 
         dsWriterIds[dsmCount] = dsw->config.dataSetWriterId;

+ 3 - 0
tests/CMakeLists.txt

@@ -323,6 +323,9 @@ if(UA_ENABLE_PUBSUB)
     add_executable(check_pubsub_config_freeze pubsub/check_pubsub_config_freeze.c $<TARGET_OBJECTS:open62541-object> $<TARGET_OBJECTS:open62541-plugins>)
     target_link_libraries(check_pubsub_config_freeze ${LIBS})
     add_test_valgrind(check_pubsub_config_freeze ${TESTS_BINARY_DIR}/check_pubsub_config_freeze)
+    add_executable(check_pubsub_publish_rt_levels pubsub/check_pubsub_publish_rt_levels.c $<TARGET_OBJECTS:open62541-object> $<TARGET_OBJECTS:open62541-plugins>)
+    target_link_libraries(check_pubsub_publish_rt_levels ${LIBS})
+    add_test_valgrind(check_pubsub_publish_rt_levels ${TESTS_BINARY_DIR}/check_pubsub_publish_rt_levels)
 
     add_executable(check_pubsub_multiple_layer pubsub/check_pubsub_multiple_layer.c $<TARGET_OBJECTS:open62541-object> $<TARGET_OBJECTS:open62541-plugins>)
     target_link_libraries(check_pubsub_multiple_layer ${LIBS})

+ 8 - 4
tests/pubsub/check_pubsub_config_freeze.c

@@ -53,7 +53,7 @@ START_TEST(CreateAndLockConfiguration) {
     writerGroupConfig.name = UA_STRING("WriterGroup 1");
     writerGroupConfig.publishingInterval = 10;
     writerGroupConfig.encodingMimeType = UA_PUBSUB_ENCODING_UADP;
-    writerGroupConfig.rtLevel = UA_PUBSUB_RT_FIXED_SIZE;
+    writerGroupConfig.rtLevel = UA_PUBSUB_RT_NONE;
     UA_Server_addWriterGroup(server, connection1, &writerGroupConfig, &writerGroup1);
 
     UA_PublishedDataSetConfig pdsConfig;
@@ -95,9 +95,11 @@ START_TEST(CreateAndLockConfiguration) {
     dataSetWriterConfig.name = UA_STRING("DataSetWriter 1");
     UA_Server_addDataSetWriter(server, writerGroup1, publishedDataSet1, &dataSetWriterConfig, &dataSetWriter1);
     UA_DataSetWriter *dataSetWriter = UA_DataSetWriter_findDSWbyId(server, dataSetWriter1);
+    ck_assert(dataSetWriter != NULL);
 
     //get internal PubSubConnection Pointer
     UA_PubSubConnection *pubSubConnection = UA_PubSubConnection_findConnectionbyId(server, connection1);
+    ck_assert(pubSubConnection != NULL);
 
     ck_assert(dataSetWriter->config.configurationFrozen == UA_FALSE);
     //Lock the writer group and the child pubsub entities
@@ -132,7 +134,7 @@ START_TEST(CreateAndLockConfigurationWithExternalAPI) {
         writerGroupConfig.name = UA_STRING("WriterGroup 1");
         writerGroupConfig.publishingInterval = 10;
         writerGroupConfig.encodingMimeType = UA_PUBSUB_ENCODING_UADP;
-        writerGroupConfig.rtLevel = UA_PUBSUB_RT_FIXED_SIZE;
+        writerGroupConfig.rtLevel = UA_PUBSUB_RT_NONE;
         UA_Server_addWriterGroup(server, connection1, &writerGroupConfig, &writerGroup1);
 
         UA_PublishedDataSetConfig pdsConfig;
@@ -159,6 +161,7 @@ START_TEST(CreateAndLockConfigurationWithExternalAPI) {
         dataSetWriterConfig.name = UA_STRING("DataSetWriter 1");
         UA_Server_addDataSetWriter(server, writerGroup1, publishedDataSet1, &dataSetWriterConfig, &dataSetWriter1);
         UA_DataSetWriter *dataSetWriter = UA_DataSetWriter_findDSWbyId(server, dataSetWriter1);
+        ck_assert(dataSetWriter != NULL);
 
         //get internal PubSubConnection Pointer
         UA_PubSubConnection *pubSubConnection = UA_PubSubConnection_findConnectionbyId(server, connection1);
@@ -197,7 +200,7 @@ START_TEST(CreateAndReleaseMultiplePDSLocks) {
     writerGroupConfig.name = UA_STRING("WriterGroup 1");
     writerGroupConfig.publishingInterval = 10;
     writerGroupConfig.encodingMimeType = UA_PUBSUB_ENCODING_UADP;
-    writerGroupConfig.rtLevel = UA_PUBSUB_RT_FIXED_SIZE;
+    writerGroupConfig.rtLevel = UA_PUBSUB_RT_NONE;
     UA_Server_addWriterGroup(server, connection1, &writerGroupConfig, &writerGroup1);
     writerGroupConfig.name = UA_STRING("WriterGroup 2");
     UA_Server_addWriterGroup(server, connection1, &writerGroupConfig, &writerGroup2);
@@ -268,7 +271,7 @@ START_TEST(CreateLockAndEditConfiguration) {
     writerGroupConfig.name = UA_STRING("WriterGroup 1");
     writerGroupConfig.publishingInterval = 10;
     writerGroupConfig.encodingMimeType = UA_PUBSUB_ENCODING_UADP;
-    writerGroupConfig.rtLevel = UA_PUBSUB_RT_FIXED_SIZE;
+    writerGroupConfig.rtLevel = UA_PUBSUB_RT_NONE;
     UA_Server_addWriterGroup(server, connection1, &writerGroupConfig, &writerGroup1);
 
     UA_PublishedDataSetConfig pdsConfig;
@@ -293,6 +296,7 @@ START_TEST(CreateLockAndEditConfiguration) {
     dataSetWriterConfig.name = UA_STRING("DataSetWriter 1");
     UA_Server_addDataSetWriter(server, writerGroup1, publishedDataSet1, &dataSetWriterConfig, &dataSetWriter1);
     UA_DataSetWriter *dataSetWriter = UA_DataSetWriter_findDSWbyId(server, dataSetWriter1);
+    ck_assert(dataSetWriter != NULL);
 
     ck_assert(dataSetWriter->config.configurationFrozen == UA_FALSE);
     //Lock the writer group and the child pubsub entities

+ 16 - 16
tests/pubsub/check_pubsub_encoding.c

@@ -35,7 +35,7 @@ START_TEST(UA_PubSub_EnDecode_ShallWorkOn1DS1ValueVariantKeyFrame) {
 
     UA_StatusCode rv = UA_STATUSCODE_UNCERTAININITIALVALUE;
     UA_ByteString buffer;
-    size_t msgSize = UA_NetworkMessage_calcSizeBinary(&m);
+    size_t msgSize = UA_NetworkMessage_calcSizeBinary(&m, NULL);
     rv = UA_ByteString_allocBuffer(&buffer, msgSize);
     ck_assert_int_eq(rv, UA_STATUSCODE_GOOD);
 
@@ -103,7 +103,7 @@ START_TEST(UA_PubSub_EnDecode_ShallWorkOn1DS1ValueDataValueKeyFrame) {
 
     UA_StatusCode rv = UA_STATUSCODE_UNCERTAININITIALVALUE;
     UA_ByteString buffer;
-    size_t msgSize = UA_NetworkMessage_calcSizeBinary(&m);
+    size_t msgSize = UA_NetworkMessage_calcSizeBinary(&m, NULL);
     rv = UA_ByteString_allocBuffer(&buffer, msgSize);
     ck_assert_int_eq(rv, UA_STATUSCODE_GOOD);
 
@@ -177,7 +177,7 @@ START_TEST(UA_PubSub_EnDecode_ShallWorkOn1DS2ValuesVariantKeyFrame) {
 
     UA_StatusCode rv = UA_STATUSCODE_UNCERTAININITIALVALUE;
     UA_ByteString buffer;
-    size_t msgSize = UA_NetworkMessage_calcSizeBinary(&m);
+    size_t msgSize = UA_NetworkMessage_calcSizeBinary(&m, NULL);
     rv = UA_ByteString_allocBuffer(&buffer, msgSize);
     ck_assert_int_eq(rv, UA_STATUSCODE_GOOD);
 
@@ -253,7 +253,7 @@ START_TEST(UA_PubSub_EnDecode_ShallWorkOn1DS2ValuesDataValueKeyFrame) {
 
     UA_StatusCode rv = UA_STATUSCODE_UNCERTAININITIALVALUE;
     UA_ByteString buffer;
-    size_t msgSize = UA_NetworkMessage_calcSizeBinary(&m);
+    size_t msgSize = UA_NetworkMessage_calcSizeBinary(&m, NULL);
     rv = UA_ByteString_allocBuffer(&buffer, msgSize);
     ck_assert_int_eq(rv, UA_STATUSCODE_GOOD);
 
@@ -326,7 +326,7 @@ START_TEST(UA_PubSub_EnDecode_ShallWorkOn1DS1ValueVariantDeltaFrame) {
 
     UA_StatusCode rv = UA_STATUSCODE_UNCERTAININITIALVALUE;
     UA_ByteString buffer;
-    size_t msgSize = UA_NetworkMessage_calcSizeBinary(&m);
+    size_t msgSize = UA_NetworkMessage_calcSizeBinary(&m, NULL);
     rv = UA_ByteString_allocBuffer(&buffer, msgSize);
     ck_assert_int_eq(rv, UA_STATUSCODE_GOOD);
 
@@ -395,7 +395,7 @@ START_TEST(UA_PubSub_EnDecode_ShallWorkOn1DS1ValueDataValueDeltaFrame) {
 
     UA_StatusCode rv = UA_STATUSCODE_UNCERTAININITIALVALUE;
     UA_ByteString buffer;
-    size_t msgSize = UA_NetworkMessage_calcSizeBinary(&m);
+    size_t msgSize = UA_NetworkMessage_calcSizeBinary(&m, NULL);
     rv = UA_ByteString_allocBuffer(&buffer, msgSize);
     ck_assert_int_eq(rv, UA_STATUSCODE_GOOD);
 
@@ -461,7 +461,7 @@ START_TEST(UA_PubSub_Encode_WithBufferTooSmallShallReturnError) {
 
     UA_StatusCode rv = UA_STATUSCODE_UNCERTAININITIALVALUE;
     UA_ByteString buffer;
-    size_t msgSize = UA_NetworkMessage_calcSizeBinary(&m);
+    size_t msgSize = UA_NetworkMessage_calcSizeBinary(&m, NULL);
 
     // to generate an error we make the buffer too small
     msgSize -= 5;
@@ -504,7 +504,7 @@ START_TEST(UA_PubSub_Decode_WithBufferTooSmallShallReturnError) {
 
     UA_StatusCode rv = UA_STATUSCODE_UNCERTAININITIALVALUE;
     UA_ByteString buffer;
-    size_t msgSize = UA_NetworkMessage_calcSizeBinary(&m);
+    size_t msgSize = UA_NetworkMessage_calcSizeBinary(&m, NULL);
     rv = UA_ByteString_allocBuffer(&buffer, msgSize);
     ck_assert_int_eq(rv, UA_STATUSCODE_GOOD);
 
@@ -576,7 +576,7 @@ START_TEST(UA_PubSub_EnDecode_ShallWorkOn1DS2ValuesVariantDeltaFrame) {
 
     UA_StatusCode rv = UA_STATUSCODE_UNCERTAININITIALVALUE;
     UA_ByteString buffer;
-    size_t msgSize = UA_NetworkMessage_calcSizeBinary(&m);
+    size_t msgSize = UA_NetworkMessage_calcSizeBinary(&m, NULL);
     rv = UA_ByteString_allocBuffer(&buffer, msgSize);
     ck_assert_int_eq(rv, UA_STATUSCODE_GOOD);
 
@@ -672,7 +672,7 @@ START_TEST(UA_PubSub_EnDecode_ShallWorkOn1DS2ValuesDataValueDeltaFrame) {
 
     UA_StatusCode rv = UA_STATUSCODE_UNCERTAININITIALVALUE;
     UA_ByteString buffer;
-    size_t msgSize = UA_NetworkMessage_calcSizeBinary(&m);
+    size_t msgSize = UA_NetworkMessage_calcSizeBinary(&m, NULL);
     rv = UA_ByteString_allocBuffer(&buffer, msgSize);
     ck_assert_int_eq(rv, UA_STATUSCODE_GOOD);
 
@@ -767,7 +767,7 @@ START_TEST(UA_PubSub_EnDecode_ShallWorkOn1DS2ValuesVariantKeyFrameGroupHeader) {
 
     UA_StatusCode rv = UA_STATUSCODE_UNCERTAININITIALVALUE;
     UA_ByteString buffer;
-    size_t msgSize = UA_NetworkMessage_calcSizeBinary(&m);
+    size_t msgSize = UA_NetworkMessage_calcSizeBinary(&m, NULL);
     rv = UA_ByteString_allocBuffer(&buffer, msgSize);
     ck_assert_int_eq(rv, UA_STATUSCODE_GOOD);
 
@@ -866,7 +866,7 @@ START_TEST(UA_PubSub_EnDecode_ShallWorkOn1DS2ValuesVariantDeltaFramePublDSCID) {
 
     UA_StatusCode rv = UA_STATUSCODE_UNCERTAININITIALVALUE;
     UA_ByteString buffer;
-    size_t msgSize = UA_NetworkMessage_calcSizeBinary(&m);
+    size_t msgSize = UA_NetworkMessage_calcSizeBinary(&m, NULL);
     rv = UA_ByteString_allocBuffer(&buffer, msgSize);
     ck_assert_int_eq(rv, UA_STATUSCODE_GOOD);
 
@@ -961,7 +961,7 @@ START_TEST(UA_PubSub_EnDecode_ShallWorkOn1DS2ValuesDataValueKeyFramePH) {
 
     UA_StatusCode rv = UA_STATUSCODE_UNCERTAININITIALVALUE;
     UA_ByteString buffer;
-    size_t msgSize = UA_NetworkMessage_calcSizeBinary(&m);
+    size_t msgSize = UA_NetworkMessage_calcSizeBinary(&m, NULL);
     rv = UA_ByteString_allocBuffer(&buffer, msgSize);
     ck_assert_int_eq(rv, UA_STATUSCODE_GOOD);
 
@@ -1050,7 +1050,7 @@ START_TEST(UA_PubSub_EnDecode_ShallWorkOn1DS2ValuesVariantKeyFrameTSProm) {
 
     UA_StatusCode rv = UA_STATUSCODE_UNCERTAININITIALVALUE;
     UA_ByteString buffer;
-    size_t msgSize = UA_NetworkMessage_calcSizeBinary(&m);
+    size_t msgSize = UA_NetworkMessage_calcSizeBinary(&m, NULL);
     rv = UA_ByteString_allocBuffer(&buffer, msgSize);
     ck_assert_int_eq(rv, UA_STATUSCODE_GOOD);
 
@@ -1155,7 +1155,7 @@ START_TEST(UA_PubSub_EnDecode_ShallWorkOn1DS2ValuesDataValueDeltaFrameGHProm2) {
 
     UA_StatusCode rv = UA_STATUSCODE_UNCERTAININITIALVALUE;
     UA_ByteString buffer;
-    size_t msgSize = UA_NetworkMessage_calcSizeBinary(&m);
+    size_t msgSize = UA_NetworkMessage_calcSizeBinary(&m, NULL);
     rv = UA_ByteString_allocBuffer(&buffer, msgSize);
     ck_assert_int_eq(rv, UA_STATUSCODE_GOOD);
 
@@ -1277,7 +1277,7 @@ START_TEST(UA_PubSub_EnDecode_ShallWorkOn2DSVariant) {
 
     UA_StatusCode rv = UA_STATUSCODE_UNCERTAININITIALVALUE;
     UA_ByteString buffer;
-    size_t msgSize = UA_NetworkMessage_calcSizeBinary(&m);
+    size_t msgSize = UA_NetworkMessage_calcSizeBinary(&m, NULL);
     rv = UA_ByteString_allocBuffer(&buffer, msgSize);
     ck_assert_int_eq(rv, UA_STATUSCODE_GOOD);
 

+ 390 - 0
tests/pubsub/check_pubsub_publish_rt_levels.c

@@ -0,0 +1,390 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * Copyright (c) 2019 Fraunhofer IOSB (Author: Andreas Ebner)
+ */
+
+#include <open62541/server.h>
+#include <open62541/server_config_default.h>
+#include <open62541/plugin/pubsub_udp.h>
+
+#include <check.h>
+#include <stdio.h>
+#include <ua_pubsub.h>
+#include <ua_pubsub_networkmessage.h>
+
+
+UA_Server *server = NULL;
+UA_NodeId connectionIdentifier, publishedDataSetIdent, writerGroupIdent, dataSetWriterIdent, dataSetFieldIdent;
+
+static UA_StatusCode
+addMinimalPubSubConfiguration(void){
+    UA_StatusCode retVal = UA_STATUSCODE_GOOD;
+    /* Add one PubSubConnection */
+    UA_PubSubConnectionConfig connectionConfig;
+    memset(&connectionConfig, 0, sizeof(connectionConfig));
+    connectionConfig.name = UA_STRING("UDP-UADP Connection 1");
+    connectionConfig.transportProfileUri = UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-udp-uadp");
+    connectionConfig.enabled = UA_TRUE;
+    UA_NetworkAddressUrlDataType networkAddressUrl = {UA_STRING_NULL , UA_STRING("opc.udp://224.0.0.22:4840/")};
+    UA_Variant_setScalar(&connectionConfig.address, &networkAddressUrl, &UA_TYPES[UA_TYPES_NETWORKADDRESSURLDATATYPE]);
+    connectionConfig.publisherId.numeric = UA_UInt32_random();
+    retVal = UA_Server_addPubSubConnection(server, &connectionConfig, &connectionIdentifier);
+    if(retVal != UA_STATUSCODE_GOOD)
+        return retVal;
+    /* Add one PublishedDataSet */
+    UA_PublishedDataSetConfig publishedDataSetConfig;
+    memset(&publishedDataSetConfig, 0, sizeof(UA_PublishedDataSetConfig));
+    publishedDataSetConfig.publishedDataSetType = UA_PUBSUB_DATASET_PUBLISHEDITEMS;
+    publishedDataSetConfig.name = UA_STRING("Demo PDS");
+    /* Add one DataSetField to the PDS */
+    UA_AddPublishedDataSetResult addResult = UA_Server_addPublishedDataSet(server, &publishedDataSetConfig, &publishedDataSetIdent);
+    return addResult.addResult;
+}
+
+static void setup(void) {
+    server = UA_Server_new();
+    UA_ServerConfig *config = UA_Server_getConfig(server);
+    UA_ServerConfig_setDefault(config);
+
+    config->pubsubTransportLayers = (UA_PubSubTransportLayer*)
+            UA_malloc(sizeof(UA_PubSubTransportLayer));
+    config->pubsubTransportLayers[0] = UA_PubSubTransportLayerUDPMP();
+    config->pubsubTransportLayersSize++;
+    UA_Server_run_startup(server);
+}
+
+static void teardown(void) {
+    UA_Server_run_shutdown(server);
+    UA_Server_delete(server);
+}
+
+static void receiveSingleMessage(UA_ByteString buffer, UA_PubSubConnection *connection, UA_NetworkMessage *networkMessage) {
+    if (UA_ByteString_allocBuffer(&buffer, 512) != UA_STATUSCODE_GOOD) {
+        ck_abort_msg("Message buffer allocation failed!");
+    }
+    UA_StatusCode retval =
+            connection->channel->receive(connection->channel, &buffer, NULL, 1000000);
+    if(retval != UA_STATUSCODE_GOOD || buffer.length == 0) {
+        buffer.length = 512;
+        UA_ByteString_clear(&buffer);
+        ck_abort_msg("Expected message not received!");
+    }
+    memset(networkMessage, 0, sizeof(UA_NetworkMessage));
+    size_t currentPosition = 0;
+    UA_NetworkMessage_decodeBinary(&buffer, &currentPosition, networkMessage);
+    UA_ByteString_clear(&buffer);
+}
+
+START_TEST(PublishSingleFieldWithStaticValueSource) {
+    ck_assert(addMinimalPubSubConfiguration() == UA_STATUSCODE_GOOD);
+    UA_PubSubConnection *connection = UA_PubSubConnection_findConnectionbyId(server, connectionIdentifier);
+    if(connection != NULL) {
+        UA_StatusCode rv = connection->channel->regist(connection->channel, NULL, NULL);
+        ck_assert(rv == UA_STATUSCODE_GOOD);
+    }
+    UA_WriterGroupConfig writerGroupConfig;
+    memset(&writerGroupConfig, 0, sizeof(UA_WriterGroupConfig));
+    writerGroupConfig.name = UA_STRING("Demo WriterGroup");
+    writerGroupConfig.publishingInterval = 10;
+    writerGroupConfig.enabled = UA_FALSE;
+    writerGroupConfig.writerGroupId = 100;
+    writerGroupConfig.encodingMimeType = UA_PUBSUB_ENCODING_UADP;
+    writerGroupConfig.rtLevel = UA_PUBSUB_RT_DIRECT_VALUE_ACCESS;
+    UA_UadpWriterGroupMessageDataType *wgm = UA_UadpWriterGroupMessageDataType_new();
+    wgm->networkMessageContentMask = UA_UADPNETWORKMESSAGECONTENTMASK_PAYLOADHEADER;
+    writerGroupConfig.messageSettings.content.decoded.data = wgm;
+    writerGroupConfig.messageSettings.content.decoded.type =
+            &UA_TYPES[UA_TYPES_UADPWRITERGROUPMESSAGEDATATYPE];
+    writerGroupConfig.messageSettings.encoding = UA_EXTENSIONOBJECT_DECODED;
+    ck_assert(UA_Server_addWriterGroup(server, connectionIdentifier, &writerGroupConfig, &writerGroupIdent) == UA_STATUSCODE_GOOD);
+    UA_UadpWriterGroupMessageDataType_delete(wgm);
+    UA_DataSetWriterConfig dataSetWriterConfig;
+    memset(&dataSetWriterConfig, 0, sizeof(UA_DataSetWriterConfig));
+    dataSetWriterConfig.name = UA_STRING("Test DataSetWriter");
+    dataSetWriterConfig.dataSetWriterId = 62541;
+    ck_assert(UA_Server_addDataSetWriter(server, writerGroupIdent, publishedDataSetIdent, &dataSetWriterConfig, &dataSetWriterIdent) == UA_STATUSCODE_GOOD);
+    UA_DataSetFieldConfig dsfConfig;
+    memset(&dsfConfig, 0, sizeof(UA_DataSetFieldConfig));
+    /* Create Variant and configure as DataSetField source */
+    UA_UInt32 intValue = 1000;
+    UA_Variant variant;
+    memset(&variant, 0, sizeof(UA_Variant));
+    UA_Variant_setScalar(&variant, &intValue, &UA_TYPES[UA_TYPES_UINT32]);
+    UA_DataValue staticValueSource;
+    memset(&staticValueSource, 0, sizeof(staticValueSource));
+    staticValueSource.value = variant;
+    dsfConfig.field.variable.staticValueSourceEnabled = UA_TRUE;
+    dsfConfig.field.variable.staticValueSource.value = variant;
+    dsfConfig.field.variable.publishParameters.attributeId = UA_ATTRIBUTEID_VALUE;
+    ck_assert(UA_Server_addDataSetField(server, publishedDataSetIdent, &dsfConfig, &dataSetFieldIdent).result == UA_STATUSCODE_GOOD);
+    ck_assert(UA_Server_freezeWriterGroupConfiguration(server, writerGroupIdent) == UA_STATUSCODE_GOOD);
+    ck_assert(UA_Server_setWriterGroupOperational(server, writerGroupIdent) == UA_STATUSCODE_GOOD);
+    UA_ByteString buffer;
+    UA_ByteString_init(&buffer);
+    UA_NetworkMessage networkMessage;
+    receiveSingleMessage(buffer, connection, &networkMessage);
+    ck_assert((*((UA_UInt32 *)networkMessage.payload.dataSetPayload.dataSetMessages->data.keyFrameData.dataSetFields->value.data)) == 1000);
+    UA_NetworkMessage_deleteMembers(&networkMessage);
+    } END_TEST
+
+START_TEST(PublishSingleFieldWithDifferentBinarySizes) {
+    ck_assert(addMinimalPubSubConfiguration() == UA_STATUSCODE_GOOD);
+    UA_PubSubConnection *connection = UA_PubSubConnection_findConnectionbyId(server, connectionIdentifier);
+    if(connection != NULL) {
+        UA_StatusCode rv = connection->channel->regist(connection->channel, NULL, NULL);
+        ck_assert(rv == UA_STATUSCODE_GOOD);
+    }
+    UA_WriterGroupConfig writerGroupConfig;
+    memset(&writerGroupConfig, 0, sizeof(UA_WriterGroupConfig));
+    writerGroupConfig.name = UA_STRING("Test WriterGroup");
+    writerGroupConfig.publishingInterval = 10;
+    writerGroupConfig.enabled = UA_FALSE;
+    writerGroupConfig.writerGroupId = 100;
+    writerGroupConfig.encodingMimeType = UA_PUBSUB_ENCODING_UADP;
+    writerGroupConfig.rtLevel = UA_PUBSUB_RT_DIRECT_VALUE_ACCESS;
+    UA_UadpWriterGroupMessageDataType *wgm = UA_UadpWriterGroupMessageDataType_new();
+    wgm->networkMessageContentMask = UA_UADPNETWORKMESSAGECONTENTMASK_PAYLOADHEADER;
+    writerGroupConfig.messageSettings.content.decoded.data = wgm;
+    writerGroupConfig.messageSettings.content.decoded.type =
+            &UA_TYPES[UA_TYPES_UADPWRITERGROUPMESSAGEDATATYPE];
+    writerGroupConfig.messageSettings.encoding = UA_EXTENSIONOBJECT_DECODED;
+    ck_assert(UA_Server_addWriterGroup(server, connectionIdentifier, &writerGroupConfig, &writerGroupIdent) == UA_STATUSCODE_GOOD);
+    UA_UadpWriterGroupMessageDataType_delete(wgm);
+    UA_DataSetWriterConfig dataSetWriterConfig;
+    memset(&dataSetWriterConfig, 0, sizeof(UA_DataSetWriterConfig));
+    dataSetWriterConfig.name = UA_STRING("Demo DataSetWriter");
+    dataSetWriterConfig.dataSetWriterId = 62541;
+    ck_assert(UA_Server_addDataSetWriter(server, writerGroupIdent, publishedDataSetIdent, &dataSetWriterConfig, &dataSetWriterIdent) == UA_STATUSCODE_GOOD);
+    UA_DataSetFieldConfig dsfConfig;
+    memset(&dsfConfig, 0, sizeof(UA_DataSetFieldConfig));
+    /* Create Variant and configure as DataSetField source */
+    UA_String stringValue = UA_STRING_ALLOC("12345");
+    UA_Variant variant;
+    memset(&variant, 0, sizeof(UA_Variant));
+    UA_Variant_setScalar(&variant, &stringValue, &UA_TYPES[UA_TYPES_STRING]);
+    UA_DataValue staticValueSource;
+    memset(&staticValueSource, 0, sizeof(staticValueSource));
+    staticValueSource.value = variant;
+    dsfConfig.field.variable.staticValueSourceEnabled = UA_TRUE;
+    dsfConfig.field.variable.staticValueSource.value = variant;
+    dsfConfig.field.variable.publishParameters.attributeId = UA_ATTRIBUTEID_VALUE;
+    ck_assert(UA_Server_addDataSetField(server, publishedDataSetIdent, &dsfConfig, &dataSetFieldIdent).result == UA_STATUSCODE_GOOD);
+    ck_assert(UA_Server_freezeWriterGroupConfiguration(server, writerGroupIdent) == UA_STATUSCODE_GOOD);
+    ck_assert(UA_Server_setWriterGroupOperational(server, writerGroupIdent) == UA_STATUSCODE_GOOD);
+    UA_ByteString buffer;
+    UA_ByteString_init(&buffer);
+    UA_NetworkMessage networkMessage;
+    memset(&networkMessage, 0, sizeof(networkMessage));
+    receiveSingleMessage(buffer, connection, &networkMessage);
+    UA_String compareString = UA_STRING("12345");
+    ck_assert(UA_String_equal(((UA_String *) networkMessage.payload.dataSetPayload.dataSetMessages->data.keyFrameData.dataSetFields->value.data), &compareString) == UA_TRUE);
+    UA_NetworkMessage_deleteMembers(&networkMessage);
+    compareString = UA_STRING("123456789");
+    stringValue.data = (UA_Byte *) UA_realloc(stringValue.data, 9);
+    stringValue.length = 9;
+    memcpy(stringValue.data, "123456789", 9);
+    UA_ByteString_init(&buffer);
+    memset(&networkMessage, 0, sizeof(networkMessage));
+    ck_assert(UA_Server_setWriterGroupDisabled(server, writerGroupIdent) == UA_STATUSCODE_GOOD);
+    ck_assert(UA_Server_setWriterGroupOperational(server, writerGroupIdent) == UA_STATUSCODE_GOOD);
+    receiveSingleMessage(buffer, connection, &networkMessage);
+    ck_assert(UA_String_equal(((UA_String *) networkMessage.payload.dataSetPayload.dataSetMessages->data.keyFrameData.dataSetFields->value.data), &compareString) == UA_TRUE);
+    UA_NetworkMessage_deleteMembers(&networkMessage);
+    UA_String_deleteMembers(&stringValue);
+} END_TEST
+
+START_TEST(SetupInvalidPubSubConfigWithStaticValueSource) {
+    ck_assert(addMinimalPubSubConfiguration() == UA_STATUSCODE_GOOD);
+    UA_PubSubConnection *connection = UA_PubSubConnection_findConnectionbyId(server, connectionIdentifier);
+    if(connection != NULL) {
+        UA_StatusCode rv = connection->channel->regist(connection->channel, NULL, NULL);
+        ck_assert(rv == UA_STATUSCODE_GOOD);
+    }
+    UA_WriterGroupConfig writerGroupConfig;
+    memset(&writerGroupConfig, 0, sizeof(UA_WriterGroupConfig));
+    writerGroupConfig.name = UA_STRING("Test WriterGroup");
+    writerGroupConfig.publishingInterval = 10;
+    writerGroupConfig.enabled = UA_FALSE;
+    writerGroupConfig.writerGroupId = 100;
+    writerGroupConfig.encodingMimeType = UA_PUBSUB_ENCODING_UADP;
+    writerGroupConfig.rtLevel = UA_PUBSUB_RT_DIRECT_VALUE_ACCESS;
+    UA_UadpWriterGroupMessageDataType *wgm = UA_UadpWriterGroupMessageDataType_new();
+    wgm->networkMessageContentMask = UA_UADPNETWORKMESSAGECONTENTMASK_PAYLOADHEADER;
+    writerGroupConfig.messageSettings.content.decoded.data = wgm;
+    writerGroupConfig.messageSettings.content.decoded.type =
+            &UA_TYPES[UA_TYPES_UADPWRITERGROUPMESSAGEDATATYPE];
+    writerGroupConfig.messageSettings.encoding = UA_EXTENSIONOBJECT_DECODED;
+    ck_assert(UA_Server_addWriterGroup(server, connectionIdentifier, &writerGroupConfig, &writerGroupIdent) == UA_STATUSCODE_GOOD);
+    UA_UadpWriterGroupMessageDataType_delete(wgm);
+    UA_DataSetWriterConfig dataSetWriterConfig;
+    memset(&dataSetWriterConfig, 0, sizeof(UA_DataSetWriterConfig));
+    dataSetWriterConfig.name = UA_STRING("Demo DataSetWriter");
+    dataSetWriterConfig.dataSetWriterId = 62541;
+
+    UA_DataSetFieldConfig dataSetFieldConfig;
+    memset(&dataSetFieldConfig, 0, sizeof(UA_DataSetFieldConfig));
+    dataSetFieldConfig.dataSetFieldType = UA_PUBSUB_DATASETFIELD_VARIABLE;
+    dataSetFieldConfig.field.variable.fieldNameAlias = UA_STRING("Server localtime");
+    dataSetFieldConfig.field.variable.promotedField = UA_FALSE;
+    dataSetFieldConfig.field.variable.publishParameters.publishedVariable =
+            UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME);
+    dataSetFieldConfig.field.variable.publishParameters.attributeId = UA_ATTRIBUTEID_VALUE;
+    UA_Server_addDataSetField(server, publishedDataSetIdent,
+                              &dataSetFieldConfig, &dataSetFieldIdent);
+    ck_assert(UA_Server_addDataSetWriter(server, writerGroupIdent, publishedDataSetIdent, &dataSetWriterConfig, &dataSetWriterIdent) == UA_STATUSCODE_BADCONFIGURATIONERROR);
+} END_TEST
+
+START_TEST(PublishSingleFieldWithFixedOffsets) {
+    ck_assert(addMinimalPubSubConfiguration() == UA_STATUSCODE_GOOD);
+    UA_PubSubConnection *connection = UA_PubSubConnection_findConnectionbyId(server, connectionIdentifier);
+    if(connection != NULL) {
+        UA_StatusCode rv = connection->channel->regist(connection->channel, NULL, NULL);
+        ck_assert(rv == UA_STATUSCODE_GOOD);
+    }
+    UA_WriterGroupConfig writerGroupConfig;
+    memset(&writerGroupConfig, 0, sizeof(UA_WriterGroupConfig));
+    writerGroupConfig.name = UA_STRING("Demo WriterGroup");
+    writerGroupConfig.publishingInterval = 10;
+    writerGroupConfig.enabled = UA_FALSE;
+    writerGroupConfig.writerGroupId = 100;
+    writerGroupConfig.encodingMimeType = UA_PUBSUB_ENCODING_UADP;
+    writerGroupConfig.rtLevel = UA_PUBSUB_RT_FIXED_SIZE;
+    UA_UadpWriterGroupMessageDataType *wgm = UA_UadpWriterGroupMessageDataType_new();
+    wgm->networkMessageContentMask = UA_UADPNETWORKMESSAGECONTENTMASK_PAYLOADHEADER;
+    writerGroupConfig.messageSettings.content.decoded.data = wgm;
+    writerGroupConfig.messageSettings.content.decoded.type =
+            &UA_TYPES[UA_TYPES_UADPWRITERGROUPMESSAGEDATATYPE];
+    writerGroupConfig.messageSettings.encoding = UA_EXTENSIONOBJECT_DECODED;
+    ck_assert(UA_Server_addWriterGroup(server, connectionIdentifier, &writerGroupConfig, &writerGroupIdent) == UA_STATUSCODE_GOOD);
+    UA_UadpWriterGroupMessageDataType_delete(wgm);
+    UA_DataSetWriterConfig dataSetWriterConfig;
+    memset(&dataSetWriterConfig, 0, sizeof(UA_DataSetWriterConfig));
+    dataSetWriterConfig.name = UA_STRING("Test DataSetWriter");
+    dataSetWriterConfig.dataSetWriterId = 62541;
+    ck_assert(UA_Server_addDataSetWriter(server, writerGroupIdent, publishedDataSetIdent, &dataSetWriterConfig, &dataSetWriterIdent) == UA_STATUSCODE_GOOD);
+    UA_DataSetFieldConfig dsfConfig;
+    memset(&dsfConfig, 0, sizeof(UA_DataSetFieldConfig));
+    // Create Variant and configure as DataSetField source
+    UA_UInt32 *intValue = UA_UInt32_new();
+    *intValue = (UA_UInt32) 1000;
+    UA_Variant variant;
+    memset(&variant, 0, sizeof(UA_Variant));
+    UA_Variant_setScalar(&variant, intValue, &UA_TYPES[UA_TYPES_UINT32]);
+    UA_DataValue staticValueSource;
+    memset(&staticValueSource, 0, sizeof(staticValueSource));
+    staticValueSource.value = variant;
+    dsfConfig.field.variable.staticValueSourceEnabled = UA_TRUE;
+    dsfConfig.field.variable.staticValueSource.value = variant;
+    dsfConfig.field.variable.publishParameters.attributeId = UA_ATTRIBUTEID_VALUE;
+    ck_assert(UA_Server_addDataSetField(server, publishedDataSetIdent, &dsfConfig, &dataSetFieldIdent).result == UA_STATUSCODE_GOOD);
+    ck_assert(UA_Server_freezeWriterGroupConfiguration(server, writerGroupIdent) == UA_STATUSCODE_GOOD);
+    ck_assert(UA_Server_setWriterGroupOperational(server, writerGroupIdent) == UA_STATUSCODE_GOOD);
+    UA_ByteString buffer;
+    UA_ByteString_init(&buffer);
+    UA_NetworkMessage networkMessage;
+    receiveSingleMessage(buffer, connection, &networkMessage);
+    ck_assert((*((UA_UInt32 *)networkMessage.payload.dataSetPayload.dataSetMessages->data.keyFrameData.dataSetFields->value.data)) == 1000);
+    UA_NetworkMessage_deleteMembers(&networkMessage);
+} END_TEST
+
+START_TEST(PublishPDSWithMultipleFieldsAndFixedOffset) {
+        ck_assert(addMinimalPubSubConfiguration() == UA_STATUSCODE_GOOD);
+        UA_PubSubConnection *connection = UA_PubSubConnection_findConnectionbyId(server, connectionIdentifier);
+        if(connection != NULL) {
+            UA_StatusCode rv = connection->channel->regist(connection->channel, NULL, NULL);
+            ck_assert(rv == UA_STATUSCODE_GOOD);
+        }
+        UA_WriterGroupConfig writerGroupConfig;
+        memset(&writerGroupConfig, 0, sizeof(UA_WriterGroupConfig));
+        writerGroupConfig.name = UA_STRING("Demo WriterGroup");
+        writerGroupConfig.publishingInterval = 10;
+        writerGroupConfig.enabled = UA_FALSE;
+        writerGroupConfig.writerGroupId = 100;
+        writerGroupConfig.encodingMimeType = UA_PUBSUB_ENCODING_UADP;
+        writerGroupConfig.rtLevel = UA_PUBSUB_RT_FIXED_SIZE;
+        UA_UadpWriterGroupMessageDataType *wgm = UA_UadpWriterGroupMessageDataType_new();
+        wgm->networkMessageContentMask = UA_UADPNETWORKMESSAGECONTENTMASK_PAYLOADHEADER;
+        writerGroupConfig.messageSettings.content.decoded.data = wgm;
+        writerGroupConfig.messageSettings.content.decoded.type =
+                &UA_TYPES[UA_TYPES_UADPWRITERGROUPMESSAGEDATATYPE];
+        writerGroupConfig.messageSettings.encoding = UA_EXTENSIONOBJECT_DECODED;
+        ck_assert(UA_Server_addWriterGroup(server, connectionIdentifier, &writerGroupConfig, &writerGroupIdent) == UA_STATUSCODE_GOOD);
+        UA_UadpWriterGroupMessageDataType_delete(wgm);
+        UA_DataSetWriterConfig dataSetWriterConfig;
+        memset(&dataSetWriterConfig, 0, sizeof(UA_DataSetWriterConfig));
+        dataSetWriterConfig.name = UA_STRING("Test DataSetWriter");
+        dataSetWriterConfig.dataSetWriterId = 62541;
+        ck_assert(UA_Server_addDataSetWriter(server, writerGroupIdent, publishedDataSetIdent, &dataSetWriterConfig, &dataSetWriterIdent) == UA_STATUSCODE_GOOD);
+        UA_DataSetFieldConfig dsfConfig;
+        memset(&dsfConfig, 0, sizeof(UA_DataSetFieldConfig));
+        // Create Variant and configure as DataSetField source
+        UA_UInt32 *intValue = UA_UInt32_new();
+        *intValue = (UA_UInt32) 1000;
+        UA_Variant variant;
+        memset(&variant, 0, sizeof(UA_Variant));
+        UA_Variant_setScalar(&variant, intValue, &UA_TYPES[UA_TYPES_UINT32]);
+        UA_DataValue staticValueSource;
+        memset(&staticValueSource, 0, sizeof(staticValueSource));
+        staticValueSource.value = variant;
+        dsfConfig.field.variable.staticValueSourceEnabled = UA_TRUE;
+        dsfConfig.field.variable.staticValueSource.value = variant;
+        dsfConfig.field.variable.publishParameters.attributeId = UA_ATTRIBUTEID_VALUE;
+        ck_assert(UA_Server_addDataSetField(server, publishedDataSetIdent, &dsfConfig, &dataSetFieldIdent).result == UA_STATUSCODE_GOOD);
+        UA_UInt32 *intValue2 = UA_UInt32_new();
+        *intValue2 = (UA_UInt32) 2000;
+        UA_Variant variant2;
+        memset(&variant2, 0, sizeof(UA_Variant));
+        UA_Variant_setScalar(&variant2, intValue2, &UA_TYPES[UA_TYPES_UINT32]);
+        UA_DataValue staticValueSource2;
+        memset(&staticValueSource2, 0, sizeof(staticValueSource));
+        staticValueSource2.value = variant2;
+        dsfConfig.field.variable.staticValueSource.value = variant2;
+        ck_assert(UA_Server_addDataSetField(server, publishedDataSetIdent, &dsfConfig, &dataSetFieldIdent).result == UA_STATUSCODE_GOOD);
+        ck_assert(UA_Server_freezeWriterGroupConfiguration(server, writerGroupIdent) == UA_STATUSCODE_GOOD);
+        ck_assert(UA_Server_setWriterGroupOperational(server, writerGroupIdent) == UA_STATUSCODE_GOOD);
+        UA_ByteString buffer;
+        UA_ByteString_init(&buffer);
+        UA_NetworkMessage networkMessage;
+        receiveSingleMessage(buffer, connection, &networkMessage);
+        ck_assert((*((UA_UInt32 *)networkMessage.payload.dataSetPayload.dataSetMessages->data.keyFrameData.dataSetFields->value.data)) == 1000);
+        ck_assert(*((UA_UInt32 *) networkMessage.payload.dataSetPayload.dataSetMessages->data.keyFrameData.dataSetFields[1].value.data) == 2000);
+        UA_NetworkMessage_deleteMembers(&networkMessage);
+        *intValue = (UA_UInt32) 1001;
+        *intValue2 = (UA_UInt32) 2001;
+        UA_ByteString_init(&buffer);
+        memset(&networkMessage, 0, sizeof(networkMessage));
+        ck_assert(UA_Server_setWriterGroupDisabled(server, writerGroupIdent) == UA_STATUSCODE_GOOD);
+        ck_assert(UA_Server_setWriterGroupOperational(server, writerGroupIdent) == UA_STATUSCODE_GOOD);
+        receiveSingleMessage(buffer, connection, &networkMessage);
+        ck_assert((*((UA_UInt32 *)networkMessage.payload.dataSetPayload.dataSetMessages->data.keyFrameData.dataSetFields->value.data)) == 1001);
+        ck_assert(*((UA_UInt32 *) networkMessage.payload.dataSetPayload.dataSetMessages->data.keyFrameData.dataSetFields[1].value.data) == 2001);
+        UA_NetworkMessage_deleteMembers(&networkMessage);
+} END_TEST
+
+int main(void) {
+    TCase *tc_pubsub_rt_static_value_source = tcase_create("PubSub RT publish with static value sources");
+    tcase_add_checked_fixture(tc_pubsub_rt_static_value_source, setup, teardown);
+    tcase_add_test(tc_pubsub_rt_static_value_source, PublishSingleFieldWithStaticValueSource);
+    tcase_add_test(tc_pubsub_rt_static_value_source, PublishSingleFieldWithDifferentBinarySizes);
+    tcase_add_test(tc_pubsub_rt_static_value_source, SetupInvalidPubSubConfigWithStaticValueSource);
+
+
+    TCase *tc_pubsub_rt_fixed_offsets = tcase_create("PubSub RT publish with fixed offsets");
+    tcase_add_checked_fixture(tc_pubsub_rt_fixed_offsets, setup, teardown);
+    tcase_add_test(tc_pubsub_rt_fixed_offsets, PublishSingleFieldWithFixedOffsets);
+    tcase_add_test(tc_pubsub_rt_fixed_offsets, PublishPDSWithMultipleFieldsAndFixedOffset);
+
+    Suite *s = suite_create("PubSub RT configuration levels");
+    suite_add_tcase(s, tc_pubsub_rt_static_value_source);
+    suite_add_tcase(s, tc_pubsub_rt_fixed_offsets);
+
+
+    SRunner *sr = srunner_create(s);
+    srunner_set_fork_status(sr, CK_NOFORK);
+    srunner_run_all(sr,CK_NORMAL);
+    int number_failed = srunner_ntests_failed(sr);
+    srunner_free(sr);
+    return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}

+ 1 - 2
tests/pubsub/check_pubsub_publish_uadp.c

@@ -189,7 +189,7 @@ START_TEST(CheckNMandDSMBufferCalculation){
         writerGroupConfig.enabled = UA_FALSE;
         writerGroupConfig.writerGroupId = 100;
         writerGroupConfig.encodingMimeType = UA_PUBSUB_ENCODING_UADP;
-        writerGroupConfig.rtLevel = UA_PUBSUB_RT_FIXED_SIZE;
+        writerGroupConfig.rtLevel = UA_PUBSUB_RT_NONE;
 
         UA_UadpWriterGroupMessageDataType *wgm = UA_UadpWriterGroupMessageDataType_new();
         wgm->networkMessageContentMask = UA_UADPNETWORKMESSAGECONTENTMASK_PAYLOADHEADER;
@@ -216,7 +216,6 @@ START_TEST(CheckNMandDSMBufferCalculation){
                                        &dataSetWriterConfig, &dataSetWriterIdent);
         }
 
-        //TODO extend this test with the buffer and offset calculation of the uadp network layer
         UA_Server_freezeWriterGroupConfiguration(server, writerGroupIdent);
         UA_Server_unfreezeWriterGroupConfiguration(server, writerGroupIdent);