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