UniSet  2.6.0
MBExchange.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 _MBExchange_H_
00018 #define _MBExchange_H_
00019 // -----------------------------------------------------------------------------
00020 #include <ostream>
00021 #include <string>
00022 #include <map>
00023 #include <unordered_map>
00024 #include <memory>
00025 #include "IONotifyController.h"
00026 #include "UniSetObject.h"
00027 #include "PassiveTimer.h"
00028 #include "DelayTimer.h"
00029 #include "Trigger.h"
00030 #include "Mutex.h"
00031 #include "Calibration.h"
00032 #include "SMInterface.h"
00033 #include "SharedMemory.h"
00034 #include "ThreadCreator.h"
00035 #include "IOBase.h"
00036 #include "VTypes.h"
00037 #include "MTR.h"
00038 #include "RTUStorage.h"
00039 #include "modbus/ModbusClient.h"
00040 #include "LogAgregator.h"
00041 #include "LogServer.h"
00042 #include "LogAgregator.h"
00043 #include "VMonitor.h"
00044 // -----------------------------------------------------------------------------
00045 #ifndef vmonit
00046 #define vmonit( var ) vmon.add( #var, var )
00047 #endif
00048 // -------------------------------------------------------------------------
00049 namespace uniset
00050 {
00051 // -----------------------------------------------------------------------------
00055 class MBExchange:
00056     public UniSetObject
00057 {
00058     public:
00059         MBExchange( uniset::ObjectId objId, uniset::ObjectId shmID, const std::shared_ptr<SharedMemory>& ic = nullptr,
00060                     const std::string& prefix = "mb" );
00061         virtual ~MBExchange();
00062 
00064         static void help_print( int argc, const char* const* argv );
00065 
00066         static const int NoSafetyState = -1;
00067 
00069         enum ExchangeMode
00070         {
00071             emNone = 0,       
00072             emWriteOnly = 1,  
00073             emReadOnly = 2,   
00074             emSkipSaveToSM = 3, 
00075             emSkipExchange = 4 
00076         };
00077 
00078         friend std::ostream& operator<<( std::ostream& os, const ExchangeMode& em );
00079 
00080         enum DeviceType
00081         {
00082             dtUnknown,      
00083             dtRTU,          
00084             dtMTR,          
00085             dtRTU188        
00086         };
00087 
00088         static DeviceType getDeviceType( const std::string& dtype );
00089         friend std::ostream& operator<<( std::ostream& os, const DeviceType& dt );
00090 
00091         struct RTUDevice;
00092         struct RegInfo;
00093 
00094         struct RSProperty:
00095             public IOBase
00096         {
00097             // only for RTU
00098             short nbit;             
00099             VTypes::VType vType;    
00100             unsigned short rnum;    
00101             unsigned short nbyte;   
00103             RSProperty():
00104                 nbit(-1), vType(VTypes::vtUnknown),
00105                 rnum(VTypes::wsize(VTypes::vtUnknown)),
00106                 nbyte(0)
00107             {}
00108 
00109             // т.к. IOBase содержит rwmutex с запрещённым конструктором копирования
00110             // приходится здесь тоже объявлять разрешенными только операции "перемещения"
00111             RSProperty( const RSProperty& r ) = delete;
00112             RSProperty& operator=(const RSProperty& r) = delete;
00113             RSProperty( RSProperty&& r ) = default;
00114             RSProperty& operator=(RSProperty&& r) = default;
00115 
00116             std::shared_ptr<RegInfo> reg;
00117         };
00118 
00119         friend std::ostream& operator<<( std::ostream& os, const RSProperty& p );
00120 
00121         typedef std::list<RSProperty> PList;
00122         static std::ostream& print_plist( std::ostream& os, const PList& p );
00123 
00124         typedef std::map<ModbusRTU::RegID, std::shared_ptr<RegInfo>> RegMap;
00125         struct RegInfo
00126         {
00127             // т.к. RSProperty содержит rwmutex с запрещённым конструктором копирования
00128             // приходится здесь тоже объявлять разрешенными только операции "перемещения"
00129             RegInfo( const RegInfo& r ) = default;
00130             RegInfo& operator=(const RegInfo& r) = delete;
00131             RegInfo( RegInfo&& r ) = delete;
00132             RegInfo& operator=(RegInfo&& r) = default;
00133 
00134             RegInfo():
00135                 mbval(0), mbreg(0), mbfunc(ModbusRTU::fnUnknown),
00136                 id(0), dev(0),
00137                 rtuJack(RTUStorage::nUnknown), rtuChan(0),
00138                 mtrType(MTR::mtUnknown),
00139                 q_num(0), q_count(1), mb_initOK(false), sm_initOK(false)
00140             {}
00141 
00142             ModbusRTU::ModbusData mbval;
00143             ModbusRTU::ModbusData mbreg;            
00144             ModbusRTU::SlaveFunctionCode mbfunc;    
00145             PList slst;
00146             ModbusRTU::RegID id;
00147 
00148             std::shared_ptr<RTUDevice> dev;
00149 
00150             // only for RTU188
00151             RTUStorage::RTUJack rtuJack;
00152             int rtuChan;
00153 
00154             // only for MTR
00155             MTR::MTRType mtrType;    
00157             // optimization
00158             size_t q_num;      
00159             size_t q_count;    
00161             RegMap::iterator rit;
00162 
00163             // начальная инициалиазция для "записываемых" регистров
00164             // Механизм:
00165             // Если tcp_preinit="1", то сперва будет сделано чтение значения из устройства.
00166             // при этом флаг mb_init=false пока не пройдёт успешной инициализации
00167             // Если tcp_preinit="0", то флаг mb_init сразу выставляется в true.
00168             bool mb_initOK;    
00170             // Флаг sm_init означает, что писать в устройство нельзя, т.к. значение в "карте регистров"
00171             // ещё не инициализировано из SM
00172             bool sm_initOK;    
00173         };
00174 
00175         friend std::ostream& operator<<( std::ostream& os, RegInfo& r );
00176         friend std::ostream& operator<<( std::ostream& os, RegInfo* r );
00177 
00178         struct RTUDevice
00179         {
00180             RTUDevice():
00181                 mbaddr(0),
00182                 dtype(dtUnknown),
00183                 resp_id(uniset::DefaultObjectId),
00184                 resp_state(false),
00185                 resp_invert(false),
00186                 numreply(0),
00187                 prev_numreply(0),
00188                 ask_every_reg(false),
00189                 mode_id(uniset::DefaultObjectId),
00190                 mode(emNone),
00191                 speed(ComPort::ComSpeed38400),
00192                 rtu188(0)
00193             {
00194             }
00195 
00196             ModbusRTU::ModbusAddr mbaddr;    
00197             std::unordered_map<unsigned int, std::shared_ptr<RegMap>> pollmap;
00198 
00199             DeviceType dtype;    
00201             // resp - respond..(контроль наличия связи)
00202             uniset::ObjectId resp_id;
00203             IOController::IOStateList::iterator resp_it;
00204             DelayTimer resp_Delay; // таймер для формирования задержки на отпускание (пропадание связи)
00205             PassiveTimer resp_ptInit; // таймер для формирования задержки на инициализацию связи (задержка на выставление датчика связи после запуска)
00206             bool resp_state;
00207             bool resp_invert;
00208             bool resp_force = { false };
00209             Trigger trInitOK; // триггер для "инициализации"
00210             std::atomic<size_t> numreply; // количество успешных запросов..
00211             std::atomic<size_t> prev_numreply;
00212 
00213             //
00214             bool ask_every_reg; 
00216             // режим работы
00217             uniset::ObjectId mode_id;
00218             IOController::IOStateList::iterator mode_it;
00219             long mode; // режим работы с устройством (см. ExchangeMode)
00220 
00221             // return TRUE if state changed
00222             bool checkRespond( std::shared_ptr<DebugStream>& log );
00223 
00224             // специфические поля для RS
00225             ComPort::Speed speed;
00226             std::shared_ptr<RTUStorage> rtu188;
00227 
00228             std::string getShortInfo() const;
00229         };
00230 
00231         friend std::ostream& operator<<( std::ostream& os, RTUDevice& d );
00232 
00233         typedef std::unordered_map<ModbusRTU::ModbusAddr, std::shared_ptr<RTUDevice>> RTUDeviceMap;
00234 
00235         friend std::ostream& operator<<( std::ostream& os, RTUDeviceMap& d );
00236         void printMap(RTUDeviceMap& d);
00237 
00238         // ----------------------------------
00239         enum Timer
00240         {
00241             tmExchange
00242         };
00243 
00244         void execute();
00245 
00246         inline std::shared_ptr<LogAgregator> getLogAggregator()
00247         {
00248             return loga;
00249         }
00250         inline std::shared_ptr<DebugStream> log()
00251         {
00252             return mblog;
00253         }
00254 
00255         virtual uniset::SimpleInfo* getInfo( const char* userparam = 0 ) override;
00256 
00257     protected:
00258         virtual void step();
00259         virtual void sysCommand( const uniset::SystemMessage* msg ) override;
00260         virtual void sensorInfo( const uniset::SensorMessage* sm ) override;
00261         virtual void timerInfo( const uniset::TimerMessage* tm ) override;
00262         virtual void askSensors( UniversalIO::UIOCommand cmd );
00263         virtual void initOutput();
00264         virtual void sigterm( int signo ) override;
00265         virtual bool activateObject() override;
00266         virtual void initIterators();
00267         virtual void initValues();
00268 
00269         struct InitRegInfo
00270         {
00271             InitRegInfo():
00272                 dev(0), mbreg(0),
00273                 mbfunc(ModbusRTU::fnUnknown),
00274                 initOK(false)
00275             {}
00276             RSProperty p;
00277             std::shared_ptr<RTUDevice> dev;
00278             ModbusRTU::ModbusData mbreg;
00279             ModbusRTU::SlaveFunctionCode mbfunc;
00280             bool initOK;
00281             std::shared_ptr<RegInfo> ri;
00282         };
00283         typedef std::list<InitRegInfo> InitList;
00284 
00285         void firstInitRegisters();
00286         bool preInitRead( InitList::iterator& p );
00287         bool initSMValue( ModbusRTU::ModbusData* data, int count, RSProperty* p );
00288         bool allInitOK;
00289 
00290         RTUDeviceMap devices;
00291         InitList initRegList;    
00292         //      uniset::uniset_rwmutex pollMutex;
00293 
00294         virtual std::shared_ptr<ModbusClient> initMB( bool reopen = false ) = 0;
00295 
00296         virtual bool poll();
00297         bool pollRTU( std::shared_ptr<RTUDevice>& dev, RegMap::iterator& it );
00298 
00299         void updateSM();
00300         void updateRTU(RegMap::iterator& it);
00301         void updateMTR(RegMap::iterator& it);
00302         void updateRTU188(RegMap::iterator& it);
00303         void updateRSProperty( RSProperty* p, bool write_only = false );
00304         virtual void updateRespondSensors();
00305 
00306         bool checkUpdateSM( bool wrFunc, long devMode );
00307         bool checkPoll( bool wrFunc ) const;
00308 
00309         bool checkProcActive() const;
00310         void setProcActive( bool st );
00311         void waitSMReady();
00312 
00313         void readConfiguration();
00314         bool readItem( const std::shared_ptr<UniXML>& xml, UniXML::iterator& it, xmlNode* sec );
00315         bool initItem( UniXML::iterator& it );
00316         void initDeviceList();
00317         void initOffsetList();
00318 
00319         std::shared_ptr<RTUDevice> addDev( RTUDeviceMap& dmap, ModbusRTU::ModbusAddr a, UniXML::iterator& it );
00320         std::shared_ptr<RegInfo> addReg(std::shared_ptr<RegMap>& devices, ModbusRTU::RegID id, ModbusRTU::ModbusData r, UniXML::iterator& it, std::shared_ptr<RTUDevice> dev );
00321         RSProperty* addProp( PList& plist, RSProperty&& p );
00322 
00323         bool initMTRitem(UniXML::iterator& it, std::shared_ptr<RegInfo>& p );
00324         bool initRTU188item(UniXML::iterator& it, std::shared_ptr<RegInfo>& p );
00325         bool initRSProperty( RSProperty& p, UniXML::iterator& it );
00326         bool initRegInfo(std::shared_ptr<RegInfo>& r, UniXML::iterator& it, std::shared_ptr<RTUDevice>& dev  );
00327         bool initRTUDevice( std::shared_ptr<RTUDevice>& d, UniXML::iterator& it );
00328         virtual bool initDeviceInfo( RTUDeviceMap& m, ModbusRTU::ModbusAddr a, UniXML::iterator& it );
00329 
00330         std::string initPropPrefix( const std::string& def_prop_prefix = "" );
00331 
00332         void rtuQueryOptimization( RTUDeviceMap& m );
00333 
00334         xmlNode* cnode = { 0 };
00335         std::string s_field;
00336         std::string s_fvalue;
00337 
00338         std::shared_ptr<SMInterface> shm;
00339 
00340         timeout_t initPause = { 3000 };
00341         uniset::uniset_rwmutex mutex_start;
00342 
00343         bool force =  { false };        
00344         bool force_out = { false };    
00345         bool mbregFromID = { false };
00346         timeout_t polltime = { 100 };    
00347         timeout_t sleepPause_msec;
00348         size_t maxQueryCount = { ModbusRTU::MAXDATALEN }; 
00350         PassiveTimer ptHeartBeat;
00351         uniset::ObjectId sidHeartBeat = { uniset::DefaultObjectId };
00352         long maxHeartBeat = { 10 };
00353         IOController::IOStateList::iterator itHeartBeat;
00354         uniset::ObjectId test_id = { uniset::DefaultObjectId };
00355 
00356         uniset::ObjectId sidExchangeMode = { uniset::DefaultObjectId }; 
00357         IOController::IOStateList::iterator itExchangeMode;
00358         long exchangeMode = {emNone}; 
00360         std::atomic_bool activated = { false };
00361         timeout_t activateTimeout = { 20000 }; // msec
00362         bool noQueryOptimization = { false };
00363         bool no_extimer = { false };
00364 
00365         std::string prefix;
00366 
00367         timeout_t stat_time = { 0 };      
00368         size_t poll_count = { 0 };
00369         PassiveTimer ptStatistic; 
00370         std::string statInfo = { "" };
00371 
00372         std::string prop_prefix;  
00374         std::shared_ptr<ModbusClient> mb;
00375 
00376         // определение timeout для соединения
00377         timeout_t recv_timeout = { 500 }; // msec
00378         timeout_t default_timeout = { 5000 }; // msec
00379 
00380         timeout_t aftersend_pause = { 0 };
00381 
00382         PassiveTimer ptReopen; 
00383         Trigger trReopen;
00384 
00385         PassiveTimer ptInitChannel; 
00387         // т.к. пороговые датчики не связаны напрямую с обменом, создаём для них отдельный список
00388         // и отдельно его проверяем потом
00389         typedef std::list<IOBase> ThresholdList;
00390         ThresholdList thrlist;
00391 
00392         std::string defaultMBtype;
00393         std::string defaultMBaddr;
00394         bool defaultMBinitOK = { false }; // флаг определяющий нужно ли ждать "первого обмена" или при запуске сохранять в SM значение default.
00395 
00396         std::shared_ptr<LogAgregator> loga;
00397         std::shared_ptr<DebugStream> mblog;
00398         std::shared_ptr<LogServer> logserv;
00399         std::string logserv_host = {""};
00400         int logserv_port = {0};
00401         const std::shared_ptr<SharedMemory> ic;
00402 
00403         VMonitor vmon;
00404 
00405         size_t ncycle = { 0 }; 
00407     private:
00408         MBExchange();
00409 
00410 };
00411 // --------------------------------------------------------------------------
00412 } // end of namespace uniset
00413 // -----------------------------------------------------------------------------
00414 #endif // _MBExchange_H_
00415 // -----------------------------------------------------------------------------