ANSI C UA Server SDK  1.6.0.341
 All Data Structures Functions Variables Typedefs Enumerations Enumerator Modules Pages
ANSI C SDK Demo Server

The ANSI C SDK Demo Server is a collection of examples for developing different features of an OPC UA server and contains the Unified Automation Demo address space with nodes in the Demo folder.

The complete project can be found in Examples → UA Demo Server Project.

Command Line Arguments

The Demo Server application is able to recognize a set of command line arguments. On Linux systems, the native getopt implementation is used, on Windows, the pthread-win32 compatibility library is used which provides a getopt implementation for Windows.

The following command line arguments are recognized:

Usage: uaserverc.exe [-h] [-v] [-n <hostname>] [-c <config file>] [-d] [-s <shutdown delay>]
  -h: Shows this help
  -v: Shows detailed version information
  -n: Sets the hostname to bind on
  -c: Sets the configuration file to use (default=settings.ini)
  -d: For each 'd' argument, the trace level is increased by one (e.g. '-ddd' for INFO)
  -s: Sets the shutdown delay in seconds (default=3)

The sample code can be found in the files

Structured Data Type Example

The demo address space code contains generated sample code for the handling of structured data types. A method with a structured type as parameter can be found in Objects → Demo → 003_Method → VectorAdd. This methods takes two parameters of type Demo_Vector and adds them.

The sample code can be found in the files

The structured data type nodes and the dictionary are created in the functions UaProvider_Demo_AddDictionary() and UaProvider_Demo_AddVector().

Custom encodeable types are not registered at the UaStack anymore, as doing do leads to problems when reinitializing the SDK during runtime. Instead, following functions can be used to (de-)serialize values of custom encodeable types:

  • UaBase_Structure_To_ExtensionObject
  • UaBase_Structures_To_ExtensionObjects
  • UaBase_Structures_To_Variant
  • UaBase_Structure_From_ExtensionObject
  • UaBase_Structures_From_ExtensionObjects

The method arguments are checked for validity and extracted in the function UaProvider_Demo_Method_CallVectorAdd(). From there the function UaProvider_Demo_Method_VectorAdd() is called, this is where the actual addition is executed.

Historical Data Access Example

The demo address space code contains sample code for the handling of historical data access. The variables providing history can be found in Objects → Demo → 002_History. The data changes are monitored with internal monitored items and are stored in a file store using the “datalogger” module.

The sample code can be found in the files

The data logger is instantiated and initialized using the settings in the function UaProvider_Demo_SetupDataLogger():

g_hDataLogger = UaServer_FileLogger_Create( szDataLoggerPath );

After that, the internal history monitored items are created using the function UaProvider_Demo_HistorizeItem():

/* create datalog item if it does not already exist. */
iSamplingInterval,
monitoringMode,
100,
OpcUa_Null,
g_hDataLogger,
&g_hDataLogItemDouble);
if (OpcUa_IsBad(uStatus) != OpcUa_False)
{
OpcUa_Free(pUserDataHistoryDataLogger);
OpcUa_ReturnError(uStatus);
}

The data log item information is stored in the user data of the nodes in order to retrieve the history for these items later in the function UaProvider_Demo_HistoryReadRawModifiedAsync:

HistoryDataLogger *pLoggerData = (HistoryDataLogger*)pUserData;
pLoggerData->DataLogger,
pLoggerData->DataLogItem,
a_pHistoryReadRawModifiedCtx->pHistoryReadRawModifiedDetails,
a_pHistoryReadRawModifiedCtx->TimestampsToReturn,
a_pHistoryReadRawModifiedCtx->ReleaseContinuationPoints,
&a_pHistoryReadRawModifiedCtx->pNodesToRead[i],
pHistoryResult,
a_pHistoryReadRawModifiedCtx->RequestHeader.TimeoutHint);
a_pHistoryReadRawModifiedCtx->pResponse->Results[i].StatusCode = ret;

Model Change Event Example

The demo address space code contains sample code for dynamic creation of nodes including model change event. The folder with the functionality can be found in Objects → Demo → 008_DynamicNodes. This folder contains two methods for node creation and deletion, a NodeVersion property and the dynamic node. Only nodes with a NodeVersion property are allowed to fire specific model change events of type GeneralModelChangeEventType. This event indicates the changed nodes with a NodeVersion property and the changes (node added/deleted, reference added/deleted).

Changes of nodes without NodeVersion property can be indicated by using the BaseModelChangeEvent. But this event does not indicate which part of the address space has changed.

The sample code can be found in the files

The full sample code for the generation of the model change event can be found in the method UaProvider_Demo_SendModelChangeEvent(). The following code is the essential part of the event generation.

modelChanges.Datatype = OpcUaType_ExtensionObject;
modelChanges.ArrayType = OpcUa_VariantArrayType_Array;
modelChanges.Value.Array.Value.ExtensionObjectArray = (OpcUa_ExtensionObject*)OpcUa_Alloc(1 * sizeof(OpcUa_ExtensionObject));
OpcUa_ReturnErrorIfAllocFailed(modelChanges.Value.Array.Value.ExtensionObjectArray);
modelChanges.Value.Array.Length = 1;
OpcUa_ExtensionObject_Initialize(&modelChanges.Value.Array.Value.ExtensionObjectArray[0]);
ret = OpcUa_EncodeableObject_CreateExtension(&OpcUa_ModelChangeStructureDataType_EncodeableType,
&modelChanges.Value.Array.Value.ExtensionObjectArray[0],
(OpcUa_Void**)&pModelChanges);
OpcUa_ReturnErrorIfBad(ret);
pModelChanges->Verb = verb;
OpcUa_NodeId_CopyTo(pParentId, &pModelChanges->Affected);
pModelChanges->AffectedType.Identifier.Numeric = OpcUaId_FolderType;
UaServer_Events_SetEventField(pEvent, GeneralModelChangeEventTypeField_Changes, &modelChanges);

The sample code creates only one change. If more than one node with a NodeVersion property is affected, all changes should be combined in one event.

Adding custom settings

The SDK brings the option to load its configuration from a settings backend, by default using a settings file. Using the function UaServer_Settings_GetConfigurationFromSettings the SDK is configured using the passed UaBase_Settings structure.

Applications and providers can extend the configuration with their own custom settings as needed; the demo provider adds settings for the data logger as an example.

The sample code can be found in the file

The settings file delivered with the SDK contains one additional section [DemoProvider] which contains the custom settings. The $ENV{} placeholder is dynamically replaced with the content of the accordant environment variable by the settings module:

[DemoProvider]
# Start logging on startup
StartLogging = false
# Folder to contain the logged data
DataLoggerPath = $ENV{ALLUSERSPROFILE}/UnifiedAutomation/UaSdkAnsiCServerPro/historian

In the function UaProvider_Demo_SetupDataLogger a UaBase_Settings structure is initialized with the name of the settings file. On Windows “settings.ini” is used, on all other operating systems “settings.conf”. Using this settings object the custom settings are retrieved and used for initializing the data logger:

#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), "");