.. _details: 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 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 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.