Commit eb6f42a3 authored by Pavel Vainerman's avatar Pavel Vainerman

(ModbusSlave): ГЛОБАЛЬНОЕ ПЕРЕПИСЫВАНИЕ ФОРМАТОВ.

Чтобы посылать в соответсвии со стандартом, посылать сообщение одним "пакетом" (по крайней мере одним write(buf,len), изменён формат ModbusMessage. А также проведён небольшой рефакторинг классов ModbusXXX.
parent bb43c2e0
......@@ -170,12 +170,12 @@ class ModbusClient
\param len - size of buf
\return real data lenght ( must be <= len )
*/
virtual size_t getNextData( unsigned char* buf, int len ) = 0;
virtual size_t getNextData( unsigned char* buf, size_t len ) = 0;
/*! set timeout for send/receive data */
virtual void setChannelTimeout( timeout_t msec ) = 0;
virtual ModbusRTU::mbErrCode sendData( unsigned char* buf, int len ) = 0;
virtual ModbusRTU::mbErrCode sendData( unsigned char* buf, size_t len ) = 0;
/*! функция запрос-ответ */
virtual ModbusRTU::mbErrCode query( ModbusRTU::ModbusAddr addr, ModbusRTU::ModbusMessage& msg,
......
......@@ -46,12 +46,12 @@ class ModbusRTUMaster:
\param len - size of buf
\return real data lenght ( must be <= len )
*/
virtual size_t getNextData( unsigned char* buf, int len ) override;
virtual size_t getNextData( unsigned char* buf, size_t len ) override;
/*! set timeout for send/receive data */
virtual void setChannelTimeout( timeout_t msec ) override;
virtual ModbusRTU::mbErrCode sendData( unsigned char* buf, int len ) override;
virtual ModbusRTU::mbErrCode sendData( unsigned char* buf, size_t len ) override;
/*! функция запрос-ответ */
virtual ModbusRTU::mbErrCode query( ModbusRTU::ModbusAddr addr, ModbusRTU::ModbusMessage& msg,
......
......@@ -299,11 +299,11 @@ class ModbusServer
virtual ModbusRTU::mbErrCode send( ModbusRTU::ModbusMessage& buf );
// Если заголовок не должен использоваться оставляйте request.header.len = 0
virtual ModbusRTU::mbErrCode make_adu_header( ModbusTCP::ADU& request )
virtual ModbusRTU::mbErrCode make_adu_header( ModbusRTU::ModbusMessage& request )
{
return ModbusRTU::erNoError;
}
virtual ModbusRTU::mbErrCode post_send_request( ModbusTCP::ADU& request )
virtual ModbusRTU::mbErrCode post_send_request( ModbusRTU::ModbusMessage& request )
{
return ModbusRTU::erNoError;
}
......
......@@ -50,9 +50,9 @@ class ModbusTCPMaster:
protected:
virtual size_t getNextData( unsigned char* buf, int len ) override;
virtual size_t getNextData(unsigned char* buf, size_t len ) override;
virtual void setChannelTimeout( timeout_t msec ) override;
virtual ModbusRTU::mbErrCode sendData( unsigned char* buf, int len ) override;
virtual ModbusRTU::mbErrCode sendData( unsigned char* buf, size_t len ) override;
virtual ModbusRTU::mbErrCode query( ModbusRTU::ModbusAddr addr, ModbusRTU::ModbusMessage& msg,
ModbusRTU::ModbusMessage& reply, timeout_t timeout ) override;
......
......@@ -137,7 +137,7 @@ class ModbusTCPServer:
ost::InetAddress iaddr;
std::string myname;
std::queue<unsigned char> qrecv;
ModbusTCP::MBAPHeader curQueryHeader;
ModbusRTU::ADUHeader curQueryHeader;
std::mutex sMutex;
typedef std::list<std::shared_ptr<ModbusTCPSession>> SessionList;
......
......@@ -72,9 +72,9 @@ class ModbusTCPSession:
virtual size_t getNextData( unsigned char* buf, int len ) override;
virtual void setChannelTimeout( timeout_t msec );
virtual ModbusRTU::mbErrCode sendData( unsigned char* buf, int len ) override;
virtual ModbusRTU::mbErrCode tcp_processing(ModbusTCP::MBAPHeader& mhead );
virtual ModbusRTU::mbErrCode make_adu_header( ModbusTCP::ADU& request ) override;
virtual ModbusRTU::mbErrCode post_send_request( ModbusTCP::ADU& request ) override;
virtual ModbusRTU::mbErrCode tcp_processing( ModbusRTU::ADUHeader& mhead );
virtual ModbusRTU::mbErrCode make_adu_header( ModbusRTU::ModbusMessage& request ) override;
virtual ModbusRTU::mbErrCode post_send_request(ModbusRTU::ModbusMessage& request ) override;
virtual ModbusRTU::mbErrCode readCoilStatus( ModbusRTU::ReadCoilMessage& query,
ModbusRTU::ReadCoilRetMessage& reply );
......@@ -120,8 +120,8 @@ class ModbusTCPSession:
private:
std::queue<unsigned char> qrecv;
ModbusTCP::MBAPHeader curQueryHeader;
std::unordered_set<ModbusRTU::ModbusAddr> vaddr;
ModbusRTU::ADUHeader curQueryHeader;
PassiveTimer ptTimeout;
timeout_t timeout = { 0 };
ModbusRTU::ModbusMessage buf;
......
......@@ -21,12 +21,12 @@
namespace ModbusRTU
{
// Базовые типы
typedef unsigned char ModbusByte; /*!< modbus-байт */
typedef uint8_t ModbusByte; /*!< modbus-байт */
const size_t BitsPerByte = 8;
typedef unsigned char ModbusAddr; /*!< адрес узла в modbus-сети */
typedef unsigned short ModbusData; /*!< размер данных в modbus-сообщениях */
typedef uint8_t ModbusAddr; /*!< адрес узла в modbus-сети */
typedef uint16_t ModbusData; /*!< размер данных в modbus-сообщениях */
const size_t BitsPerData = 16;
typedef unsigned short ModbusCRC; /*!< размер CRC16 в modbus-сообщениях */
typedef uint16_t ModbusCRC; /*!< размер CRC16 в modbus-сообщениях */
// ---------------------------------------------------------------------
/*! Коды используемых функций (согласно описанию modbus) */
......@@ -132,10 +132,10 @@ namespace ModbusRTU
const unsigned char MBErrMask = 0x80;
// ---------------------------------------------------------------------
unsigned short SWAPSHORT(unsigned short x);
uint16_t SWAPSHORT( uint16_t x );
// ---------------------------------------------------------------------
/*! Расчёт контрольной суммы */
ModbusCRC checkCRC( ModbusByte* start, int len );
ModbusCRC checkCRC( ModbusByte* start, size_t len );
const size_t szCRC = sizeof(ModbusCRC); /*!< размер данных для контрольной суммы */
// ---------------------------------------------------------------------
/*! вывод сообщения */
......@@ -161,15 +161,29 @@ namespace ModbusRTU
} __attribute__((packed));
const size_t szModbusHeader = sizeof(ModbusHeader);
std::ostream& operator<<(std::ostream& os, const ModbusHeader& m );
std::ostream& operator<<(std::ostream& os, const ModbusHeader* m );
// -----------------------------------------------------------------------
struct ADUHeader
{
ModbusRTU::ModbusData tID; /*!< transaction ID */
ModbusRTU::ModbusData pID; /*!< protocol ID */
ModbusRTU::ModbusData len; /*!< lenght */
ADUHeader(): tID(0), pID(0), len(0) {}
void swapdata();
} __attribute__((packed));
std::ostream& operator<<(std::ostream& os, const ADUHeader& m );
// -----------------------------------------------------------------------
/*! Базовое (сырое) сообщение
\todo Может переименовать ModbusMessage в TransportMessage?
*/
struct ModbusMessage:
public ModbusHeader
struct ModbusMessage
{
ModbusMessage();
......@@ -178,10 +192,29 @@ namespace ModbusRTU
ModbusMessage( const ModbusMessage& ) = default;
ModbusMessage& operator=(const ModbusMessage& ) = default;
inline ModbusByte func() const { return pduhead.func; }
inline ModbusAddr addr() const { return pduhead.addr; }
inline ModbusRTU::ModbusData tID() const { return aduhead.tID; }
inline ModbusRTU::ModbusData pID() const { return aduhead.pID; }
inline ModbusRTU::ModbusData aduLen() const { return aduhead.len; }
unsigned char* buf();
ModbusRTU::ModbusData len() const;
void swapHead();
void makeHead( ModbusRTU::ModbusData tID, bool noCRC = true, ModbusRTU::ModbusData pID=0 );
ModbusRTU::ModbusData pduLen() const;
ModbusCRC pduCRC( size_t len ) const;
static size_t maxSizeOfMessage();
void clear();
ADUHeader aduhead;
ModbusHeader pduhead;
ModbusByte data[MAXLENPACKET + szCRC]; /*!< данные */
// Это поле вспомогательное и игнорируется при пересылке
size_t len = { 0 }; /*!< фактическая длина */
size_t dlen = { 0 }; /*!< фактическая длина сообщения */
} __attribute__((packed));
std::ostream& operator<<(std::ostream& os, const ModbusMessage& m );
......@@ -1573,39 +1606,5 @@ namespace ModbusRTU
// -----------------------------------------------------------------------
} // end of ModbusRTU namespace
// ---------------------------------------------------------------------------
namespace ModbusTCP
{
struct MBAPHeader
{
ModbusRTU::ModbusData tID; /*!< transaction ID */
ModbusRTU::ModbusData pID; /*!< protocol ID */
ModbusRTU::ModbusData len; /*!< lenght */
/* ModbusRTU::ModbusByte uID; */ /*!< unit ID */ /* <------- see ModbusHeader */
MBAPHeader(): tID(0), pID(0), len(0) /*,uID(0) */ {}
void swapdata();
} __attribute__((packed));
std::ostream& operator<<(std::ostream& os, const MBAPHeader& m );
// просто агрегированное сообщение
struct ADU
{
MBAPHeader header;
ModbusRTU::ModbusMessage pdu; // здесь ссылка!! (т.к. ADU это просто обёртка для удобной посылки данных)
size_t len = { 0 };
ADU( const ModbusRTU::ModbusMessage& m ):pdu(m),len(sizeof(header) + m.len){}
} __attribute__((packed));
std::ostream& operator<<(std::ostream& os, const ADU& m );
// -----------------------------------------------------------------------
} // end of namespace ModbusTCP
// ---------------------------------------------------------------------------
#endif // ModbusTypes_H_
// ---------------------------------------------------------------------------
......@@ -124,7 +124,7 @@ int ModbusRTUMaster::getTimeout()
return port->getTimeout();
}
// -------------------------------------------------------------------------
size_t ModbusRTUMaster::getNextData( unsigned char* buf, int len )
size_t ModbusRTUMaster::getNextData( unsigned char* buf, size_t len )
{
// if( !port ) return 0;
return port->receiveBlock(buf, len);
......@@ -136,7 +136,7 @@ void ModbusRTUMaster::setChannelTimeout( timeout_t msec )
port->setTimeout(msec);
}
// --------------------------------------------------------------------------------
mbErrCode ModbusRTUMaster::sendData( unsigned char* buf, int len )
mbErrCode ModbusRTUMaster::sendData(unsigned char* buf, size_t len )
{
try
{
......@@ -159,6 +159,6 @@ mbErrCode ModbusRTUMaster::query( ModbusAddr addr, ModbusMessage& msg,
if( res != erNoError )
return res;
return recv(addr, msg.func, reply, timeout);
return recv(addr, msg.pduhead.func, reply, timeout);
}
// --------------------------------------------------------------------------------
......@@ -169,7 +169,7 @@ mbErrCode ModbusRTUSlave::realReceive(const std::unordered_set<ModbusAddr>& vmba
// то посылаем
if( res < erInternalErrorCode )
{
ErrorRetMessage em( buf.addr, buf.func, res );
ErrorRetMessage em( buf.addr(), buf.func(), res );
buf = em.transport_msg();
send(buf);
printProcessingTime();
......
......@@ -80,11 +80,11 @@ size_t ModbusTCPCore::getNextData(UTCPStream* tcp,
std::queue<unsigned char>& qrecv,
unsigned char* buf, size_t len, timeout_t t )
{
if( !tcp || !tcp->isConnected() )
return 0;
if( qrecv.empty() )
if( qrecv.empty() || qrecv.size() < len )
{
if( !tcp || !tcp->isConnected() )
return 0;
if( len <= 0 )
len = 7;
......@@ -159,7 +159,7 @@ size_t ModbusTCPCore::readDataFD( int fd, std::queue<unsigned char>& qrecv, size
size_t ModbusTCPCore::getDataFD( int fd, std::queue<unsigned char>& qrecv,
unsigned char* buf, size_t len, size_t attempts )
{
if( qrecv.empty() || qrecv.size() < len )
if( qrecv.empty() || qrecv.size() < len )
{
if( len == 0 )
len = 7;
......
......@@ -49,7 +49,7 @@ ModbusTCPMaster::~ModbusTCPMaster()
tcp.reset();
}
// -------------------------------------------------------------------------
size_t ModbusTCPMaster::getNextData( unsigned char* buf, int len )
size_t ModbusTCPMaster::getNextData( unsigned char* buf, size_t len )
{
return ModbusTCPCore::getNextData(tcp.get(), qrecv, buf, len);
}
......@@ -63,7 +63,7 @@ void ModbusTCPMaster::setChannelTimeout( timeout_t msec )
}
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPMaster::sendData( unsigned char* buf, int len )
mbErrCode ModbusTCPMaster::sendData( unsigned char* buf, size_t len )
{
return ModbusTCPCore::sendData(tcp.get(), buf, len);
}
......@@ -102,39 +102,12 @@ mbErrCode ModbusTCPMaster::query( ModbusAddr addr, ModbusMessage& msg,
tcp->setTimeout(timeout);
// ost::Thread::setException(ost::Thread::throwException);
// ost::tpport_t port;
// cerr << "****** peer: " << tcp->getPeer(&port) << " err: " << tcp->getErrorNumber() << endl;
if( nTransaction >= numeric_limits<ModbusRTU::ModbusData>::max() )
nTransaction = 0;
ModbusTCP::MBAPHeader mh;
mh.tID = ++nTransaction;
mh.pID = 0;
mh.len = msg.len + szModbusHeader;
// mh.uID = addr;
if( crcNoCheckit )
mh.len -= szCRC;
mh.swapdata();
// send TCP header
if( dlog->is_info() )
{
dlog->info() << iaddr << "(ModbusTCPMaster::query): send tcp header(" << sizeof(mh) << "): ";
mbPrintMessage( dlog->info(false), (ModbusByte*)(&mh), sizeof(mh));
dlog->info(false) << endl;
}
msg.makeHead(++nTransaction,crcNoCheckit);
for( unsigned int i = 0; i < 2; i++ )
{
if( tcp->isPending(ost::Socket::pendingOutput, timeout) )
{
tcp->writeData(&mh, sizeof(mh));
// send PDU
mbErrCode res = send(msg);
if( res != erNoError )
......@@ -163,8 +136,6 @@ mbErrCode ModbusTCPMaster::query( ModbusAddr addr, ModbusMessage& msg,
dlog->info() << "(ModbusTCPMaster::query): no write pending.. reconnnect OK" << endl;
}
mh.swapdata();
if( timeout != UniSetTimer::WaitUpTime )
{
timeout = ptTimeout.getLeft(timeout);
......@@ -182,19 +153,29 @@ mbErrCode ModbusTCPMaster::query( ModbusAddr addr, ModbusMessage& msg,
tcp->sync();
//reply.clear();
if( tcp->isPending(ost::Socket::pendingInput, timeout) )
{
ModbusTCP::MBAPHeader rmh;
int ret = getNextData((unsigned char*)(&rmh), sizeof(rmh));
size_t ret = 0;
while( !ptTimeout.checkTime() )
{
ret = getNextData((unsigned char*)(&reply.aduhead), sizeof(reply.aduhead));
if( dlog->is_info() )
if( ret == sizeof(reply.aduhead) )
break;
if( !tcp->isPending(ost::Socket::pendingInput, timeout) )
break;
}
if( ret > 0 && dlog->is_info() )
{
dlog->info() << "(ModbusTCPMaster::query): recv tcp header(" << ret << "): ";
mbPrintMessage( dlog->info(false), (ModbusByte*)(&rmh), sizeof(rmh));
mbPrintMessage( dlog->info(false), (ModbusByte*)(&reply.aduhead), sizeof(reply.aduhead));
dlog->info(false) << endl;
}
if( ret < (int)sizeof(rmh) )
if( ret < sizeof(reply.aduhead) )
{
ost::tpport_t port;
......@@ -204,8 +185,8 @@ mbErrCode ModbusTCPMaster::query( ModbusAddr addr, ModbusMessage& msg,
try
{
dlog->warn() << "(ModbusTCPMaster::query): ret=" << (int)ret
<< " < rmh=" << (int)sizeof(rmh)
dlog->warn() << "(ModbusTCPMaster::query): ret=" << ret
<< " < rmh=" << sizeof(reply.aduhead)
<< " errnum: " << tcp->getErrorNumber()
<< " perr: " << tcp->getPeer(&port)
<< " err: " << (err ? string(err) : "")
......@@ -218,19 +199,30 @@ mbErrCode ModbusTCPMaster::query( ModbusAddr addr, ModbusMessage& msg,
}
}
cleanInputStream();
tcp->forceDisconnect();
return erTimeOut; // return erHardwareError;
}
rmh.swapdata();
reply.swapHead();
if( dlog->is_info() )
dlog->info() << "(ModbusTCPMaster::query): ADU len=" << reply.aduLen()
<< endl;
if( rmh.tID != mh.tID )
if( reply.tID() != msg.tID() )
{
if( dlog->is_warn() )
dlog->warn() << "(ModbusTCPMaster::query): tID=" << reply.tID()
<< " != " << msg.tID()
<< " (len=" << reply.len() << ")"
<< endl;
cleanInputStream();
return erBadReplyNodeAddress;
}
if( rmh.pID != 0 )
if( reply.pID() != 0 )
{
cleanInputStream();
return erBadReplyNodeAddress;
......@@ -249,7 +241,8 @@ mbErrCode ModbusTCPMaster::query( ModbusAddr addr, ModbusMessage& msg,
return erTimeOut; // return erHardwareError;
}
mbErrCode res = recv(addr, msg.func, reply, timeout);
//msg.aduhead = reply.aduhead;
mbErrCode res = recv(addr, msg.func(), reply, timeout);
if( force_disconnect )
{
......
......@@ -206,8 +206,8 @@ ModbusRTU::mbErrCode ModbusTCPSession::realReceive( const std::unordered_set<Mod
ptTimeout.setTiming(msec);
{
memset(&curQueryHeader, 0, sizeof(curQueryHeader));
res = tcp_processing(curQueryHeader);
buf.clear();
res = tcp_processing(buf.aduhead);
if( res != erNoError )
return res;
......@@ -223,12 +223,16 @@ ModbusRTU::mbErrCode ModbusTCPSession::realReceive( const std::unordered_set<Mod
if( qrecv.empty() )
return erTimeOut;
unsigned char q_addr = qrecv.front();
if( cancelled )
return erSessionClosed;
memset(&buf, 0, sizeof(buf));
// запоминаем принятый заголовок,
// для формирования ответа (см. make_adu_header)
curQueryHeader = buf.aduhead;
if( dlog->is_info() )
dlog->info() << "(ModbusTCPSession::recv): ADU len=" << curQueryHeader.len << endl;
res = recv( vmbaddr, buf, msec );
if( cancelled )
......@@ -238,7 +242,7 @@ ModbusRTU::mbErrCode ModbusTCPSession::realReceive( const std::unordered_set<Mod
{
if( res < erInternalErrorCode )
{
ErrorRetMessage em( q_addr, buf.func, res );
ErrorRetMessage em( buf.addr(), buf.func(), res );
buf = em.transport_msg();
send(buf);
printProcessingTime();
......@@ -300,7 +304,7 @@ size_t ModbusTCPSession::getNextData( unsigned char* buf, int len )
return 0;
}
// --------------------------------------------------------------------------------
mbErrCode ModbusTCPSession::tcp_processing( ModbusTCP::MBAPHeader& mhead )
mbErrCode ModbusTCPSession::tcp_processing( ModbusRTU::ADUHeader& mhead )
{
// чистим очередь
while( !qrecv.empty() )
......@@ -321,7 +325,6 @@ mbErrCode ModbusTCPSession::tcp_processing( ModbusTCP::MBAPHeader& mhead )
if( dlog->is_info() )
{
//dlog->info() << peername << "(tcp_processing): recv tcp header(" << len << "): " << mhead << endl;
dlog->info() << peername << "(tcp_processing): recv tcp header(" << len << "): ";
mbPrintMessage( dlog->info(false), (ModbusByte*)(&mhead), sizeof(mhead));
dlog->info(false) << endl;
......@@ -331,6 +334,14 @@ mbErrCode ModbusTCPSession::tcp_processing( ModbusTCP::MBAPHeader& mhead )
if( mhead.pID != 0 )
return erUnExpectedPacketType; // erTimeOut;
if( mhead.len == 0 )
{
if( dlog->is_info() )
dlog->info() << "(ModbusTCPServer::tcp_processing): BAD FORMAT: len=0!" << endl;
return erInvalidFormat;
}
if( mhead.len > ModbusRTU::MAXLENPACKET )
{
if( dlog->is_info() )
......@@ -363,33 +374,25 @@ mbErrCode ModbusTCPSession::tcp_processing( ModbusTCP::MBAPHeader& mhead )
return erNoError;
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode ModbusTCPSession::post_send_request( ModbusTCP::ADU& request )
ModbusRTU::mbErrCode ModbusTCPSession::post_send_request( ModbusRTU::ModbusMessage& request )
{
return erNoError;
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPSession::make_adu_header( ModbusTCP::ADU& req )
mbErrCode ModbusTCPSession::make_adu_header( ModbusMessage& req )
{
req.header = curQueryHeader;
req.header.len = req.pdu.len + szModbusHeader;
if( crcNoCheckit )
req.header.len -= szCRC;
req.len = sizeof(req.header) + req.header.len;
//req.header.swapdata();
req.makeHead(curQueryHeader.tID,isCRCNoCheckit(),curQueryHeader.pID);
return erNoError;
}
// -------------------------------------------------------------------------
void ModbusTCPSession::cleanInputStream()
{
unsigned char buf[100];
int ret = 0;
unsigned char tmpbuf[100];
size_t ret = 0;
do
{
ret = getNextData(buf, sizeof(buf));
ret = getNextData(tmpbuf, sizeof(tmpbuf));
}
while( ret > 0);
}
......
......@@ -438,6 +438,7 @@ tests/UniXmlTest/XmlTest.cc
tests/int_unsigned.cc
tests/Makefile.am
tests/test.xml
tests/develop.cc
tests/test_callbacktimer.cc
tests/test_conftest.cc
tests/test_delaytimer.cc
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment