|
@@ -0,0 +1,116 @@
|
|
|
|
+#include <open62541/server.h>
|
|
|
|
+#include <open62541/plugin/log_stdout.h>
|
|
|
|
+#include "helper_functions.h"
|
|
|
|
+#include <libconfig.h>
|
|
|
|
+// C++ includes
|
|
|
|
+#include <iostream>
|
|
|
|
+
|
|
|
|
+using namespace std;
|
|
|
|
+UA_StatusCode setVariable(UA_Server* server, void *value, const UA_DataType *dataType, UA_NodeId variableNodeid) {
|
|
|
|
+ UA_StatusCode res;
|
|
|
|
+ UA_Variant var;
|
|
|
|
+ UA_Variant_setScalar(&var, value, dataType);
|
|
|
|
+ res = UA_Server_writeValue(server, variableNodeid, var);
|
|
|
|
+ if(res != UA_STATUSCODE_GOOD)
|
|
|
|
+ UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Failed to init variable node NS=%d,i=%d. Error: %s\n", variableNodeid.namespaceIndex, variableNodeid.identifier.numeric, UA_StatusCode_name(res));
|
|
|
|
+ return res;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+UA_StatusCode setEURangeVariable(UA_Server* server, UA_Double low, UA_Double high, UA_NodeId euRangeVariableNodeid) {
|
|
|
|
+ UA_StatusCode res;
|
|
|
|
+ UA_Range range;
|
|
|
|
+ UA_Range_init(&range);
|
|
|
|
+ range.low = low;
|
|
|
|
+ range.high = high;
|
|
|
|
+ res = setVariable(server, &range, &UA_TYPES[UA_TYPES_RANGE], euRangeVariableNodeid);
|
|
|
|
+ if(res != UA_STATUSCODE_GOOD)
|
|
|
|
+ UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Failed to set range for node NS=%d,i=%d. Error: %s\n", euRangeVariableNodeid.namespaceIndex, euRangeVariableNodeid.identifier.numeric, UA_StatusCode_name(res));
|
|
|
|
+ return res ;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// UA State-machine handling
|
|
|
|
+bool inState(UA_Server* server, UA_NodeId currentStateIdNodeId, UA_NodeId stateNodeId) {
|
|
|
|
+ UA_Variant out;
|
|
|
|
+ UA_Variant_init(&out);
|
|
|
|
+ UA_Server_readValue(server, currentStateIdNodeId, &out);
|
|
|
|
+ UA_NodeId *currentStateId = (UA_NodeId*)(out.data);
|
|
|
|
+ if(UA_NodeId_equal(currentStateId, &stateNodeId))
|
|
|
|
+ return true;
|
|
|
|
+ return false;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+UA_StatusCode setCurrentState(UA_Server *server, UA_NodeId currentStateVariableNodeId, UA_NodeId currentStateVariableIdNodeId, UA_NodeId newStateNodeId) {
|
|
|
|
+ // set the Id property of the CurrentState variable to newStateNodeId
|
|
|
|
+ UA_Variant var;
|
|
|
|
+ UA_Variant_init(&var);
|
|
|
|
+ UA_Variant_setScalar(&var, &newStateNodeId, &UA_TYPES[UA_TYPES_NODEID]);
|
|
|
|
+ UA_Server_writeValue(server, currentStateVariableIdNodeId, var);
|
|
|
|
+
|
|
|
|
+ // set the CurrentState variable to a human-readable string
|
|
|
|
+ UA_LocalizedText stateName;
|
|
|
|
+ UA_LocalizedText_init(&stateName);
|
|
|
|
+ UA_Server_readDisplayName(server, newStateNodeId, &stateName);
|
|
|
|
+ UA_Variant_setScalar(&var, &stateName, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
|
|
|
|
+ UA_Server_writeValue(server, currentStateVariableNodeId, var);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+// Configuration file handling
|
|
|
|
+bool getIntFromConfig(const config_t* cfg, const char* name, int *res) {
|
|
|
|
+ if (!config_lookup_int(cfg, name, res)) {
|
|
|
|
+ cerr << "No " << name << " setting in configuration file." << endl;
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ return true;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+bool getBoolFromConfig(const config_t* cfg, const char* name, bool *res) {
|
|
|
|
+ int resInt;
|
|
|
|
+ *res = false;
|
|
|
|
+ if (!config_lookup_bool(cfg, name, &resInt)) {
|
|
|
|
+ cerr << "No " << name << " setting in configuration file." << endl;
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ if (resInt != 0)
|
|
|
|
+ *res = true;
|
|
|
|
+
|
|
|
|
+ return true;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+bool getStringFromConfig(const config_t* cfg, const char* name, char **res) {
|
|
|
|
+ if (!config_lookup_string(cfg, name, (const char **) res)) {
|
|
|
|
+ cerr << "No " << name << " setting in configuration file." << endl;
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ return true;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+bool getStringListFromConfig(const config_t* cfg, const char* name, char **res, int *listLength) {
|
|
|
|
+ config_setting_t *setting = config_lookup(cfg, name);
|
|
|
|
+ *listLength = config_setting_length(setting);
|
|
|
|
+
|
|
|
|
+ if (*listLength == 0) {
|
|
|
|
+ cerr << "No " << name << " setting in configuration file or wrong format. Note that a list of strings should look like this: (\"item1\", \"item2\")." << endl;
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ for(int i = 0; i < *listLength; i++){
|
|
|
|
+ const char *elem = config_setting_get_string_elem (setting, i);
|
|
|
|
+ if (elem == NULL) {
|
|
|
|
+ cerr << "No " << name << " setting in configuration file or wrong format. Note that a list of strings should look like this: (\"item1\", \"item2\")." << endl;
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ res[i] = strdup(elem);
|
|
|
|
+ }
|
|
|
|
+ return true;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+bool getDoubleFromConfig(const config_t* cfg, const char* name, double *res) {
|
|
|
|
+ if (!config_lookup_float(cfg, name, res)) {
|
|
|
|
+ cerr << "No " << name << " setting in configuration file." << endl;
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ return true;
|
|
|
|
+}
|
|
|
|
+
|