Details of the SDK¶
The SDK is designed to run in multithreaded mode. It needs few categories of threads. 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);.
At least one thread is used for TCP communications.
The SDK performs callbacks when different kinds of events occur: when state of 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. By default, one thread is created for such callbacks.
General thread pool.¶
The SDK provides general thread pool which can be used by the application for its own purposes. This instance of the thread pool can be retrieved by calling function
std::shared_ptr<ThreadPool> Utils::getThreadPool();. To clean this thread pool, function
void Utils::closeThreadPool(); is used. To add new tasks to the pool, method
enqueue is used.
To run tasks (functions) at certiain point of time in the future, the SDK uses
Timer class. This class creates own thread maintain list of tasks. Tasks launched in threads belonging to the Callbacks Thread Pool. Its instance 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.
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.¶
The SDK can be used without initialization. In this case default thread model settings will be used. To initialize the SDK with different settings, function
Utils::initSDK can be used.
Clean-up of the SDK can also be omitted. In this case, some resourses can be reported as not un-initialized by tools such as memory leak detectors.
To free all resources used by the SDK in controlled way, function
Utils::cleanSDK can be used.
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 fo 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, 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. to most commonly used way might be using of the Endpoint URL. But in fact server can change endpoints after their configuration change. For example, port number of 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
The SDK also uses
GetEndpoints request in cases if connection in secured mode is required, to retrieve server certificate.
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 the it, after its restart or endpoint URL change.
If there are created 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 future object, with argument type OperationResult. 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
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.
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.
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.
Connection::sendmethod. 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
sendmethod 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
geton 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, assiciated 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.
It is possible to access call result in both ways: via callback funciton and future object. First, cannback function is called, and after that result value on the futue object is set.