UniSet  2.24.2
extensions/ModbusSlave/MBSlave.h
1 /*
2  * Copyright (c) 2015 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 _MBSlave_H_
18 #define _MBSlave_H_
19 // -----------------------------------------------------------------------------
20 #include <ostream>
21 #include <string>
22 #include <memory>
23 #include <map>
24 #include <unordered_map>
25 #include <vector>
26 #include <condition_variable>
27 #include <atomic>
28 #include <mutex>
29 #include "UniSetObject.h"
30 #include "modbus/ModbusTypes.h"
31 #include "modbus/ModbusServerSlot.h"
32 #include "modbus/ModbusTCPServer.h"
33 #include "modbus/ModbusTCPServerSlot.h"
34 #include "PassiveTimer.h"
35 #include "Trigger.h"
36 #include "Mutex.h"
37 #include "SMInterface.h"
38 #include "SharedMemory.h"
39 #include "IOBase.h"
40 #include "VTypes.h"
41 #include "ThreadCreator.h"
42 #include "LogServer.h"
43 #include "LogAgregator.h"
44 #include "VMonitor.h"
45 // -----------------------------------------------------------------------------
46 #ifndef vmonit
47 #define vmonit( var ) vmon.add( #var, var )
48 #endif
49 // -------------------------------------------------------------------------
50 namespace uniset
51 {
52  // -----------------------------------------------------------------------------
310  // -----------------------------------------------------------------------------
312  class MBSlave:
313  public UniSetObject
314  {
315  public:
316  MBSlave( uniset::ObjectId objId, uniset::ObjectId shmID, const std::shared_ptr<SharedMemory>& ic = nullptr, const std::string& prefix = "mbs" );
317  virtual ~MBSlave();
318 
320  static std::shared_ptr<MBSlave> init_mbslave(int argc, const char* const* argv,
321  uniset::ObjectId shmID, const std::shared_ptr<SharedMemory>& ic = nullptr,
322  const std::string& prefix = "mbs" );
323 
324  static void help_print( int argc, const char* const* argv );
325 
326  static const int NoSafetyState = -1;
327 
328  enum AccessMode
329  {
330  amRW,
331  amRO,
332  amWO
333  };
334 
335  std::string amode2str( AccessMode m );
336 
337  struct BitRegProperty;
338 
339  struct IOProperty:
340  public IOBase
341  {
342  ModbusRTU::ModbusData mbreg;
343  AccessMode amode;
344  VTypes::VType vtype;
345  size_t wnum;
346  size_t nbyte;
347  std::shared_ptr<BitRegProperty> bitreg;
348  ModbusRTU::RegID regID;
349 
350  IOProperty():
351  mbreg(0),
352  amode(amRW),
353  vtype(VTypes::vtUnknown),
354  wnum(0),
355  nbyte(0),
356  regID(0)
357  {}
358 
359  friend std::ostream& operator<<( std::ostream& os, IOProperty& p );
360  };
361 
362 
364  {
365  typedef std::vector<IOProperty> BitSensorMap;
366 
367  ModbusRTU::ModbusData mbreg;
368  BitSensorMap bvec;
369 
370  BitRegProperty(): mbreg(0), bvec(ModbusRTU::BitsPerData) {}
371 
373  bool check( const IOController_i::SensorInfo& si );
374 
375  friend std::ostream& operator<<( std::ostream& os, BitRegProperty& p );
376  friend std::ostream& operator<<( std::ostream& os, BitRegProperty* p );
377  };
378 
379  inline long getConnCount()
380  {
381  return connCount;
382  }
383 
384  inline std::shared_ptr<LogAgregator> getLogAggregator()
385  {
386  return loga;
387  }
388  inline std::shared_ptr<DebugStream> log()
389  {
390  return mblog;
391  }
392 
393  virtual uniset::SimpleInfo* getInfo( const char* userparam = 0 ) override;
394 
395 #ifndef DISABLE_REST_API
396  // http API
397  virtual Poco::JSON::Object::Ptr httpHelp( const Poco::URI::QueryParameters& p ) override;
398  virtual Poco::JSON::Object::Ptr httpRequest( const std::string& req, const Poco::URI::QueryParameters& p ) override;
399 #endif
400 
401  protected:
402 
404  ModbusRTU::mbErrCode readCoilStatus( ModbusRTU::ReadCoilMessage& query,
405  ModbusRTU::ReadCoilRetMessage& reply );
407  ModbusRTU::mbErrCode readInputStatus( ModbusRTU::ReadInputStatusMessage& query,
408  ModbusRTU::ReadInputStatusRetMessage& reply );
409 
411  ModbusRTU::mbErrCode readOutputRegisters( ModbusRTU::ReadOutputMessage& query,
412  ModbusRTU::ReadOutputRetMessage& reply );
413 
415  ModbusRTU::mbErrCode readInputRegisters( ModbusRTU::ReadInputMessage& query,
416  ModbusRTU::ReadInputRetMessage& reply );
417 
419  ModbusRTU::mbErrCode forceSingleCoil( ModbusRTU::ForceSingleCoilMessage& query,
420  ModbusRTU::ForceSingleCoilRetMessage& reply );
421 
423  ModbusRTU::mbErrCode forceMultipleCoils( ModbusRTU::ForceCoilsMessage& query,
424  ModbusRTU::ForceCoilsRetMessage& reply );
425 
426 
428  ModbusRTU::mbErrCode writeOutputRegisters( ModbusRTU::WriteOutputMessage& query,
429  ModbusRTU::WriteOutputRetMessage& reply );
430 
432  ModbusRTU::mbErrCode writeOutputSingleRegister( ModbusRTU::WriteSingleOutputMessage& query,
433  ModbusRTU::WriteSingleOutputRetMessage& reply );
434 
436  // ModbusRTU::mbErrCode journalCommand( ModbusRTU::JournalCommandMessage& query,
437  // ModbusRTU::JournalCommandRetMessage& reply );
438 
440  ModbusRTU::mbErrCode setDateTime( ModbusRTU::SetDateTimeMessage& query,
441  ModbusRTU::SetDateTimeRetMessage& reply );
442 
444  ModbusRTU::mbErrCode remoteService( ModbusRTU::RemoteServiceMessage& query,
445  ModbusRTU::RemoteServiceRetMessage& reply );
446 
447  ModbusRTU::mbErrCode fileTransfer( ModbusRTU::FileTransferMessage& query,
448  ModbusRTU::FileTransferRetMessage& reply );
449 
450  ModbusRTU::mbErrCode diagnostics( ModbusRTU::DiagnosticMessage& query,
451  ModbusRTU::DiagnosticRetMessage& reply );
452 
453  ModbusRTU::mbErrCode read4314( ModbusRTU::MEIMessageRDI& query,
454  ModbusRTU::MEIMessageRetRDI& reply );
455 
456  // т.к. в функциях (much_real_read,nuch_real_write) расчёт на отсортированность IOMap
457  // то использовать unordered_map нельзя
458  typedef std::map<ModbusRTU::RegID, IOProperty> RegMap;
459 
460  typedef std::unordered_map<ModbusRTU::ModbusAddr, RegMap> IOMap;
461 
462  IOMap iomap;
464  // т.к. пороговые датчики не связаны напрямую с обменом, создаём для них отдельный список
465  // и отдельно его проверяем потом
466  typedef std::list<IOBase> ThresholdList;
467  ThresholdList thrlist;
468 
469  std::shared_ptr<ModbusServerSlot> mbslot;
470  std::unordered_set<ModbusRTU::ModbusAddr> vaddr;
471  std::string default_mbaddr = { "" };
472 
473  xmlNode* cnode = { 0 };
474  std::string s_field = { "" };
475  std::string s_fvalue = { "" };
476  int default_mbfunc = {0}; // функция по умолчанию, для вычисления RegID
477 
478  std::shared_ptr<SMInterface> shm;
479 
480  virtual void sysCommand( const uniset::SystemMessage* msg ) override;
481  virtual void sensorInfo( const uniset::SensorMessage* sm ) override;
482  virtual void timerInfo( const uniset::TimerMessage* tm ) override;
483  void askSensors( UniversalIO::UIOCommand cmd );
484  bool waitSMReady();
485  virtual void execute_rtu();
486  virtual void execute_tcp();
487  virtual void updateStatistics();
488  virtual void updateTCPStatistics();
489  virtual void updateThresholds();
490  virtual void postReceiveEvent( ModbusRTU::mbErrCode res );
491  void runTCPServer();
492 
493  virtual bool activateObject() override;
494  virtual bool deactivateObject() override;
495 
496  // действия при завершении работы
497  virtual void finalThread();
498 
499  enum Timer
500  {
501  tmCheckExchange
502  };
503 
504  uniset::timeout_t checkExchangeTime = { 10000 }; // контроль "живости" потока обмена, мсек
505 
506  virtual void initIterators();
507  bool initItem( UniXML::iterator& it );
508  bool readItem( const std::shared_ptr<UniXML>& xml, UniXML::iterator& it, xmlNode* sec );
509 
510  void readConfiguration();
511  bool check_item( UniXML::iterator& it );
512 
513  ModbusRTU::mbErrCode real_write( RegMap& rmap, const ModbusRTU::ModbusData regOKOK, ModbusRTU::ModbusData val, const int fn = 0 );
514  ModbusRTU::mbErrCode real_write( RegMap& rmap, const ModbusRTU::ModbusData regOKOK, ModbusRTU::ModbusData* dat, size_t& i, size_t count, const int fn = 0 );
515  ModbusRTU::mbErrCode real_read( RegMap& rmap, const ModbusRTU::ModbusData regOKOK, ModbusRTU::ModbusData& val, const int fn = 0 );
516  ModbusRTU::mbErrCode much_real_read( RegMap& rmap, const ModbusRTU::ModbusData regOKOK, ModbusRTU::ModbusData* dat, size_t count, const int fn = 0 );
517  ModbusRTU::mbErrCode much_real_write(RegMap& rmap, const ModbusRTU::ModbusData regOKOK, ModbusRTU::ModbusData* dat, size_t count, const int fn = 0 );
518 
519  ModbusRTU::mbErrCode real_read_it( RegMap& rmap, RegMap::iterator& it, ModbusRTU::ModbusData& val );
520  ModbusRTU::mbErrCode real_bitreg_read_it( std::shared_ptr<BitRegProperty>& bp, ModbusRTU::ModbusData& val );
521  ModbusRTU::mbErrCode real_read_prop( IOProperty* p, ModbusRTU::ModbusData& val );
522 
523  ModbusRTU::mbErrCode real_write_it(RegMap& rmap, RegMap::iterator& it, ModbusRTU::ModbusData* dat, size_t& i, size_t count );
524  ModbusRTU::mbErrCode real_bitreg_write_it( std::shared_ptr<BitRegProperty>& bp, const ModbusRTU::ModbusData val );
525  ModbusRTU::mbErrCode real_write_prop(IOProperty* p, ModbusRTU::ModbusData* dat, size_t& i, size_t count );
526 
527 #ifndef DISABLE_REST_API
528  // http api
529  Poco::JSON::Object::Ptr request_regs( const std::string& req, const Poco::URI::QueryParameters& p );
530  Poco::JSON::Object::Ptr get_regs(ModbusRTU::ModbusAddr addr, const RegMap& rmap, const std::vector<std::string>& q_regs );
531  Poco::JSON::Object::Ptr get_reginfo( const IOProperty& prop );
532 #endif
533  MBSlave();
534  timeout_t initPause = { 3000 };
535  uniset::uniset_rwmutex mutex_start;
536  std::unique_ptr< ThreadCreator<MBSlave> > thr;
537 
538  std::mutex mutexStartNotify;
539  std::condition_variable startNotifyEvent;
540 
541  PassiveTimer ptHeartBeat;
542  uniset::ObjectId sidHeartBeat = { uniset::DefaultObjectId };
543  long maxHeartBeat = { 10 };
544  IOController::IOStateList::iterator itHeartBeat;
546 
547  IOController::IOStateList::iterator itAskCount;
548  uniset::ObjectId askcount_id = { uniset::DefaultObjectId };
549 
550  IOController::IOStateList::iterator itRespond;
551  uniset::ObjectId respond_id = { uniset::DefaultObjectId };
552  bool respond_invert = { false };
553 
554  PassiveTimer ptTimeout;
555  long connCount = { 0 };
556  long restartTCPServerCount = { 0 };
557 
558  std::atomic_bool activated = { false };
559  std::atomic_bool cancelled = { false };
560  timeout_t activateTimeout = { 20000 }; // msec
561  bool smPingOK = { false };
562  timeout_t wait_msec = { 3000 };
563  bool force = { false };
565  bool mbregFromID = {0};
566  bool checkMBFunc = {0};
567  bool noMBFuncOptimize = {0}; // флаг отключающий принудительное преобразование функций (0x06->0x10, 0x05->0x0F) см. initItem()
568 
569  int getOptimizeWriteFunction( const int fn ); // функция возвращает оптимизированную функцию (если оптимизация включена)
570 
571  typedef std::unordered_map<int, std::string> FileList;
572  FileList flist;
573  std::string prefix = { "" };
574  std::string prop_prefix = { "" };
575 
576  ModbusRTU::ModbusData buf[ModbusRTU::MAXLENPACKET / 2 + 1];
578  // данные для ответа на запрос 0x2B(43)/0x0E(14)
579  // 'MEI' - modbus encapsulated interface
580  // 'RDI' - read device identification
581  typedef std::unordered_map<int, std::string> MEIValMap;
582  typedef std::unordered_map<int, MEIValMap> MEIObjIDMap;
583  typedef std::unordered_map<int, MEIObjIDMap> MEIDevIDMap;
584 
585  MEIDevIDMap meidev;
586 
587  std::shared_ptr<LogAgregator> loga;
588  std::shared_ptr<DebugStream> mblog;
589  std::shared_ptr<LogServer> logserv;
590  std::string logserv_host = {""};
591  int logserv_port = {0};
592  VMonitor vmon;
593  std::string mbtype = { "" };
594 
595  // ----------------------------------------------------------------------------
596  // TCPServer section..
597  void initTCPClients( UniXML::iterator confnode );
598 
599  timeout_t sockTimeout = { 30000 };
600  timeout_t sessTimeout = { 2000 };
601  timeout_t updateStatTime = { 4000 };
602  ModbusTCPServer::Sessions sess;
603  std::mutex sessMutex;
604  size_t sessMaxNum = { 5 };
605  std::shared_ptr<ModbusTCPServerSlot> tcpserver;
606 
607  struct ClientInfo
608  {
609  ClientInfo(): iaddr(""), respond_s(uniset::DefaultObjectId), invert(false),
610  askCount(0), askcount_s(uniset::DefaultObjectId)
611  {
612  ptTimeout.setTiming(0);
613  }
614 
615  std::string iaddr = { "" };
616 
618  IOController::IOStateList::iterator respond_it;
619  bool invert = { false };
620  PassiveTimer ptTimeout;
621  timeout_t tout = { 2000 };
622 
623  long askCount = { 0 };
624  uniset::ObjectId askcount_s = { uniset::DefaultObjectId };
625  IOController::IOStateList::iterator askcount_it;
626 
627  inline void initIterators( const std::shared_ptr<SMInterface>& shm )
628  {
629  shm->initIterator( respond_it );
630  shm->initIterator( askcount_it );
631  }
632 
633  const std::string getShortInfo() const;
634  };
635 
636  typedef std::unordered_map<std::string, ClientInfo> ClientsMap;
637  ClientsMap cmap;
638 
639  uniset::ObjectId sesscount_id = { uniset::DefaultObjectId };
640  IOController::IOStateList::iterator sesscount_it;
641 
642  std::atomic_bool tcpCancelled = { true };
643 
644  bool tcpBreakIfFailRun = { false };
645  timeout_t tcpRepeatCreateSocketPause = { 30000 };
646  };
647  // --------------------------------------------------------------------------
648 } // end of namespace uniset
649 // -----------------------------------------------------------------------------
650 #endif // _MBSlave_H_
651 // -----------------------------------------------------------------------------
Definition: Utilities/MBTester/MBSlave.h:13
Definition: extensions/ModbusSlave/MBSlave.h:314
ModbusRTU::mbErrCode readInputRegisters(ModbusRTU::ReadInputMessage &query, ModbusRTU::ReadInputRetMessage &reply)
Definition: Utilities/MBTester/mbslave.cc:179
virtual bool activateObject() override
Активизация объекта (переопределяется для необходимых действий после активизации)
Definition: extensions/ModbusSlave/mbslave.cc:1173
IOMap iomap
Definition: extensions/ModbusSlave/MBSlave.h:462
ModbusRTU::mbErrCode writeOutputSingleRegister(ModbusRTU::WriteSingleOutputMessage &query, ModbusRTU::WriteSingleOutputRetMessage &reply)
Definition: Utilities/MBTester/mbslave.cc:295
ModbusRTU::ModbusData buf[ModbusRTU::MAXLENPACKET/2+1]
Definition: extensions/ModbusSlave/MBSlave.h:576
ModbusRTU::mbErrCode writeOutputRegisters(ModbusRTU::WriteOutputMessage &query, ModbusRTU::WriteOutputRetMessage &reply)
Definition: Utilities/MBTester/mbslave.cc:283
ModbusRTU::mbErrCode readOutputRegisters(ModbusRTU::ReadOutputMessage &query, ModbusRTU::ReadOutputRetMessage &reply)
Definition: Utilities/MBTester/mbslave.cc:225
ModbusRTU::mbErrCode readInputStatus(ModbusRTU::ReadInputStatusMessage &query, ModbusRTU::ReadInputStatusRetMessage &reply)
Definition: Utilities/MBTester/mbslave.cc:135
ModbusTCPServer::Sessions sess
Definition: extensions/ModbusSlave/MBSlave.h:602
ModbusRTU::mbErrCode readCoilStatus(ModbusRTU::ReadCoilMessage &query, ModbusRTU::ReadCoilRetMessage &reply)
Definition: Utilities/MBTester/mbslave.cc:109
timeout_t sessTimeout
Definition: extensions/ModbusSlave/MBSlave.h:600
ModbusRTU::mbErrCode setDateTime(ModbusRTU::SetDateTimeMessage &query, ModbusRTU::SetDateTimeRetMessage &reply)
Definition: Utilities/MBTester/mbslave.cc:355
ModbusRTU::mbErrCode remoteService(ModbusRTU::RemoteServiceMessage &query, ModbusRTU::RemoteServiceRetMessage &reply)
Definition: Utilities/MBTester/mbslave.cc:367
virtual bool deactivateObject() override
Деактивация объекта (переопределяется для необходимых действий при завершении работы)
Definition: extensions/ModbusSlave/mbslave.cc:1190
std::unordered_set< ModbusRTU::ModbusAddr > vaddr
Definition: extensions/ModbusSlave/MBSlave.h:470
static std::shared_ptr< MBSlave > init_mbslave(int argc, const char *const *argv, uniset::ObjectId shmID, const std::shared_ptr< SharedMemory > &ic=nullptr, const std::string &prefix="mbs")
Definition: extensions/ModbusSlave/mbslave.cc:1644
bool force
Definition: extensions/ModbusSlave/MBSlave.h:563
timeout_t sockTimeout
Definition: extensions/ModbusSlave/MBSlave.h:599
ModbusRTU::mbErrCode forceMultipleCoils(ModbusRTU::ForceCoilsMessage &query, ModbusRTU::ForceCoilsRetMessage &reply)
Definition: Utilities/MBTester/mbslave.cc:272
ModbusRTU::mbErrCode forceSingleCoil(ModbusRTU::ForceSingleCoilMessage &query, ModbusRTU::ForceSingleCoilRetMessage &reply)
Definition: Utilities/MBTester/mbslave.cc:306
Пассивный таймер
Definition: PassiveTimer.h:94
Definition: MessageType.h:127
Definition: MessageType.h:171
Definition: MessageType.h:214
Definition: UniSetObject.h:80
Definition: Mutex.h:32
Definition: CommonEventLoop.h:15
const ObjectId DefaultObjectId
Definition: UniSetTypes.h:70
long ObjectId
Definition: UniSetTypes_i.idl:30
Definition: IOController_i.idl:58
Definition: IOBase.h:35
Definition: extensions/ModbusSlave/MBSlave.h:364
ModbusRTU::ModbusData mbreg
Definition: extensions/ModbusSlave/MBSlave.h:367
bool check(const IOController_i::SensorInfo &si)
Definition: extensions/ModbusSlave/mbslave.cc:1519
Definition: extensions/ModbusSlave/MBSlave.h:608
Definition: extensions/ModbusSlave/MBSlave.h:341
size_t wnum
Definition: extensions/ModbusSlave/MBSlave.h:345
ModbusRTU::ModbusData mbreg
Definition: extensions/ModbusSlave/MBSlave.h:342
std::shared_ptr< BitRegProperty > bitreg
Definition: extensions/ModbusSlave/MBSlave.h:347
VTypes::VType vtype
Definition: extensions/ModbusSlave/MBSlave.h:344
size_t nbyte
Definition: extensions/ModbusSlave/MBSlave.h:346
Definition: UniSetTypes_i.idl:65