/* * ModbusRtu.hh * * Created on: 26 авг. 2020 г. * Author: LeonidTitov */ #ifndef UMLIBRARY_DRIVER_MODBUSRTU_HH_ #define UMLIBRARY_DRIVER_MODBUSRTU_HH_ #include #include #include #include #include #include #include "../common/Crc.hpp" #include "../peripheral/IUartPort.hh" #include "IModBus.hh" namespace driver { namespace modbus { using peripheral::IUartPort; using std::pmr::memory_resource; using std::pmr::polymorphic_allocator; using std::pmr::get_default_resource; using std::deque; using std::vector; using std::map; using std::pair; using std::make_pair; typedef deque > DequePolyAlloc; typedef deque > DequeU16PolyAlloc; typedef map, polymorphic_allocator > > MapPolyAlloc; typedef vector > VecPolyAlloc; typedef map, polymorphic_allocator > > MapDispPolyAlloc; class ModBusPdu; class ModBusDispatch; class ModBusAdu { IUartPort & mIUartPort; const unsigned char mAddr; memory_resource * const mpMemRes; friend class ModBusPdu; friend class ModBusDispatch; bool crc_error_flag; public: typedef common::crc::Crc16_IBM ModbusCrc; ModBusAdu ( unsigned char addr, IUartPort& port, memory_resource* pMemRes ) : mIUartPort(port), mAddr(addr), mpMemRes(pMemRes), crc_error_flag(false) {} /* Запрос фрэйма PDU */ bool getFrm( DequePolyAlloc & deqFrm ); bool putFrm( DequePolyAlloc & deqFrm ); bool isCrcError() const; }; class ModBusPdu { enum FuncCode { DummyCode, // ?? ReadCoil = 1, WriteSingleCoil = 5, WriteMultipleCoil = 15, // DO ReadDiscreteInput = 2, // DI ReadHoldingReg = 3, WriteSingleReg = 6, WriteMultipleReg = 16, // AO ReadInputReg = 4, // AI }; friend class ModBusDispatch; public: enum ExceptCode { NoException, IllegalFunc, IllegalDataAddr, IllegalDataValue, ServerDeviceFail, Acknowledge, ServerDeviceBusy, MemoryParityErr = 8, GatewayPathUnvail = 10, GatewayTargetDeviceFailResp }; private: struct DataTableBegin { static const uint16_t DO = 1; static const uint16_t DI = 10001; static const uint16_t AI = 30001; static const uint16_t AO = 40001; }; ModBusAdu & mAdu; DequePolyAlloc deqFrmReq; //!<Буфер для запроса DequePolyAlloc deqFrmRes; //!<Буфер для ответа bool mIsBroadcast; //!<Флаг широковешательного запроса uint16_t mFuncCode; //!< != 0 Текущий активный код, 0 -> состояние ожидания ExceptCode mExcCode; //!<Код исключения uint16_t packet_counter; public: MapPolyAlloc mMapTaskRd; //!<Очередь заданий на чтение MapPolyAlloc mMapTaskWr; //!<Очередь заданий на запись MapPolyAlloc mMapTaskRes; //!<Очередь полученных результатов public: ModBusPdu ( ModBusAdu& adu ) : mAdu(adu), mIsBroadcast(false), mFuncCode(DummyCode), mExcCode(NoException), deqFrmReq(adu.mpMemRes), deqFrmRes(adu.mpMemRes), mMapTaskRd(std::less(),adu.mpMemRes), mMapTaskWr(std::less(),adu.mpMemRes), mMapTaskRes(std::less(),adu.mpMemRes), packet_counter(0) {} //!Процесс ожидания запроса и формирования по нему списка заданий void processReq(); //!Процесс ожидания выполнение списка заданий и отправка ответа на запрос void processResp(); void setExceptCode( ExceptCode code ); bool isException() const; uint16_t getPacketCounter() const; ExceptCode getExceptCode() const; private: //!Получение максимально количества регистров в операции по ее коду uint16_t getLimitQuantity( FuncCode code ) const; //!Получение начального смещения в таблице данных по коду операции uint16_t getDataTblShift( FuncCode code ) const; }; class ModBusDispatch { enum TaskType { TaskRead, TaskWrite }; MapDispPolyAlloc mBase; ModBusPdu & mPdu; public: ModBusDispatch ( ModBusPdu& pdu ) : mPdu(pdu), mBase(std::less(), pdu.mAdu.mpMemRes) {} void add( uint16_t nReg, IModBusDispatch & disp ); void del( uint16_t nReg ); void process(); private: void dispatch( TaskType typeOp, MapPolyAlloc & mapTasks ); }; class ModBusRtu : public IModBus { ModBusAdu mAdu; ModBusPdu mPdu; ModBusDispatch mDisp; IUartPort& mPort; public: ModBusRtu ( uint16_t addr, IUartPort& port, memory_resource* pMemRes = get_default_resource () ) : mAdu(addr,port,pMemRes), mPdu(mAdu), mDisp(mPdu), mPort(port) {} void process(); void add( uint16_t nReg, IModBusDispatch & disp ); void del( uint16_t nReg ); bool isCrcError() const; bool isException() const; float getPacketCounter() const; }; } // namespace modbus } // namespace driver #endif /* UMLIBRARY_DRIVER_MODBUSRTU_HH_ */