Browse Source

client: allow adding several monitoreditems at once

Julius Pfrommer 7 years ago
parent
commit
90b1ebbfd9

+ 36 - 20
include/ua_client_highlevel.h

@@ -587,37 +587,53 @@ UA_Client_Subscriptions_remove(UA_Client *client, UA_UInt32 subscriptionId);
 UA_StatusCode UA_EXPORT
 UA_Client_Subscriptions_manuallySendPublishRequest(UA_Client *client);
 
-typedef void (*UA_MonitoredEventHandlingFunction)(const UA_UInt32 monId,
-                                                  const size_t nEventFields,
-                                                  const UA_Variant *eventFields,
-                                                  void *context);
+/* Addition of monitored DataChanges */
+/* TODO for v0.4: Rename method to _DataChange. */
+typedef void (*UA_MonitoredItemHandlingFunction)(UA_UInt32 monId, UA_DataValue *value,
+                                                 void *context);
 
 UA_StatusCode UA_EXPORT
-UA_Client_Subscriptions_addMonitoredEvent(UA_Client *client, const UA_UInt32 subscriptionId,
-                                          const UA_NodeId nodeId, const UA_UInt32 attributeID,
-                                          UA_SimpleAttributeOperand *selectClause,
-                                          const size_t nSelectClauses,
-                                          UA_ContentFilterElement *whereClause,
-                                          const size_t nWhereClauses,
-                                          const UA_MonitoredEventHandlingFunction hf,
-                                          void *hfContext, UA_UInt32 *newMonitoredItemId);
-
-typedef void (*UA_MonitoredItemHandlingFunction)(UA_UInt32 monId,
-                                                 UA_DataValue *value,
-                                                 void *context);
+UA_Client_Subscriptions_addMonitoredItems(UA_Client *client, const UA_UInt32 subscriptionId,
+                                          UA_MonitoredItemCreateRequest *items, size_t itemsSize,
+                                          UA_MonitoredItemHandlingFunction **hfs,
+                                          void **hfContexts, UA_StatusCode *itemResults,
+                                          UA_UInt32 *newMonitoredItemIds);
 
 UA_StatusCode UA_EXPORT
-UA_Client_Subscriptions_addMonitoredItem(UA_Client *client,
-                                         UA_UInt32 subscriptionId,
+UA_Client_Subscriptions_addMonitoredItem(UA_Client *client, UA_UInt32 subscriptionId,
                                          UA_NodeId nodeId, UA_UInt32 attributeID,
                                          UA_MonitoredItemHandlingFunction hf,
                                          void *hfContext,
                                          UA_UInt32 *newMonitoredItemId,
                                          UA_Double samplingInterval);
 
+/* Monitored Events have different payloads from DataChanges. So they use a
+ * different callback method signature. */
+typedef void (*UA_MonitoredEventHandlingFunction)(const UA_UInt32 monId,
+                                                  const size_t nEventFields,
+                                                  const UA_Variant *eventFields,
+                                                  void *context);
+
+UA_StatusCode UA_EXPORT
+UA_Client_Subscriptions_addMonitoredEvents(UA_Client *client, const UA_UInt32 subscriptionId,
+                                           UA_MonitoredItemCreateRequest *items, size_t itemsSize,
+                                           UA_MonitoredEventHandlingFunction **hfs,
+                                           void **hfContexts, UA_StatusCode *itemResults,
+                                           UA_UInt32 *newMonitoredItemIds);
+
+/* TODO for 0.4: attribute is fix for events. */
+UA_StatusCode UA_EXPORT
+UA_Client_Subscriptions_addMonitoredEvent(UA_Client *client, UA_UInt32 subscriptionId,
+                                          const UA_NodeId nodeId, UA_UInt32 attributeID,
+                                          const UA_SimpleAttributeOperand *selectClauses,
+                                          size_t selectClausesSize,
+                                          const UA_ContentFilterElement *whereClauses,
+                                          size_t whereClausesSize,
+                                          const UA_MonitoredEventHandlingFunction hf,
+                                          void *hfContext, UA_UInt32 *newMonitoredItemId);
+
 UA_StatusCode UA_EXPORT
-UA_Client_Subscriptions_removeMonitoredItem(UA_Client *client,
-                                            UA_UInt32 subscriptionId,
+UA_Client_Subscriptions_removeMonitoredItem(UA_Client *client, UA_UInt32 subscriptionId,
                                             UA_UInt32 monitoredItemId);
 
 #endif

+ 179 - 134
src/client/ua_client_highlevel_subscriptions.c

@@ -111,159 +111,177 @@ UA_Client_Subscriptions_forceDelete(UA_Client *client,
     UA_free(sub);
 }
 
-UA_StatusCode
-UA_Client_Subscriptions_addMonitoredEvent(UA_Client *client, const UA_UInt32 subscriptionId,
-                                         const UA_NodeId nodeId, const UA_UInt32 attributeID,
-                                         UA_SimpleAttributeOperand *selectClause,
-                                         const size_t nSelectClauses,
-                                         UA_ContentFilterElement *whereClause,
-                                         const size_t nWhereClauses,
-                                         const UA_MonitoredEventHandlingFunction hf,
-                                         void *hfContext, UA_UInt32 *newMonitoredItemId) {
+static UA_StatusCode
+addMonitoredItems(UA_Client *client, const UA_UInt32 subscriptionId,
+                  UA_MonitoredItemCreateRequest *items, size_t itemsSize,
+                  void **hfs, void **hfContexts, UA_StatusCode *itemResults,
+                  UA_UInt32 *newMonitoredItemIds, UA_Boolean isEventMonitoredItem) {
     UA_Client_Subscription *sub = findSubscription(client, subscriptionId);
     if(!sub)
         return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
 
-    /* Send the request */
     UA_CreateMonitoredItemsRequest request;
     UA_CreateMonitoredItemsRequest_init(&request);
-    request.subscriptionId = subscriptionId;
-
-    UA_MonitoredItemCreateRequest item;
-    UA_MonitoredItemCreateRequest_init(&item);
-    item.itemToMonitor.nodeId = nodeId;
-    item.itemToMonitor.attributeId = attributeID;
-    item.monitoringMode = UA_MONITORINGMODE_REPORTING;
-    item.requestedParameters.clientHandle = ++(client->monitoredItemHandles);
-    item.requestedParameters.samplingInterval = 0;
-    item.requestedParameters.discardOldest = false;
+    UA_CreateMonitoredItemsResponse response;
+    UA_CreateMonitoredItemsResponse_init(&response);
 
-    UA_EventFilter *evFilter = UA_EventFilter_new();
-    if(!evFilter) {
-        return UA_STATUSCODE_BADOUTOFMEMORY;
+    /* Create the handlers */
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    UA_Client_MonitoredItem **mis = (UA_Client_MonitoredItem**)
+        UA_alloca(sizeof(void*) * itemsSize);
+    memset(mis, 0, sizeof(void*) * itemsSize);
+    for(size_t i = 0; i < itemsSize; i++) {
+        mis[i] = (UA_Client_MonitoredItem*)UA_malloc(sizeof(UA_Client_MonitoredItem));
+        if(!mis[i]) {
+            retval = UA_STATUSCODE_BADOUTOFMEMORY;
+            goto cleanup;
+        }
     }
-    UA_EventFilter_init(evFilter);
-    evFilter->selectClausesSize = nSelectClauses;
-    evFilter->selectClauses = selectClause;
-    evFilter->whereClause.elementsSize = nWhereClauses;
-    evFilter->whereClause.elements = whereClause;
 
-    item.requestedParameters.filter.encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE;
-    item.requestedParameters.filter.content.decoded.type = &UA_TYPES[UA_TYPES_EVENTFILTER];
-    item.requestedParameters.filter.content.decoded.data = evFilter;
+    /* Set the clientHandle */
+    for(size_t i = 0; i < itemsSize; i++)
+        items[i].requestedParameters.clientHandle = ++(client->monitoredItemHandles);
 
-    request.itemsToCreate = &item;
-    request.itemsToCreateSize = 1;
-    UA_CreateMonitoredItemsResponse response = UA_Client_Service_createMonitoredItems(client, request);
+    /* Initialize the request */
+    request.subscriptionId = subscriptionId;
+    request.itemsToCreate = items;
+    request.itemsToCreateSize = itemsSize;
 
-    // slight misuse of retval here to check if the deletion was successful.
-    UA_StatusCode retval;
-    if(response.resultsSize == 0)
-        retval = response.responseHeader.serviceResult;
-    else
-        retval = response.results[0].statusCode;
-    if(retval != UA_STATUSCODE_GOOD) {
-        UA_CreateMonitoredItemsResponse_deleteMembers(&response);
-        UA_EventFilter_delete(evFilter);
-        return retval;
-    }
+    /* Send the request */
+    response = UA_Client_Service_createMonitoredItems(client, request);
 
-    /* Create the handler */
-    UA_Client_MonitoredItem *newMon = (UA_Client_MonitoredItem *)UA_malloc(sizeof(UA_Client_MonitoredItem));
-    if(!newMon) {
-        UA_CreateMonitoredItemsResponse_deleteMembers(&response);
-        UA_EventFilter_delete(evFilter);
-        return UA_STATUSCODE_BADOUTOFMEMORY;
+    /* Remove for _deleteMembers */
+    request.itemsToCreate = NULL;
+    request.itemsToCreateSize = 0;
+
+    retval = response.responseHeader.serviceResult;
+    if(retval != UA_STATUSCODE_GOOD)
+        goto cleanup;
+
+    if(response.resultsSize != itemsSize) {
+        retval = UA_STATUSCODE_BADINTERNALERROR;
+        goto cleanup;
     }
 
-    newMon->monitoringMode = UA_MONITORINGMODE_REPORTING;
-    UA_NodeId_copy(&nodeId, &newMon->monitoredNodeId);
-    newMon->attributeID = attributeID;
-    newMon->clientHandle = client->monitoredItemHandles;
-    newMon->samplingInterval = 0;
-    newMon->queueSize = 0;
-    newMon->discardOldest = false;
+    for(size_t i = 0; i < itemsSize; i++) {
+        UA_MonitoredItemCreateResult *result = &response.results[i];
+        UA_Client_MonitoredItem *newMon = mis[i];
 
-    newMon->handlerEvents = hf;
-    newMon->handlerEventsContext = hfContext;
-    newMon->monitoredItemId = response.results[0].monitoredItemId;
-    LIST_INSERT_HEAD(&sub->monitoredItems, newMon, listEntry);
-    *newMonitoredItemId = newMon->monitoredItemId;
+        itemResults[i] = result->statusCode;
+        if(result->statusCode != UA_STATUSCODE_GOOD) {
+            UA_free(newMon);
+            continue;
+        }
 
-    UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_CLIENT,
-                 "Created a monitored item with client handle %u", client->monitoredItemHandles);
+        /* Set the internal representation */
+        newMon->monitoringMode = UA_MONITORINGMODE_REPORTING;
+        UA_NodeId_copy(&items[i].itemToMonitor.nodeId, &newMon->monitoredNodeId);
+        newMon->attributeID = items[i].itemToMonitor.attributeId;
+        newMon->clientHandle = items[i].requestedParameters.clientHandle;
+        newMon->samplingInterval = result->revisedSamplingInterval;
+        newMon->queueSize = result->revisedQueueSize;
+        newMon->discardOldest = items[i].requestedParameters.discardOldest;
+        newMon->monitoredItemId = response.results[i].monitoredItemId;
+        newMon->isEventMonitoredItem = isEventMonitoredItem;
+        /* eventHandler is at the same position in the union */
+        newMon->handler.dataChangeHandler = (UA_MonitoredItemHandlingFunction)(uintptr_t)hfs[i];
+        newMon->handlerContext = hfContexts[i];
+
+        LIST_INSERT_HEAD(&sub->monitoredItems, newMon, listEntry);
+        newMonitoredItemIds[i] = newMon->monitoredItemId;
+        UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_CLIENT,
+                     "Created a monitored item with client handle %u",
+                     client->monitoredItemHandles);
+    }
 
-    UA_EventFilter_delete(evFilter);
+ cleanup:
+    if(retval != UA_STATUSCODE_GOOD) {
+        for(size_t i = 0; i < itemsSize; i++)
+            UA_free(mis[i]);
+    }
+    UA_CreateMonitoredItemsRequest_deleteMembers(&request);
     UA_CreateMonitoredItemsResponse_deleteMembers(&response);
-    return UA_STATUSCODE_GOOD;
+    return retval;
 }
 
+
 UA_StatusCode
+UA_Client_Subscriptions_addMonitoredItems(UA_Client *client, const UA_UInt32 subscriptionId,
+                                          UA_MonitoredItemCreateRequest *items, size_t itemsSize, 
+                                          UA_MonitoredItemHandlingFunction **hfs,
+                                          void **hfContexts, UA_StatusCode *itemResults,
+                                          UA_UInt32 *newMonitoredItemIds) {
+    return addMonitoredItems(client, subscriptionId, items, itemsSize, (void**)hfs,
+                             hfContexts, itemResults, newMonitoredItemIds, false);
+}
+
+UA_StatusCode UA_EXPORT
 UA_Client_Subscriptions_addMonitoredItem(UA_Client *client, UA_UInt32 subscriptionId,
                                          UA_NodeId nodeId, UA_UInt32 attributeID,
-                                         UA_MonitoredItemHandlingFunction hf,
-                                         void *hfContext, UA_UInt32 *newMonitoredItemId,
-                                         UA_Double samplingInterval) {
-    UA_Client_Subscription *sub = findSubscription(client, subscriptionId);
-    if(!sub)
-        return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
-
-    /* Create the handler */
-    UA_Client_MonitoredItem *newMon = (UA_Client_MonitoredItem*)UA_malloc(sizeof(UA_Client_MonitoredItem));
-    if(!newMon)
-        return UA_STATUSCODE_BADOUTOFMEMORY;
-
-    /* Send the request */
-    UA_CreateMonitoredItemsRequest request;
-    UA_CreateMonitoredItemsRequest_init(&request);
-    request.subscriptionId = subscriptionId;
+                                         UA_MonitoredItemHandlingFunction hf, void *hfContext,
+                                         UA_UInt32 *newMonitoredItemId, UA_Double samplingInterval) {
     UA_MonitoredItemCreateRequest item;
     UA_MonitoredItemCreateRequest_init(&item);
     item.itemToMonitor.nodeId = nodeId;
     item.itemToMonitor.attributeId = attributeID;
     item.monitoringMode = UA_MONITORINGMODE_REPORTING;
-    item.requestedParameters.clientHandle = ++(client->monitoredItemHandles);
     item.requestedParameters.samplingInterval = samplingInterval;
     item.requestedParameters.discardOldest = true;
     item.requestedParameters.queueSize = 1;
-    request.itemsToCreate = &item;
-    request.itemsToCreateSize = 1;
-    UA_CreateMonitoredItemsResponse response = UA_Client_Service_createMonitoredItems(client, request);
 
-    // slight misuse of retval here to check if the addition was successful.
-    UA_StatusCode retval = response.responseHeader.serviceResult;
-    if(retval == UA_STATUSCODE_GOOD) {
-        if(response.resultsSize == 1)
-            retval = response.results[0].statusCode;
-        else
-            retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
-    }
-    if(retval != UA_STATUSCODE_GOOD) {
-        UA_free(newMon);
-        UA_CreateMonitoredItemsResponse_deleteMembers(&response);
-        return retval;
-    }
+    UA_StatusCode retval_item = UA_STATUSCODE_GOOD;
+    UA_StatusCode retval = addMonitoredItems(client, subscriptionId, &item, 1,
+                                             (void**)(uintptr_t)&hf, &hfContext,
+                                             &retval_item, newMonitoredItemId, false);
+    return retval | retval_item;
+}
 
-    /* Set the handler */
-    newMon->monitoringMode = UA_MONITORINGMODE_REPORTING;
-    UA_NodeId_copy(&nodeId, &newMon->monitoredNodeId);
-    newMon->attributeID = attributeID;
-    newMon->clientHandle = client->monitoredItemHandles;
-    newMon->samplingInterval = samplingInterval;
-    newMon->queueSize = 1;
-    newMon->discardOldest = true;
-    newMon->handler = hf;
-    newMon->handlerContext = hfContext;
-    newMon->monitoredItemId = response.results[0].monitoredItemId;
-    LIST_INSERT_HEAD(&sub->monitoredItems, newMon, listEntry);
-    *newMonitoredItemId = newMon->monitoredItemId;
-
-    UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_CLIENT,
-                 "Created a monitored item with client handle %u",
-                 client->monitoredItemHandles);
 
-    UA_CreateMonitoredItemsResponse_deleteMembers(&response);
-    return UA_STATUSCODE_GOOD;
+UA_StatusCode
+UA_Client_Subscriptions_addMonitoredEvents(UA_Client *client, const UA_UInt32 subscriptionId,
+                                           UA_MonitoredItemCreateRequest *items, size_t itemsSize, 
+                                           UA_MonitoredEventHandlingFunction **hfs,
+                                           void **hfContexts, UA_StatusCode *itemResults,
+                                           UA_UInt32 *newMonitoredItemIds) {
+    return addMonitoredItems(client, subscriptionId, items, itemsSize, (void**)hfs,
+                             hfContexts, itemResults, newMonitoredItemIds, true);
+}
+
+UA_StatusCode
+UA_Client_Subscriptions_addMonitoredEvent(UA_Client *client, UA_UInt32 subscriptionId,
+                                          const UA_NodeId nodeId, UA_UInt32 attributeID,
+                                          const UA_SimpleAttributeOperand *selectClauses,
+                                          size_t selectClausesSize,
+                                          const UA_ContentFilterElement *whereClauses,
+                                          size_t whereClausesSize,
+                                          const UA_MonitoredEventHandlingFunction hf,
+                                          void *hfContext, UA_UInt32 *newMonitoredItemId) {
+    UA_MonitoredItemCreateRequest item;
+    UA_MonitoredItemCreateRequest_init(&item);
+    item.itemToMonitor.nodeId = nodeId;
+    item.itemToMonitor.attributeId = attributeID;
+    item.monitoringMode = UA_MONITORINGMODE_REPORTING;
+    item.requestedParameters.samplingInterval = 0;
+    item.requestedParameters.discardOldest = false;
+
+    UA_EventFilter *evFilter = UA_EventFilter_new();
+    if(!evFilter)
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+    UA_EventFilter_init(evFilter);
+    evFilter->selectClausesSize = selectClausesSize;
+    evFilter->selectClauses = (UA_SimpleAttributeOperand*)(uintptr_t)selectClauses;
+    evFilter->whereClause.elementsSize = whereClausesSize;
+    evFilter->whereClause.elements = (UA_ContentFilterElement*)(uintptr_t)whereClauses;
+
+    item.requestedParameters.filter.encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE;
+    item.requestedParameters.filter.content.decoded.type = &UA_TYPES[UA_TYPES_EVENTFILTER];
+    item.requestedParameters.filter.content.decoded.data = evFilter;
+    UA_StatusCode retval_item = UA_STATUSCODE_GOOD;
+    UA_StatusCode retval = addMonitoredItems(client, subscriptionId, &item, 1,
+                                             (void**)(uintptr_t)&hf, &hfContext,
+                                             &retval_item, newMonitoredItemId, true);
+    UA_free(evFilter);
+    return retval | retval_item;
 }
 
 UA_StatusCode
@@ -344,44 +362,71 @@ UA_Client_processPublishResponse(UA_Client *client, UA_PublishRequest *request,
         if(msg->notificationData[k].encoding != UA_EXTENSIONOBJECT_DECODED)
             continue;
 
+        /* Handle DataChangeNotification */
         if(msg->notificationData[k].content.decoded.type == &UA_TYPES[UA_TYPES_DATACHANGENOTIFICATION]) {
-            UA_DataChangeNotification *dataChangeNotification = (UA_DataChangeNotification *)msg->notificationData[k].content.decoded.data;
+            UA_DataChangeNotification *dataChangeNotification =
+                (UA_DataChangeNotification *)msg->notificationData[k].content.decoded.data;
             for(size_t j = 0; j < dataChangeNotification->monitoredItemsSize; ++j) {
                 UA_MonitoredItemNotification *mitemNot = &dataChangeNotification->monitoredItems[j];
+
+                /* Find the MonitoredItem */
                 UA_Client_MonitoredItem *mon;
                 LIST_FOREACH(mon, &sub->monitoredItems, listEntry) {
-                    if(mon->clientHandle == mitemNot->clientHandle) {
-                        mon->handler(mon->monitoredItemId, &mitemNot->value, mon->handlerContext);
+                    if(mon->clientHandle == mitemNot->clientHandle)
                         break;
-                    }
                 }
-                if(!mon)
+
+                if(!mon) {
                     UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_CLIENT,
                                  "Could not process a notification with clienthandle %u on subscription %u",
                                  mitemNot->clientHandle, sub->subscriptionID);
+                    continue;
+                }
+
+                if(mon->isEventMonitoredItem) {
+                    UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_CLIENT,
+                                 "MonitoredItem is configured for Events. But received a "
+                                 "DataChangeNotification.");
+                    continue;
+                }
+
+                mon->handler.dataChangeHandler(mon->monitoredItemId, &mitemNot->value, mon->handlerContext);
             }
+            continue;
         }
-        else if(msg->notificationData[k].content.decoded.type == &UA_TYPES[UA_TYPES_EVENTNOTIFICATIONLIST]) {
-            UA_EventNotificationList *eventNotificationList = (UA_EventNotificationList *)msg->notificationData[k].content.decoded.data;
+
+        /* Handle EventNotification */
+        if(msg->notificationData[k].content.decoded.type == &UA_TYPES[UA_TYPES_EVENTNOTIFICATIONLIST]) {
+            UA_EventNotificationList *eventNotificationList =
+                (UA_EventNotificationList *)msg->notificationData[k].content.decoded.data;
             for (size_t j = 0; j < eventNotificationList->eventsSize; ++j) {
                 UA_EventFieldList *eventFieldList = &eventNotificationList->events[j];
+
+                /* Find the MonitoredItem */
                 UA_Client_MonitoredItem *mon;
                 LIST_FOREACH(mon, &sub->monitoredItems, listEntry) {
-                    if(mon->clientHandle == eventFieldList->clientHandle) {
-                        mon->handlerEvents(mon->monitoredItemId, eventFieldList->eventFieldsSize,
-                                           eventFieldList->eventFields, mon->handlerContext);
+                    if(mon->clientHandle == eventFieldList->clientHandle)
                         break;
-                    }
                 }
-                if(!mon)
+
+                if(!mon) {
                     UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_CLIENT,
                                  "Could not process a notification with clienthandle %u on subscription %u",
                                  eventFieldList->clientHandle, sub->subscriptionID);
+                    continue;
+                }
+
+                if(!mon->isEventMonitoredItem) {
+                    UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_CLIENT,
+                                 "MonitoredItem is configured for DataChanges. But received a "
+                                 "EventNotification.");
+                    continue;
+                }
+
+                mon->handler.eventHandler(mon->monitoredItemId, eventFieldList->eventFieldsSize,
+                                          eventFieldList->eventFields, mon->handlerContext);
             }
         }
-        else {
-            continue; // no other types are supported
-        }
     }
 
     /* Add to the list of pending acks */

+ 7 - 3
src/client/ua_client_internal.h

@@ -6,6 +6,7 @@
 #define UA_CLIENT_INTERNAL_H_
 
 #include "ua_securechannel.h"
+#include "ua_client_highlevel.h"
 #include "queue.h"
 
  /**************************/
@@ -29,10 +30,13 @@ typedef struct UA_Client_MonitoredItem {
     UA_Double samplingInterval;
     UA_UInt32 queueSize;
     UA_Boolean discardOldest;
-    void(*handler)(UA_UInt32 monId, UA_DataValue *value, void *context);
+
+    UA_Boolean isEventMonitoredItem; /* Otherwise a DataChange MoniitoredItem */
+    union {
+        UA_MonitoredItemHandlingFunction dataChangeHandler;
+        UA_MonitoredEventHandlingFunction eventHandler;
+    } handler;
     void *handlerContext;
-    void(*handlerEvents)(const UA_UInt32 monId, const size_t nEventFields, const UA_Variant *eventFields, void *context);
-    void *handlerEventsContext;
 } UA_Client_MonitoredItem;
 
 typedef struct UA_Client_Subscription {

+ 25 - 14
tests/check_types_memory.c

@@ -14,7 +14,8 @@
 #include "ua_util.h"
 #include "check.h"
 
-// Define types to a dummy value if they are not available (e.g. not built with NS0 full)
+/* Define types to a dummy value if they are not available (e.g. not built with
+ * NS0 full) */
 #ifndef UA_TYPES_UNION
 #define UA_TYPES_UNION UA_TYPES_COUNT
 #endif
@@ -24,6 +25,9 @@
 #ifndef UA_TYPES_NOTIFICATIONDATA
 #define UA_TYPES_NOTIFICATIONDATA UA_TYPES_COUNT
 #endif
+#ifndef UA_TYPES_MONITORINGFILTER
+#define UA_TYPES_MONITORINGFILTER UA_TYPES_COUNT
+#endif
 #ifndef UA_TYPES_MONITORINGFILTERRESULT
 #define UA_TYPES_MONITORINGFILTERRESULT UA_TYPES_COUNT
 #endif
@@ -107,7 +111,8 @@ START_TEST(encodeShallYieldDecode) {
     // then
     msg1.length = offset;
     msg2.length = offset;
-    ck_assert_msg(UA_ByteString_equal(&msg1, &msg2) == true, "messages differ idx=%d,nodeid=%i", _i,
+    ck_assert_msg(UA_ByteString_equal(&msg1, &msg2) == true,
+                  "messages differ idx=%d,nodeid=%i", _i,
                   UA_TYPES[_i].typeId.identifier.numeric);
 
     // finally
@@ -121,12 +126,12 @@ END_TEST
 START_TEST(decodeShallFailWithTruncatedBufferButSurvive) {
     //Skip test for void*
     if (_i == UA_TYPES_DISCOVERYCONFIGURATION ||
-            _i == UA_TYPES_FILTEROPERAND ||
-            _i == UA_TYPES_MONITORINGFILTER ||
-            _i == UA_TYPES_UNION ||
-            _i == UA_TYPES_HISTORYREADDETAILS ||
-            _i == UA_TYPES_NOTIFICATIONDATA ||
-            _i == UA_TYPES_MONITORINGFILTERRESULT)
+        _i == UA_TYPES_FILTEROPERAND ||
+        _i == UA_TYPES_UNION ||
+        _i == UA_TYPES_HISTORYREADDETAILS ||
+        _i == UA_TYPES_NOTIFICATIONDATA ||
+        _i == UA_TYPES_MONITORINGFILTER ||
+        _i == UA_TYPES_MONITORINGFILTERRESULT)
         return;
     // given
     UA_ByteString msg1;
@@ -182,7 +187,9 @@ START_TEST(decodeScalarBasicTypeFromRandomBufferShallSucceed) {
         obj1 = UA_new(&UA_TYPES[_i]);
         retval |= UA_decodeBinary(&msg1, &pos, obj1, &UA_TYPES[_i], 0, NULL);
         //then
-        ck_assert_msg(retval == UA_STATUSCODE_GOOD, "Decoding %d from random buffer", UA_TYPES[_i].typeId.identifier.numeric);
+        ck_assert_msg(retval == UA_STATUSCODE_GOOD,
+                      "Decoding %d from random buffer",
+                      UA_TYPES[_i].typeId.identifier.numeric);
         // finally
         UA_delete(obj1, &UA_TYPES[_i]);
     }
@@ -224,16 +231,17 @@ START_TEST(decodeComplexTypeFromRandomBufferShallSurvive) {
 END_TEST
 
 START_TEST(calcSizeBinaryShallBeCorrect) {
-    /* Empty variants (with no type defined) cannot be encoded. This is intentional. Discovery configuration is just a base class and void * */
+    /* Empty variants (with no type defined) cannot be encoded. This is
+     * intentional. Discovery configuration is just a base class and void * */
     if(_i == UA_TYPES_VARIANT ||
        _i == UA_TYPES_VARIABLEATTRIBUTES ||
        _i == UA_TYPES_VARIABLETYPEATTRIBUTES ||
        _i == UA_TYPES_FILTEROPERAND ||
-       _i == UA_TYPES_MONITORINGFILTER ||
        _i == UA_TYPES_DISCOVERYCONFIGURATION ||
        _i == UA_TYPES_UNION ||
        _i == UA_TYPES_HISTORYREADDETAILS ||
        _i == UA_TYPES_NOTIFICATIONDATA ||
+       _i == UA_TYPES_MONITORINGFILTER ||
        _i == UA_TYPES_MONITORINGFILTERRESULT)
         return;
     void *obj = UA_new(&UA_TYPES[_i]);
@@ -265,12 +273,15 @@ int main(void) {
     tcase_add_loop_test(tc, encodeShallYieldDecode, UA_TYPES_BOOLEAN, UA_TYPES_COUNT - 1);
     suite_add_tcase(s, tc);
     tc = tcase_create("Truncated Buffers");
-    tcase_add_loop_test(tc, decodeShallFailWithTruncatedBufferButSurvive, UA_TYPES_BOOLEAN, UA_TYPES_COUNT - 1);
+    tcase_add_loop_test(tc, decodeShallFailWithTruncatedBufferButSurvive,
+                        UA_TYPES_BOOLEAN, UA_TYPES_COUNT - 1);
     suite_add_tcase(s, tc);
 
     tc = tcase_create("Fuzzing with Random Buffers");
-    tcase_add_loop_test(tc, decodeScalarBasicTypeFromRandomBufferShallSucceed, UA_TYPES_BOOLEAN, UA_TYPES_DOUBLE);
-    tcase_add_loop_test(tc, decodeComplexTypeFromRandomBufferShallSurvive, UA_TYPES_NODEID, UA_TYPES_COUNT - 1);
+    tcase_add_loop_test(tc, decodeScalarBasicTypeFromRandomBufferShallSucceed,
+                        UA_TYPES_BOOLEAN, UA_TYPES_DOUBLE);
+    tcase_add_loop_test(tc, decodeComplexTypeFromRandomBufferShallSurvive,
+                        UA_TYPES_NODEID, UA_TYPES_COUNT - 1);
     suite_add_tcase(s, tc);
 
     tc = tcase_create("Test calcSizeBinary");

+ 3 - 2
tools/schema/datatypes_minimal.txt

@@ -171,7 +171,6 @@ FindServersOnNetworkResponse
 DataChangeTrigger
 DeadbandType
 DataChangeFilter
-MonitoringFilter
 EventFilter
 FilterOperand
 SimpleAttributeOperand
@@ -193,4 +192,6 @@ NumericRange
 EndpointUrlListDataType
 ModelChangeStructureDataType
 SemanticChangeStructureDataType
-TimeZoneDataType
+TimeZoneDataType
+AggregateConfiguration
+AggregateFilter