UniSet  2.6.0
MBSlave.h
00001 /*
00002  * Copyright (c) 2015 Pavel Vainerman.
00003  *
00004  * This program is free software: you can redistribute it and/or modify
00005  * it under the terms of the GNU Lesser General Public License as
00006  * published by the Free Software Foundation, version 2.1.
00007  *
00008  * This program is distributed in the hope that it will be useful, but
00009  * WITHOUT ANY WARRANTY; without even the implied warranty of
00010  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00011  * Lesser General Lesser Public License for more details.
00012  *
00013  * You should have received a copy of the GNU Lesser General Public License
00014  * along with this program. If not, see <http://www.gnu.org/licenses/>.
00015  */
00016 // -----------------------------------------------------------------------------
00017 #ifndef _MBSlave_H_
00018 #define _MBSlave_H_
00019 // -----------------------------------------------------------------------------
00020 #include <ostream>
00021 #include <string>
00022 #include <memory>
00023 #include <map>
00024 #include <unordered_map>
00025 #include <vector>
00026 #include <condition_variable>
00027 #include <atomic>
00028 #include <mutex>
00029 #include "UniSetObject.h"
00030 #include "modbus/ModbusTypes.h"
00031 #include "modbus/ModbusServerSlot.h"
00032 #include "modbus/ModbusTCPServer.h"
00033 #include "modbus/ModbusTCPServerSlot.h"
00034 #include "PassiveTimer.h"
00035 #include "Trigger.h"
00036 #include "Mutex.h"
00037 #include "SMInterface.h"
00038 #include "SharedMemory.h"
00039 #include "IOBase.h"
00040 #include "VTypes.h"
00041 #include "ThreadCreator.h"
00042 #include "LogServer.h"
00043 #include "LogAgregator.h"
00044 #include "VMonitor.h"
00045 // -----------------------------------------------------------------------------
00046 #ifndef vmonit
00047 #define vmonit( var ) vmon.add( #var, var )
00048 #endif
00049 // -------------------------------------------------------------------------
00050 namespace uniset
00051 {
00052 // -----------------------------------------------------------------------------
00307 // -----------------------------------------------------------------------------
00309 class MBSlave:
00310     public UniSetObject
00311 {
00312     public:
00313         MBSlave( uniset::ObjectId objId, uniset::ObjectId shmID, const std::shared_ptr<SharedMemory>& ic = nullptr, const std::string& prefix = "mbs" );
00314         virtual ~MBSlave();
00315 
00317         static std::shared_ptr<MBSlave> init_mbslave(int argc, const char* const* argv,
00318                                                      uniset::ObjectId shmID, const std::shared_ptr<SharedMemory>& ic = nullptr,
00319                                                      const std::string& prefix = "mbs" );
00320 
00322         static void help_print( int argc, const char* const* argv );
00323 
00324         static const int NoSafetyState = -1;
00325 
00326         enum AccessMode
00327         {
00328             amRW,
00329             amRO,
00330             amWO
00331         };
00332 
00333         struct BitRegProperty;
00334 
00335         struct IOProperty:
00336             public IOBase
00337         {
00338             ModbusRTU::ModbusData mbreg;    
00339             AccessMode amode;
00340             VTypes::VType vtype;    
00341             size_t wnum;               
00342             size_t nbyte;              
00343             std::shared_ptr<BitRegProperty> bitreg; 
00344             ModbusRTU::RegID regID;
00345 
00346             IOProperty():
00347                 mbreg(0),
00348                 amode(amRW),
00349                 vtype(VTypes::vtUnknown),
00350                 wnum(0),
00351                 nbyte(0),
00352                 regID(0)
00353             {}
00354 
00355             friend std::ostream& operator<<( std::ostream& os, IOProperty& p );
00356         };
00357 
00358 
00359         struct BitRegProperty
00360         {
00361             typedef std::vector<IOProperty> BitSensorMap;
00362 
00363             ModbusRTU::ModbusData mbreg; 
00364             BitSensorMap bvec;
00365 
00366             BitRegProperty(): mbreg(0), bvec(ModbusRTU::BitsPerData) {}
00367 
00369             bool check( const IOController_i::SensorInfo& si );
00370 
00371             friend std::ostream& operator<<( std::ostream& os, BitRegProperty& p );
00372             friend std::ostream& operator<<( std::ostream& os, BitRegProperty* p );
00373         };
00374 
00375         inline long getAskCount()
00376         {
00377             return askCount;
00378         }
00379 
00380         inline std::shared_ptr<LogAgregator> getLogAggregator()
00381         {
00382             return loga;
00383         }
00384         inline std::shared_ptr<DebugStream> log()
00385         {
00386             return mblog;
00387         }
00388 
00389         virtual uniset::SimpleInfo* getInfo( const char* userparam = 0 ) override;
00390 
00391     protected:
00392 
00394         ModbusRTU::mbErrCode readCoilStatus( ModbusRTU::ReadCoilMessage& query,
00395                                              ModbusRTU::ReadCoilRetMessage& reply );
00397         ModbusRTU::mbErrCode readInputStatus( ModbusRTU::ReadInputStatusMessage& query,
00398                                               ModbusRTU::ReadInputStatusRetMessage& reply );
00399 
00401         ModbusRTU::mbErrCode readOutputRegisters( ModbusRTU::ReadOutputMessage& query,
00402                                                   ModbusRTU::ReadOutputRetMessage& reply );
00403 
00405         ModbusRTU::mbErrCode readInputRegisters( ModbusRTU::ReadInputMessage& query,
00406                                                  ModbusRTU::ReadInputRetMessage& reply );
00407 
00409         ModbusRTU::mbErrCode forceSingleCoil( ModbusRTU::ForceSingleCoilMessage& query,
00410                                               ModbusRTU::ForceSingleCoilRetMessage& reply );
00411 
00413         ModbusRTU::mbErrCode forceMultipleCoils( ModbusRTU::ForceCoilsMessage& query,
00414                                                  ModbusRTU::ForceCoilsRetMessage& reply );
00415 
00416 
00418         ModbusRTU::mbErrCode writeOutputRegisters( ModbusRTU::WriteOutputMessage& query,
00419                                                    ModbusRTU::WriteOutputRetMessage& reply );
00420 
00422         ModbusRTU::mbErrCode writeOutputSingleRegister( ModbusRTU::WriteSingleOutputMessage& query,
00423                                                         ModbusRTU::WriteSingleOutputRetMessage& reply );
00424 
00426         //        ModbusRTU::mbErrCode journalCommand( ModbusRTU::JournalCommandMessage& query,
00427         //                                                            ModbusRTU::JournalCommandRetMessage& reply );
00428 
00430         ModbusRTU::mbErrCode setDateTime( ModbusRTU::SetDateTimeMessage& query,
00431                                           ModbusRTU::SetDateTimeRetMessage& reply );
00432 
00434         ModbusRTU::mbErrCode remoteService( ModbusRTU::RemoteServiceMessage& query,
00435                                             ModbusRTU::RemoteServiceRetMessage& reply );
00436 
00437         ModbusRTU::mbErrCode fileTransfer( ModbusRTU::FileTransferMessage& query,
00438                                            ModbusRTU::FileTransferRetMessage& reply );
00439 
00440         ModbusRTU::mbErrCode diagnostics( ModbusRTU::DiagnosticMessage& query,
00441                                           ModbusRTU::DiagnosticRetMessage& reply );
00442 
00443         ModbusRTU::mbErrCode read4314( ModbusRTU::MEIMessageRDI& query,
00444                                        ModbusRTU::MEIMessageRetRDI& reply );
00445 
00449         virtual ModbusRTU::mbErrCode checkRegister( ModbusRTU::ModbusData reg, ModbusRTU::ModbusData& val )
00450         {
00451             return ModbusRTU::erNoError;
00452         }
00453 
00454         // т.к. в функциях (much_real_read,nuch_real_write) рассчёт на отсортированность IOMap
00455         // то использовать unordered_map нельзя
00456         typedef std::map<ModbusRTU::RegID, IOProperty> RegMap;
00457 
00458         typedef std::unordered_map<ModbusRTU::ModbusAddr, RegMap> IOMap;
00459 
00460         IOMap iomap;  
00462         // т.к. пороговые датчики не связаны напрямую с обменом, создаём для них отдельный список
00463         // и отдельно его проверяем потом
00464         typedef std::list<IOBase> ThresholdList;
00465         ThresholdList thrlist;
00466 
00467         std::shared_ptr<ModbusServerSlot> mbslot;
00468         std::unordered_set<ModbusRTU::ModbusAddr> vaddr; 
00469         std::string default_mbaddr = { "" };
00470 
00471         xmlNode* cnode = { 0 };
00472         std::string s_field = { "" };
00473         std::string s_fvalue = { "" };
00474         int default_mbfunc = {0}; // функция по умолчанию, для вычисления RegID
00475 
00476         std::shared_ptr<SMInterface> shm;
00477 
00478         virtual void sysCommand( const uniset::SystemMessage* msg ) override;
00479         virtual void sensorInfo( const uniset::SensorMessage* sm ) override;
00480         void askSensors( UniversalIO::UIOCommand cmd );
00481         void waitSMReady();
00482         virtual void execute_rtu();
00483         virtual void execute_tcp();
00484         virtual void updateStatistics();
00485         virtual void updateTCPStatistics();
00486         virtual void updateThresholds();
00487         virtual void postReceiveEvent( ModbusRTU::mbErrCode res );
00488 
00489         virtual bool activateObject() override;
00490         virtual bool deactivateObject() override;
00491 
00492         // действия при завершении работы
00493         virtual void sigterm( int signo ) override;
00494         virtual void finalThread();
00495 
00496         virtual void initIterators();
00497         bool initItem( UniXML::iterator& it );
00498         bool readItem( const std::shared_ptr<UniXML>& xml, UniXML::iterator& it, xmlNode* sec );
00499 
00500         void readConfiguration();
00501         bool check_item( UniXML::iterator& it );
00502 
00503         ModbusRTU::mbErrCode real_write( RegMap& rmap, const ModbusRTU::ModbusData regOKOK, ModbusRTU::ModbusData val, const int fn = 0 );
00504         ModbusRTU::mbErrCode real_write( RegMap& rmap, const ModbusRTU::ModbusData regOKOK, ModbusRTU::ModbusData* dat, size_t& i, size_t count, const int fn = 0  );
00505         ModbusRTU::mbErrCode real_read( RegMap& rmap, const ModbusRTU::ModbusData regOKOK, ModbusRTU::ModbusData& val, const int fn = 0  );
00506         ModbusRTU::mbErrCode much_real_read( RegMap& rmap, const ModbusRTU::ModbusData regOKOK, ModbusRTU::ModbusData* dat, size_t count, const int fn = 0  );
00507         ModbusRTU::mbErrCode much_real_write(RegMap& rmap, const ModbusRTU::ModbusData regOKOK, ModbusRTU::ModbusData* dat, size_t count, const int fn = 0  );
00508 
00509         ModbusRTU::mbErrCode real_read_it( RegMap& rmap, RegMap::iterator& it, ModbusRTU::ModbusData& val );
00510         ModbusRTU::mbErrCode real_bitreg_read_it( std::shared_ptr<BitRegProperty>& bp, ModbusRTU::ModbusData& val );
00511         ModbusRTU::mbErrCode real_read_prop( IOProperty* p, ModbusRTU::ModbusData& val );
00512 
00513         ModbusRTU::mbErrCode real_write_it(RegMap& rmap, RegMap::iterator& it, ModbusRTU::ModbusData* dat, size_t& i, size_t count );
00514         ModbusRTU::mbErrCode real_bitreg_write_it( std::shared_ptr<BitRegProperty>& bp, const ModbusRTU::ModbusData val );
00515         ModbusRTU::mbErrCode real_write_prop(IOProperty* p, ModbusRTU::ModbusData* dat, size_t& i, size_t count );
00516 
00517         MBSlave();
00518         timeout_t initPause = { 3000 };
00519         uniset::uniset_rwmutex mutex_start;
00520         std::shared_ptr< ThreadCreator<MBSlave> > thr;
00521 
00522         std::mutex mutexStartNotify;
00523         std::condition_variable startNotifyEvent;
00524 
00525         PassiveTimer ptHeartBeat;
00526         uniset::ObjectId sidHeartBeat = { uniset::DefaultObjectId };
00527         long maxHeartBeat = { 10 };
00528         IOController::IOStateList::iterator itHeartBeat;
00529         uniset::ObjectId test_id = { uniset::DefaultObjectId };
00530 
00531         IOController::IOStateList::iterator itAskCount;
00532         uniset::ObjectId askcount_id = { uniset::DefaultObjectId };
00533 
00534         IOController::IOStateList::iterator itRespond;
00535         uniset::ObjectId respond_id = { uniset::DefaultObjectId };
00536         bool respond_invert = { false };
00537 
00538         PassiveTimer ptTimeout;
00539         long askCount = { 0 };
00540 
00541         std::atomic_bool activated = { false };
00542         std::atomic_bool cancelled = { false };
00543         timeout_t activateTimeout = { 20000 }; // msec
00544         bool pingOK = { false };
00545         timeout_t wait_msec = { 3000 };
00546         bool force = { false };        
00548         bool mbregFromID = {0};
00549         bool checkMBFunc = {0};
00550         bool noMBFuncOptimize = {0}; // флаг отключающий принудительное преобразование функций (0x06->0x10, 0x05->0x0F) см. initItem()
00551 
00552         int getOptimizeWriteFunction( const int fn ); // функция возвращает оптимизированную функцию (если оптимизация включена)
00553 
00554         typedef std::unordered_map<int, std::string> FileList;
00555         FileList flist;
00556         std::string prefix = { "" };
00557         std::string prop_prefix = { "" };
00558 
00559         ModbusRTU::ModbusData buf[ModbusRTU::MAXLENPACKET / 2 + 1]; 
00561         // данные для ответа на запрос 0x2B(43)/0x0E(14)
00562         // 'MEI' - modbus encapsulated interface
00563         // 'RDI' - read device identification
00564         typedef std::unordered_map<int, std::string> MEIValMap;
00565         typedef std::unordered_map<int, MEIValMap> MEIObjIDMap;
00566         typedef std::unordered_map<int, MEIObjIDMap> MEIDevIDMap;
00567 
00568         MEIDevIDMap meidev;
00569 
00570         std::shared_ptr<LogAgregator> loga;
00571         std::shared_ptr<DebugStream> mblog;
00572         std::shared_ptr<LogServer> logserv;
00573         std::string logserv_host = {""};
00574         int logserv_port = {0};
00575         VMonitor vmon;
00576         std::string mbtype = { "" };
00577 
00578         // ----------------------------------------------------------------------------
00579         // TCPServer section..
00580         void initTCPClients( UniXML::iterator confnode );
00581 
00582         timeout_t sessTimeout = { 2000 };  
00583         timeout_t updateStatTime = { 4000 };
00584         ModbusTCPServer::Sessions sess; 
00585         std::mutex sessMutex;
00586         size_t sessMaxNum = { 5 };
00587         std::shared_ptr<ModbusTCPServerSlot> tcpserver;
00588 
00589         struct ClientInfo
00590         {
00591             ClientInfo(): iaddr(""), respond_s(uniset::DefaultObjectId), invert(false),
00592                 askCount(0), askcount_s(uniset::DefaultObjectId)
00593             {
00594                 ptTimeout.setTiming(0);
00595             }
00596 
00597             std::string iaddr = { "" };
00598 
00599             uniset::ObjectId respond_s = { uniset::DefaultObjectId };
00600             IOController::IOStateList::iterator respond_it;
00601             bool invert = { false };
00602             PassiveTimer ptTimeout;
00603             timeout_t tout = { 2000 };
00604 
00605             long askCount = { 0 };
00606             uniset::ObjectId askcount_s = { uniset::DefaultObjectId };
00607             IOController::IOStateList::iterator askcount_it;
00608 
00609             inline void initIterators( const std::shared_ptr<SMInterface>& shm )
00610             {
00611                 shm->initIterator( respond_it );
00612                 shm->initIterator( askcount_it );
00613             }
00614 
00615             const std::string getShortInfo() const;
00616         };
00617 
00618         typedef std::unordered_map<std::string, ClientInfo> ClientsMap;
00619         ClientsMap cmap;
00620 
00621         uniset::ObjectId sesscount_id = { uniset::DefaultObjectId };
00622         IOController::IOStateList::iterator sesscount_it;
00623 
00624         std::atomic_bool tcpCancelled = { true };
00625 };
00626 // --------------------------------------------------------------------------
00627 } // end of namespace uniset
00628 // -----------------------------------------------------------------------------
00629 #endif // _MBSlave_H_
00630 // -----------------------------------------------------------------------------