.NET Based OPC UA Client/Server SDK  2.6.0.418
Lesson 4: Adding Support for Methods

Introduction

In the previous Lesson 3: Connecting the Nodes to Real Time Data we connected the variables in our address space to real word data.

This example shows how to add the implementation of the OPC UA Methods of the instances in our address space. Calling the methods will trigger actions in our underlying system.

Address the Methods

We need to be able to find the implementation that has to be called if a method is called. In this example, we define a class that addresses the method in the underlying system.

The underlying system has a fixed set of methods. We are using an integer variable to identify the method.

private class SystemFunction
{
public int Address;
public int Function;
}

This class is used to assign user data to Method nodes after object creation in Startup().

// set addressing information for method nodes that allows them to be called.
SetChildUserData(
new NodeId(block.Name, InstanceNamespaceIndex),
new QualifiedName(yourorganisation.BA.BrowseNames.Start, TypeNamespaceIndex),
new SystemFunction() { Address = block.Address, Function = 1 });
SetChildUserData(
new NodeId(block.Name, InstanceNamespaceIndex),
new QualifiedName(yourorganisation.BA.BrowseNames.Stop, TypeNamespaceIndex),
new SystemFunction() { Address = block.Address, Function = 2 });
SetChildUserData(
new NodeId(block.Name, InstanceNamespaceIndex),
new QualifiedName(yourorganisation.BA.BrowseNames.StartWithSetPoint, TypeNamespaceIndex),
new SystemFunction() { Address = block.Address, Function = 3 });

Implement Method Handling

For method calls the NodeManager has override the GetMethodDispatcher method to find the right method handler. In this example, we check if the MethodData of the methodHandle is an instance of the class we used as user data in the last step.

protected override CallMethodEventHandler GetMethodDispatcher(
RequestContext context,
MethodHandle methodHandle)
{
if (methodHandle.MethodData is SystemFunction)
{
return DispatchControllerMethod;
}
return null;
}

In the returned method handle we are using the address data to get the device address and the function of the underlying system to call.

Functions 1 and 2 do not have any method arguments. Function 3 expects input arguments. The SDK guarantees that the DataType and the ValueRank of the input arguments are correct, so we can access the inputArguments without further type checks.

private StatusCode DispatchControllerMethod(
RequestContext context,
MethodHandle methodHandle,
IList<Variant> inputArguments,
List<StatusCode> inputArgumentResults,
List<Variant> outputArguments)
{
SystemFunction data = methodHandle.MethodData as SystemFunction;
if (data != null)
{
switch (data.Function)
{
case 1:
{
return m_system.Start(data.Address);
}
case 2:
{
return m_system.Stop(data.Address);
}
case 3:
{
return m_system.StartWithSetPoint(data.Address, inputArguments[0].ToDouble(), inputArguments[1].ToDouble());
}
}
}
return StatusCodes.BadNotImplemented;
}

Calling Method from UaExpert

After compiling and starting the server we can call the Methods from UaExpert. Calling Stop changes the State to 0 (OFF), calling Start changes State to 1 (ON).

Figure 4.1:

serverlesson04_expert.png