uatools 1.0.0-pre2
 
Loading...
Searching...
No Matches
icomm_adapter_min_v1.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <chrono>
4#include <cstdint>
5#include <functional>
6#include <memory>
7#include <stdexcept>
8#include <string>
9#include <utility>
10#include <variant>
11#include <vector>
12
13// =============================================================================
14// Minimum communication adapter interface (v1)
15//
16// Scope: a small, value-typed C++ abstraction over an OPC UA client.
17// Models exactly what the uatools/protocol layer needs today and
18// nothing more. Drafted as the counter-proposal to icomm_adapter_ultimate_v1.hpp:
19// the ultimate version aims to be a general-purpose comm-adapter contract that
20// could host non-OPC-UA backends (RTMS, Modbus, REST, ...) later. This minimum
21// version is honest about the fact that there is exactly one backend today
22// (open62541) and is shaped accordingly.
23//
24// Key differences from the existing IComm in
25// protocol/base/src/include/eso/uatools/protocol/base/iComm.hpp:
26// * Read returns DataValue by value (not VectorVariant&).
27// * Write takes (node, value) directly (not VectorVariant pairs).
28// * Rpc(...) is renamed to Call(...) and returns vector<Variant>; the
29// fake short{0} synthesis is gone.
30// * Three-step subscription (StartMonitorItem + RegisterCB + StopMonitorItem)
31// collapses to Subscribe(node, cb) -> SubscriptionHandle. RAII teardown.
32// * Typed exceptions (ConnectError / ReadError / WriteError / ...) replace
33// bool-returns and runtime_error("..."). Each carries device + node +
34// StatusCode for programmatic handling.
35// * No factory / REGISTER_COMM. Tests substitute mock implementations
36// directly.
37//
38// Thread safety:
39// - Every method is safe to call from any thread concurrently.
40// - The implementation serialises access to the underlying open62541 client
41// on its own connection mutex.
42// - Subscription callbacks fire on the backend worker thread; do not call
43// IComm methods from inside a callback (deadlock risk).
44// =============================================================================
45
47
48// -----------------------------------------------------------------------------
49// Variant — the value carrier. Same alternatives as the existing uatools
50// Variant. The order matters: variantConverter uses std::variant::index()
51// numerically. APPEND ONLY — never reorder existing entries.
52// -----------------------------------------------------------------------------
53using Variant = std::variant<
54 bool,
55 std::int8_t, std::uint8_t,
56 short, unsigned short,
57 int, unsigned int,
58 float, double,
59 std::string,
60 std::vector<bool>,
61 std::vector<short>,
62 std::vector<int>,
63 std::vector<unsigned int>,
64 std::vector<float>,
65 std::vector<double>,
66 std::vector<std::string>
67>;
68
69// -----------------------------------------------------------------------------
70// StatusCode — opaque wrapper around UA_StatusCode. Public API stays free
71// of open62541 includes; the backend translates internally.
72// -----------------------------------------------------------------------------
73struct StatusCode {
74 std::uint32_t value{0}; // 0 == Good
75
76 constexpr bool Good() const noexcept { return value == 0; }
77 constexpr bool Bad() const noexcept { return value != 0; }
78
79 friend constexpr bool operator==(StatusCode a, StatusCode b) noexcept {
80 return a.value == b.value;
81 }
82 friend constexpr bool operator!=(StatusCode a, StatusCode b) noexcept {
83 return a.value != b.value;
84 }
85};
86
87// -----------------------------------------------------------------------------
88// DataValue — what a Read returns and what a subscription delivers.
89// Mirrors UA_DataValue: value plus the metadata that today's Variant-only
90// shape silently drops on the floor.
91// -----------------------------------------------------------------------------
92struct DataValue {
95 std::chrono::system_clock::time_point source_timestamp;
96 std::chrono::system_clock::time_point server_timestamp;
97};
98
99// -----------------------------------------------------------------------------
100// Client configuration. Single struct passed to Connect().
101// -----------------------------------------------------------------------------
103 std::string endpoint; // opc.tcp://host:port
104 std::chrono::milliseconds connect_timeout{30'000};
105 std::chrono::milliseconds session_timeout{30'000};
106 std::chrono::milliseconds keepalive_interval{5'000};
108
109 // Anonymous if username is empty.
110 std::string username;
111 std::string password;
112};
113
114// -----------------------------------------------------------------------------
115// Typed exceptions. All derive from ProtocolError, all carry enough context
116// (device + node + StatusCode) for programmatic handling — no string parsing.
117// -----------------------------------------------------------------------------
118struct ProtocolError : std::runtime_error {
120 std::string device;
121 std::string node;
122
123 ProtocolError(StatusCode sc, std::string dev, std::string nd,
124 const std::string& what)
125 : std::runtime_error(what)
126 , status_code(sc), device(std::move(dev)), node(std::move(nd)) {}
127};
128
135
136// -----------------------------------------------------------------------------
137// Subscription callback + options.
138// -----------------------------------------------------------------------------
139using DataCallback = std::function<void(const std::string& node,
140 const DataValue& value)>;
141
143 std::chrono::milliseconds sampling_interval{250};
144 std::uint32_t queue_size{1};
145 bool discard_oldest{true};
146};
147
148// -----------------------------------------------------------------------------
149// SubscriptionHandle — RAII. Move-only. Destroying it unsubscribes
150// (best effort: server may already be gone). Reset() does the same thing
151// explicitly. No three-step setup; no callback registration drift.
152// -----------------------------------------------------------------------------
154public:
157
160
162 SubscriptionHandle& operator=(const SubscriptionHandle&) = delete;
163
165 bool Active() const noexcept;
166
168 void Reset() noexcept;
169
170private:
171 // Opaque impl pointer; keeps open62541 types out of this header.
172 struct Impl;
173 std::unique_ptr<Impl> m_impl;
174
175 // The backend constructs handles directly; users don't.
176 friend class Open62541;
177 explicit SubscriptionHandle(std::unique_ptr<Impl>);
178};
179
180// =============================================================================
181// The interface itself. One class. Eight methods. Done.
182// =============================================================================
183class IComm {
184public:
185 virtual ~IComm() = default;
186
187 IComm() = default;
188 IComm(const IComm&) = delete;
189 IComm& operator=(const IComm&) = delete;
190 IComm(IComm&&) = delete;
191 IComm& operator=(IComm&&) = delete;
192
193 // --- Lifecycle ---
194
196 virtual void Connect(const ClientConfig& cfg) = 0;
197
199 virtual void Disconnect() noexcept = 0;
200
204 virtual bool IsConnected() const noexcept = 0;
205
206 // --- Synchronous data plane ---
207
209 virtual DataValue Read(const std::string& node) = 0;
210
213 virtual std::vector<DataValue>
214 Read(const std::vector<std::string>& nodes) = 0;
215
217 virtual void Write(const std::string& node, const Variant& value) = 0;
218
221 virtual std::vector<StatusCode>
222 Write(const std::vector<std::pair<std::string, Variant>>& writes) = 0;
223
233 virtual std::vector<Variant>
234 Call(const std::string& object,
235 const std::string& method,
236 const std::vector<Variant>& args) = 0;
237
238 // --- Subscriptions ---
239
244 virtual SubscriptionHandle
245 Subscribe(const std::string& node,
246 DataCallback callback,
247 const SubscriptionOpts& opts = {}) = 0;
248
252 virtual std::vector<SubscriptionHandle>
253 Subscribe(const std::vector<std::string>& nodes,
254 DataCallback callback,
255 const SubscriptionOpts& opts = {}) = 0;
256};
257
258} // namespace eso::uatools::protocol::base
virtual void Connect(const ClientConfig &cfg)=0
virtual void Write(const std::string &node, const Variant &value)=0
virtual DataValue Read(const std::string &node)=0
IComm & operator=(IComm &&)=delete
virtual void Disconnect() noexcept=0
Safe to call when already disconnected.
virtual std::vector< Variant > Call(const std::string &object, const std::string &method, const std::vector< Variant > &args)=0
IComm & operator=(const IComm &)=delete
virtual std::vector< SubscriptionHandle > Subscribe(const std::vector< std::string > &nodes, DataCallback callback, const SubscriptionOpts &opts={})=0
virtual SubscriptionHandle Subscribe(const std::string &node, DataCallback callback, const SubscriptionOpts &opts={})=0
virtual bool IsConnected() const noexcept=0
Definition icomm_adapter_min_v1.hpp:153
SubscriptionHandle(SubscriptionHandle &&) noexcept
friend class Open62541
Definition icomm_adapter_min_v1.hpp:176
void Reset() noexcept
Drop the subscription early (same as destructor).
Definition icomm_adapter_generic_v2.hpp:49
std::function< void(const std::string &node, const DataValue & value)> DataCallback
Definition icomm_adapter_min_v1.hpp:139
std::variant< bool, std::int8_t, std::uint8_t, short, unsigned short, int, unsigned int, float, double, std::string, std::vector< bool >, std::vector< short >, std::vector< int >, std::vector< unsigned int >, std::vector< float >, std::vector< double >, std::vector< std::string > > Variant
Definition icomm_adapter_min_v1.hpp:53
Definition icomm_adapter_min_v1.hpp:132
ProtocolError(StatusCode sc, std::string dev, std::string nd, const std::string &what)
Definition icomm_adapter_min_v1.hpp:123
Definition icomm_adapter_min_v1.hpp:102
std::string password
Definition icomm_adapter_min_v1.hpp:111
int publish_requests
Definition icomm_adapter_min_v1.hpp:107
std::chrono::milliseconds keepalive_interval
Definition icomm_adapter_min_v1.hpp:106
std::chrono::milliseconds connect_timeout
Definition icomm_adapter_min_v1.hpp:104
std::string endpoint
Definition icomm_adapter_min_v1.hpp:103
std::string username
Definition icomm_adapter_min_v1.hpp:110
std::chrono::milliseconds session_timeout
Definition icomm_adapter_min_v1.hpp:105
Definition icomm_adapter_min_v1.hpp:129
ProtocolError(StatusCode sc, std::string dev, std::string nd, const std::string &what)
Definition icomm_adapter_min_v1.hpp:123
Definition icomm_adapter_generic_v2.hpp:247
std::chrono::system_clock::time_point server_timestamp
Definition icomm_adapter_min_v1.hpp:96
Value value
Definition icomm_adapter_generic_v2.hpp:248
std::chrono::system_clock::time_point source_timestamp
Definition icomm_adapter_min_v1.hpp:95
Status status
Definition icomm_adapter_generic_v2.hpp:249
std::string node
Definition icomm_adapter_min_v1.hpp:121
StatusCode status_code
Definition icomm_adapter_min_v1.hpp:119
ProtocolError(StatusCode sc, std::string dev, std::string nd, const std::string &what)
Definition icomm_adapter_min_v1.hpp:123
std::string device
Definition icomm_adapter_min_v1.hpp:120
Definition icomm_adapter_min_v1.hpp:130
ProtocolError(StatusCode sc, std::string dev, std::string nd, const std::string &what)
Definition icomm_adapter_min_v1.hpp:123
Definition icomm_adapter_min_v1.hpp:73
friend constexpr bool operator==(StatusCode a, StatusCode b) noexcept
Definition icomm_adapter_min_v1.hpp:79
std::uint32_t value
Definition icomm_adapter_min_v1.hpp:74
constexpr bool Good() const noexcept
Definition icomm_adapter_min_v1.hpp:76
constexpr bool Bad() const noexcept
Definition icomm_adapter_min_v1.hpp:77
friend constexpr bool operator!=(StatusCode a, StatusCode b) noexcept
Definition icomm_adapter_min_v1.hpp:82
Definition icomm_adapter_min_v1.hpp:133
ProtocolError(StatusCode sc, std::string dev, std::string nd, const std::string &what)
Definition icomm_adapter_min_v1.hpp:123
Definition icomm_adapter_min_v1.hpp:142
bool discard_oldest
Definition icomm_adapter_min_v1.hpp:145
std::uint32_t queue_size
Definition icomm_adapter_min_v1.hpp:144
std::chrono::milliseconds sampling_interval
Definition icomm_adapter_min_v1.hpp:143
Definition icomm_adapter_min_v1.hpp:134
ProtocolError(StatusCode sc, std::string dev, std::string nd, const std::string &what)
Definition icomm_adapter_min_v1.hpp:123
Definition icomm_adapter_min_v1.hpp:131
ProtocolError(StatusCode sc, std::string dev, std::string nd, const std::string &what)
Definition icomm_adapter_min_v1.hpp:123