198 lines
5.7 KiB
C++
198 lines
5.7 KiB
C++
/*
|
||
* ModbusRtu.hh
|
||
*
|
||
* Created on: 26 авг. 2020 г.
|
||
* Author: LeonidTitov
|
||
*/
|
||
|
||
#ifndef UMLIBRARY_DRIVER_MODBUSRTU_HH_
|
||
|
||
#define UMLIBRARY_DRIVER_MODBUSRTU_HH_
|
||
|
||
#include <cstddef>
|
||
#include <stdint.h>
|
||
#include <memory_resource>
|
||
#include <deque>
|
||
#include <vector>
|
||
#include <map>
|
||
|
||
#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<char,polymorphic_allocator<char> > DequePolyAlloc;
|
||
typedef deque<uint16_t,polymorphic_allocator<uint16_t> > DequeU16PolyAlloc;
|
||
typedef map<uint16_t, uint16_t, std::less<uint16_t>,
|
||
polymorphic_allocator<pair<const uint16_t,uint16_t> > > MapPolyAlloc;
|
||
typedef vector<char,polymorphic_allocator<char> > VecPolyAlloc;
|
||
typedef map<uint16_t,IModBusDispatch*,std::less<uint16_t>,
|
||
polymorphic_allocator<pair<const uint16_t,IModBusDispatch*> > > 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<uint16_t>(),adu.mpMemRes),
|
||
mMapTaskWr(std::less<uint16_t>(),adu.mpMemRes),
|
||
mMapTaskRes(std::less<uint16_t>(),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<uint16_t>(), 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_ */
|