Refactored the node adding and added an interval option.
authorPat Thoyts <pat.thoyts@gmail.com>
Wed, 28 Jun 2023 05:55:11 +0000 (06:55 +0100)
committerPat Thoyts <pat.thoyts@gmail.com>
Wed, 28 Jun 2023 05:55:11 +0000 (06:55 +0100)
opc_app.h
opc_util.c
server.c

index 65a4600a353a98f3be0c317fc72ef722cddfd1b4..bc40944558746862f0af8430e6c79858601cbbb8 100644 (file)
--- a/opc_app.h
+++ b/opc_app.h
@@ -21,17 +21,16 @@ typedef struct {
     float *ilist;
 } App;
 
-UA_StatusCode add_float(App *app, UA_NodeId parentNode,
-    const char *name, const char *displayName, UA_Float value);
-UA_StatusCode add_int32(App *app, UA_NodeId parentNode,
-    const char *name, const char *displayName, UA_Int32 value);
-UA_StatusCode add_int64(App *app, UA_NodeId parentNode,
-    const char *name, const char *displayName, UA_Int64 value);
-UA_StatusCode add_float_vector(App *app, UA_NodeId parentNode,
-    const char *name, const char *displayName, size_t len, UA_Float *value);
+UA_StatusCode add_scalar(App *app, UA_NodeId parentNode,
+    const char *fullname, const char *displayName,
+    void *value, const UA_DataType *valueType);
 UA_StatusCode add_object_node(App *app, UA_NodeId parentNode,
-    const char *name, const char *displayName,
+    const char *fullname, const char *displayName,
     UA_NodeId *newNodeId);
+UA_StatusCode add_vector(App *app, UA_NodeId parentNode,
+    const char *fullname, const char *displayName,
+    size_t len, UA_Float *value, const UA_DataType *valueType);
+
 UA_StatusCode update_scalar(App *app, UA_NodeId nodeId, void *valuePtr, const UA_DataType *typePtr);
 UA_StatusCode update_float_vector(App *app, UA_NodeId nodeId, size_t len, const float *vector);
 UA_StatusCode update_xlist(App *app);
index c70f3c5a42882dd0bd53719214d394a7575ff180..43083bd252e9f3c6dbdf06cee97275e922f096fb 100644 (file)
@@ -4,77 +4,58 @@
 #include "opc_app.h"
 #include "wdf_utils.h"
 
-UA_StatusCode add_float(App *app, UA_NodeId parentNode, const char *name, const char *displayName, UA_Float value)
+static UA_StatusCode addVariableNode(UA_Server *server, UA_Int16 nsIndex, UA_NodeId parentNode,
+    const char *fullname, const char *displayName, const UA_VariableAttributes attr)
 {
-    UA_VariableAttributes attr = UA_VariableAttributes_default;
-    if (displayName != NULL)
-        attr.displayName = UA_LOCALIZEDTEXT_ALLOC("en-US", displayName);
-    UA_Variant_setScalar(&attr.value, &value, &UA_TYPES[UA_TYPES_FLOAT]);
+    const char *name = strrchr(fullname, '.');
+    name = (name == NULL) ? fullname : name + 1;
 
-    char id[64] = {0};
-    strcat(id, "renishaw.spd.");
-    strcat(id, name);
-
-    UA_NodeId nodeId = UA_NODEID_STRING(app->ns, id);
+    UA_NodeId nodeId = UA_NODEID_STRING_ALLOC(nsIndex, fullname);
     UA_NodeId parentRefId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
     UA_NodeId varType = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE);
-    UA_QualifiedName browseName = UA_QUALIFIEDNAME_ALLOC(app->ns, name);
+    UA_QualifiedName browseName = UA_QUALIFIEDNAME_ALLOC(nsIndex, displayName);
 
     return UA_Server_addVariableNode(
-        app->server, nodeId, parentNode, parentRefId, browseName,
+        server, nodeId, parentNode, parentRefId, browseName,
         varType, attr, NULL, NULL);
 }
 
-UA_StatusCode add_int32(App *app, UA_NodeId parentNode, const char *name, const char *displayName, UA_Int32 value)
+UA_StatusCode add_scalar(App *app, UA_NodeId parentNode, const char *fullname, const char *displayName, void *value, const UA_DataType *valueType)
 {
+    // create a variant with the data and datatype and the display name
     UA_VariableAttributes attr = UA_VariableAttributes_default;
     if (displayName != NULL)
         attr.displayName = UA_LOCALIZEDTEXT_ALLOC("en-US", displayName);
-    UA_Variant_setScalar(&attr.value, &value, &UA_TYPES[UA_TYPES_INT32]);
-
-    char id[64] = {0};
-    strcat(id, "renishaw.spd.");
-    strcat(id, name);
-
-    UA_NodeId nodeId = UA_NODEID_STRING_ALLOC(app->ns, id);
-    UA_NodeId parentRefId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
-    UA_NodeId varType = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE);
-    UA_QualifiedName browseName = UA_QUALIFIEDNAME_ALLOC(app->ns, name);
-
-    return UA_Server_addVariableNode(
-        app->server, nodeId, parentNode, parentRefId, browseName,
-        varType, attr, NULL, NULL);
+    UA_Variant_setScalar(&attr.value, value, valueType);
+    return addVariableNode(app->server, app->ns, parentNode, fullname, displayName, attr);
 }
 
-UA_StatusCode add_int64(App *app, UA_NodeId parentNode, const char *name, const char *displayName, UA_Int64 value)
+UA_StatusCode add_vector(App *app, UA_NodeId parentNode, const char *fullname, const char *displayName, size_t len, UA_Float *value, const UA_DataType *valueType)
 {
+    UA_Int32 dims = (UA_Int32)len;
     UA_VariableAttributes attr = UA_VariableAttributes_default;
+    attr.valueRank = UA_VALUERANK_ONE_DIMENSION;
+    attr.arrayDimensions = &dims;
+    attr.arrayDimensionsSize = 1;
     if (displayName != NULL)
         attr.displayName = UA_LOCALIZEDTEXT_ALLOC("en-US", displayName);
-    UA_Variant_setScalar(&attr.value, &value, &UA_TYPES[UA_TYPES_INT64]);
-
-    char id[64] = {0};
-    strcat(id, "renishaw.spd.");
-    strcat(id, name);
-
-    UA_NodeId nodeId = UA_NODEID_STRING_ALLOC(app->ns, id);
-    UA_NodeId parentRefId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
-    UA_NodeId varType = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE);
-    UA_QualifiedName browseName = UA_QUALIFIEDNAME_ALLOC(app->ns, name);
-
-    return UA_Server_addVariableNode(
-        app->server, nodeId, parentNode, parentRefId, browseName,
-        varType, attr, NULL, NULL);
+    UA_Variant_setArray(&attr.value, value, len, valueType);
+    return addVariableNode(app->server, app->ns, parentNode, fullname, displayName, attr);
 }
 
 UA_StatusCode add_object_node(App *app,
     UA_NodeId parentNode,
-    const char *name, const char *displayName,
+    const char *fullname, const char *displayName,
     UA_NodeId *newNodeId)
 {
+    const char *name = strrchr(fullname, '.');
+    name = (name == NULL) ? fullname : name + 1;
+
     UA_ObjectAttributes attr = UA_ObjectAttributes_default;
+    if (displayName != NULL)
+        attr.displayName = UA_LOCALIZEDTEXT_ALLOC("en-US", displayName);
     return UA_Server_addObjectNode(app->server,
-        UA_NODEID_STRING_ALLOC(app->ns, name),
+        UA_NODEID_STRING_ALLOC(app->ns, fullname),
         parentNode,
         UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
         UA_QUALIFIEDNAME_ALLOC(app->ns, displayName),
@@ -82,31 +63,6 @@ UA_StatusCode add_object_node(App *app,
         attr, NULL, newNodeId);
 }
 
-UA_StatusCode add_float_vector(App *app, UA_NodeId parentNode, const char *name, const char *displayName, size_t len, UA_Float *value)
-{
-    UA_Int32 dims = (UA_Int32)len;
-    UA_VariableAttributes attr = UA_VariableAttributes_default;
-    attr.valueRank = UA_VALUERANK_ONE_DIMENSION;
-    attr.arrayDimensions = &dims;
-    attr.arrayDimensionsSize = 1;
-    if (displayName != NULL)
-        attr.displayName = UA_LOCALIZEDTEXT_ALLOC("en-US", displayName);
-    UA_Variant_setArray(&attr.value, value, len, &UA_TYPES[UA_TYPES_FLOAT]);
-
-    char id[64] = {0};
-    strcat(id, "renishaw.spd.");
-    strcat(id, name);
-
-    UA_NodeId nodeId = UA_NODEID_STRING_ALLOC(app->ns, id);
-    UA_NodeId parentRefId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
-    UA_NodeId varType = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE);
-    UA_QualifiedName browseName = UA_QUALIFIEDNAME_ALLOC(app->ns, name);
-
-    return UA_Server_addVariableNode(
-        app->server, nodeId, parentNode, parentRefId, browseName,
-        varType, attr, NULL, NULL);
-}
-
 UA_StatusCode update_float_vector(App *app, UA_NodeId nodeId, size_t len, const float *vector)
 {
     UA_Variant value;
@@ -131,7 +87,7 @@ UA_StatusCode update_xlist(App *app)
         ssize_t count = wdf_read_xlist(app->filehandle, app->hdr.npoints, app->xlist);
         if (count > 0)
         {
-            UA_NodeId node = UA_NODEID_STRING_ALLOC(app->ns, "renishaw.spd.xlist");
+            UA_NodeId node = UA_NODEID_STRING_ALLOC(app->ns, "renishaw.spd.spectrum.xlist");
             status = update_float_vector(app, node, app->hdr.npoints, app->xlist);
         }
     }
@@ -143,7 +99,7 @@ UA_StatusCode update_ilist(App *app)
     WdfBlock section = {0};
     uint64_t pos = wdf_find_section(app->filehandle, WDF_BLOCKID_DATA, WDF_BLOCKID_ANY, &section);
     wdf_read_spectrum(app->filehandle, pos, app->hdr.npoints, app->spectrumIndex, app->ilist);
-    UA_NodeId node = UA_NODEID_STRING_ALLOC(app->ns, "renishaw.spd.ilist");
+    UA_NodeId node = UA_NODEID_STRING_ALLOC(app->ns, "renishaw.spd.spectrum.ilist");
     return update_float_vector(app, node, app->hdr.npoints, app->ilist);
 }
 
index 7f73ac3f58a3c22ba555ab2fe569dbabcde50518..e5648b9e613205c4ba0ef7a524cd7618650d3c42 100644 (file)
--- a/server.c
+++ b/server.c
@@ -36,7 +36,7 @@ static void on_interrupt(int signo)
 
 static int usage(int exitCode)
 {
-    fprintf(stderr, "usage: opc_server ?-port NUM? ?-register? FILENAME\n");
+    fprintf(stderr, "usage: opc_server ?-port NUM? ?-register? ?-interval MS? FILENAME\n");
     exit(exitCode);
 }
 
@@ -62,7 +62,7 @@ static void getSpectrumCallback(UA_Server *server, void *clientData)
         update_xlist(app);
     update_ilist(app);
 
-    UA_NodeId node = UA_NODEID_STRING_ALLOC(app->ns, "renishaw.spd.index");
+    UA_NodeId node = UA_NODEID_STRING_ALLOC(app->ns, "renishaw.spd.spectrum.index");
     update_scalar(app, node, &app->spectrumIndex, &UA_TYPES[UA_TYPES_INT64]);
 
     ++app->spectrumIndex;
@@ -70,11 +70,41 @@ static void getSpectrumCallback(UA_Server *server, void *clientData)
         app->spectrumIndex = 0;
 }
 
+static UA_StatusCode add_nodes(App *app)
+{
+    // Add new object node for our data as Renishaw
+    UA_NodeId mainNode, spdNode;
+    UA_StatusCode status = add_object_node(app, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), "renishaw", "Renishaw", &mainNode);
+    if (UA_StatusCode_isGood(status))
+        status = add_object_node(app, mainNode, "renishaw.spd", "SPD", &spdNode);
+    if (UA_StatusCode_isGood(status))
+        status = add_scalar(app, spdNode, "renishaw.spd.nspectra", "Capacity", &app->hdr.nspectra, &UA_TYPES[UA_TYPES_INT64]);
+    if (UA_StatusCode_isGood(status))
+        status = add_scalar(app, spdNode, "renishaw.spd.ncollected", "Count", &app->hdr.ncollected, &UA_TYPES[UA_TYPES_INT64]);
+    if (UA_StatusCode_isGood(status))
+        status = add_scalar(app, spdNode, "renishaw.spd.npoints", "Points", &app->hdr.npoints, &UA_TYPES[UA_TYPES_INT32]);
+    if (UA_StatusCode_isGood(status))
+        status = add_scalar(app, spdNode, "renishaw.spd.laserwavenum", "Laser Wavenumber", &app->hdr.laserwavenum, &UA_TYPES[UA_TYPES_FLOAT]);
+    if (UA_StatusCode_isGood(status))
+    {
+        UA_NodeId spectrumNode;
+        status = add_object_node(app, spdNode, "renishaw.spd.spectrum", "Spectrum", &spectrumNode);
+        if (UA_StatusCode_isGood(status))
+            status = add_scalar(app, spectrumNode, "renishaw.spd.spectrum.index", "Index", &app->spectrumIndex, &UA_TYPES[UA_TYPES_INT64]);
+        if (UA_StatusCode_isGood(status))
+            status = add_vector(app, spectrumNode, "renishaw.spd.spectrum.xlist", "XList", app->hdr.npoints, app->xlist, &UA_TYPES[UA_TYPES_FLOAT]);
+        if (UA_StatusCode_isGood(status))
+            status = add_vector(app, spectrumNode, "renishaw.spd.spectrum.ilist", "IList", app->hdr.npoints, app->ilist, &UA_TYPES[UA_TYPES_FLOAT]);
+    }
+    return status;
+}
+
 int main(int argc, char** argv)
 {
     App application = {0};
     App *app = &application;
     unsigned short port = 4840;
+    unsigned int interval = 1000;
     const char *filename = argv[argc - 1];
 
     {
@@ -90,6 +120,11 @@ int main(int argc, char** argv)
             {
                 app->regUri = DISCOVERY_SERVER_ENDPOINT;
             }
+            else if (strncmp("-interval", argv[n], 9) == 0)
+            {
+                interval = strtoul(argv[n+1], NULL, 0);
+                ++n;
+            }
             else
                 break;
         }
@@ -133,31 +168,9 @@ int main(int argc, char** argv)
     config->mdnsConfig.mdnsServerName = UA_String_fromChars("Renishaw Demo");
 #endif
 
-    // Add new object node for our data as Renishaw
-    UA_NodeId mainNode, spdNode;
-    if (UA_StatusCode_isGood(status))
-        status = add_object_node(app, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), "renishaw", "Renishaw", &mainNode);
-    if (UA_StatusCode_isGood(status))
-        status = add_object_node(app, mainNode, "renishaw.spd", "SPD", &spdNode);
-    if (UA_StatusCode_isGood(status))
-        status = add_int32(app, spdNode, "nspectra", "Capacity", (int32_t)app->hdr.nspectra);
-    if (UA_StatusCode_isGood(status))
-        status = add_int32(app, spdNode, "ncollected", "Count", (int32_t)app->hdr.ncollected);
     if (UA_StatusCode_isGood(status))
-        status = add_int32(app, spdNode, "npoints", "Points", app->hdr.npoints);
-    if (UA_StatusCode_isGood(status))
-        status = add_float(app, spdNode, "laserwavenum", "Laser Wavenumber", app->hdr.laserwavenum);
-    if (UA_StatusCode_isGood(status))
-    {
-        UA_NodeId spectrumNode;
-        status = add_object_node(app, spdNode, "renishaw.spd.spectrum", "Spectrum", &spectrumNode);
-        if (UA_StatusCode_isGood(status))
-            status = add_int64(app, spectrumNode, "index", "Index", app->spectrumIndex);
-        if (UA_StatusCode_isGood(status))
-            status = add_float_vector(app, spectrumNode, "xlist", "XList", app->hdr.npoints, app->xlist);
-        if (UA_StatusCode_isGood(status))
-            status = add_float_vector(app, spectrumNode, "ilist", "IList", app->hdr.npoints, app->ilist);
-    }
+        status = add_nodes(app);
+
     if (UA_StatusCode_isGood(status))
     {
         if (app->regUri != NULL)
@@ -176,7 +189,7 @@ int main(int argc, char** argv)
 
     /* Add a repeated callback to the server */
     if (UA_StatusCode_isGood(status))
-        status = UA_Server_addRepeatedCallback(app->server, getSpectrumCallback, app, 1000, NULL);
+        status = UA_Server_addRepeatedCallback(app->server, getSpectrumCallback, app, interval, NULL);
 
     if (UA_StatusCode_isGood(status))
         status = UA_Server_run(app->server, &is_running);