Files
open62541/examples/tutorial_server_alarms_conditions.c
Urs Fässler c7c57e9aba fix: create condition source object with a parent
Without a parent, the error "Node for event must be in ObjectsFolder!"
occurs when an event is sent.
2020-01-15 17:19:31 +01:00

525 lines
24 KiB
C

/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
* See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
#include <open62541/plugin/log_stdout.h>
#include <open62541/server.h>
#include <open62541/server_config_default.h>
#include <signal.h>
#include <stdlib.h>
/**
* Using Alarms and Conditions Server
* -----------------
* Besides the usage of monitored items and events to observe the changes in the server, it is also important to
* make use of the Alarms and Conditions Server Model. Alarms are events which are triggered automatically by the server
* dependent on internal server logic or user specific logic when the state of server components change.
* The state of a component is represented through a condition. So the values of all the condition children (Fields)
* are the actual state of the component.
*
* Trigger Alarm events by changing States
* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
* The following example will be based on the server events tutorial. Please make sure to understand the principle
* of normal events before proceeding with this example!
**/
static UA_NodeId conditionSource;
static UA_NodeId conditionInstance_1;
static UA_NodeId conditionInstance_2;
static UA_StatusCode
addConditionSourceObject(UA_Server *server) {
UA_ObjectAttributes object_attr = UA_ObjectAttributes_default;
object_attr.eventNotifier = 1;
object_attr.displayName = UA_LOCALIZEDTEXT("en", "ConditionSourceObject");
UA_StatusCode retval = UA_Server_addObjectNode(server, UA_NODEID_NULL,
UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
UA_QUALIFIEDNAME(0, "ConditionSourceObject"),
UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
object_attr, NULL, &conditionSource);
if(retval != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
"creating Condition Source failed. StatusCode %s", UA_StatusCode_name(retval));
}
/* ConditionSource should be EventNotifier of another Object (usually the Server Object).
* If this Reference is not created by user then the A&C Server will create "HasEventSource"
* reference to the Server Object automatically when the condition is created*/
retval = UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER),
UA_NODEID_NUMERIC(0, UA_NS0ID_HASNOTIFIER),
UA_EXPANDEDNODEID_NUMERIC(conditionSource.namespaceIndex,
conditionSource.identifier.numeric),
UA_TRUE);
return retval;
}
/**
* create a condition instance from OffNormalAlarmType. The condition source is the Object created in
* addConditionSourceObject(). The condition will be exposed in Address Space through the HasComponent
* reference to the condition source.
*/
static UA_StatusCode
addCondition_1(UA_Server *server) {
UA_StatusCode retval = addConditionSourceObject(server);
if(retval != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
"creating Condition Source failed. StatusCode %s", UA_StatusCode_name(retval));
}
retval = UA_Server_createCondition(server,
UA_NODEID_NULL, UA_NODEID_NUMERIC(0, UA_NS0ID_OFFNORMALALARMTYPE),
UA_QUALIFIEDNAME(0, "Condition 1"), conditionSource,
UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), &conditionInstance_1);
return retval;
}
/**
* create a condition instance from OffNormalAlarmType. The condition source is the server Object.
* The condition won't be exposed in Address Space.
*/
static UA_StatusCode
addCondition_2(UA_Server *server) {
UA_StatusCode retval = UA_Server_createCondition(server,
UA_NODEID_NULL, UA_NODEID_NUMERIC(0, UA_NS0ID_OFFNORMALALARMTYPE),
UA_QUALIFIEDNAME(0, "Condition 2"), UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER),
UA_NODEID_NULL, &conditionInstance_2);
return retval;
}
static void
addVariable_1_triggerAlarmOfCondition_1(UA_Server *server, UA_NodeId* outNodeId) {
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("en", "Activate Condition 1");
attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
UA_Boolean tboolValue = UA_FALSE;
UA_Variant_setScalar(&attr.value, &tboolValue, &UA_TYPES[UA_TYPES_BOOLEAN]);
UA_QualifiedName CallbackTestVariableName = UA_QUALIFIEDNAME(0, "Activate Condition 1");
UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
UA_NodeId variableTypeNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE);
UA_Server_addVariableNode(server, UA_NODEID_NULL, parentNodeId,
parentReferenceNodeId, CallbackTestVariableName,
variableTypeNodeId, attr, NULL, outNodeId);
}
static void
addVariable_2_changeSeverityOfCondition_2(UA_Server *server, UA_NodeId* outNodeId) {
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("en", "Change Severity Condition 2");
attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
UA_UInt16 severityValue = 0;
UA_Variant_setScalar(&attr.value, &severityValue, &UA_TYPES[UA_TYPES_UINT16]);
UA_QualifiedName CallbackTestVariableName = UA_QUALIFIEDNAME(0, "Change Severity Condition 2");
UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
UA_NodeId variableTypeNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE);
UA_Server_addVariableNode(server, UA_NODEID_NULL, parentNodeId,
parentReferenceNodeId, CallbackTestVariableName,
variableTypeNodeId, attr, NULL, outNodeId);
}
static void
addVariable_3_returnCondition_1_toNormalState(UA_Server *server, UA_NodeId* outNodeId) {
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("en", "Return to Normal Condition 1");
attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
UA_Boolean rtn = 0;
UA_Variant_setScalar(&attr.value, &rtn, &UA_TYPES[UA_TYPES_BOOLEAN]);
UA_QualifiedName CallbackTestVariableName = UA_QUALIFIEDNAME(0, "Return to Normal Condition 1");
UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
UA_NodeId variableTypeNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE);
UA_Server_addVariableNode(server, UA_NODEID_NULL, parentNodeId,
parentReferenceNodeId, CallbackTestVariableName,
variableTypeNodeId, attr, NULL, outNodeId);
}
static void
afterWriteCallbackVariable_1(UA_Server *server,
const UA_NodeId *sessionId, void *sessionContext,
const UA_NodeId *nodeId, void *nodeContext,
const UA_NumericRange *range, const UA_DataValue *data) {
UA_QualifiedName activeStateField = UA_QUALIFIEDNAME(0,"ActiveState");
UA_QualifiedName activeStateIdField = UA_QUALIFIEDNAME(0,"Id");
UA_Variant value;
UA_StatusCode retval = UA_Server_writeObjectProperty_scalar(server, conditionInstance_1, UA_QUALIFIEDNAME(0, "Time"),
&data->sourceTimestamp, &UA_TYPES[UA_TYPES_DATETIME]);
if(*(UA_Boolean *)(data->value.data) == true) {
/**
* by writing "true" in ActiveState/Id, the A&C server will set the related fields
* automatically and then will trigger event notification.
*/
UA_Boolean activeStateId = true;
UA_Variant_setScalar(&value, &activeStateId, &UA_TYPES[UA_TYPES_BOOLEAN]);
retval |= UA_Server_setConditionVariableFieldProperty(server, conditionInstance_1,
&value, activeStateField, activeStateIdField);
if(retval != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
"Setting ActiveState/Id Field failed. StatusCode %s", UA_StatusCode_name(retval));
return;
}
}
else {
/**
* by writing "false" in ActiveState/Id, the A&C server will set only the ActiveState field
* automatically to the value "Inactive". The user should trigger the event manually by calling
* UA_Server_triggerConditionEvent inside the application or call
* ConditionRefresh method with client to update the event notification.
*/
UA_Boolean activeStateId = false;
UA_Variant_setScalar(&value, &activeStateId, &UA_TYPES[UA_TYPES_BOOLEAN]);
retval = UA_Server_setConditionVariableFieldProperty(server, conditionInstance_1,
&value, activeStateField, activeStateIdField);
if(retval != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
"Setting ActiveState/Id Field failed. StatusCode %s", UA_StatusCode_name(retval));
return;
}
retval = UA_Server_triggerConditionEvent(server, conditionInstance_1, conditionSource, NULL);
if(retval != UA_STATUSCODE_GOOD) {
UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
"Triggering condition event failed. StatusCode %s", UA_StatusCode_name(retval));
return;
}
}
}
/**
* the callback only changes the severity field of the condition 2. The severity
* field is of ConditionVariableType, so changes in it triggers an event notification
* automatically by the server.
*/
static void
afterWriteCallbackVariable_2(UA_Server *server,
const UA_NodeId *sessionId, void *sessionContext,
const UA_NodeId *nodeId, void *nodeContext,
const UA_NumericRange *range, const UA_DataValue *data) {
/**
* another way to set fields of conditions
*/
UA_Server_writeObjectProperty_scalar(server, conditionInstance_2, UA_QUALIFIEDNAME(0, "Severity"),
(UA_UInt16 *)data->value.data, &UA_TYPES[UA_TYPES_UINT16]);
}
/**
* RTN = return to normal.
* Retain will be set to false, thus no events will be generated for condition 1 (although EnabledState/=true).
* To set Retain to true again, the disable and enable methods should be called respectively.
*/
static void
afterWriteCallbackVariable_3(UA_Server *server,
const UA_NodeId *sessionId, void *sessionContext,
const UA_NodeId *nodeId, void *nodeContext,
const UA_NumericRange *range, const UA_DataValue *data) {
//UA_QualifiedName enabledStateField = UA_QUALIFIEDNAME(0,"EnabledState");
UA_QualifiedName ackedStateField = UA_QUALIFIEDNAME(0,"AckedState");
UA_QualifiedName confirmedStateField = UA_QUALIFIEDNAME(0,"ConfirmedState");
UA_QualifiedName activeStateField = UA_QUALIFIEDNAME(0,"ActiveState");
UA_QualifiedName severityField = UA_QUALIFIEDNAME(0,"Severity");
UA_QualifiedName messageField = UA_QUALIFIEDNAME(0,"Message");
UA_QualifiedName commentField = UA_QUALIFIEDNAME(0,"Comment");
UA_QualifiedName retainField = UA_QUALIFIEDNAME(0,"Retain");
UA_QualifiedName idField = UA_QUALIFIEDNAME(0,"Id");
UA_StatusCode retval = UA_Server_writeObjectProperty_scalar(server, conditionInstance_1, UA_QUALIFIEDNAME(0, "Time"),
&data->serverTimestamp, &UA_TYPES[UA_TYPES_DATETIME]);
UA_Variant value;
UA_Boolean idValue = false;
UA_Variant_setScalar(&value, &idValue, &UA_TYPES[UA_TYPES_BOOLEAN]);
retval |= UA_Server_setConditionVariableFieldProperty(server, conditionInstance_1,
&value, activeStateField, idField);
if(retval != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
"Setting ActiveState/Id Field failed. StatusCode %s", UA_StatusCode_name(retval));
return;
}
retval = UA_Server_setConditionVariableFieldProperty(server, conditionInstance_1,
&value, ackedStateField, idField);
if(retval != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
"Setting AckedState/Id Field failed. StatusCode %s", UA_StatusCode_name(retval));
return;
}
retval = UA_Server_setConditionVariableFieldProperty(server, conditionInstance_1,
&value, confirmedStateField, idField);
if(retval != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
"Setting ConfirmedState/Id Field failed. StatusCode %s", UA_StatusCode_name(retval));
return;
}
UA_UInt16 severityValue = 100;
UA_Variant_setScalar(&value, &severityValue, &UA_TYPES[UA_TYPES_UINT16]);
retval = UA_Server_setConditionField(server, conditionInstance_1,
&value, severityField);
if(retval != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
"Setting Severity Field failed. StatusCode %s", UA_StatusCode_name(retval));
return;
}
UA_LocalizedText messageValue = UA_LOCALIZEDTEXT("en", "Condition returned to normal state");
UA_Variant_setScalar(&value, &messageValue, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
retval = UA_Server_setConditionField(server, conditionInstance_1,
&value, messageField);
if(retval != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
"Setting Message Field failed. StatusCode %s", UA_StatusCode_name(retval));
return;
}
UA_LocalizedText commentValue = UA_LOCALIZEDTEXT("en", "Normal State");
UA_Variant_setScalar(&value, &commentValue, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
retval = UA_Server_setConditionField(server, conditionInstance_1,
&value, commentField);
if(retval != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
"Setting Comment Field failed. StatusCode %s", UA_StatusCode_name(retval));
return;
}
UA_Boolean retainValue = false;
UA_Variant_setScalar(&value, &retainValue, &UA_TYPES[UA_TYPES_BOOLEAN]);
retval = UA_Server_setConditionField(server, conditionInstance_1,
&value, retainField);
if(retval != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
"Setting Retain Field failed. StatusCode %s", UA_StatusCode_name(retval));
return;
}
retval = UA_Server_triggerConditionEvent(server, conditionInstance_1, conditionSource, NULL);
if (retval != UA_STATUSCODE_GOOD) {
UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
"Triggering condition event failed. StatusCode %s", UA_StatusCode_name(retval));
return;
}
}
static UA_StatusCode
enteringEnabledStateCallback(UA_Server *server, const UA_NodeId *condition) {
UA_Boolean retain = UA_TRUE;
return UA_Server_writeObjectProperty_scalar(server, *condition, UA_QUALIFIEDNAME(0, "Retain"),
&retain, &UA_TYPES[UA_TYPES_BOOLEAN]);
}
/**
* this is user specific function which will be called upon acknowledging an alarm notification.
* In this example we will set the Alarm to Inactive state. The server is responsible of setting
* standard fields related to Acknowledge Method and triggering the alarm notification.
*/
static UA_StatusCode
enteringAckedStateCallback(UA_Server *server, const UA_NodeId *condition) {
/* deactivate Alarm when acknowledging*/
UA_Boolean activeStateId = false;
UA_Variant value;
UA_QualifiedName activeStateField = UA_QUALIFIEDNAME(0,"ActiveState");
UA_QualifiedName activeStateIdField = UA_QUALIFIEDNAME(0,"Id");
UA_Variant_setScalar(&value, &activeStateId, &UA_TYPES[UA_TYPES_BOOLEAN]);
UA_StatusCode retval = UA_Server_setConditionVariableFieldProperty(server, *condition,
&value, activeStateField, activeStateIdField);
if(retval != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
"Setting ActiveState/Id Field failed. StatusCode %s", UA_StatusCode_name(retval));
}
return retval;
}
static UA_StatusCode
enteringConfirmedStateCallback(UA_Server *server, const UA_NodeId *condition) {
/* deactivate Alarm and put it out of the interesting state (by writing false to Retain field) when confirming*/
UA_Boolean activeStateId = false;
UA_Boolean retain = false;
UA_Variant value;
UA_QualifiedName activeStateField = UA_QUALIFIEDNAME(0,"ActiveState");
UA_QualifiedName activeStateIdField = UA_QUALIFIEDNAME(0,"Id");
UA_QualifiedName retainField = UA_QUALIFIEDNAME(0,"Retain");
UA_Variant_setScalar(&value, &activeStateId, &UA_TYPES[UA_TYPES_BOOLEAN]);
UA_StatusCode retval = UA_Server_setConditionVariableFieldProperty(server, *condition,
&value, activeStateField, activeStateIdField);
if(retval != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
"Setting ActiveState/Id Field failed. StatusCode %s", UA_StatusCode_name(retval));
return retval;
}
UA_Variant_setScalar(&value, &retain, &UA_TYPES[UA_TYPES_BOOLEAN]);
retval = UA_Server_setConditionField(server, *condition,
&value, retainField);
if(retval != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
"Setting ActiveState/Id Field failed. StatusCode %s", UA_StatusCode_name(retval));
}
return retval;
}
static UA_StatusCode
setUpEnvironment(UA_Server *server) {
UA_NodeId variable_1;
UA_NodeId variable_2;
UA_NodeId variable_3;
UA_ValueCallback callback;
callback.onRead = NULL;
/**
* exposed condition 1. We will add to it user specific callbacks when entering enabled state,
* when acknowledging and when confirming
*/
UA_StatusCode retval = addCondition_1(server);
if(retval != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
"adding condition 1 failed. StatusCode %s", UA_StatusCode_name(retval));
return retval;
}
UA_TwoStateVariableChangeCallback userSpecificCallback = enteringEnabledStateCallback;
retval = UA_Server_setConditionTwoStateVariableCallback(server, conditionInstance_1,
conditionSource, false, userSpecificCallback,
UA_ENTERING_ENABLEDSTATE);
if(retval != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
"adding entering enabled state callback failed. StatusCode %s", UA_StatusCode_name(retval));
return retval;
}
userSpecificCallback = enteringAckedStateCallback;
retval = UA_Server_setConditionTwoStateVariableCallback(server, conditionInstance_1,
conditionSource, false, userSpecificCallback,
UA_ENTERING_ACKEDSTATE);
if(retval != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
"adding entering acked state callback failed. StatusCode %s", UA_StatusCode_name(retval));
return retval;
}
userSpecificCallback = enteringConfirmedStateCallback;
retval = UA_Server_setConditionTwoStateVariableCallback(server, conditionInstance_1,
conditionSource, false, userSpecificCallback,
UA_ENTERING_CONFIRMEDSTATE);
if(retval != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
"adding entering confirmed state callback failed. StatusCode %s", UA_StatusCode_name(retval));
return retval;
}
/**
* unexposed condition 2. No user specific callbacks, so the server will behave in a standard manner
* upon entering enabled state, acknowledging and confirming.
* We will set Retain field to true and enable the condition so we can receive event
* notifications (we cannot call enable method on unexposed condition using a
* client like UaExpert or Softing).
*/
retval = addCondition_2(server);
if(retval != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
"adding condition 2 failed. StatusCode %s", UA_StatusCode_name(retval));
return retval;
}
UA_Boolean retain = UA_TRUE;
UA_Server_writeObjectProperty_scalar(server, conditionInstance_2, UA_QUALIFIEDNAME(0, "Retain"),
&retain, &UA_TYPES[UA_TYPES_BOOLEAN]);
UA_Variant value;
UA_Boolean enabledStateId = true;
UA_QualifiedName enabledStateField = UA_QUALIFIEDNAME(0,"EnabledState");
UA_QualifiedName enabledStateIdField = UA_QUALIFIEDNAME(0,"Id");
UA_Variant_setScalar(&value, &enabledStateId, &UA_TYPES[UA_TYPES_BOOLEAN]);
retval = UA_Server_setConditionVariableFieldProperty(server, conditionInstance_2,
&value, enabledStateField, enabledStateIdField);
if(retval != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
"Setting EnabledState/Id Field failed. StatusCode %s", UA_StatusCode_name(retval));
return retval;
}
/**
* add 3 variables to trigger condition events
*/
addVariable_1_triggerAlarmOfCondition_1(server, &variable_1);
callback.onWrite = afterWriteCallbackVariable_1;
retval = UA_Server_setVariableNode_valueCallback(server, variable_1, callback);
if(retval != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
"setting variable 1 Callback failed. StatusCode %s", UA_StatusCode_name(retval));
return retval;
}
/**
* severity can change internally also when the condition disabled and retain is false. However,
* in this case no events will be generated.
*/
addVariable_2_changeSeverityOfCondition_2(server, &variable_2);
callback.onWrite = afterWriteCallbackVariable_2;
retval = UA_Server_setVariableNode_valueCallback(server, variable_2, callback);
if(retval != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
"setting variable 2 Callback failed. StatusCode %s", UA_StatusCode_name(retval));
return retval;
}
addVariable_3_returnCondition_1_toNormalState(server, &variable_3);
callback.onWrite = afterWriteCallbackVariable_3;
retval = UA_Server_setVariableNode_valueCallback(server, variable_3, callback);
if(retval != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
"setting variable 3 Callback failed. StatusCode %s", UA_StatusCode_name(retval));
}
return retval;
}
/** It follows the main server code, making use of the above definitions. */
static UA_Boolean running = true;
static void stopHandler(int sig) {
running = false;
}
int main (void) {
/* default server values */
signal(SIGINT, stopHandler);
signal(SIGTERM, stopHandler);
UA_Server *server = UA_Server_new();
UA_ServerConfig_setDefault(UA_Server_getConfig(server));
UA_StatusCode retval = setUpEnvironment(server);
if(retval == UA_STATUSCODE_GOOD)
{
retval = UA_Server_run(server, &running);
}
UA_Server_delete(server);
return retval == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE;
}