UniSet 2.41.2
OPCUAExchange.h
1/*
2 * Copyright (c) 2023 Pavel Vainerman.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as
6 * published by the Free Software Foundation, version 2.1.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Lesser Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16// -----------------------------------------------------------------------------
17#ifndef OPCUAExchange_H_
18#define OPCUAExchange_H_
19// -----------------------------------------------------------------------------
20#include <vector>
21#include <memory>
22#include <deque>
23#include <string>
24#include <regex>
25#include <optional>
26#include "UniXML.h"
27#include "ThreadCreator.h"
28#include "PassiveTimer.h"
29#include "Trigger.h"
30#include "IONotifyController.h"
31#include "UniSetObject.h"
32#include "Mutex.h"
33#include "MessageType.h"
34#include "SMInterface.h"
35#include "IOBase.h"
36#include "SharedMemory.h"
37#include "LogServer.h"
38#include "DebugStream.h"
39#include "LogAgregator.h"
40#include "OPCUAClient.h"
41#include "USingleProcess.h"
42// -------------------------------------------------------------------------
43#ifndef vmonit
44#define vmonit( var ) vmon.add( #var, var )
45#endif
46// -------------------------------------------------------------------------
47namespace uniset
48{
49 // ---------------------------------------------------------------------
178 // ---------------------------------------------------------------------
180 class OPCUAExchange:
181 private USingleProcess,
182 public UniSetObject
183 {
184 public:
185 OPCUAExchange( uniset::ObjectId id, xmlNode* cnode,
186 uniset::ObjectId icID, const std::shared_ptr<SharedMemory>& shm = nullptr,
187 const std::string& _prefix = "opcua" );
188 virtual ~OPCUAExchange();
189
190 static std::shared_ptr<OPCUAExchange> init_opcuaexchange(int argc, const char* const* argv,
191 uniset::ObjectId icID, const std::shared_ptr<SharedMemory>& ic = nullptr,
192 const std::string& prefix = "opcua");
193
194 static void help_print( int argc, const char* const* argv );
195
196 virtual uniset::SimpleInfo* getInfo( const char* userparam = 0 ) override;
197
198 static uint8_t firstBit( uint32_t mask );
199
200 // offset = firstBit(mask)
201 static uint32_t getBits( uint32_t value, uint32_t mask, uint8_t offset );
202 // if mask = 0 return value
203 static uint32_t setBits( uint32_t value, uint32_t set, uint32_t mask, uint8_t offset );
204 // if mask=0 return set
205 static uint32_t forceSetBits( uint32_t value, uint32_t set, uint32_t mask, uint8_t offset );
206
207 using Tick = uint8_t;
208
209 static const size_t numChannels = 2;
211 {
212 std::vector<std::vector<OPCUAClient::ResultVar>> results;
213 std::vector<std::vector<UA_ReadValueId>> ids;
214 };
216 {
217 std::vector<std::vector<UA_WriteValue>> ids;
218 };
219
220 struct OPCAttribute:
221 public IOBase
222 {
223 // т.к. IOBase содержит rwmutex с запрещённым конструктором копирования
224 // приходится здесь тоже объявлять разрешенными только операции "перемещения"
225 OPCAttribute(const OPCAttribute& r ) = delete;
226 OPCAttribute& operator=(const OPCAttribute& r) = delete;
227 OPCAttribute(OPCAttribute&& r ) = default;
228 OPCAttribute& operator=(OPCAttribute&& r) = default;
229 OPCAttribute() = default;
230
232 int32_t val { 0 };
233 Tick tick = { 0 }; // на каждом ли тике работать с этим аттрибутом
234 uint32_t mask = { 0 };
235 uint8_t offset = { 0 };
236 OPCUAClient::VarType vtype = { OPCUAClient::VarType::Int32 };
237
238 // with precision
239 float as_float();
240
241 // with precision/noprecision
242 int32_t set( float val );
243
244 std::string attrName = {""};
245 struct RdValue
246 {
247 std::shared_ptr<ReadGroup> gr;
248 size_t grIndex = {0}; // индекс в запросе (номер в запросе)
249 size_t grNumber = {0}; // Номер группы запроса в общем списке
250 int32_t get();
251 float getF();
252 bool statusOk();
253 UA_StatusCode status();
254 const UA_ReadValueId& ref();
255 // Subscription
256 uint32_t subscriptionId = {0U};
257 uint32_t monitoredItemId = {0U};
258 bool subscriptionState = {false};
259 };
260 RdValue rval[numChannels];
261
262 struct WrValue
263 {
264 std::shared_ptr<WriteGroup> gr;
265 size_t grIndex = {0}; // индекс в запросе (номер в запросе)
266 size_t grNumber = {0}; // Номер группы запроса в общем списке
267 bool set( int32_t val );
268 bool setF( float val );
269 bool statusOk();
270 UA_StatusCode status();
271 const UA_WriteValue& ref();
272 static void init( UA_WriteValue* wval, const std::string& nodeId, const std::string& type, int32_t defvalue );
273 };
274 WrValue wval[numChannels];
275
276 friend std::ostream& operator<<(std::ostream& os, const OPCAttribute& inf );
277 friend std::ostream& operator<<(std::ostream& os, const std::shared_ptr<OPCAttribute>& inf );
278 };
279
282 {
283 emNone = 0,
288 emLastNumber
289 };
290
293 {
294 smNone = 0,
296 smAny = 2,
297 smLastNumber
298 };
299
300 typedef std::list<IOBase> ThresholdList;
301 // т.к. пороговые датчики не связаны напрямую с обменом, создаём для них отдельный список
302 // и отдельно его проверяем потом
303 ThresholdList thrlist;
304
305#ifndef DISABLE_REST_API
306 // HTTP API
307 virtual Poco::JSON::Object::Ptr httpHelp( const Poco::URI::QueryParameters& p ) override;
308 virtual Poco::JSON::Object::Ptr httpRequest( const std::string& req, const Poco::URI::QueryParameters& p ) override;
309#endif
310
311 protected:
312
313 enum Timers
314 {
315 tmUpdates
316 };
317
318 struct Channel;
319 void channel1Thread();
320 void channel2Thread();
321 void channelThread( Channel* ch );
322 bool prepare();
323 void channelExchange( Tick tick, Channel* ch, bool writeOn );
324 void updateFromChannel( Channel* ch );
325 void updateToChannel( Channel* ch );
326 void updateFromSM();
327 void writeToSM();
328 bool isUpdateSM( bool wrFunc ) const noexcept;
329
330 virtual void sysCommand( const uniset::SystemMessage* sm ) override;
331 virtual void askSensors( UniversalIO::UIOCommand cmd );
332 virtual void sensorInfo( const uniset::SensorMessage* sm ) override;
333 virtual void timerInfo( const uniset::TimerMessage* sm ) override;
334 virtual bool activateObject() override;
335 virtual bool deactivateObject() override;
336
337#ifndef DISABLE_REST_API
338 // Публичные HTTP-обработчики параметров
339 Poco::JSON::Object::Ptr httpGetParam( const Poco::URI::QueryParameters& p );
340 Poco::JSON::Object::Ptr httpSetParam( const Poco::URI::QueryParameters& p );
341 Poco::JSON::Object::Ptr httpStatus();
342
343 // Защитный флаг: запретить /setparam при false
344 bool httpEnabledSetParams { true };
345#endif
346
347
348 // чтение файла конфигурации
349 void readConfiguration();
350 bool initIOItem( UniXML::iterator& it );
351 bool readItem( const std::shared_ptr<UniXML>& xml, UniXML::iterator& it, xmlNode* sec );
352 bool waitSM();
353 bool tryConnect(Channel* ch);
354 void initOutputs();
355 void createSubscription(int nchannel);
356
357 xmlNode* confnode = { nullptr };
358 timeout_t polltime = { 100 };
359 timeout_t updatetime = { 100 };
360
361 typedef std::vector< std::shared_ptr<OPCAttribute> > IOList;
362 IOList iolist;
363 size_t maxItem = { 0 };
364 size_t maxReadItems = { 0 };
365 size_t maxWriteItems = { 0 };
366
367 struct Channel
368 {
369 size_t num;
370 size_t idx;
371 std::shared_ptr<OPCUAClient> client;
372 uniset::Trigger trStatus;
373 uniset::PassiveTimer ptTimeout;
374 std::atomic_bool status = { false };
375 std::string addr;
376 std::string user;
377 std::string pass;
378 std::unordered_map<Tick, std::shared_ptr<ReadGroup>> readValues;
379 std::unordered_map<Tick, std::shared_ptr<WriteGroup>> writeValues;
381 IOController::IOStateList::iterator respond_it;
382 };
383 Channel channels[numChannels];
384 uniset::Trigger noConnections;
385 std::atomic_uint32_t currentChannel = { 0 };
386
387 uniset::timeout_t reconnectPause = { 10000 };
388 int filtersize = { 0 };
389 float filterT = { 0.0 };
390
391 std::string s_field;
392 std::string s_fvalue;
393 std::optional<std::regex> s_fvalue_re;
394
395 std::shared_ptr<SMInterface> shm;
396 std::string prop_prefix;
397 const std::string argprefix;
398
399 PassiveTimer ptHeartBeat;
400 uniset::ObjectId sidHeartBeat;
401 int maxHeartBeat = { 10 };
402 IOController::IOStateList::iterator itHeartBeat;
403
404 bool force = { false };
405 bool force_out = { false };
406 bool writeToAllChannels = { false };
407 timeout_t smReadyTimeout = { 15000 };
408 bool enableSubscription = {false};
409 double publishingInterval = { 0.0 };
410 double samplingInterval = { -1.0 };
411 uint16_t timeoutIterate = {100};
412 uint16_t stopOnError = {0U};
413 uint32_t connectCount = {0U};
414 std::atomic_bool subscription_ok = {false};
415
416 std::atomic_bool activated = { false };
417 std::atomic_bool cancelled = { false };
418 std::atomic_bool readconf_ok = { false };
419
420 int activateTimeout;
421 uniset::ObjectId sidTestSMReady = { uniset::DefaultObjectId };
423 IOController::IOStateList::iterator itRespond;
424
425 std::shared_ptr<LogAgregator> loga;
426 std::shared_ptr<DebugStream> opclog;
427 std::shared_ptr<LogServer> logserv;
428 std::string logserv_host = {""};
429 int logserv_port = {0};
430
431 std::shared_ptr< ThreadCreator<OPCUAExchange> > thrChannel[numChannels];
432
434 IOController::IOStateList::iterator itExchangeMode;
435 long exchangeMode = { emNone };
436
437 VMonitor vmon;
438
439 private:
440 };
441 // --------------------------------------------------------------------------
442} // end of namespace uniset
443// -----------------------------------------------------------------------------
444#endif // OPCUAExchange_H_
445// -----------------------------------------------------------------------------
timeout_t smReadyTimeout
Определения OPCUAExchange.h:407
bool writeToAllChannels
Определения OPCUAExchange.h:406
uniset::ObjectId sidExchangeMode
Определения OPCUAExchange.h:433
bool force
Определения OPCUAExchange.h:404
timeout_t updatetime
Определения OPCUAExchange.h:359
virtual bool activateObject() override
Активизация объекта (переопределяется для необходимых действий после активизации).
Определения OPCUAExchange.cc:1374
bool force_out
Определения OPCUAExchange.h:405
uint16_t stopOnError
Определения OPCUAExchange.h:412
xmlNode * confnode
Определения OPCUAExchange.h:357
virtual bool deactivateObject() override
Деактивация объекта (переопределяется для необходимых действий при завершении работы).
Определения OPCUAExchange.cc:1388
IOList iolist
Определения OPCUAExchange.h:362
uint32_t connectCount
Определения OPCUAExchange.h:413
timeout_t polltime
Определения OPCUAExchange.h:358
StopMode
Определения OPCUAExchange.h:293
@ smFirstOnly
Определения OPCUAExchange.h:295
@ smAny
Определения OPCUAExchange.h:296
@ smNone
Определения OPCUAExchange.h:294
ExchangeMode
Определения OPCUAExchange.h:282
@ emSkipExchange
Определения OPCUAExchange.h:287
@ emNone
Определения OPCUAExchange.h:283
@ emWriteOnly
Определения OPCUAExchange.h:284
@ emSkipSaveToSM
Определения OPCUAExchange.h:286
@ emReadOnly
Определения OPCUAExchange.h:285
long exchangeMode
Определения OPCUAExchange.h:435
Пассивный таймер
Определения PassiveTimer.h:94
Определения MessageType.h:127
Определения MessageType.h:171
Определения MessageType.h:214
Определения Trigger.h:31
UniSetObject(const std::string &name, const std::string &section)
Определения UniSetObject.cc:89
Определения VMonitor.h:117
Определения Mutex.h:32
Определения Calibration.h:27
const ObjectId DefaultObjectId
Определения UniSetTypes.h:71
long ObjectId
Определения UniSetTypes_i.idl:30
Определения OPCUAExchange.h:368
Определения OPCUAExchange.h:246
Определения OPCUAExchange.h:263
Определения OPCUAExchange.h:211
Определения OPCUAExchange.h:216
Определения UniSetTypes_i.idl:65