ANSI C UA Server SDK  1.5.1.313
 All Data Structures Functions Variables Typedefs Enumerations Enumerator Modules Pages
uaprovider_demo_simulation.c
/*****************************************************************************
* *
* Copyright (c) 2006-2015 Unified Automation GmbH. All rights reserved. *
* *
* Software License Agreement ("SLA") Version 2.5 *
* *
* 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.5, 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.5/ *
* *
* Project: Unified Automation ANSI C based OPC UA Server SDK *
* *
*****************************************************************************/
#include <uaserver_config.h>
#include <opcua_statuscodes.h>
#include <opcua_attributes.h>
#include <uabase_p_atomic.h>
#include <uaserver_basenode.h>
#include <uaserver_utilities.h>
#if UASERVER_SUPPORT_UNITS
# include <uaserver_units.h>
#endif /* UASERVER_SUPPORT_UNITS */
#define _USE_MATH_DEFINES
#include <math.h>
#ifndef M_PI
# define M_PI 3.14159265
#endif
#include "uaprovider_demo.h"
#include "uaprovider_demo_helper.h"
#include "uaprovider_demo_identifiers_1.h"
#include "uaprovider_demo_types_1.h"
#include "uaprovider_demo_simulation.h"
#if UASERVER_SUPPORT_EVENTS
# include "uaprovider_demo_events_1.h"
# include "uaprovider_demo_alarmcondition.h"
#endif /* UASERVER_SUPPORT_EVENTS */
#if HAVE_DATA_LOGGER
# include <uabase_settings.h>
# include <uaserver_monitoring.h>
# include <uaserver_datalogger.h>
# if HAVE_DATA_LOGGER_FILE_BACKEND
# include <uaserver_filelogger.h>
# endif /* HAVE_DATA_LOGGER_FILE_BACKEND */
# if HAVE_DATA_LOGGER_SQLITE_BACKEND
# include <uaserver_sqlitelogger.h>
# endif /* HAVE_DATA_LOGGER_SQLITE_BACKEND */
static OpcUa_Boolean *g_pDataLoggerActive = 0;
#endif /* HAVE_DATA_LOGGER */
/* timer handle */
static OpcUa_Timer g_hSimulationTimer = 0;
static OpcUa_UInt32 g_SimulationInterval = 50;
static OpcUa_UInt32 *g_pSimulationSpeed = 0;
static OpcUa_Boolean *g_pSimulationActive = 0;
/* dynamic variables */
static OpcUa_Boolean *g_pDynBoolean = 0;
static OpcUa_SByte *g_pDynSByte = 0;
static OpcUa_Byte *g_pDynByte = 0;
static OpcUa_Int16 *g_pDynInt16 = 0;
static OpcUa_UInt16 *g_pDynUInt16 = 0;
static OpcUa_Int32 *g_pDynInt32 = 0;
static OpcUa_UInt32 *g_pDynUInt32 = 0;
static OpcUa_Int64 *g_pDynInt64 = 0;
static OpcUa_UInt64 *g_pDynUInt64 = 0;
static OpcUa_Float *g_pDynFloat = 0;
static OpcUa_Double *g_pDynDouble = 0;
static OpcUa_DateTime *g_pDynDateTime = 0;
static OpcUa_String *g_pDynString = 0;
static OpcUa_Guid **g_ppDynGuid = 0;
static OpcUa_ByteString *g_pDynByteString = 0;
static OpcUa_LocalizedText **g_ppDynLocalizedText = 0;
static OpcUa_QualifiedName **g_ppDynQualifiedName = 0;
static OpcUa_NodeId **g_ppDynNodeId = 0;
static OpcUa_ExpandedNodeId **g_ppDynExpandedNodeId = 0;
static OpcUa_StatusCode *g_pDynStatusCode = 0;
static OpcUa_XmlElement *g_pDynXmlElement = 0;
static OpcUa_VariantArrayValue *g_pDynArrayBoolean = 0;
static OpcUa_VariantArrayValue *g_pDynArraySByte = 0;
static OpcUa_VariantArrayValue *g_pDynArrayByte = 0;
static OpcUa_VariantArrayValue *g_pDynArrayInt16 = 0;
static OpcUa_VariantArrayValue *g_pDynArrayUInt16 = 0;
static OpcUa_VariantArrayValue *g_pDynArrayInt32 = 0;
static OpcUa_VariantArrayValue *g_pDynArrayUInt32 = 0;
static OpcUa_VariantArrayValue *g_pDynArrayInt64 = 0;
static OpcUa_VariantArrayValue *g_pDynArrayUInt64 = 0;
static OpcUa_VariantArrayValue *g_pDynArrayFloat = 0;
static OpcUa_VariantArrayValue *g_pDynArrayDouble = 0;
static OpcUa_VariantArrayValue *g_pDynArrayDateTime = 0;
static OpcUa_VariantArrayValue *g_pDynArrayString = 0;
static OpcUa_VariantArrayValue *g_pDynArrayGuid = 0;
static OpcUa_VariantArrayValue *g_pDynArrayByteString = 0;
static OpcUa_VariantArrayValue *g_pDynArrayLocalizedText = 0;
static OpcUa_VariantArrayValue *g_pDynArrayQualifiedName = 0;
static OpcUa_VariantArrayValue *g_pDynArrayNodeId = 0;
static OpcUa_VariantArrayValue *g_pDynArrayExpandedNodeId = 0;
static OpcUa_VariantArrayValue *g_pDynArrayStatusCode = 0;
static OpcUa_VariantArrayValue *g_pDynArrayXmlElement = 0;
#if UAPROVIDER_DEMO_HAVE_MASS_ITEMS
/* massfolder dynamic variables */
static OpcUa_UInt32 *g_pMassDynUInt32[UAPROVIDER_DEMO_NUM_MASS_DYNAMIC_VARIABLES];
#endif /* UAPROVIDER_DEMO_HAVE_MASS_ITEMS */
/* history variables */
static OpcUa_Double *g_pHistoryDouble = 0;
static OpcUa_Byte *g_pHistoryByte = 0;
#if UAPROVIDER_DEMO_HAVE_ANIMATION_ITEM
static OpcUa_ByteString *g_pAnimation = 0;
#endif /* UAPROVIDER_DEMO_HAVE_ANIMATION_ITEM */
static BoilerType g_Boiler1;
#if HAVE_DATA_LOGGER
static OpcUa_Int g_hDataLogger = 0;
static OpcUa_Int g_hDataLogItemDouble = 0;
#endif /* HAVE_DATA_LOGGER */
#if UASERVER_SUPPORT_EVENTS
static Machine g_machine;
#endif
struct _ItemVariableMapping
{
void **ppVariable;
const char* szNodeId;
};
typedef struct _ItemVariableMapping ItemVariableMapping;
static ItemVariableMapping g_Items[] =
{
#if HAVE_DATA_LOGGER
{ (void**) &g_pDataLoggerActive, Demo_Objects_Demo_History_DataLoggerActive },
#endif /* HAVE_DATA_LOGGER */
{ (void**) &g_pSimulationSpeed, Demo_Objects_Demo_SimulationSpeed },
{ (void**) &g_pSimulationActive, Demo_Objects_Demo_SimulationActive },
{ (void**) &g_pDynBoolean, Demo_Objects_Demo_Dynamic_Scalar_Boolean },
{ (void**) &g_pDynByte, Demo_Objects_Demo_Dynamic_Scalar_Byte },
{ (void**) &g_pDynSByte, Demo_Objects_Demo_Dynamic_Scalar_SByte },
{ (void**) &g_pDynUInt16, Demo_Objects_Demo_Dynamic_Scalar_UInt16 },
{ (void**) &g_pDynInt16, Demo_Objects_Demo_Dynamic_Scalar_Int16 },
{ (void**) &g_pDynUInt32, Demo_Objects_Demo_Dynamic_Scalar_UInt32 },
{ (void**) &g_pDynInt32, Demo_Objects_Demo_Dynamic_Scalar_Int32 },
{ (void**) &g_pDynUInt64, Demo_Objects_Demo_Dynamic_Scalar_UInt64 },
{ (void**) &g_pDynInt64, Demo_Objects_Demo_Dynamic_Scalar_Int64 },
{ (void**) &g_pDynFloat, Demo_Objects_Demo_Dynamic_Scalar_Float },
{ (void**) &g_pDynDouble, Demo_Objects_Demo_Dynamic_Scalar_Double },
{ (void**) &g_pDynDateTime, Demo_Objects_Demo_Dynamic_Scalar_DateTime },
{ (void**) &g_pDynString, Demo_Objects_Demo_Dynamic_Scalar_String },
{ (void**) &g_pDynByteString, Demo_Objects_Demo_Dynamic_Scalar_ByteString },
{ (void**) &g_ppDynGuid, Demo_Objects_Demo_Dynamic_Scalar_Guid },
{ (void**) &g_ppDynLocalizedText, Demo_Objects_Demo_Dynamic_Scalar_LocalizedText },
{ (void**) &g_ppDynQualifiedName, Demo_Objects_Demo_Dynamic_Scalar_QualifiedName },
{ (void**) &g_ppDynNodeId, Demo_Objects_Demo_Dynamic_Scalar_NodeId },
{ (void**) &g_ppDynExpandedNodeId, Demo_Objects_Demo_Dynamic_Scalar_ExpandedNodeId },
{ (void**) &g_pDynStatusCode, Demo_Objects_Demo_Dynamic_Scalar_StatusCode },
{ (void**) &g_pDynXmlElement, Demo_Objects_Demo_Dynamic_Scalar_XmlElement },
{ (void**) &g_pDynArrayBoolean, Demo_Objects_Demo_Dynamic_Arrays_Boolean },
{ (void**) &g_pDynArrayByte, Demo_Objects_Demo_Dynamic_Arrays_Byte },
{ (void**) &g_pDynArraySByte, Demo_Objects_Demo_Dynamic_Arrays_SByte },
{ (void**) &g_pDynArrayUInt16, Demo_Objects_Demo_Dynamic_Arrays_UInt16 },
{ (void**) &g_pDynArrayInt16, Demo_Objects_Demo_Dynamic_Arrays_Int16 },
{ (void**) &g_pDynArrayUInt32, Demo_Objects_Demo_Dynamic_Arrays_UInt32 },
{ (void**) &g_pDynArrayInt32, Demo_Objects_Demo_Dynamic_Arrays_Int32 },
{ (void**) &g_pDynArrayUInt64, Demo_Objects_Demo_Dynamic_Arrays_UInt64 },
{ (void**) &g_pDynArrayInt64, Demo_Objects_Demo_Dynamic_Arrays_Int64 },
{ (void**) &g_pDynArrayFloat, Demo_Objects_Demo_Dynamic_Arrays_Float },
{ (void**) &g_pDynArrayDouble, Demo_Objects_Demo_Dynamic_Arrays_Double },
{ (void**) &g_pDynArrayGuid, Demo_Objects_Demo_Dynamic_Arrays_Guid },
{ (void**) &g_pDynArrayDateTime, Demo_Objects_Demo_Dynamic_Arrays_DateTime },
{ (void**) &g_pDynArrayString, Demo_Objects_Demo_Dynamic_Arrays_String },
{ (void**) &g_pDynArrayByteString, Demo_Objects_Demo_Dynamic_Arrays_ByteString },
{ (void**) &g_pDynArrayLocalizedText, Demo_Objects_Demo_Dynamic_Arrays_LocalizedText },
{ (void**) &g_pDynArrayQualifiedName, Demo_Objects_Demo_Dynamic_Arrays_QualifiedName },
{ (void**) &g_pDynArrayNodeId, Demo_Objects_Demo_Dynamic_Arrays_NodeId },
{ (void**) &g_pDynArrayExpandedNodeId, Demo_Objects_Demo_Dynamic_Arrays_ExpandedNodeId },
{ (void**) &g_pDynArrayStatusCode, Demo_Objects_Demo_Dynamic_Arrays_StatusCode },
{ (void**) &g_pDynArrayXmlElement, Demo_Objects_Demo_Dynamic_Arrays_XmlElement },
{ (void**) &g_pHistoryByte, Demo_Objects_Demo_History_ByteWithHistory },
{ (void**) &g_pHistoryDouble, Demo_Objects_Demo_History_DoubleWithHistory },
{ 0, 0 }
};
OPCUA_BEGIN_EXTERN_C
OpcUa_Variant* UaProvider_Demo_GetNodeValueNumeric(int id)
{
OpcUa_NodeId nodeId;
OpcUa_BaseNode *pNode = 0;
OpcUa_Variant *pVal = 0;
pNode = UaServer_GetNodeById(&nodeId);
if (pNode && OpcUa_BaseNode_GetType(pNode) == eVariable)
{
pVal = OpcUa_Variable_GetValue(pNode);
}
return pVal;
}
OpcUa_Variant* UaProvider_Demo_GetNodeValueString(const char *szId)
{
OpcUa_NodeId nodeId;
OpcUa_BaseNode *pNode = 0;
OpcUa_Variant *pVal = 0;
UaBase_CreateStringNodeId(&nodeId, szId);
pNode = UaServer_GetNodeById(&nodeId);
if (pNode && OpcUa_BaseNode_GetType(pNode) == eVariable)
{
pVal = OpcUa_Variable_GetValue(pNode);
}
return pVal;
}
#if UAPROVIDER_DEMO_HAVE_MASS_ITEMS
OpcUa_StatusCode UaProvider_Demo_CreateNodes()
{
UaServer_AddressSpace *pAddressSpace = &(g_pDemoProvider->AddressSpace);
OpcUa_NodeId nodeId;
OpcUa_BaseNode *pNode = 0;
OpcUa_DataVariable *pVariable = 0;
OpcUa_Variant value;
OpcUa_Variant *pVal;
char szName[50];
int i;
OpcUa_InitializeStatus(OpcUa_Module_Server, "UaProvider_Demo_CreateNodes");
OpcUa_Variant_Initialize(&value);
#if UAPROVIDER_DEMO_HAVE_ANIMATION_ITEM
value.Datatype = OpcUaType_ByteString;
value.Value.ByteString.Length = 0;
value.Value.ByteString.Data = 0;
/* create animation variable */
UaBase_CreateStringNodeId( &nodeId, Demo_Objects_Demo );
pNode = UaServer_GetNodeById( &nodeId );
uStatus = UaServer_CreateDataVariableS(pAddressSpace, &pVariable, pNode, "Animation", g_UaProviderDemo_uNamespaceIndex1, "Animation");
OpcUa_GotoErrorIfBad(uStatus);
/* set datatype attribute */
OpcUa_Variable_SetDataType_Numeric(pVariable, OpcUaId_ImageGIF, 0);
/* set value attribute */
OpcUa_Variable_AttachValue(pVariable, &value);
/* set access level attribute */
OpcUa_Variable_SetAccessLevel(pVariable, OpcUa_AccessLevels_CurrentRead);
/* store variable pointer for simulation */
pVal = OpcUa_Variable_GetValue(pVariable);
if (pVal)
{
g_pAnimation = &pVal->Value.ByteString;
}
#endif /* UAPROVIDER_DEMO_HAVE_ANIMATION_ITEM */
/* default value for masss items */
value.Datatype = OpcUaType_UInt32;
value.Value.UInt32 = 123;
/* create mass folders nodes */
UaBase_CreateStringNodeId( &nodeId, Demo_Objects_Demo_Massfolder_Static );
pNode = UaServer_GetNodeById( &nodeId );
for (i=0; i<UAPROVIDER_DEMO_NUM_MASS_STATIC_VARIABLES; i++)
{
OpcUa_SnPrintfA(szName, 50, "Variable%03i", i);
uStatus = UaServer_CreateDataVariable(pAddressSpace, &pVariable, pNode, 20000 + i, g_UaProviderDemo_uNamespaceIndex1, szName);
OpcUa_GotoErrorIfBad(uStatus);
/* set datatype attribute */
OpcUa_Variable_SetDataType_Numeric(pVariable, OpcUaId_UInt32, 0);
/* set value attribute */
OpcUa_Variable_AttachValue(pVariable, &value);
/* set access level attribute */
OpcUa_Variable_SetAccessLevel(pVariable, OpcUa_AccessLevels_CurrentReadOrWrite);
}
/* create mass folders nodes */
UaBase_CreateStringNodeId( &nodeId, Demo_Objects_Demo_Massfolder_Dynamic );
pNode = UaServer_GetNodeById( &nodeId );
for (i=0; i<UAPROVIDER_DEMO_NUM_MASS_DYNAMIC_VARIABLES; i++)
{
OpcUa_SnPrintfA(szName, 50, "Variable%03i", i);
uStatus = UaServer_CreateDataVariable(pAddressSpace, &pVariable, pNode, 20000+UAPROVIDER_DEMO_NUM_MASS_STATIC_VARIABLES+i, g_UaProviderDemo_uNamespaceIndex1, szName);
OpcUa_GotoErrorIfBad(uStatus);
/* set datatype attribute */
OpcUa_Variable_SetDataType_Numeric(pVariable, OpcUaId_UInt32, 0);
/* set value attribute */
OpcUa_Variable_AttachValue(pVariable, &value);
/* set access level attribute */
OpcUa_Variable_SetAccessLevel(pVariable, OpcUa_AccessLevels_CurrentRead);
/* store variable pointer for simulation */
pVal = OpcUa_Variable_GetValue(pVariable);
if (pVal)
{
g_pMassDynUInt32[i] = &pVal->Value.UInt32;
}
}
OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;
OpcUa_FinishErrorHandling;
}
#endif /* UAPROVIDER_DEMO_HAVE_MASS_ITEMS */
#if HAVE_DATA_LOGGER
/* Helper function for historizing demo variables. */
void UaProvider_Demo_HistorizeItem(OpcUa_NodeId *pId, OpcUa_Boolean bStartLogging)
{
HistoryDataLogger *pUserDataHistoryDataLogger = 0;
UaServer_DataLog *pDataLogItem;
OpcUa_Int32 iSamplingInterval = 500;
OpcUa_BaseNode *pNode = 0;
OpcUa_Byte AccessLevel;
pNode = UaServer_GetNodeById(pId);
if (pNode)
{
/* create user data object with data logger options */
pUserDataHistoryDataLogger = (HistoryDataLogger*)OpcUa_Alloc(sizeof(HistoryDataLogger));
/* read persistent configuration from datalogger */
if (UaServer_DataLogger_FindDataLogItem(g_hDataLogger, pId, &pDataLogItem) == OpcUa_Good)
{
iSamplingInterval = (OpcUa_Int32)pDataLogItem->SamplingRate;
monitoringMode = pDataLogItem->Active == OpcUa_False ? OpcUa_MonitoringMode_Disabled : OpcUa_MonitoringMode_Reporting;
}
if (bStartLogging == OpcUa_False)
{
/* disable logging */
}
/* create datalog item if it does not already exist. */
iSamplingInterval,
monitoringMode,
100,
OpcUa_Null,
g_hDataLogger,
&g_hDataLogItemDouble);
/* store configuration in the node's userdata */
pUserDataHistoryDataLogger->Type = UserDataHistoryDataLogger;
pUserDataHistoryDataLogger->DataLogger = g_hDataLogger;
pUserDataHistoryDataLogger->DataLogItem = g_hDataLogItemDouble;
OpcUa_BaseNode_SetUserData(pNode, pUserDataHistoryDataLogger);
/* update node attributes */
OpcUa_Variable_SetHistorizing(pNode, bStartLogging);
AccessLevel = OpcUa_Variable_GetAccessLevel(pNode);
AccessLevel |= OpcUa_AccessLevels_HistoryRead;
OpcUa_Variable_SetAccessLevel(pNode, AccessLevel);
}
}
void UaProvider_Demo_EnableHistorizedItem(OpcUa_NodeId *pId, OpcUa_Boolean bEnabled)
{
HistoryDataLogger *pUserDataHistoryDataLogger = 0;
OpcUa_BaseNode *pNode = 0;
OpcUa_MonitoringMode monitoringMode;
UaServer_DataLog *pDataLogItem;
OpcUa_Int32 iSamplingInterval = 500;
pNode = UaServer_GetNodeById(pId);
if (pNode)
{
/* create user data object with data logger options */
pUserDataHistoryDataLogger = (HistoryDataLogger*)OpcUa_BaseNode_GetUserData(pNode);
if (pUserDataHistoryDataLogger == 0) return;
/* read persistent configuration from datalogger */
if (UaServer_DataLogger_FindDataLogItem(g_hDataLogger, pId, &pDataLogItem) == OpcUa_Good)
{
iSamplingInterval = (OpcUa_Int32)pDataLogItem->SamplingRate;
}
/* disable historization */
g_hDataLogger,
pUserDataHistoryDataLogger->DataLogItem,
iSamplingInterval,
monitoringMode,
100,
OpcUa_Null
);
/* update node attributes */
}
}
void UaProvider_Demo_SetupDataLogger()
{
OpcUa_NodeId nodeId;
UaBase_Settings settings;
OpcUa_Boolean bStartLogging;
char szDataLoggerPath[512] = "";
#if defined(__WIN32) || defined(WIN32)
UaBase_Settings_Initialize(&settings, "settings.ini");
#else
UaBase_Settings_Initialize(&settings, "settings.conf");
#endif
UaBase_Settings_BeginGroup(&settings, "DemoProvider");
UaBase_Settings_ReadBool(&settings, "StartLogging", &bStartLogging, OpcUa_False);
UaBase_Settings_ReadString(&settings, "DataLoggerPath", szDataLoggerPath, sizeof(szDataLoggerPath), "");
/* create file logger */
#if HAVE_DATA_LOGGER_SQLITE_BACKEND
g_hDataLogger = UaServer_SQLiteLogger_Create( szDataLoggerPath, 600, 5);
#elif HAVE_DATA_LOGGER_FILE_BACKEND
g_hDataLogger = UaServer_FileLogger_Create( szDataLoggerPath );
#else
# error "Configuration error. No datalogger is configured."
#endif
if (g_hDataLogger < 0) return;
UaBase_CreateStringNodeId(&nodeId, Demo_Objects_Demo_History_ByteWithHistory);
UaProvider_Demo_HistorizeItem(&nodeId, bStartLogging);
UaBase_CreateStringNodeId(&nodeId, Demo_Objects_Demo_History_DoubleWithHistory);
UaProvider_Demo_HistorizeItem(&nodeId, bStartLogging);
UaBase_CreateStringNodeId(&nodeId, Demo_Objects_Demo_BoilerDemo_Boiler1_TemperatureSensor_Temperature);
UaProvider_Demo_HistorizeItem(&nodeId, bStartLogging);
UaServer_DataLogger_Start(g_hDataLogger);
if (g_pDataLoggerActive) *g_pDataLoggerActive = bStartLogging;
}
void UaProvider_Demo_CleanupDataLogger()
{
OpcUa_NodeId nodeId;
OpcUa_BaseNode *pNode;
UserDataCommon *pUserData;
UaServer_DataLogger_Stop(g_hDataLogger);
UaBase_CreateStringNodeId(&nodeId, Demo_Objects_Demo_History_ByteWithHistory);
pNode = UaServer_GetNodeById(&nodeId);
if (pNode)
{
pUserData = (UserDataCommon*)OpcUa_BaseNode_GetUserData(pNode);
if (pUserData)
{
if (pUserData->Type == UserDataHistoryDataLogger)
{
HistoryDataLogger *pUserDataHistoryDataLogger = (HistoryDataLogger*)pUserData;
UaServer_DataLoggerItemData_Remove(pUserDataHistoryDataLogger->DataLogger, pUserDataHistoryDataLogger->DataLogItem);
}
OpcUa_Free(pUserData);
}
}
UaBase_CreateStringNodeId(&nodeId, Demo_Objects_Demo_History_DoubleWithHistory);
pNode = UaServer_GetNodeById(&nodeId);
if (pNode)
{
pUserData = (UserDataCommon*)OpcUa_BaseNode_GetUserData(pNode);
if (pUserData)
{
if (pUserData->Type == UserDataHistoryDataLogger)
{
HistoryDataLogger *pUserDataHistoryDataLogger = (HistoryDataLogger*)pUserData;
UaServer_DataLoggerItemData_Remove(pUserDataHistoryDataLogger->DataLogger, pUserDataHistoryDataLogger->DataLogItem);
}
OpcUa_Free(pUserData);
}
}
UaBase_CreateStringNodeId(&nodeId, Demo_Objects_Demo_BoilerDemo_Boiler1_TemperatureSensor_Temperature);
pNode = UaServer_GetNodeById(&nodeId);
if (pNode)
{
pUserData = (UserDataCommon*)OpcUa_BaseNode_GetUserData(pNode);
if (pUserData)
{
if (pUserData->Type == UserDataHistoryDataLogger)
{
HistoryDataLogger *pUserDataHistoryDataLogger = (HistoryDataLogger*)pUserData;
UaServer_DataLoggerItemData_Remove(pUserDataHistoryDataLogger->DataLogger, pUserDataHistoryDataLogger->DataLogItem);
}
OpcUa_Free(pUserData);
}
}
UaServer_DataLogger_Delete(g_hDataLogger);
}
OpcUa_StatusCode UaProvider_Demo_StartLogging()
{
OpcUa_NodeId nodeId;
if (g_pDataLoggerActive == 0) return OpcUa_BadInternalError;
if (*g_pDataLoggerActive) return OpcUa_BadInvalidState;
*g_pDataLoggerActive = OpcUa_True;
/* enable items to start sampling */
UaBase_CreateStringNodeId(&nodeId, Demo_Objects_Demo_History_ByteWithHistory);
UaProvider_Demo_EnableHistorizedItem(&nodeId, OpcUa_True);
UaBase_CreateStringNodeId(&nodeId, Demo_Objects_Demo_History_DoubleWithHistory);
UaProvider_Demo_EnableHistorizedItem(&nodeId, OpcUa_True);
UaBase_CreateStringNodeId(&nodeId, Demo_Objects_Demo_BoilerDemo_Boiler1_TemperatureSensor_Temperature);
UaProvider_Demo_EnableHistorizedItem(&nodeId, OpcUa_True);
return OpcUa_Good;
}
OpcUa_StatusCode UaProvider_Demo_StopLogging()
{
OpcUa_NodeId nodeId;
if (g_pDataLoggerActive == 0) return OpcUa_BadInternalError;
if (*g_pDataLoggerActive == OpcUa_False) return OpcUa_BadInvalidState;
/* disable items to stop sampling*/
UaBase_CreateStringNodeId(&nodeId, Demo_Objects_Demo_History_ByteWithHistory);
UaProvider_Demo_EnableHistorizedItem(&nodeId, OpcUa_False);
UaBase_CreateStringNodeId(&nodeId, Demo_Objects_Demo_History_DoubleWithHistory);
UaProvider_Demo_EnableHistorizedItem(&nodeId, OpcUa_False);
UaBase_CreateStringNodeId(&nodeId, Demo_Objects_Demo_BoilerDemo_Boiler1_TemperatureSensor_Temperature);
UaProvider_Demo_EnableHistorizedItem(&nodeId, OpcUa_False);
*g_pDataLoggerActive = OpcUa_False;
return OpcUa_Good;
}
#endif /* HAVE_DATA_LOGGER */
#if UASERVER_SUPPORT_UNITS
/* The usage of UaServer_UnitIdFromCommonCode and UaServer_EUInformationFromUnitId is demonstrated here.
* The UaModeler generates correct type information, so this is only necessary for dynamically created
* EUInformation properties. */
void UaProvider_Demo_SetEngineeringUnits(const char *szNodeId, const char *szCommonCode)
{
OpcUa_Variant *pVal;
OpcUa_Int32 UnitId = UaServer_UnitIdFromCommonCode(szCommonCode);
OpcUa_EUInformation *pEUInfoDst;
OpcUa_EUInformation *pEUInfoSrc;
pVal = UaProvider_Demo_GetNodeValueString(szNodeId);
if ( pVal
&& pVal->Datatype == OpcUaType_ExtensionObject
&& pVal->Value.ExtensionObject->Encoding == OpcUa_ExtensionObjectEncoding_EncodeableObject
&& pVal->Value.ExtensionObject->Body.EncodeableObject.Type->TypeId == OpcUaId_EUInformation)
{
pEUInfoSrc = UaServer_EUInformationFromUnitId(UnitId);
pEUInfoDst = (OpcUa_EUInformation*)pVal->Value.ExtensionObject->Body.EncodeableObject.Object;
if (pEUInfoSrc && pEUInfoDst)
{
OpcUa_EUInformation_Clear(pEUInfoDst);
OpcUa_MemCpy(pEUInfoDst, sizeof(OpcUa_EUInformation), pEUInfoSrc, sizeof(OpcUa_EUInformation));
}
}
}
#endif /* UASERVER_SUPPORT_UNITS */
#if UASERVER_SUPPORT_AUTHORIZATION
struct NodePermission
{
int id;
const char *szId;
const char *szOwner;
const char *szGroup;
const char *szMode;
};
static struct NodePermission g_permissions[] =
{
{ Demo_Objects_Demo_AccessRights_Access_All, 0,
"root", "root", "-br--ebr--ebr--e" },
{ Demo_Objects_Demo_AccessRights_Access_All_TestVar_RW, 0,
"root", "root", "-brwaebrwaebrwae" },
{ Demo_Objects_Demo_AccessRights_Access_All_TestVar_WO, 0,
"root", "root", "-b-w-eb-w-eb-w-e" },
{ Demo_Objects_Demo_AccessRights_Access_All_TestVar_RO, 0,
"root", "root", "-br--ebr--ebr--e" },
{ Demo_Objects_Demo_AccessRights_Access_All_TestVar_RO_John_RW, 0,
"john", "root", "-brwaebr--ebr--e" },
{ Demo_Objects_Demo_AccessRights_Access_All_TestVar_RO_Operators_RW, 0,
"root", "operators", "-br--ebrwaebr--e" },
{ Demo_Objects_Demo_AccessRights_Access_John, 0,
"john", "root", "-br--e----e----e" },
{ Demo_Objects_Demo_AccessRights_Access_John_TestVar_RW, 0,
"john", "root", "-brwae----e----e" },
{ Demo_Objects_Demo_AccessRights_Access_John_TestVar_RO, 0,
"john", "root", "-br--e----e----e" },
{ Demo_Objects_Demo_AccessRights_Access_John_TestVar_WO, 0,
"john", "root", "-b-w-e----e----e" },
{ Demo_Objects_Demo_AccessRights_Access_Operators, 0,
"root", "operators", "-br--ebr--e----e" },
{ Demo_Objects_Demo_AccessRights_Access_Operators_TestVar_RW, 0,
"root", "operators", "-brwaebrwae----e" },
{ Demo_Objects_Demo_AccessRights_Access_Operators_TestVar_RO, 0,
"root", "operators", "-br--ebr--e----e" },
{ Demo_Objects_Demo_AccessRights_Access_Operators_TestVar_WO, 0,
"root", "operators", "-b-w-eb-w-e----e" },
{ 0, Demo_Objects_Demo_History_DataLoggerActive,
"root", "operators", "-brwaebrwaebr--e" },
{ 0, Demo_Objects_Demo_History_StartLogging,
"root", "operators", "-brwaebrwaebr--e" },
{ 0, Demo_Objects_Demo_History_StopLogging,
"root", "operators", "-brwaebrwaebr--e" }
};
static int g_numPermissions = sizeof(g_permissions)/sizeof(struct NodePermission);
void UaProvider_Demo_SetupAccessRights()
{
OpcUa_StatusCode ret;
OpcUa_NodeId nodeId;
OpcUa_BaseNode *pNode = 0;
OpcUa_UInt16 mode;
OpcUa_uid_t uid;
OpcUa_gid_t gid;
OpcUa_String pass_hash;
int i;
for (i=0; i<g_numPermissions; i++)
{
/* get uid and gid */
ret = UaServer_GetUserIdentity(OpcUa_String_FromCString(g_permissions[i].szOwner), &uid, &gid, &pass_hash);
if (OpcUa_IsBad(ret)) continue;
OpcUa_String_Clear(&pass_hash); /* the password hash must be freed by the caller */
ret = UaServer_GetGroupId(OpcUa_String_FromCString(g_permissions[i].szGroup), &gid);
if (OpcUa_IsBad(ret)) continue;
/* create mode mask */
mode = 0;
if (g_permissions[i].szMode[0] == 'E') mode |= UA_ALL_ENCRYPTION_REQUIRED;
if (g_permissions[i].szMode[1] == 'b') mode |= UA_USER_BROWSEABLE;
if (g_permissions[i].szMode[2] == 'r') mode |= UA_USER_READABLE;
if (g_permissions[i].szMode[3] == 'w') mode |= UA_USER_WRITABLE;
if (g_permissions[i].szMode[4] == 'a') mode |= UA_USER_ATTRWRITABLE;
if (g_permissions[i].szMode[5] == 'e') mode |= UA_USER_EVENTREADABLE;
if (g_permissions[i].szMode[6] == 'b') mode |= UA_GROUP_BROWSEABLE;
if (g_permissions[i].szMode[7] == 'r') mode |= UA_GROUP_READABLE;
if (g_permissions[i].szMode[8] == 'w') mode |= UA_GROUP_WRITABLE;
if (g_permissions[i].szMode[9] == 'a') mode |= UA_GROUP_ATTRWRITABLE;
if (g_permissions[i].szMode[10] == 'e') mode |= UA_GROUP_EVENTREADABLE;
if (g_permissions[i].szMode[11] == 'b') mode |= UA_OTHER_BROWSEABLE;
if (g_permissions[i].szMode[12] == 'r') mode |= UA_OTHER_READABLE;
if (g_permissions[i].szMode[13] == 'w') mode |= UA_OTHER_WRITABLE;
if (g_permissions[i].szMode[14] == 'a') mode |= UA_OTHER_ATTRWRITABLE;
if (g_permissions[i].szMode[15] == 'e') mode |= UA_OTHER_EVENTREADABLE;
/* get node */
if (g_permissions[i].id == 0)
{
UaBase_CreateStringNodeId(&nodeId, g_permissions[i].szId);
}
else
{
UaBase_CreateNumericNodeId(&nodeId, g_permissions[i].id);
}
pNode = UaServer_GetNodeById(&nodeId );
if (pNode == 0) continue;
/* update permissions */
UaServer_UserMgt_SetPermissions(pNode, uid, gid, mode);
}
}
#endif /* UASERVER_SUPPORT_AUTHORIZATION */
static OpcUa_StatusCode MultiStateDiscreteRange_Create(OpcUa_NodeId *pNodeId, OpcUa_UInt32 minValue, OpcUa_UInt32 maxValue)
{
OpcUa_BaseNode *pNode = OpcUa_Null;
MultiStateDiscreteRange *pRange = OpcUa_Null;
OpcUa_InitializeStatus(OpcUa_Module_Server, "MultiStateDiscreteRange_Create");
pNode = UaServer_GetNodeById(pNodeId);
OpcUa_GotoErrorIfNull(pNode, OpcUa_BadNodeIdUnknown);
pRange = OpcUa_Alloc(sizeof(MultiStateDiscreteRange));
OpcUa_GotoErrorIfNull(pRange, OpcUa_BadOutOfMemory);
pRange->Type = UserDataMultiStateDiscrete;
pRange->MinValue = minValue;
pRange->MaxValue = maxValue;
OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;
OpcUa_FinishErrorHandling;
}
static OpcUa_StatusCode MultiStateDiscreteRange_Delete(OpcUa_NodeId *pNodeId)
{
OpcUa_BaseNode *pNode = OpcUa_Null;
MultiStateDiscreteRange *pRange = OpcUa_Null;
OpcUa_InitializeStatus(OpcUa_Module_Server, "MultiStateDiscreteRange_Delete");
pNode = UaServer_GetNodeById(pNodeId);
OpcUa_GotoErrorIfNull(pNode, OpcUa_BadNodeIdUnknown);
pRange = OpcUa_BaseNode_GetUserData(pNode);
OpcUa_GotoErrorIfNull(pRange, OpcUa_BadInvalidArgument);
OpcUa_Free(pRange);
OpcUa_BaseNode_SetUserData(pNode, OpcUa_Null);
OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;
OpcUa_FinishErrorHandling;
}
#define SET_MATRIX_VALUE(NODEID, DATATYPE) \
{ \
OpcUa_Variant *pValue; \
OpcUa_Int32 iNumArrayDimensions, i, iNumElements; \
OpcUa_UInt32 *pArrayDimensions; \
\
UaBase_CreateStringNodeId(&nodeid, NODEID); \
pNode = UaServer_GetNodeById(&nodeid); \
pValue = OpcUa_Variable_GetValue(pNode); \
iNumArrayDimensions = OpcUa_Variable_GetNumArrayDimensions(pNode); \
pArrayDimensions = OpcUa_Variable_GetArrayDimensions(pNode); \
\
OpcUa_Variant_Clear(pValue); \
iNumElements = 1; \
pValue->Datatype = OpcUaType_##DATATYPE; \
pValue->ArrayType = OpcUa_VariantArrayType_Matrix; \
pValue->Value.Matrix.NoOfDimensions = iNumArrayDimensions; \
pValue->Value.Matrix.Dimensions = OpcUa_Alloc(iNumArrayDimensions * sizeof(OpcUa_Int32)); \
for (i = 0; i < iNumArrayDimensions; i++) \
{ \
pValue->Value.Matrix.Dimensions[i] = pArrayDimensions[i]; \
iNumElements *= pArrayDimensions[i]; \
} \
pValue->Value.Matrix.Value.DATATYPE##Array = OpcUa_Alloc(iNumElements * sizeof(OpcUa_##DATATYPE)); \
for (i = 0; i < iNumElements; i++) \
{ \
OpcUa_##DATATYPE##_Initialize(&pValue->Value.Matrix.Value.DATATYPE##Array[i]); \
} \
}
OpcUa_StatusCode UaProvider_Demo_InitializeSimulation()
{
OpcUa_Variant *pVal = 0;
OpcUa_BaseNode *pNode = 0;
OpcUa_NodeId nodeid;
#if UASERVER_SUPPORT_EVENTS
UaServer_Event *pEvent = 0;
#endif
int iItem = 0;
OpcUa_InitializeStatus(OpcUa_Module_Server, "UaProvider_Demo_InitializeSimulation");
UaBase_SetDefaultNamespace( g_UaProviderDemo_uNamespaceIndex1 );
#if UAPROVIDER_DEMO_HAVE_MASS_ITEMS
/* create dynamic nodes, that have not been modeled */
uStatus = UaProvider_Demo_CreateNodes();
OpcUa_GotoErrorIfBad(uStatus);
#endif /* UAPROVIDER_DEMO_HAVE_MASS_ITEMS */
/* connect C variables with Node values */
while (g_Items[iItem].ppVariable != 0)
{
pVal = UaProvider_Demo_GetNodeValueString(g_Items[iItem].szNodeId);
if (pVal)
{
if (pVal->ArrayType == OpcUa_VariantArrayType_Scalar)
{
/* assign union address */
*g_Items[iItem].ppVariable = &pVal->Value.Boolean;
}
else if (pVal->ArrayType == OpcUa_VariantArrayType_Array)
{
/* assign array address */
*g_Items[iItem].ppVariable = &pVal->Value.Array;
}
}
++iItem;
}
/* Boiler1 variables */
pVal = UaProvider_Demo_GetNodeValueString(Demo_Objects_Demo_BoilerDemo_Boiler1_TemperatureSensor_Temperature);
if (pVal) g_Boiler1.pTemperature = &pVal->Value.Double;
pVal = UaProvider_Demo_GetNodeValueString(Demo_Objects_Demo_BoilerDemo_Boiler1_TemperatureSetPoint);
if (pVal) g_Boiler1.pTemperatureSetPoint = &pVal->Value.Double;
pVal = UaProvider_Demo_GetNodeValueString(Demo_Objects_Demo_BoilerDemo_Boiler1_FillLevelSensor_FillLevel);
if (pVal) g_Boiler1.pFillLevel = &pVal->Value.Double;
pVal = UaProvider_Demo_GetNodeValueString(Demo_Objects_Demo_BoilerDemo_Boiler1_FillLevelSetPoint);
if (pVal) g_Boiler1.pFillLevelSetPoint = &pVal->Value.Double;
pVal = UaProvider_Demo_GetNodeValueString(Demo_Objects_Demo_BoilerDemo_Boiler1_HeaterStatus);
if (pVal) g_Boiler1.pHeaterStatus = &pVal->Value.Int32;
#if UASERVER_SUPPORT_UNITS
UaProvider_Demo_SetEngineeringUnits(Demo_Objects_Demo_BoilerDemo_Boiler1_TemperatureSensor_Temperature_EngineeringUnits, "CEL");
UaProvider_Demo_SetEngineeringUnits(Demo_Objects_Demo_BoilerDemo_Boiler1_FillLevelSensor_FillLevel_EngineeringUnits, "LTR");
#endif /* UASERVER_SUPPORT_UNITS */
UaBase_CreateStringNodeId(&nodeid, Demo_Objects_Demo_BoilerDemo_Boiler1);
pNode = UaServer_GetNodeById(&nodeid);
if (pNode) OpcUa_BaseNode_SetUserData(pNode, &g_Boiler1);
if (g_Boiler1.pTemperature) *g_Boiler1.pTemperature = 20;
if (g_Boiler1.pTemperatureSetPoint) *g_Boiler1.pTemperatureSetPoint = 90;
if (g_Boiler1.pFillLevel) *g_Boiler1.pFillLevel = 10;
if (g_Boiler1.pFillLevelSetPoint) *g_Boiler1.pFillLevelSetPoint = 50;
#if UASERVER_SUPPORT_EVENTS
/* Machine variables */
UaBase_CreateNumericNodeId(&g_machine.NodeId, Demo_Objects_Machine);
UaBase_CreateNumericNodeId(&g_machine.TemperatureSensor.NodeId, Demo_Objects_Machine_TemperatureSensor);
UaBase_CreateNumericNodeId(&g_machine.HeaterSwitch.NodeId, Demo_Objects_Machine_HeaterSwitch);
UaBase_CreateNumericNodeId(&g_machine.TemperatureSensor.HighAlarmId, 10001);
UaBase_CreateNumericNodeId(&g_machine.TemperatureSensor.LowAlarmId, 10002);
pVal = UaProvider_Demo_GetNodeValueNumeric(Demo_Objects_Machine_TemperatureSensor_Temperature);
if (pVal)
{
pVal->Value.Double = 25.0;
g_machine.TemperatureSensor.pValue = &pVal->Value.Double;
}
pVal = UaProvider_Demo_GetNodeValueNumeric(Demo_Objects_Machine_HeaterSwitch);
if (pVal)
{
g_machine.HeaterSwitch.pValue = &pVal->Value.Boolean;
}
/* create acknowledgeable condition type events */
UaBase_CreateNumericNodeIdEx(&nodeid, OpcUaId_AlarmConditionType, 0);
/* create acknowledgeable conditions used by this sensor */
pEvent = UaServer_Events_CreateEvent(&nodeid);
UaProvider_Demo_InitializeAlarmConditionTypeEvent(
pEvent,
&g_machine.TemperatureSensor.NodeId,
"Temperature Sensor",
&g_machine.TemperatureSensor.HighAlarmId,
"HighAlarm");
pEvent = UaServer_Events_CreateEvent(&nodeid);
UaProvider_Demo_InitializeAlarmConditionTypeEvent(
pEvent,
&g_machine.TemperatureSensor.NodeId,
"Temperature Sensor",
&g_machine.TemperatureSensor.LowAlarmId,
"LowAlarm");
#endif /* UASERVER_SUPPORT_EVENTS */
UaBase_CreateStringNodeId(&nodeid, Demo_Objects_Demo_CTT_DA_Profile_DiscreteType_MultiStateDiscrete1);
uStatus = MultiStateDiscreteRange_Create(&nodeid, 0, 2);
OpcUa_GotoErrorIfBad(uStatus);
UaBase_CreateStringNodeId(&nodeid, Demo_Objects_Demo_CTT_DA_Profile_DiscreteType_MultiStateDiscrete2);
uStatus = MultiStateDiscreteRange_Create(&nodeid, 0, 4);
OpcUa_GotoErrorIfBad(uStatus);
UaBase_CreateStringNodeId(&nodeid, Demo_Objects_Demo_CTT_DA_Profile_DiscreteType_MultiStateDiscrete3);
uStatus = MultiStateDiscreteRange_Create(&nodeid, 0, 2);
OpcUa_GotoErrorIfBad(uStatus);
UaBase_CreateStringNodeId(&nodeid, Demo_Objects_Demo_CTT_DA_Profile_DiscreteType_MultiStateDiscrete4);
uStatus = MultiStateDiscreteRange_Create(&nodeid, 0, 2);
OpcUa_GotoErrorIfBad(uStatus);
UaBase_CreateStringNodeId(&nodeid, Demo_Objects_Demo_CTT_DA_Profile_DiscreteType_MultiStateDiscrete5);
uStatus = MultiStateDiscreteRange_Create(&nodeid, 0, 2);
OpcUa_GotoErrorIfBad(uStatus);
#if !OPCUA_VARIANT_OMIT_MATRIX
/* workaround for setting matrix values as currently the UaModeler does not support that */
SET_MATRIX_VALUE(Demo_Objects_Demo_Static_Matrix_Boolean, Boolean)
SET_MATRIX_VALUE(Demo_Objects_Demo_Static_Matrix_Byte, Byte)
SET_MATRIX_VALUE(Demo_Objects_Demo_Static_Matrix_ByteString, ByteString)
SET_MATRIX_VALUE(Demo_Objects_Demo_Static_Matrix_DateTime, DateTime)
SET_MATRIX_VALUE(Demo_Objects_Demo_Static_Matrix_Double, Double)
SET_MATRIX_VALUE(Demo_Objects_Demo_Static_Matrix_ExpandedNodeId, ExpandedNodeId)
SET_MATRIX_VALUE(Demo_Objects_Demo_Static_Matrix_Float, Float)
SET_MATRIX_VALUE(Demo_Objects_Demo_Static_Matrix_Guid, Guid)
SET_MATRIX_VALUE(Demo_Objects_Demo_Static_Matrix_Int16, Int16)
SET_MATRIX_VALUE(Demo_Objects_Demo_Static_Matrix_Int32, Int32)
SET_MATRIX_VALUE(Demo_Objects_Demo_Static_Matrix_Int64, Int64)
SET_MATRIX_VALUE(Demo_Objects_Demo_Static_Matrix_LocalizedText, LocalizedText)
SET_MATRIX_VALUE(Demo_Objects_Demo_Static_Matrix_NodeId, NodeId)
SET_MATRIX_VALUE(Demo_Objects_Demo_Static_Matrix_QualifiedName, QualifiedName)
SET_MATRIX_VALUE(Demo_Objects_Demo_Static_Matrix_SByte, SByte)
SET_MATRIX_VALUE(Demo_Objects_Demo_Static_Matrix_StatusCode, StatusCode)
SET_MATRIX_VALUE(Demo_Objects_Demo_Static_Matrix_String, String)
SET_MATRIX_VALUE(Demo_Objects_Demo_Static_Matrix_UInt16, UInt16)
SET_MATRIX_VALUE(Demo_Objects_Demo_Static_Matrix_UInt32, UInt32)
SET_MATRIX_VALUE(Demo_Objects_Demo_Static_Matrix_UInt64, UInt64)
SET_MATRIX_VALUE(Demo_Objects_Demo_Static_Matrix_XmlElement, XmlElement)
/* create Vector structures */
{
OpcUa_Variant *pValue;
OpcUa_Int32 iNumArrayDimensions, i, iNumElements;
OpcUa_UInt32 *pArrayDimensions;
UaBase_CreateStringNodeId(&nodeid, Demo_Objects_Demo_Static_Matrix_Vector);
pNode = UaServer_GetNodeById(&nodeid);
pValue = OpcUa_Variable_GetValue(pNode);
iNumArrayDimensions = OpcUa_Variable_GetNumArrayDimensions(pNode);
pArrayDimensions = OpcUa_Variable_GetArrayDimensions(pNode);
OpcUa_Variant_Clear(pValue);
iNumElements = 1;
pValue->Datatype = OpcUaType_ExtensionObject;
pValue->ArrayType = OpcUa_VariantArrayType_Matrix;
pValue->Value.Matrix.NoOfDimensions = iNumArrayDimensions;
pValue->Value.Matrix.Dimensions = OpcUa_Alloc(iNumArrayDimensions * sizeof(OpcUa_Int32));
for (i = 0; i < iNumArrayDimensions; i++)
{
pValue->Value.Matrix.Dimensions[i] = pArrayDimensions[i];
iNumElements *= pArrayDimensions[i];
}
pValue->Value.Matrix.Value.ExtensionObjectArray = OpcUa_Alloc(iNumElements * sizeof(OpcUa_ExtensionObject));
for (i = 0; i < iNumElements; i++)
{
Demo_Vector *pVector = OpcUa_Null;
OpcUa_ExtensionObject_Initialize(&pValue->Value.Matrix.Value.ExtensionObjectArray[i]);
OpcUa_EncodeableObject_CreateExtension(&Demo_Vector_EncodeableType,
&pValue->Value.Matrix.Value.ExtensionObjectArray[i],
(OpcUa_Void**)&pVector);
}
}
#endif /* !OPCUA_VARIANT_OMIT_MATRIX */
#if HAVE_DATA_LOGGER
UaProvider_Demo_SetupDataLogger();
#endif /* HAVE_DATA_LOGGER */
#if UASERVER_SUPPORT_AUTHORIZATION
UaProvider_Demo_SetupAccessRights();
#endif /* UASERVER_SUPPORT_AUTHORIZATION */
OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;
OpcUa_FinishErrorHandling;
}
void UaProvider_Demo_CleanupSimulation()
{
OpcUa_NodeId nodeid;
#if UASERVER_SUPPORT_EVENTS
UaServer_Event *pEvent = 0;
pEvent = UaServer_Events_GetConditionByNodeId(g_UaProviderDemo_uNamespaceIndex1, &g_machine.TemperatureSensor.HighAlarmId);
if (pEvent) UaServer_Events_DeleteEvent(&pEvent);
pEvent = UaServer_Events_GetConditionByNodeId(g_UaProviderDemo_uNamespaceIndex1, &g_machine.TemperatureSensor.LowAlarmId);
if (pEvent) UaServer_Events_DeleteEvent(&pEvent);
#endif /* UASERVER_SUPPORT_EVENTS */
#if HAVE_DATA_LOGGER
UaProvider_Demo_CleanupDataLogger();
#endif /* HAVE_DATA_LOGGER */
UaBase_CreateStringNodeId(&nodeid, Demo_Objects_Demo_CTT_DA_Profile_DiscreteType_MultiStateDiscrete1);
MultiStateDiscreteRange_Delete(&nodeid);
UaBase_CreateStringNodeId(&nodeid, Demo_Objects_Demo_CTT_DA_Profile_DiscreteType_MultiStateDiscrete2);
MultiStateDiscreteRange_Delete(&nodeid);
UaBase_CreateStringNodeId(&nodeid, Demo_Objects_Demo_CTT_DA_Profile_DiscreteType_MultiStateDiscrete3);
MultiStateDiscreteRange_Delete(&nodeid);
UaBase_CreateStringNodeId(&nodeid, Demo_Objects_Demo_CTT_DA_Profile_DiscreteType_MultiStateDiscrete4);
MultiStateDiscreteRange_Delete(&nodeid);
UaBase_CreateStringNodeId(&nodeid, Demo_Objects_Demo_CTT_DA_Profile_DiscreteType_MultiStateDiscrete5);
MultiStateDiscreteRange_Delete(&nodeid);
}
OpcUa_StatusCode UaProvider_Demo_StartSimulation()
{
OpcUa_StatusCode ret;
if (g_hSimulationTimer != 0) return OpcUa_BadInvalidState;
ret = OpcUa_Timer_Create(
&g_hSimulationTimer,
g_SimulationInterval,
UaProvider_Demo_SimulationTimer,
OpcUa_Null,
OpcUa_Null );
if (g_pSimulationActive)
{
*g_pSimulationActive = OpcUa_True;
}
if (g_pSimulationSpeed)
{
*g_pSimulationSpeed = g_SimulationInterval;
}
return ret;
}
OpcUa_StatusCode UaProvider_Demo_StopSimulation()
{
OpcUa_StatusCode ret;
if (g_hSimulationTimer == 0) return OpcUa_BadInvalidState;
ret = OpcUa_Timer_Delete(&g_hSimulationTimer);
if (g_pSimulationActive)
{
*g_pSimulationActive = OpcUa_False;
}
return ret;
}
OpcUa_StatusCode UaProvider_Demo_SetSimulationSpeed(OpcUa_UInt32 interval)
{
OpcUa_StatusCode ret = OpcUa_Good;
if (interval < 50) interval = 50;
if (interval > 5000) interval = 5000;
if (g_SimulationInterval == interval) return ret;
g_SimulationInterval = interval;
if (g_hSimulationTimer)
{
UaProvider_Demo_StopSimulation();
UaProvider_Demo_StartSimulation();
}
if (g_pSimulationSpeed)
{
*g_pSimulationSpeed = g_SimulationInterval;
}
return ret;
}
static void UaProvider_Demo_SimulateDynamicVariables()
{
static char szText[] = "*** stone - paper - scissors - lizard - spock ";
static char szTmp[] = " ";
static int len = sizeof(szText);
static int pos = 0;
int i;
#define INCREMENT_ARRAY(var, type) \
if (var && var->Length > 0) { \
var->Value.type##Array[0]++; \
for (i = 1; i < var->Length; i++) \
{ \
var->Value.type##Array[i] = var->Value.type##Array[i-1]+1; \
} \
}
/* simulate scalar values */
*g_pDynBoolean = ! *g_pDynBoolean;
(*g_pDynSByte)++;
(*g_pDynByte) -= 3;
(*g_pDynInt16) += 21;
(*g_pDynUInt16) -= 53;
(*g_pDynInt32)++;
(*g_pDynUInt32)++;
(*g_pDynInt64) += 2376452644LL;
(*g_pDynUInt64) -= 987654321ULL;
(*g_pDynFloat) += 0.1f;
(*g_pDynDouble) += 0.1;
(*g_pDynStatusCode)++;
if (++pos >= len-1) pos = 0;
UaBase_strlcpy( szTmp, szText+pos, len-pos );
UaBase_strlcpy( szTmp+len-pos-1, szText, pos+1 );
OpcUa_String_AttachReadOnly( g_pDynString, szTmp);
*g_pDynDateTime = OpcUa_DateTime_UtcNow();
OpcUa_Guid_Create( *g_ppDynGuid );
if (g_pDynByteString->Length <= 0)
{
g_pDynByteString->Length = sizeof(szTmp);
if (g_pDynByteString->Data) OpcUa_Free(g_pDynByteString->Data);
g_pDynByteString->Data = OpcUa_Alloc(sizeof(szTmp));
}
if (g_pDynByteString->Data)
{
OpcUa_MemCpy(
g_pDynByteString->Data, g_pDynByteString->Length,
szTmp, sizeof(szTmp)
);
}
if (g_pDynXmlElement->Length <= 0)
{
g_pDynXmlElement->Length = sizeof(szTmp);
if (g_pDynXmlElement->Data) OpcUa_Free(g_pDynXmlElement->Data);
g_pDynXmlElement->Data = OpcUa_Alloc(sizeof(szTmp));
}
if (g_pDynXmlElement->Data)
{
OpcUa_MemCpy(
g_pDynXmlElement->Data, g_pDynXmlElement->Length,
szTmp, sizeof(szTmp)
);
}
OpcUa_String_AttachReadOnly( &(*g_ppDynLocalizedText)->Text, szTmp);
(*g_ppDynQualifiedName)->NamespaceIndex++;
OpcUa_String_AttachReadOnly( &(*g_ppDynQualifiedName)->Name, szTmp);
(*g_ppDynNodeId)->NamespaceIndex++;
(*g_ppDynNodeId)->IdentifierType = OpcUa_IdentifierType_String;
OpcUa_String_AttachReadOnly( &(*g_ppDynNodeId)->Identifier.String, szTmp);
(*g_ppDynExpandedNodeId)->ServerIndex++;
(*g_ppDynExpandedNodeId)->NodeId.NamespaceIndex++;
(*g_ppDynExpandedNodeId)->NodeId.IdentifierType = OpcUa_IdentifierType_String;
OpcUa_String_AttachReadOnly( &(*g_ppDynExpandedNodeId)->NodeId.Identifier.String, szTmp);
/* simulate array values */
if (g_pDynArrayBoolean && g_pDynArrayBoolean->Length > 0)
{
g_pDynArrayBoolean->Value.BooleanArray[0] = !g_pDynArrayBoolean->Value.BooleanArray[0];
for (i = 1; i < g_pDynArrayBoolean->Length; i++)
{
g_pDynArrayBoolean->Value.BooleanArray[i] = !g_pDynArrayBoolean->Value.BooleanArray[i-1];
}
}
INCREMENT_ARRAY(g_pDynArrayByte, Byte);
INCREMENT_ARRAY(g_pDynArraySByte, SByte);
INCREMENT_ARRAY(g_pDynArrayUInt16, UInt16);
INCREMENT_ARRAY(g_pDynArrayInt16, Int16);
INCREMENT_ARRAY(g_pDynArrayUInt32, UInt32);
INCREMENT_ARRAY(g_pDynArrayInt32, Int32);
INCREMENT_ARRAY(g_pDynArrayUInt64, UInt64);
INCREMENT_ARRAY(g_pDynArrayInt64, Int64);
INCREMENT_ARRAY(g_pDynArrayFloat, Float);
INCREMENT_ARRAY(g_pDynArrayDouble, Double);
INCREMENT_ARRAY(g_pDynArrayStatusCode, StatusCode);
if (g_pDynArrayGuid)
{
for (i = 0; i < g_pDynArrayGuid->Length; i++)
{
OpcUa_Guid_Create(&g_pDynArrayGuid->Value.GuidArray[i]);
}
}
if (g_pDynArrayDateTime)
{
for (i = 0; i < g_pDynArrayDateTime->Length; i++)
{
g_pDynArrayDateTime->Value.DateTimeArray[i] = OpcUa_DateTime_UtcNow();
}
}
if (g_pDynArrayString)
{
for (i = 0; i < g_pDynArrayString->Length; i++)
{
OpcUa_String_AttachReadOnly( &g_pDynArrayString->Value.StringArray[i], szTmp);
}
}
if (g_pDynArrayByteString)
{
for (i = 0; i < g_pDynArrayByteString->Length; i++)
{
if (g_pDynArrayByteString->Value.ByteStringArray[i].Length <= 0)
{
g_pDynArrayByteString->Value.ByteStringArray[i].Length = sizeof(szTmp);
if (g_pDynArrayByteString->Value.ByteStringArray[i].Data) OpcUa_Free(g_pDynArrayByteString->Value.ByteStringArray[i].Data);
g_pDynArrayByteString->Value.ByteStringArray[i].Data = OpcUa_Alloc(sizeof(szTmp));
}
if (g_pDynArrayByteString->Value.ByteStringArray[i].Data)
{
OpcUa_MemCpy(
g_pDynArrayByteString->Value.ByteStringArray[i].Data, g_pDynArrayByteString->Value.ByteStringArray[i].Length,
szTmp, sizeof(szTmp));
}
}
}
if (g_pDynArrayXmlElement)
{
for (i = 0; i < g_pDynArrayXmlElement->Length; i++)
{
if (g_pDynArrayXmlElement->Value.XmlElementArray[i].Length <= 0)
{
g_pDynArrayXmlElement->Value.XmlElementArray[i].Length = sizeof(szTmp);
if (g_pDynArrayXmlElement->Value.XmlElementArray[i].Data) OpcUa_Free(g_pDynArrayXmlElement->Value.XmlElementArray[i].Data);
g_pDynArrayXmlElement->Value.XmlElementArray[i].Data = OpcUa_Alloc(sizeof(szTmp));
}
if (g_pDynArrayXmlElement->Value.XmlElementArray[i].Data)
{
OpcUa_MemCpy(
g_pDynArrayXmlElement->Value.XmlElementArray[i].Data, g_pDynArrayXmlElement->Value.XmlElementArray[i].Length,
szTmp, sizeof(szTmp)
);
}
}
}
if (g_pDynArrayLocalizedText)
{
for (i = 0; i < g_pDynArrayLocalizedText->Length; i++)
{
OpcUa_String_AttachReadOnly( &g_pDynArrayLocalizedText->Value.LocalizedTextArray[i].Text, szTmp);
}
}
if (g_pDynArrayQualifiedName)
{
for (i = 0; i < g_pDynArrayQualifiedName->Length; i++)
{
g_pDynArrayQualifiedName->Value.QualifiedNameArray[i].NamespaceIndex++;
OpcUa_String_AttachReadOnly( &g_pDynArrayQualifiedName->Value.QualifiedNameArray[i].Name, szTmp);
}
}
if (g_pDynArrayNodeId)
{
for (i = 0; i < g_pDynArrayNodeId->Length; i++)
{
g_pDynArrayNodeId->Value.NodeIdArray[i].NamespaceIndex++;
g_pDynArrayNodeId->Value.NodeIdArray[i].IdentifierType = OpcUa_IdentifierType_String;
OpcUa_String_AttachReadOnly( &g_pDynArrayNodeId->Value.NodeIdArray[i].Identifier.String, szTmp);
}
}
if (g_pDynArrayExpandedNodeId)
{
for (i = 0; i < g_pDynArrayExpandedNodeId->Length; i++)
{
g_pDynArrayExpandedNodeId->Value.ExpandedNodeIdArray[i].ServerIndex++;
g_pDynArrayExpandedNodeId->Value.ExpandedNodeIdArray[i].NodeId.NamespaceIndex++;
g_pDynArrayExpandedNodeId->Value.ExpandedNodeIdArray[i].NodeId.IdentifierType = OpcUa_IdentifierType_String;
OpcUa_String_AttachReadOnly( &g_pDynArrayExpandedNodeId->Value.ExpandedNodeIdArray[i].NodeId.Identifier.String, szTmp);
}
}
}
#if UAPROVIDER_DEMO_HAVE_MASS_ITEMS
static void UaProvider_Demo_SimulateMassfolderDynamicVariables()
{
int i;
OpcUa_UInt32 val = *g_pMassDynUInt32[0]+1;
for (i=0; i<UAPROVIDER_DEMO_NUM_MASS_DYNAMIC_VARIABLES; i++)
{
*g_pMassDynUInt32[i] = val;
}
}
#endif /* UAPROVIDER_DEMO_HAVE_MASS_ITEMS */
static void UaProvider_Demo_SimulateHistoryVariables()
{
static int t = 0;
static int mode = 1;
if (g_pHistoryByte) (*g_pHistoryByte) += (OpcUa_Byte)mode;
if (g_pHistoryDouble) (*g_pHistoryDouble) = 90 + 90 * sin(t*M_PI/180.0);
t++;
if ((t % 180) == 0) mode *= -1;
if (t == 360) t = 0;
}
static void UaProvider_Demo_SimulateBoiler( BoilerType *pBoiler )
{
double dtT;
double dtTDeadband = 2;
double C = 4187; /* [J/kgK] */
double dt = 10; /* [s] simulation speed */
double P = 1.5; /* [kW] */
double m;
double J = 1000 * P * dt; /* [J] */
if (pBoiler == 0) return;
if (pBoiler->pTemperature == 0) return;
if (pBoiler->pTemperatureSetPoint == 0) return;
if (pBoiler->pHeaterStatus == 0) return;
dtT = *pBoiler->pTemperature - *pBoiler->pTemperatureSetPoint;
m = *pBoiler->pFillLevel; /* [1l]=[1kg] */
/* heater control */
if ( dtT >= dtTDeadband )
{
*pBoiler->pHeaterStatus = Heater_Off;
}
else
{
*pBoiler->pHeaterStatus = Heater_Heating;
}
/* simulate heater */
if ( *pBoiler->pHeaterStatus == Heater_Heating )
{
if (m > 0)
{
dtT =J / ( C * m );
*pBoiler->pTemperature += dtT;
}
}
else
{
dtT = *pBoiler->pTemperature - 20;
*pBoiler->pTemperature -= dtT / 100.0;
}
/* simulate fill level */
if ( *pBoiler->pFillLevel < *pBoiler->pFillLevelSetPoint )
{
(*pBoiler->pFillLevel)++;
}
else if ( *pBoiler->pFillLevel > *pBoiler->pFillLevelSetPoint )
{
(*pBoiler->pFillLevel)--;
}
}
#if UAPROVIDER_DEMO_HAVE_ANIMATION_ITEM && UABASE_USE_FILESYSTEM
static void UaProvider_Demo_SimulateAnimation()
{
static int frame_counter = 0;
char filename[200] = {0};
FILE *f;
OpcUa_SnPrintfA(filename, sizeof(filename), "animation/animation_%d.gif", frame_counter++);
f = fopen(filename, "rb");
if (f == OpcUa_Null)
{
frame_counter = 0;
OpcUa_SnPrintfA(filename, sizeof(filename), "animation/animation_%d.gif", frame_counter++);
f = fopen(filename, "rb");
}
if (f)
{
if (g_pAnimation->Data == 0)
{
g_pAnimation->Data = OpcUa_Alloc(131072);
}
if (g_pAnimation->Data != 0)
{
g_pAnimation->Length = (OpcUa_Int32)fread(g_pAnimation->Data, 1, 131072, f);
}
fclose(f);
}
}
#endif /* UAPROVIDER_DEMO_HAVE_ANIMATION_ITEM && UABASE_USE_FILESYSTEM */
IFMETHODIMP(UaProvider_Demo_SimulationTimer)(
OpcUa_Void* a_pvCallbackData,
OpcUa_Timer a_hTimer,
OpcUa_UInt32 a_msecElapsed )
{
OpcUa_ReferenceParameter(a_pvCallbackData);
OpcUa_ReferenceParameter(a_hTimer);
OpcUa_ReferenceParameter(a_msecElapsed);
#if UAPROVIDER_DEMO_HAVE_ANIMATION_ITEM && UABASE_USE_FILESYSTEM
UaProvider_Demo_SimulateAnimation();
#endif /* UAPROVIDER_DEMO_HAVE_ANIMATION_ITEM && UABASE_USE_FILESYSTEM */
UaProvider_Demo_SimulateDynamicVariables();
UaProvider_Demo_SimulateHistoryVariables();
#if UAPROVIDER_DEMO_HAVE_MASS_ITEMS
UaProvider_Demo_SimulateMassfolderDynamicVariables();
#endif /* UAPROVIDER_DEMO_HAVE_MASS_ITEMS */
UaProvider_Demo_SimulateBoiler(&g_Boiler1);
#if UASERVER_SUPPORT_EVENTS
UaProvider_Demo_SimulateMachine(&g_machine);
#endif /* UASERVER_SUPPORT_EVENTS */
return OpcUa_Good;
}
#if UASERVER_SUPPORT_EVENTS
OpcUa_StatusCode UaProvider_Demo_SendModelChangeEvent(OpcUa_BaseNode *pParent, OpcUa_Byte verb)
{
OpcUa_StatusCode ret = OpcUa_Good;
OpcUa_NodeId *pParentId = OpcUa_Null;
UaServer_Event *pEvent = OpcUa_Null;
OpcUa_ModelChangeStructureDataType *pModelChanges = OpcUa_Null;
OpcUa_QualifiedName *pParentBrowseName = OpcUa_Null;
OpcUa_DateTime utcNow = OpcUa_DateTime_UtcNow();
OpcUa_ByteString bsEventId;
OpcUa_Variant modelChanges;
OpcUa_NodeId typeId;
OpcUa_ByteString_Initialize(&bsEventId);
OpcUa_Variant_Initialize(&modelChanges);
OpcUa_NodeId_Initialize(&typeId);
pParentId = OpcUa_BaseNode_GetId(pParent);
pParentBrowseName = OpcUa_BaseNode_GetBrowseName(pParent);
typeId.Identifier.Numeric = OpcUaId_GeneralModelChangeEventType;
pEvent = UaServer_Events_CreateEvent(&typeId);
UaServer_Events_SetEventType(pEvent, &typeId);
UaServer_Events_SetSourceNode(pEvent, pParentId);
UaServer_Events_SetSourceName(pEvent, OpcUa_String_GetRawString(&pParentBrowseName->Name));
UaServer_Events_SetMessage(pEvent, "", "The address space model has changed");
UaServer_Events_CreateEventId(OpcUa_Null, &bsEventId);
UaServer_Events_SetEventId(pEvent, &bsEventId);
OpcUa_ByteString_Clear(&bsEventId);
UaServer_Events_SetTime(pEvent, utcNow);
modelChanges.Datatype = OpcUaType_ExtensionObject;
modelChanges.ArrayType = OpcUa_VariantArrayType_Array;
modelChanges.Value.Array.Length = 1;
modelChanges.Value.Array.Value.ExtensionObjectArray = (OpcUa_ExtensionObject*)OpcUa_Alloc(modelChanges.Value.Array.Length * sizeof(OpcUa_ExtensionObject));
OpcUa_ExtensionObject_Initialize(&modelChanges.Value.Array.Value.ExtensionObjectArray[0]);
OpcUa_EncodeableObject_CreateExtension(&OpcUa_ModelChangeStructureDataType_EncodeableType,
&modelChanges.Value.Array.Value.ExtensionObjectArray[0],
(OpcUa_Void**)&pModelChanges);
pModelChanges->Verb = verb;
OpcUa_NodeId_CopyTo(pParentId, &pModelChanges->Affected);
pModelChanges->AffectedType.Identifier.Numeric = OpcUaId_FolderType;
UaServer_Events_SetEventField(pEvent, GeneralModelChangeEventTypeField_Changes, &modelChanges);
OpcUa_Variant_Clear(&modelChanges);
return ret;
}
OpcUa_Void UaProvider_Demo_SimulateMachine(Machine *a_pMachine)
{
OpcUa_Boolean *pSwitch = a_pMachine->HeaterSwitch.pValue;
OpcUa_Double *pTemp = a_pMachine->TemperatureSensor.pValue;
OpcUa_Double oldTemperature = *pTemp;
/* simulate sensors of a_pMachine */
if (*pSwitch == OpcUa_True && *pTemp < 110.0)
{
*pTemp += 0.5;
}
else if (*pSwitch == OpcUa_False && *pTemp > -10.0)
{
*pTemp -= 0.5;
}
/* check if the temperature has over-/underrun certain values and fire events if necessary */
if (oldTemperature < 100 && *pTemp >= 100)
{
UaServer_Event *pHighAlarm = UaServer_Events_GetConditionByNodeId(
g_UaProviderDemo_uNamespaceIndex1,
&a_pMachine->TemperatureSensor.HighAlarmId);
if (pHighAlarm)
UaProvider_Demo_FireAlarmConditionTypeEvent(pHighAlarm);
}
if (oldTemperature > 0 && *pTemp <= 0)
{
UaServer_Event *pLowAlarm = UaServer_Events_GetConditionByNodeId(
g_UaProviderDemo_uNamespaceIndex1,
&a_pMachine->TemperatureSensor.LowAlarmId);
if (pLowAlarm)
UaProvider_Demo_FireAlarmConditionTypeEvent(pLowAlarm);
}
if (oldTemperature >= 100 && *pTemp < 100)
{
UaServer_Event *pHighAlarm = UaServer_Events_GetConditionByNodeId(
g_UaProviderDemo_uNamespaceIndex1,
&a_pMachine->TemperatureSensor.HighAlarmId);
if (pHighAlarm)
UaProvider_Demo_DisableAlarmConditionTypeEvent(pHighAlarm);
}
if (oldTemperature <= 0 && *pTemp > 0)
{
UaServer_Event *pLowAlarm = UaServer_Events_GetConditionByNodeId(
g_UaProviderDemo_uNamespaceIndex1,
&a_pMachine->TemperatureSensor.LowAlarmId);
if (pLowAlarm)
UaProvider_Demo_DisableAlarmConditionTypeEvent(pLowAlarm);
}
}
#endif /* UASERVER_SUPPORT_EVENTS */
OPCUA_END_EXTERN_C