High Performance OPC UA Server SDK  1.2.0.193
custom_provider_subscription.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 <uabase/uatype_config.h>
#ifdef ENABLE_SERVICE_SUBSCRIPTION
#include <uaserver/monitoreditem/monitoreditem.h>
#include <uaserver/attribute/read_internal.h>
#include <uaserver/addressspace/variable.h>
#include <uabase/statuscodes.h>
#include <uabase/variant.h>
#include <uabase/datavalue.h>
#include <uabase/attributeid.h>
#include <uabase/structure/nodeclass.h>
#include <uaserver/provider/provider.h>
#include <memory/memory.h>
#include <timer/timer.h>
#include <trace/trace.h>
#include "custom_provider.h"
#include "custom_provider_read.h"
#include "custom_provider_subscription.h"
/* callback for timer if sampling interval of monitored item is due */
static int custom_provider_timer_callback(uint64_t elapsed, void *data)
{
struct ua_monitoreditem *item = data;
struct uasession_session *session;
struct ua_datavalue *dv;
uint8_t storeidx = 0;
int ret;
UA_UNUSED(elapsed);
/* allocate the value */
dv = IPC_ALLOC(dv);
if (dv == NULL)
return 0;
/* read the value */
if (node == UA_NODE_INVALID) {
} else {
if (session != NULL) {
} else {
ua_variable_get_store_index(node, &storeidx);
if (storeidx != 0 || ua_monitoreditem_get_attributeid(item) != UA_ATTRIBUTEID_VALUE) {
node,
session,
dv);
} else {
custom_provider_read_value(
node,
session,
dv);
}
}
}
/* add the value to the monitored item */
ret = ua_monitoreditem_new_value(item, dv);
if (ret != 0) {
TRACE_ERROR(TRACE_FAC_APPLICATION, "%s: ua_monitoreditem_new_value() failed with errorcode=%i\n", __func__, ret);
IPC_FREE(dv);
}
return 0;
}
ua_statuscode custom_provider_add_item(struct ua_monitoreditem *item, uint32_t max_items)
{
int ret;
uint32_t timer_id;
uint8_t storeidx = 0;
struct uasession_session *session;
struct ua_datavalue *dv;
ua_node_t node;
UA_UNUSED(max_items);
/* lookup node handle */
/* get session from monitored item */
if (session == NULL) return UA_SCBADSESSIONCLOSED;
/* allocate the initial value */
dv = IPC_ALLOC(dv);
if (dv == NULL)
/* read the initial value */
ua_variable_get_store_index(node, &storeidx);
if (storeidx != 0 || ua_monitoreditem_get_attributeid(item) != UA_ATTRIBUTEID_VALUE) {
node,
session,
dv);
} else {
custom_provider_read_value(
node,
session,
dv);
}
/* Check the result of the initial read. If bad the item is not created with few execptions:
* INDEXRANGENODATA: a bigger array may be written to this value later
* NOTREADABLE, USERACCESSDENIED: permissions of node or user may change
*/
status = dv->status;
ipc_free(dv);
return status;
}
if (ua_monitoreditem_get_sampling_interval(item) < g_appconfig.subscription.min_sampling_interval) {
ua_monitoreditem_set_sampling_interval(item, g_appconfig.subscription.min_sampling_interval);
}
/* add a timer to check the attribute periodically */
ret = timer_add(NULL,
&timer_id,
custom_provider_timer_callback,
item,
if (ret != 0) {
if (ret == UA_EBADOUTOFRESOURCE) {
TRACE_ERROR(TRACE_FAC_APPLICATION, "%s: Not enough timers to create monitoreditem\n", __func__);
}
ipc_free(dv);
}
ua_monitoreditem_set_user_data(item, 0, timer_id);
/* add the initial value */
ret = ua_monitoreditem_new_value(item, dv);
if (ret != 0) {
TRACE_ERROR(TRACE_FAC_APPLICATION, "%s: ua_monitoreditem_new_value() failed with errorcode=%i\n", __func__, ret);
IPC_FREE(dv);
}
/* set operation result, this can be done in subscribe, but we already know it will succeed */
return 0;
}
ua_statuscode custom_provider_remove_item(struct ua_monitoreditem *item, uint32_t max_items)
{
int ret;
ret = timer_remove(NULL, ua_monitoreditem_get_user_data(item, 0), NULL);
if (ret != 0) return UA_SCBADINTERNALERROR;
UA_UNUSED(max_items);
/* set operation result, this can be done in subscribe, but we already know it will succeed */
return 0;
}
ua_statuscode custom_provider_modify_item(struct ua_monitoreditem *item, uint32_t new_sampling_interval, uint32_t max_items)
{
uint32_t timer_id;
int ret;
UA_UNUSED(max_items);
if (new_sampling_interval < g_appconfig.subscription.min_sampling_interval) {
new_sampling_interval = g_appconfig.subscription.min_sampling_interval;
}
/* add new timer */
ret = timer_add(NULL,
&timer_id,
new_sampling_interval,
custom_provider_timer_callback,
item,
if (ret == UA_EBADOUTOFRESOURCE) {
TRACE_ERROR(TRACE_FAC_APPLICATION, "%s: Not enough timers to modify monitoreditem\n", __func__);
} else if (ret != 0) {
}
/* update sampling interval in the item */
ua_monitoreditem_set_sampling_interval(item, new_sampling_interval);
/* remove old timer */
/* store id of new timer in item */
ua_monitoreditem_set_user_data(item, 0, timer_id);
/* set operation result, this can be done in subscribe, but we already know it will succeed */
return 0;
}
void custom_provider_subscribe(struct uaprovider_subscribe_ctx *ctx) {
/* the item is added/removed in the sync functions completely, so nothing to do here */
}
#endif /* ENABLE_SERVICE_SUBSCRIPTION */