UA ANSI C Server Professional  1.4.0.285
 All Data Structures Functions Variables Typedefs Enumerations Enumerator Groups Pages
custom_provider_subscription.c
/******************************************************************************
**
** Copyright (C) 2011-2014 Unified Automation GmbH. All Rights Reserved.
** Web: http://www.unifiedautomation.com
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
** Project: OPC Ansi C OPC Server Examples
**
******************************************************************************/
#include <uaserver_config.h>
#include <opcua_statuscodes.h>
#include <uaserver_monitoring.h>
#include <uaserver_monitoreditemmanager.h>
#include <uaserver_basenode.h>
#include <uaserver_utilities.h>
#include <uaserver_p_atomic.h>
#include "custom_provider_helper.h"
OPCUA_BEGIN_EXTERN_C
#define NUM_SAMPLINGRATES 7
static OpcUa_Int g_aiSamplingRates[NUM_SAMPLINGRATES] = {50, 100, 250, 500, 1000, 2500, 5000};
static OpcUa_Timer g_hSamplingTimers[NUM_SAMPLINGRATES];
static UaServer_Vector g_vecSamplingLists[NUM_SAMPLINGRATES];
/* Forward declarations */
IFMETHODIMP(CustomProvider_TimerCallback)(OpcUa_Void *a_pvCallbackData,
OpcUa_Timer a_hTimer,
OpcUa_UInt32 a_msecElapsed);
OpcUa_StatusCode CustomProvider_Subscription_Initialize()
{
OpcUa_StatusCode ret = OpcUa_Good;
OpcUa_UInt32 i;
/* init vectors and start sampling timers */
for (i = 0; i < NUM_SAMPLINGRATES; i++)
{
UaServer_Vector_Initialize(&g_vecSamplingLists[i], 10, 10);
ret = OpcUa_Timer_Create(&g_hSamplingTimers[i],
g_aiSamplingRates[i],
CustomProvider_TimerCallback,
OpcUa_Null,
&g_vecSamplingLists[i]);
if (OpcUa_IsNotGood(ret))
{
break;
}
}
return ret;
}
OpcUa_StatusCode CustomProvider_Subscription_Cleanup()
{
OpcUa_UInt32 i;
for (i = 0; i < NUM_SAMPLINGRATES; i++)
{
OpcUa_Timer_Delete(&g_hSamplingTimers[i]);
UaServer_Vector_Clear(&g_vecSamplingLists[i]);
}
return OpcUa_Good;
}
IFMETHODIMP(CustomProvider_AddItem)(UaServer_MonitoredItem *a_pItem)
{
OpcUa_UInt32 i = 0;
OpcUa_UInt32 iDist = 0;
OpcUa_UInt32 iTmp = 0;
OpcUa_UInt32 iRevised = 0;
OpcUa_BaseNode *pNode = OpcUa_Null;
UaServer_AddressSpace *pAddressSpace = &(g_pCustomProvider->AddressSpace);
OpcUa_InitializeStatus(OpcUa_Module_Server, "CustomProvider_AddItem");
OpcUa_ReturnErrorIfArgumentNull(a_pItem);
iDist = UaServer_P_Abs(a_pItem->iSamplingInterval - g_aiSamplingRates[0]);
/* Find closest sampling rate */
for (i = 1; i < NUM_SAMPLINGRATES; i++)
{
iTmp = UaServer_P_Abs(a_pItem->iSamplingInterval - g_aiSamplingRates[i]);
if (iTmp < iDist)
{
iDist = iTmp;
iRevised = i;
}
}
/* Revise values */
a_pItem->uProviderHandle = iRevised;
a_pItem->iSamplingInterval = g_aiSamplingRates[iRevised];
/* Get the requested node */
UaServer_GetNode(pAddressSpace, &a_pItem->NodeId, &pNode);
if (pNode)
{
if (a_pItem->ItemType == DATA)
{
UaServer_MonitoredItemData* pMonitoredItemData = (UaServer_MonitoredItemData*)a_pItem;
if (OpcUa_BaseNode_GetClass(pNode) == OpcUa_NodeClass_Variable &&
pMonitoredItemData->AttributeId == OpcUa_Attributes_Value)
{
OpcUa_DataVariable* pVariable = (OpcUa_DataVariable*)pNode;
/* Check index range */
if (OpcUa_IsGood(uStatus) && pMonitoredItemData->NoOfIndexRanges > 0)
{
pMonitoredItemData->IndexRanges,
pMonitoredItemData->NoOfIndexRanges);
}
/* Check data change filter */
if (OpcUa_IsGood(uStatus) &&
pMonitoredItemData->DataChangeFilter.DeadbandType != OpcUa_DeadbandType_None)
{
if (pMonitoredItemData->DataChangeFilter.DeadbandType == OpcUa_DeadbandType_Percent)
{
uStatus = OpcUa_BadMonitoredItemFilterUnsupported;
}
else
{
switch (OpcUa_Variable_GetValue(pVariable)->Datatype)
{
case OpcUaType_SByte:
case OpcUaType_Byte:
case OpcUaType_Int16:
case OpcUaType_UInt16:
case OpcUaType_Int32:
case OpcUaType_UInt32:
case OpcUaType_Int64:
case OpcUaType_UInt64:
case OpcUaType_Float:
case OpcUaType_Double:
break;
default:
uStatus = OpcUa_BadFilterNotAllowed;
break;
}
}
}
if (OpcUa_IsGood(uStatus))
{
/* Add to list */
UaServer_Vector_Add(&g_vecSamplingLists[iRevised], pMonitoredItemData);
}
}
else
{
OpcUa_Variant currentValue;
OpcUa_Variant_Initialize(&currentValue);
/* Check data change filter */
if (OpcUa_IsGood(uStatus) &&
pMonitoredItemData->DataChangeFilter.DeadbandType != OpcUa_DeadbandType_None)
{
uStatus = OpcUa_BadFilterNotAllowed;
}
/* Index range not available for non-value attribute */
if (OpcUa_IsGood(uStatus) && pMonitoredItemData->NoOfIndexRanges > 0)
{
uStatus = OpcUa_BadIndexRangeNoData;
}
/* Get value of the attribute */
if (OpcUa_IsGood(uStatus))
{
uStatus = UaServer_GetNonValueAttribute(pMonitoredItemData->AttributeId,
pNode,
&currentValue,
}
if (OpcUa_IsGood(uStatus))
{
/* Add to list */
UaServer_Vector_Add(&g_vecSamplingLists[iRevised], pMonitoredItemData);
}
OpcUa_Variant_Clear(&currentValue);
}
}
}
else
{
uStatus = OpcUa_BadNodeIdUnknown;
}
OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;
OpcUa_FinishErrorHandling;
}
IFMETHODIMP(CustomProvider_RemoveItem)(UaServer_MonitoredItem *a_pItem)
{
UaServer_Vector *pVec = &g_vecSamplingLists[a_pItem->uProviderHandle];
OpcUa_UInt32 size;
OpcUa_UInt32 i;
OpcUa_Boolean bFound = OpcUa_False;
OpcUa_InitializeStatus(OpcUa_Module_Server, "CustomProvider_RemoveItem");
OpcUa_ReturnErrorIfArgumentNull(a_pItem);
/* Only data monitored items are added to the lists, nothing to do for event monitored items */
if (a_pItem->ItemType == DATA)
{
/* Search for the item to remove */
for (i = 0; i < size; i++)
{
if (UaServer_Vector_Get(pVec, i) == a_pItem)
{
bFound = OpcUa_True;
break;
}
}
/* If found, remove the item from the list */
if (bFound != OpcUa_False)
{
for (; i < size - 1; i++)
{
UaServer_Vector_Set(pVec, i, UaServer_Vector_Get(pVec, i + 1));
}
UaServer_Vector_Resize(pVec, size - 1);
}
else
{
uStatus = OpcUa_BadNotFound;
}
}
OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;
OpcUa_FinishErrorHandling;
}
IFMETHODIMP(CustomProvider_Subscribe)(UaServer_ProviderSubscribeContext *a_pCtx)
{
OpcUa_InitializeStatus(OpcUa_Module_Server, "CustomProvider_Subscribe");
/* Send the callback */
UaServer_Atomic_Increment(&a_pCtx->nOutstandingCbs);
OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;
OpcUa_FinishErrorHandling;
}
OpcUa_Void CustomProvider_SampleData(OpcUa_Void* a_pvCallbackData)
{
unsigned int i = 0;
UaServer_Vector *pVecList = OpcUa_Null;
UaServer_MonitoredItemData *pMonitoredItemData = OpcUa_Null;
OpcUa_Variable *pVariable = OpcUa_Null;
unsigned int size;
pVecList = (UaServer_Vector*)a_pvCallbackData;
size = UaServer_Vector_GetSize(pVecList);
for (i = 0; i < size; i++)
{
pMonitoredItemData = (UaServer_MonitoredItemData*)UaServer_Vector_Get(pVecList, i);
/* The status of the items is always good, so status change will never trigger a data change */
if (pMonitoredItemData->MonitoringMode == OpcUa_MonitoringMode_Disabled)
{
continue;
}
/* Get node */
UaServer_GetNode(&g_pCustomProvider->AddressSpace,
&pMonitoredItemData->NodeId,
(OpcUa_BaseNode**)&pVariable);
if (pVariable)
{
/* Create new data value */
OpcUa_DataValue *pValue = (OpcUa_DataValue*)OpcUa_Alloc(sizeof(OpcUa_DataValue));
OpcUa_DataValue_Initialize(pValue);
if (pMonitoredItemData->AttributeId == OpcUa_Attributes_Value)
{
OpcUa_Variant_Clone(OpcUa_Variable_GetValue(pVariable), &pValue->Value);
}
else
{
(OpcUa_BaseNode*)pVariable,
&pValue->Value,
}
/* set timestamps */
pValue->ServerTimestamp = OpcUa_DateTime_UtcNow();
if (pMonitoredItemData->AttributeId == OpcUa_Attributes_Value)
{
pValue->SourceTimestamp = pValue->ServerTimestamp;
}
UaServer_NewItemValue(pMonitoredItemData, pValue);
}
}
}
IFMETHODIMP(CustomProvider_TimerCallback)(OpcUa_Void *a_pvCallbackData,
OpcUa_Timer a_hTimer,
OpcUa_UInt32 a_msecElapsed)
{
OpcUa_InitializeStatus(OpcUa_Module_Server, "CustomProvider_TimerCallback");
OpcUa_ReferenceParameter(a_hTimer);
OpcUa_ReferenceParameter(a_msecElapsed);
CustomProvider_SampleData(a_pvCallbackData);
OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;
OpcUa_FinishErrorHandling;
}
OPCUA_END_EXTERN_C