High Performance OPC UA Server SDK  1.2.0.193
custom_provider_event.c
/*****************************************************************************
* *
* Copyright (c) 2006-2016 Unified Automation GmbH. All rights reserved. *
* *
* Software License Agreement ("SLA") Version 2.6 *
* *
* Unless explicitly acquired and licensed from Licensor under another *
* license, the contents of this file are subject to the Software License *
* Agreement ("SLA") Version 2.6, or subsequent versions as allowed by the *
* SLA, and You may not copy or use this file in either source code or *
* executable form, except in compliance with the terms and conditions of *
* the SLA. *
* *
* All software distributed under the SLA is provided strictly on an "AS *
* IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, *
* AND LICENSOR HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT *
* LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR *
* PURPOSE, QUIET ENJOYMENT, OR NON-INFRINGEMENT. See the SLA for specific *
* language governing rights and limitations under the SLA. *
* *
* The complete license agreement can be found here: *
* http://unifiedautomation.com/License/SLA/2.6/ *
* *
*****************************************************************************/
#include <trace/trace.h>
#include <memory/memory.h>
#include <uabase/statuscodes.h>
#include <uabase/nodeid.h>
#include <uabase/variant.h>
#include <uabase/accesslevel.h>
#include <uabase/valuerank.h>
#include <uabase/structure/nodeclass.h>
#include <uabase/structure/range.h>
#include <uabase/identifiers.h>
#include <uabase/qualifiedname.h>
#include <uabase/eventnotifier.h>
#include <uaserver/server_config.h>
#include <uaserver/addressspace/node.h>
#ifdef UASERVER_SUPPORT_EVENTS
#include <uaserver/addressspace/addressspace.h>
#include <uaserver/addressspace/object.h>
#include <uaserver/addressspace/variable.h>
#include <uaserver/addressspace/objecttype.h>
#include <uaserver/event/eventfield.h>
#include <uaserver/event/eventnotifier.h>
#include <uaserver/event/event.h>
#include "custom_provider.h"
#include "custom_provider_identifiers.h"
#include "custom_provider_event.h"
/* global variables to store regularly used handles */
static ua_node_t g_newvalue_eventtype = UA_NODE_INVALID;
static ua_node_t g_outofrange_eventtype = UA_NODE_INVALID;
static int g_newvalue_eventfield_handle = -1;
/* create the event type nodes in the addressspace */
static int custom_provider_create_eventtypes(void)
{
struct ua_nodeid nodeid, datatype_id;
ua_node_t base_eventtype;
ua_node_t newvalue_eventtype;
ua_node_t newvalue_eventfield;
ua_node_t outofrange_eventtype;
int ret;
/* create the newvalue event type node */
base_eventtype = ua_node_find0(UA_ID_BASEEVENTTYPE);
if (base_eventtype == UA_NODE_INVALID) return UA_EBAD;
ua_nodeid_set_numeric(&nodeid, g_custom_provider_nsidx, EVENT_TYPE_NEW_VALUE);
newvalue_eventtype = ua_node_create_with_attributes(
&nodeid, /* nodeid for the new node */
UA_NODECLASS_OBJECTTYPE, /* nodeclass of properties is variable */
g_custom_provider_nsidx, /* ns index for browsename is own namespace */
"NewValueEventType", /* browsename */
NULL, /* displayname, NULL is same as browsename */
UA_NODE_INVALID, /* the node has no typedefinition */
base_eventtype, /* parent of the new node is the base event type node */
UA_NODE_HASSUBTYPE); /* new node is referenced with hassubtype by parent */
if (newvalue_eventtype == UA_NODE_INVALID) return UA_EBAD;
ret = ua_objecttype_set_is_abstract(newvalue_eventtype, false);
if (ret != 0) return ret;
g_newvalue_eventtype = newvalue_eventtype;
/* create the newvalue event field node */
ua_nodeid_set_numeric(&nodeid, g_custom_provider_nsidx, EVENT_FIELD_NEW_VALUE);
newvalue_eventfield = ua_node_create_with_attributes(
&nodeid, /* nodeid for the new node */
UA_NODECLASS_VARIABLE, /* nodeclass of properties is variable */
g_custom_provider_nsidx, /* ns index for browsename is own namespace */
"NewValue", /* browsename */
NULL, /* displayname, NULL is same as browsename */
UA_NODE_PROPERTYTYPE, /* the node has the typedefinition property type */
newvalue_eventtype, /* parent of the new node is the newvalue event type node */
UA_NODE_HASPROPERTY); /* new node is referenced with hasproperty by parent */
if (newvalue_eventfield == UA_NODE_INVALID) return UA_EBAD;
ua_nodeid_set_numeric(&datatype_id, 0, UA_ID_UINT32);
ret = ua_variable_set_attributes(newvalue_eventfield, &datatype_id, UA_VALUERANK_ONEDIMENSION, UA_ACCESSLEVEL_CURRENTREAD, false);
if (ret != 0) return ret;
/* create the outofrange event type node */
ua_nodeid_set_numeric(&nodeid, g_custom_provider_nsidx, EVENT_TYPE_OUT_OF_RANGE);
outofrange_eventtype = ua_node_create_with_attributes(
&nodeid, /* nodeid for the new node */
UA_NODECLASS_OBJECTTYPE, /* nodeclass of properties is variable */
g_custom_provider_nsidx, /* ns index for browsename is own namespace */
"OutOfRangeEventType", /* browsename */
NULL, /* displayname, NULL is same as browsename */
UA_NODE_INVALID, /* the node has no typedefinition */
newvalue_eventtype, /* parent of the new node is the newvalue event type node */
UA_NODE_HASSUBTYPE); /* new node is referenced with hassubtype by parent */
if (outofrange_eventtype == UA_NODE_INVALID) return UA_EBAD;
g_outofrange_eventtype = outofrange_eventtype;
ret = ua_objecttype_set_is_abstract(outofrange_eventtype, false);
if (ret != 0) return ret;
return 0;
}
/* create the event notifier node and its references in the addressspace */
static int custom_provider_create_eventnotifier(void)
{
struct ua_nodeid nodeid;
ua_node_t notfifier;
ua_node_t custom_nodes;
ua_node_t target;
ua_ref_t new_ref;
ua_ref_t ref;
int ret;
/* lookup some node handles */
custom_nodes = ua_node_find_numeric(g_custom_provider_nsidx, CUSTOM_NODES_ID);
if (custom_nodes == UA_NODE_INVALID) return UA_EBAD;
/* create the event notifier node */
ua_nodeid_set_numeric(&nodeid, g_custom_provider_nsidx, EVENT_NOTIFIER_ID);
&nodeid, /* nodeid for the new node */
UA_NODECLASS_OBJECT, /* nodeclass of the new node */
g_custom_provider_nsidx, /* ns index for browsename is own namespace */
"MyEventNotfifier", /* browsename */
NULL, /* displayname, NULL for same as browsename */
UA_NODE_BASEOBJECTTYPE, /* typedefinition is basedatavariabletype */
custom_nodes, /* parent node of the new node */
UA_NODE_ORGANIZES); /* new node is referenced with organizes by parent */
if (notfifier == UA_NODE_INVALID) return UA_EBAD;
ret = ua_object_set_event_notifier(notfifier, UA_EVENTNOTIFIER_SUBSCRIBETOEVENTS);
if (ret != 0) return ret;
/* create HasNotifier reference from the Server object to the new notifier */
new_ref = ua_reference_add(UA_NODE_SERVEROBJECT, notfifier, UA_NODE_HASNOTIFIER);
if (new_ref == UA_REF_INVALID) return UA_EBAD;
/* ceate HasEventSource references to variable nodes */
ua_node_foreach(ref, custom_nodes) {
target = ua_reference_target(ref);
if (ua_node_get_nodeclass(target) != UA_NODECLASS_VARIABLE) {
continue;
}
new_ref = ua_reference_add(notfifier, target, UA_NODE_HASEVENTSOURCE);
if (new_ref == UA_REF_INVALID) return UA_EBAD;
}
return 0;
}
/* fire an event */
int custom_provider_event_fire(ua_node_t node, uint32_t value, bool outofrange)
{
struct ua_qualifiedname browse_path[1];
struct uaserver_event *e = NULL;
struct ua_variant v;
int field_handle;
int ret;
/* create event */
if (outofrange) {
e = uaserver_event_create(g_outofrange_eventtype, node);
if (e == NULL) {
ret = UA_EBAD;
goto error;
}
/* change severity */
if (ret != 0) goto error;
} else {
e = uaserver_event_create(g_newvalue_eventtype, node);
if (e == NULL) {
ret = UA_EBAD;
goto error;
}
}
/* fill variant for custom field */
/* alternative 1 */
ret = uaserver_event_add_field(e, g_newvalue_eventfield_handle, &v);
if (ret != 0) goto error;
/* alternative 2 */
ret = uaserver_event_overwrite_field_qn(e, "NewValue", g_custom_provider_nsidx, &v);
if (ret != 0) goto error;
/* alternative 3 */
IPC_CLEAR(browse_path);
ret = ua_qualifiedname_set(&browse_path[0], g_custom_provider_nsidx, "NewValue");
if (ret != 0) goto error;
field_handle = uaserver_eventfield_lookup(browse_path, 1);
ret = uaserver_event_overwrite_field(e, field_handle, &v);
ua_qualifiedname_clear(&browse_path[0]);
if (ret != 0) goto error;
/* clear variant with custom field */
/* fire event */
if (ret != 0) goto error;
/* delete event */
return 0;
error:
return ret;
}
/* initialize eventing for the provider */
int custom_provider_event_init(void)
{
int ret;
/* create nodes */
ret = custom_provider_create_eventtypes();
if (ret != 0) return ret;
ret = custom_provider_create_eventnotifier();
if (ret != 0) return ret;
/* register nodes */
ret = uaserver_eventfield_register_all(g_custom_provider_nsidx);
if (ret != 0) return ret;
ret = uaserver_eventnotifier_register_all(g_custom_provider_nsidx);
if (ret != 0) return ret;
/* lookup handle for later use */
g_newvalue_eventfield_handle = uaserver_eventfield_lookup_qn("NewValue", g_custom_provider_nsidx);
if (g_newvalue_eventfield_handle < 0) {
return g_newvalue_eventfield_handle;
}
return ret;
}
/* clear eventing for the provider */
void custom_provider_event_clear(void)
{
int ret;
/* invalidate handles */
g_outofrange_eventtype = UA_NODE_INVALID;
g_newvalue_eventtype = UA_NODE_INVALID;
g_newvalue_eventfield_handle = -1;
/* unregister nodes */
ret = uaserver_eventfield_unregister_all(g_custom_provider_nsidx);
if (ret != 0) {
TRACE_ERROR(TRACE_FAC_APPLICATION, "%s: uaserver_eventfield_unregister_all() failed with errorcode=%i\n", __func__, ret);
}
ret = uaserver_eventnotifier_unregister_all(g_custom_provider_nsidx);
if (ret != 0) {
TRACE_ERROR(TRACE_FAC_APPLICATION, "%s: uaserver_eventnotifier_unregister_all() failed with errorcode=%i\n", __func__, ret);
}
return;
}
#endif /* UASERVER_SUPPORT_EVENTS */