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