How to detect which instance of an object called the callback?

391 views
Skip to first unread message

Quebert Que

unread,
May 17, 2019, 11:03:27 AM5/17/19
to open62541

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 -->





bgrieco...@gmail.com

unread,
Jul 2, 2019, 9:04:42 AM7/2/19
to open62541

Hello Quebert,

There are some ways for solving that.
The easiest is returning a node-ID on the addPortObjectInstance function and storing it for further comparison.
Or
In the callback, search for the Name Attribute Node-Id starting on the Node-Id that you received and read this attribute.
Or
In the callback, search for the Node-Id of "Port-1" and "Port-2" and compare it with whatever you received.

Best Regards

Bruno

Quebert Que

unread,
Jul 24, 2019, 8:09:11 AM7/24/19
to open62541
Hello Bruno,

thank you for your answers.
Storing the node-ID in addPortObjectInstance is what I also considered but does not help me in that particular case
as it returns the nodeID of a portType but not of a particular nodeID ("Pkts") of a variable of that portType.
Searching by using UA_BrowsePath worked but I wanted to avoid to search every time a node gets selected.

I have now the following solution which works for me quite well. In addPortObjectInstance instead of using
UA_Server_addObjectNode() I now use UA_Server_addNode_begin, UA_Server_addDataSourceVariableNode and UA_Server_addNode_finish
to create the objects/variables. When calling UA_Server_addDataSourceVariableNode a nodeContext is added which can be used in
read_pkt by using UA_Server_getNodeContext. Instead of doing this here storing the nodeID UA_Server_addDataSourceVariableNode
returns and comparing in read_pkt would also be possible but the one with the context works better for me.

Thanks for you thoughts and hints,
 Best regards,
  Quebert
Reply all
Reply to author
Forward
0 new messages