Details of the SDK

Thread model.

The SDK is designed to run in multithreaded mode. It needs 2 categories of threads: IO threads to handle sending/receiving TCP messages, and threads to process callbaks. Number of threads for each category can be set in the SDK initialization function call void OWA::OpcUa::Utils::initSdk(int numberOfIoThreads = 1, int numberOfCallbackThreads = 1);.

I/O threads.

At least one thread is used for TCP communications.

Callback threads

The SDK performs callbacks when different kinds of events occur: when state of the connection is changed, OPC UA request is complete, or when publish response is received. These callbacks are made from threads different than I/O threads, and belong to separate thread pool.

Access to the thread pool.

The SDK provides access to the thread pool so the application can use it too. The instance of the thread pool can be retrieved by calling function std::shared_ptr<ThreadPool> Utils::getThreadPool();. To add new tasks to the pool, method enqueue is used.

Timer

To run tasks (functions) at certiain point of time in the future, the SDK uses Timer class. This class creates own thread to maintain list of tasks. Tasks launched in threads belonging to the Timer Thread Pool. The instance if the Timer class can be retrieved by calling of the function std::shared_ptr<Timer> Utils::getTimer();. Tasks can be added by using of its add method, which returns identifier of the task. To remove tasks, call method remove, which accepts timer identifier as argument. Note that if the task is already running, it cannot be canceled.

Particularly, Timer is used by the SDK to schedule periodic calls of Read requests to check OPC UA Servers state, or to reconnect when communication with the server is closed un-expectedly.

Initialization and clean-up.

To initialize the SDK use the function Utils::initSDK.

To free all resources used by the SDK use function Utils::cleanSDK.

Connection class

The Connection class is major entry point for OPC UA Client functionality of the SDK. Instances of the class are created by calling static create method of it. This method have a few overrides, with different types of arguments.

In simplest use case, it is enough to define Endpoint URL of the OPC UA Server to which you want to connect.

Fine turning of connection settings.

For more detailed control of connection settings, the struct ClientConfiguration can be used. In turn, this struct has members defining different aspects of connection to the server, such as information about the client application (member applicationDesctiption), about the server (member serverInfo), about application instance certificate (member certificateSettings), and others such as timeouts for different types of requests, settings at transport level, etc.

Smart connection and re-connections

In order to make sure that the SDK connects to the desired server, enough information should be given. It is possible to define this information in different ways. The most common way is using of the Endpoint URL. But in fact server can change endpoints after their configuration change. For example, port number or even host name can be changed. The SDK has built-in logic to find correct server based on additional settings such as server URI, application name, discovery URL, and using discovery services FindServers and GetEndpoints. The GetEndpoints request is also used to retrieve server certificate for connections in secured mode, and to retrieve user identity policy ID.

When connection with the server is lost, the SDK can re-discover the server’s endpoint, using discovery URL and other information about the server, and re-connect to it, after its restart or endpoint URL change.

Note

If there are subscriptions and monitored items created on the server, they will be re-created by the SDK automatically after re-connection.

How to connect to the server

In order to initiate connection process asynchronously, call method Connection::connect, on the instance of the Connection class. It takes optional argument - a function, wich will be called when connection process is completed. The method returns shared std::future type object, with argument of OperationResult type. It is possible to call its get method, to wait until connection process completion - so in this way the SDK can be used synchronously.

How to disconnect from the server.

To disconnect from the server, call method Connection::disconnect.

Request and response structs

Once connection with OPC UA server is established, user application can start calling OPC UA Services, such as Browse, Read, Write, etc.

To represent OPC UA Services, structs with the same name are used. For example, to call Browse request, instance of the Browse struct is used.

Note

Almost always arguments are passed and returned using smart pointers, particularly std::shared_ptr. This guarantees that instances of objects exist while they are in use and deleted after going out of scope.

Note

Request and reponse structs practically exactly mimic OPC UA Services as described in OPC UA Specification Part 4: they have the same name for members, as defined in the spec.

How to call OPC UA Services

  • Create instance of the struct of desired type.

  • Call Connection::send method. Optionally callback function can be passed - it will be called when the response for the request is received from the server. When this callback function is called, both original request and received response are passed as arguments. So, for the user application there is no need to keep original request. The send method returns std::future object with type of the response. This future object can be stored somewhere if required to get the result of completion later.

  • Call result can be obtained in 2 ways: - via returned future object, by calling method get on it; - via passed callback function.

Synchronous and asynchronous communication.

As already mentioned above, to support both asynchronous and synchronous call modes, methods return std::shared_future or std::future, associated with type of value desired to be returned. To get call result immediately, in synchronous mode, you can call get method of the future object.

To handle call result asynchronously, pass callback function - it will be called, when operation is completed.

Note

It is possible to access call result in both ways: via callback function and future object. First, the callback function is called, and after that the result value on the future object is set.

Disconnection and deleting of the Connection class instance.

To disconnect from the OPC UA Server, call disconnect method. After this call is completed (that is the value is set on the returned std::future type object), no more callbacks made to the application.

If the Connection object is deleted when it is still connected, it is disconnected first.

Using context member of requests.

Each request struct has a member context of std::any type. It can be used to store any application-specific data.

More about using of the SDK

For more details refer the sample application, where you can find examples of using almost all request types.