Hello (and thanks for the great work with open62541),
I've the following scenario, see enclosed source code at the end.
1. Create server object (done with UA_Server_new())
2. Create a new ObjectType (done with defineObjectTypes())
*
* BaseObjectType
* |
* +- (OT) PortType
* + (V) Name - Name is a static variable. Added with UA_Server_addVariableNode()
* + (V) Pkts - Pkts is a dynamic variable which needs to be read (on the server)
every time it is browsed by the client. Added with
UA_Server_addDataSourceVariableNode(...,read_pkt,...)
*/
2. Instantiate 2 ports (done with addPortObjectInstance(server, "Port-1") and addPortObjectInstance(server, "Port-2"))
3. Run server
4. Browse the server with a client e.g. UAExpert
So everything works fine. I can browse the 2 created ports. Both "Port-1" and "Port-2" and I see the DataVariables "Name" and "Pkts".
Also everytime when "Pkts" is browsed the read_pkt() function is called.
The problem is the following; How can I detect from inside read_pkt() whether "Port-1"->"Pkts" or "Port-2"->"Pkts" has called the function?
What I have is the nodeId inside read_pkt() but I do not know if it belongs to instance "Port-1" or to instance "Port-2". Is there a way to get
that info?
Thanks and Best Regards,
Quebert
<--- source begin -->
#include <open62541/plugin/log_stdout.h>
#include <open62541/server.h>
#include <open62541/server_config_default.h>
#include <signal.h>
#include <stdlib.h>
UA_Boolean running = true;
UA_NodeId portTypeNodeId;
static void stopHandler(int sig) {
running = false;
}
static UA_StatusCode
read_pkt(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
const UA_NodeId *nodeId, void *nodeContext, UA_Boolean sourceTimeStamp,
const UA_NumericRange *range, UA_DataValue *dataValue) {
dataValue->hasValue = true;
return UA_STATUSCODE_GOOD;
}
static void
defineObjectTypes(UA_Server *server) {
UA_NodeId nodeId;
/* Define the object type for "PortType" */
UA_ObjectTypeAttributes oAttr = UA_ObjectTypeAttributes_default;
oAttr.description = UA_LOCALIZEDTEXT("en-US", "A Port Type");
oAttr.displayName = UA_LOCALIZEDTEXT("en-US", "PortType");
UA_Server_addObjectTypeNode(server,
UA_NODEID_NULL,
UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
UA_QUALIFIEDNAME(1, "PortType"),
oAttr,
NULL,
&portTypeNodeId);
/* Add attributes to PortType */
UA_VariableAttributes vAttr = UA_VariableAttributes_default;
vAttr.description = UA_LOCALIZEDTEXT("en-US", "A Port Name");
vAttr.displayName = UA_LOCALIZEDTEXT("en-US", "Name");
UA_Server_addVariableNode( server,
UA_NODEID_NULL,
portTypeNodeId,
UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
UA_QUALIFIEDNAME(1, "Name"),
UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
vAttr,
NULL,
&nodeId
);
/* Make the port name mandatory */
UA_Server_addReference( server,
nodeId,
UA_NODEID_NUMERIC(0, UA_NS0ID_HASMODELLINGRULE),
UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_MODELLINGRULE_MANDATORY), true);
/* Add attributes to PortType */
vAttr.description = UA_LOCALIZEDTEXT("en-US", "Packets");
vAttr.displayName = UA_LOCALIZEDTEXT("en-US", "Pkts");
UA_DataSource pc;
pc.read = read_pkt;
pc.write = NULL;
UA_Server_addDataSourceVariableNode(server,
UA_NODEID_NULL,
portTypeNodeId,
UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
UA_QUALIFIEDNAME(1, "Pkts"),
UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
vAttr,
pc,
NULL,
&nodeId
);
/* Make the port name mandatory */
UA_Server_addReference( server,
nodeId,
UA_NODEID_NUMERIC(0, UA_NS0ID_HASMODELLINGRULE),
UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_MODELLINGRULE_MANDATORY), true);
}
static void
addPortObjectInstance(UA_Server *server, char *name) {
UA_NodeId nodeId;
UA_ObjectAttributes oAttr = UA_ObjectAttributes_default;
oAttr.description = UA_LOCALIZEDTEXT("en-US", name);
oAttr.displayName = UA_LOCALIZEDTEXT("en-US", name);
UA_Server_addObjectNode(server,
UA_NODEID_NULL,
UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
UA_QUALIFIEDNAME(1, name),
portTypeNodeId,
oAttr,
NULL,
&nodeId
);
}
int main(void) {
signal(SIGINT, stopHandler);
signal(SIGTERM, stopHandler);
UA_Server *server = UA_Server_new();
UA_ServerConfig_setDefault(UA_Server_getConfig(server));
/* Create a rudimentary objectType
*
* BaseObjectType
* |
* +- (OT) PortType
* + (V) Name
* + (V) Pkts
*/
defineObjectTypes(server);
/* Instantiate ports, "Port-1" and "Port-2"
* (O) Objects
* + O Port <PortType>
* + Name
* + Pkts
*/
addPortObjectInstance(server, "Port-1");
addPortObjectInstance(server, "Port-2");
UA_StatusCode retval = UA_Server_run(server, &running);
UA_Server_delete(server);
return retval == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE;
}
<-- source end -->