nauful / LibUA

Open-source OPC UA client and server library
Apache License 2.0
262 stars 94 forks source link

Method call with arguments #29

Closed maveyx closed 4 years ago

maveyx commented 4 years ago

Dear @nauful,

Thank you again for your freely available code!

Regarding the server implementation: I'm currently trying to support InputArguments/OutputArguments for a NodeMethod, which I added successfully according to https://github.com/nauful/LibUA/issues/23.

I was able to add the reference nodes to my NodeMethod "method":

// argument nodes
method.References.Add(new ReferenceNode(new NodeId(UAConst.HasProperty), new NodeId(UAConst.InputArguments), false));
method.References.Add(new ReferenceNode(new NodeId(UAConst.HasProperty), new NodeId(UAConst.OutputArguments), false));

However, I don't know how to add, for example, a string InputArgument to "method". I just found the "Argument = 296" definition in Types.cs but I think I lack understanding how to add InputArguments here.

Any advice is very much appreciated.

Thank you very much!

nauful commented 4 years ago

Hello,

Always glad to see that my work has been useful.

Perhaps the OPC UA documentation on method call modelling in the UA namespace has more information for semantic correctness but I've never needed it.

On the client side, you have: public StatusCode Call(CallMethodRequest[] requests, out CallMethodResult[] results)

On the server side, look at: protected int DispatchMessage_CallRequest(SLChannel config, RequestHeader reqHeader, MemoryBuffer recvBuf, uint messageSize)

I haven't implemented a standard way of handling these on the server side, but look at https://github.com/nauful/LibUA/issues/23 as one way to do it.

CallMethodRequest is defined as

public class CallMethodRequest
{
    public CallMethodRequest(NodeId ObjectId, NodeId MethodId, object[] InputArguments) ...
}

So the parameters are just an array of objects encoded as UA variant types. You don't need to define them yourself. As a client, just populate them as you wish (i.e. array of integers boxed as objects), and as a server, decode them as an array of variant types.

maveyx commented 4 years ago

Dear @nauful, Thank you very much for your advice!

How would you return OutputArguments in this case?

nauful commented 4 years ago

OutputArguments can be returned to the caller in this way (last part): https://github.com/nauful/LibUA/issues/23#issuecomment-636353463

Off the top of my head, it should be similar to this:

for (uint i = 0; i < NoofMethodsToCall; i++)
{
    var resp = app.HandleMethodCall(reqs[i]);
    succeeded &= respBuf.Encode((UInt32)StatusCode.Good);
    // InputArgumentResults: Array of StatusCode
    succeeded &= respBuf.Encode((UInt32)resps.NumStatusCodes);
    ... Encode each status code, then 0, then the number of result variants, then each result variant