Commit f065b491 authored by Pavel Vainerman's avatar Pavel Vainerman

(ModbusTCPServer): в соответсвии со стандартом посылка ответа

сделана одним "сообщением", а не в два write-а.
parent 34162d4d
...@@ -138,14 +138,14 @@ ModbusRTU::mbErrCode MBTCPServer::readInputStatus( ReadInputStatusMessage& query ...@@ -138,14 +138,14 @@ ModbusRTU::mbErrCode MBTCPServer::readInputStatus( ReadInputStatusMessage& query
if( replyVal == -1 ) if( replyVal == -1 )
{ {
int bnum = 0; size_t bnum = 0;
int i = 0; size_t i = 0;
while( i < query.count ) while( i < query.count )
{ {
reply.addData(0); reply.addData(0);
for( auto nbit = 0; nbit < BitsPerByte && i < query.count; nbit++, i++ ) for( size_t nbit = 0; nbit < BitsPerByte && i < query.count; nbit++, i++ )
reply.setBit(bnum, nbit, d.b[nbit]); reply.setBit(bnum, nbit, d.b[nbit]);
bnum++; bnum++;
......
...@@ -171,14 +171,14 @@ ModbusRTU::mbErrCode MBTCPTestServer::readInputStatus( ReadInputStatusMessage& q ...@@ -171,14 +171,14 @@ ModbusRTU::mbErrCode MBTCPTestServer::readInputStatus( ReadInputStatusMessage& q
if( replyVal == -1 ) if( replyVal == -1 )
{ {
int bnum = 0; size_t bnum = 0;
int i = 0; size_t i = 0;
while( i < query.count ) while( i < query.count )
{ {
reply.addData(0); reply.addData(0);
for( auto nbit = 0; nbit < BitsPerByte && i < query.count; nbit++, i++ ) for( size_t nbit = 0; nbit < BitsPerByte && i < query.count; nbit++, i++ )
reply.setBit(bnum, nbit, d.b[nbit]); reply.setBit(bnum, nbit, d.b[nbit]);
bnum++; bnum++;
...@@ -186,12 +186,12 @@ ModbusRTU::mbErrCode MBTCPTestServer::readInputStatus( ReadInputStatusMessage& q ...@@ -186,12 +186,12 @@ ModbusRTU::mbErrCode MBTCPTestServer::readInputStatus( ReadInputStatusMessage& q
} }
else else
{ {
int bcnt = query.count / ModbusRTU::BitsPerByte; size_t bcnt = query.count / ModbusRTU::BitsPerByte;
if( (query.count % ModbusRTU::BitsPerByte) > 0 ) if( (query.count % ModbusRTU::BitsPerByte) > 0 )
bcnt++; bcnt++;
for( auto i = 0; i < bcnt; i++ ) for( size_t i = 0; i < bcnt; i++ )
reply.addData(replyVal); reply.addData(replyVal);
} }
...@@ -218,7 +218,7 @@ mbErrCode MBTCPTestServer::readInputRegisters( ReadInputMessage& query, ...@@ -218,7 +218,7 @@ mbErrCode MBTCPTestServer::readInputRegisters( ReadInputMessage& query,
} }
// Фомирование ответа: // Фомирование ответа:
int num = 0; // добавленное количество данных size_t num = 0; // добавленное количество данных
ModbusData reg = query.start; ModbusData reg = query.start;
for( ; num < query.count; num++, reg++ ) for( ; num < query.count; num++, reg++ )
...@@ -263,7 +263,7 @@ ModbusRTU::mbErrCode MBTCPTestServer::readOutputRegisters( ...@@ -263,7 +263,7 @@ ModbusRTU::mbErrCode MBTCPTestServer::readOutputRegisters(
} }
// Фомирование ответа: // Фомирование ответа:
int num = 0; // добавленное количество данных size_t num = 0; // добавленное количество данных
ModbusData reg = query.start; ModbusData reg = query.start;
for( ; num < query.count; num++, reg++ ) for( ; num < query.count; num++, reg++ )
......
...@@ -298,11 +298,12 @@ class ModbusServer ...@@ -298,11 +298,12 @@ class ModbusServer
/*! послать сообщение(ответ) в канал */ /*! послать сообщение(ответ) в канал */
virtual ModbusRTU::mbErrCode send( ModbusRTU::ModbusMessage& buf ); virtual ModbusRTU::mbErrCode send( ModbusRTU::ModbusMessage& buf );
virtual ModbusRTU::mbErrCode pre_send_request( ModbusRTU::ModbusMessage& request ) // Если заголовок не должен использоваться оставляйте request.header.len = 0
virtual ModbusRTU::mbErrCode make_adu_header( ModbusTCP::ADU& request )
{ {
return ModbusRTU::erNoError; return ModbusRTU::erNoError;
} }
virtual ModbusRTU::mbErrCode post_send_request( ModbusRTU::ModbusMessage& request ) virtual ModbusRTU::mbErrCode post_send_request( ModbusTCP::ADU& request )
{ {
return ModbusRTU::erNoError; return ModbusRTU::erNoError;
} }
......
...@@ -73,8 +73,8 @@ class ModbusTCPSession: ...@@ -73,8 +73,8 @@ class ModbusTCPSession:
virtual void setChannelTimeout( timeout_t msec ); virtual void setChannelTimeout( timeout_t msec );
virtual ModbusRTU::mbErrCode sendData( unsigned char* buf, int len ) override; virtual ModbusRTU::mbErrCode sendData( unsigned char* buf, int len ) override;
virtual ModbusRTU::mbErrCode tcp_processing(ModbusTCP::MBAPHeader& mhead ); virtual ModbusRTU::mbErrCode tcp_processing(ModbusTCP::MBAPHeader& mhead );
virtual ModbusRTU::mbErrCode pre_send_request( ModbusRTU::ModbusMessage& request ) override; virtual ModbusRTU::mbErrCode make_adu_header( ModbusTCP::ADU& request ) override;
virtual ModbusRTU::mbErrCode post_send_request( ModbusRTU::ModbusMessage& request ) override; virtual ModbusRTU::mbErrCode post_send_request( ModbusTCP::ADU& request ) override;
virtual ModbusRTU::mbErrCode readCoilStatus( ModbusRTU::ReadCoilMessage& query, virtual ModbusRTU::mbErrCode readCoilStatus( ModbusRTU::ReadCoilMessage& query,
ModbusRTU::ReadCoilRetMessage& reply ); ModbusRTU::ReadCoilRetMessage& reply );
......
...@@ -334,6 +334,7 @@ mbErrCode ModbusClient::recv( ModbusAddr addr, ModbusByte qfunc, ...@@ -334,6 +334,7 @@ mbErrCode ModbusClient::recv( ModbusAddr addr, ModbusByte qfunc,
if( timeout == UniSetTimer::WaitUpTime ) if( timeout == UniSetTimer::WaitUpTime )
timeout = 15 * 60 * 1000 * 1000; // используем просто большое время (15 минут). Переведя его в наносекунды. timeout = 15 * 60 * 1000 * 1000; // используем просто большое время (15 минут). Переведя его в наносекунды.
setChannelTimeout(timeout); setChannelTimeout(timeout);
PassiveTimer tmAbort(timeout); PassiveTimer tmAbort(timeout);
...@@ -1074,7 +1075,7 @@ mbErrCode ModbusClient::recv_pdu( ModbusByte qfunc, ModbusMessage& rbuf, timeout ...@@ -1074,7 +1075,7 @@ mbErrCode ModbusClient::recv_pdu( ModbusByte qfunc, ModbusMessage& rbuf, timeout
} }
// теперь получаем CRC // теперь получаем CRC
int rlen1 = getNextData((unsigned char*)(&(rbuf.data[rlen])), szCRC); size_t rlen1 = getNextData((unsigned char*)(&(rbuf.data[rlen])), szCRC);
if( rlen1 < szCRC ) if( rlen1 < szCRC )
{ {
......
...@@ -1262,7 +1262,7 @@ mbErrCode ModbusServer::recv_pdu( ModbusMessage& rbuf, timeout_t timeout ) ...@@ -1262,7 +1262,7 @@ mbErrCode ModbusServer::recv_pdu( ModbusMessage& rbuf, timeout_t timeout )
{ {
if( !crcNoCheckit ) if( !crcNoCheckit )
{ {
int rlen1 = getNextData((unsigned char*)(&(rbuf.data[rlen])), szCRC); size_t rlen1 = getNextData((unsigned char*)(&(rbuf.data[rlen])), szCRC);
if( rlen1 < szCRC ) if( rlen1 < szCRC )
{ {
...@@ -1739,50 +1739,66 @@ ModbusRTU::mbErrCode ModbusServer::replySetDateTime( ModbusRTU::SetDateTimeMessa ...@@ -1739,50 +1739,66 @@ ModbusRTU::mbErrCode ModbusServer::replySetDateTime( ModbusRTU::SetDateTimeMessa
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
mbErrCode ModbusServer::send( ModbusMessage& msg ) mbErrCode ModbusServer::send( ModbusMessage& msg )
{ {
if( cleanBeforeSend ) if( msg.len > MAXLENPACKET + szModbusHeader )
cleanupChannel(); {
if( dlog->is_warn() )
dlog->warn() << "(ModbusServer::send): длина пакета больше разрешённой..." << endl;
mbErrCode ret = pre_send_request(msg); return erPacketTooLong;
}
// в стандарте Modbus подразумевается, что данные должны посылаться одним пакетом
// поэтому как минимум надо делать sendData одним буфером.
// Для этого используем класс ADU
ModbusTCP::ADU adu(msg);
mbErrCode ret = make_adu_header(adu);
if( ret != erNoError ) if( ret != erNoError )
return ret; return ret;
if( msg.len > MAXLENPACKET + szModbusHeader ) if( adu.len > (MAXLENPACKET + szModbusHeader + sizeof(ModbusTCP::MBAPHeader)) )
{ {
if( dlog->is_warn() ) if( dlog->is_warn() )
dlog->warn() << "(send): длина пакета больше разрешённой..." << endl; dlog->warn() << "(ModbusServer::send): длина ADU-пакета больше разрешённой..." << endl;
return erPacketTooLong; return erPacketTooLong;
} }
if( cleanBeforeSend )
cleanupChannel();
if( tmProcessing.checkTime() ) if( tmProcessing.checkTime() )
{ {
if( dlog->is_warn() ) if( dlog->is_warn() )
dlog->warn() << "(send): reply timeout(" << tmProcessing.getInterval() << ")...!!!" << endl; dlog->warn() << "(ModbusServer::send): reply timeout(" << tmProcessing.getInterval() << ")...!!!" << endl;
return erTimeOut; return erTimeOut;
} }
int len = szModbusHeader + msg.len; if( dlog->is_info() )
if( crcNoCheckit )
{ {
msg.len -= szCRC; if( adu.header.len == 0 )
len -= szCRC; dlog->info() << "(ModbusServer::send): PDU data[" << adu.pdu.len << " bytes]: " << adu.pdu << endl;
else
dlog->info() << "(ModbusServer::send): ADU data[" << adu.len << " bytes]: " << adu << endl;
} }
if( dlog->is_info() )
dlog->info() << "(send): data(" << len << " bytes): " << msg << endl;
try try
{ {
sendData((unsigned char*)(&msg), len); if( adu.header.len == 0 )
sendData((unsigned char*)(&adu.pdu), adu.pdu.len);
else
{
adu.header.swapdata();
sendData((unsigned char*)(&adu), adu.len);
adu.header.swapdata(); // обратно, т.к. потом ещё будет post_send_request
}
} }
catch( const Exception& ex ) // SystemError catch( const Exception& ex ) // SystemError
{ {
if( dlog->is_crit() ) if( dlog->is_crit() )
dlog->crit() << "(send): " << ex << endl; dlog->crit() << "(ModbusServer::send): " << ex << endl;
return erHardwareError; return erHardwareError;
} }
...@@ -1790,7 +1806,7 @@ mbErrCode ModbusServer::send( ModbusMessage& msg ) ...@@ -1790,7 +1806,7 @@ mbErrCode ModbusServer::send( ModbusMessage& msg )
if( aftersend_msec > 0 ) if( aftersend_msec > 0 )
iowait(aftersend_msec); iowait(aftersend_msec);
return post_send_request(msg); return post_send_request(adu);
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
...@@ -54,7 +54,7 @@ ModbusTCPSession::ModbusTCPSession( int sfd, const std::unordered_set<ModbusAddr ...@@ -54,7 +54,7 @@ ModbusTCPSession::ModbusTCPSession( int sfd, const std::unordered_set<ModbusAddr
ost::tpport_t p; ost::tpport_t p;
// если стремиться к "оптимизации по скорости" // если стремиться к "оптимизации по скорости"
// то resolve ip "медленная" операция и может стоит от неё отказаться. // то getpeername "медленная" операция и может стоит от неё отказаться.
ost::InetAddress iaddr = sock->getIPV4Peer(&p); ost::InetAddress iaddr = sock->getIPV4Peer(&p);
if( !iaddr.isInetAddress() ) if( !iaddr.isInetAddress() )
...@@ -274,7 +274,7 @@ void ModbusTCPSession::final() ...@@ -274,7 +274,7 @@ void ModbusTCPSession::final()
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
mbErrCode ModbusTCPSession::sendData( unsigned char* buf, int len ) mbErrCode ModbusTCPSession::sendData( unsigned char* buf, int len )
{ {
qsend.push( new UTCPCore::Buffer(buf, len) ); qsend.emplace( new UTCPCore::Buffer(buf, len) );
return erNoError; return erNoError;
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
...@@ -363,30 +363,22 @@ mbErrCode ModbusTCPSession::tcp_processing( ModbusTCP::MBAPHeader& mhead ) ...@@ -363,30 +363,22 @@ mbErrCode ModbusTCPSession::tcp_processing( ModbusTCP::MBAPHeader& mhead )
return erNoError; return erNoError;
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
ModbusRTU::mbErrCode ModbusTCPSession::post_send_request( ModbusRTU::ModbusMessage& request ) ModbusRTU::mbErrCode ModbusTCPSession::post_send_request( ModbusTCP::ADU& request )
{ {
return erNoError; return erNoError;
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
mbErrCode ModbusTCPSession::pre_send_request( ModbusMessage& request ) mbErrCode ModbusTCPSession::make_adu_header( ModbusTCP::ADU& req )
{ {
curQueryHeader.len = request.len + szModbusHeader; req.header = curQueryHeader;
req.header.len = req.pdu.len + szModbusHeader;
if( crcNoCheckit ) if( crcNoCheckit )
curQueryHeader.len -= szCRC; req.header.len -= szCRC;
curQueryHeader.swapdata(); req.len = sizeof(req.header) + req.header.len;
if( dlog->is_info() )
{
dlog->info() << peername << "(pre_send_request): send tcp header: ";
mbPrintMessage( dlog->info(false), (ModbusByte*)(&curQueryHeader), sizeof(curQueryHeader));
dlog->info(false) << endl;
}
sendData((unsigned char*)(&curQueryHeader), sizeof(curQueryHeader));
curQueryHeader.swapdata();
//req.header.swapdata();
return erNoError; return erNoError;
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
......
...@@ -194,7 +194,7 @@ bool ModbusRTU::isWriteFunction( SlaveFunctionCode c ) ...@@ -194,7 +194,7 @@ bool ModbusRTU::isWriteFunction( SlaveFunctionCode c )
return false; return false;
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
std::ostream& ModbusRTU::mbPrintMessage( std::ostream& os, ModbusByte* m, int len ) std::ostream& ModbusRTU::mbPrintMessage( std::ostream& os, ModbusByte* m, size_t len )
{ {
// Чтобы не менять настройки 'os' // Чтобы не менять настройки 'os'
// сперва создаём свой поток вывода... // сперва создаём свой поток вывода...
...@@ -203,7 +203,7 @@ std::ostream& ModbusRTU::mbPrintMessage( std::ostream& os, ModbusByte* m, int le ...@@ -203,7 +203,7 @@ std::ostream& ModbusRTU::mbPrintMessage( std::ostream& os, ModbusByte* m, int le
// << setiosflags(ios::showbase) // для вывода в формате 0xNN // << setiosflags(ios::showbase) // для вывода в формате 0xNN
s << hex << showbase << setfill('0'); // << showbase; s << hex << showbase << setfill('0'); // << showbase;
for( ssize_t i = 0; i < len; i++ ) for( size_t i = 0; i < len; i++ )
s << setw(2) << (short)(m[i]) << " "; s << setw(2) << (short)(m[i]) << " ";
// s << "<" << setw(2) << (int)(m[i]) << ">"; // s << "<" << setw(2) << (int)(m[i]) << ">";
...@@ -211,12 +211,12 @@ std::ostream& ModbusRTU::mbPrintMessage( std::ostream& os, ModbusByte* m, int le ...@@ -211,12 +211,12 @@ std::ostream& ModbusRTU::mbPrintMessage( std::ostream& os, ModbusByte* m, int le
return os << s.str(); return os << s.str();
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
std::ostream& ModbusRTU::operator<<(std::ostream& os, ModbusHeader& m ) std::ostream& ModbusRTU::operator<<(std::ostream& os, const ModbusHeader& m )
{ {
return mbPrintMessage(os, (ModbusByte*)&m, sizeof(m)); return mbPrintMessage(os, (ModbusByte*)&m, sizeof(m));
} }
std::ostream& ModbusRTU::operator<<(std::ostream& os, ModbusHeader* m ) std::ostream& ModbusRTU::operator<<(std::ostream& os, const ModbusHeader* m )
{ {
return os << (*m); return os << (*m);
} }
...@@ -230,12 +230,12 @@ ModbusMessage::ModbusMessage(): ...@@ -230,12 +230,12 @@ ModbusMessage::ModbusMessage():
memset(data, 0, sizeof(data)); memset(data, 0, sizeof(data));
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
std::ostream& ModbusRTU::operator<<(std::ostream& os, ModbusMessage& m ) std::ostream& ModbusRTU::operator<<(std::ostream& os, const ModbusMessage& m )
{ {
return mbPrintMessage(os, (ModbusByte*)(&m), szModbusHeader + m.len); return mbPrintMessage(os, (ModbusByte*)(&m), szModbusHeader + m.len);
} }
std::ostream& ModbusRTU::operator<<(std::ostream& os, ModbusMessage* m ) std::ostream& ModbusRTU::operator<<(std::ostream& os, const ModbusMessage* m )
{ {
return os << (*m); return os << (*m);
} }
...@@ -2138,7 +2138,7 @@ std::ostream& ModbusRTU::operator<<(std::ostream& os, WriteSingleOutputRetMessag ...@@ -2138,7 +2138,7 @@ std::ostream& ModbusRTU::operator<<(std::ostream& os, WriteSingleOutputRetMessag
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
int ModbusRTU::szRequestDiagnosticData( DiagnosticsSubFunction f ) ssize_t ModbusRTU::szRequestDiagnosticData( DiagnosticsSubFunction f )
{ {
if( f == subEcho ) if( f == subEcho )
return 1; // тут странно, вроде в стандарте количество динамическое return 1; // тут странно, вроде в стандарте количество динамическое
...@@ -2231,7 +2231,7 @@ void DiagnosticMessage::init( ModbusMessage& m ) ...@@ -2231,7 +2231,7 @@ void DiagnosticMessage::init( ModbusMessage& m )
memcpy(&crc, &(m.data[last]), szCRC); memcpy(&crc, &(m.data[last]), szCRC);
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
int DiagnosticMessage::getDataLen( ModbusMessage& m ) size_t DiagnosticMessage::getDataLen( ModbusMessage& m )
{ {
if( m.len == 0 ) if( m.len == 0 )
return 0; return 0;
...@@ -2241,12 +2241,12 @@ int DiagnosticMessage::getDataLen( ModbusMessage& m ) ...@@ -2241,12 +2241,12 @@ int DiagnosticMessage::getDataLen( ModbusMessage& m )
memcpy( &sf, &(m.data[0]), sizeof(sf) ); memcpy( &sf, &(m.data[0]), sizeof(sf) );
sf = SWAPSHORT(sf); sf = SWAPSHORT(sf);
int sz = szRequestDiagnosticData( (DiagnosticsSubFunction)sf ); ssize_t sz = szRequestDiagnosticData( (DiagnosticsSubFunction)sf );
if( sz >= 0 ) if( sz >= 0 )
return sz * sizeof(ModbusData); return sz * sizeof(ModbusData);
return 0; return 0;
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
DiagnosticMessage::DiagnosticMessage( ModbusAddr _addr, DiagnosticsSubFunction sf, ModbusData d ): DiagnosticMessage::DiagnosticMessage( ModbusAddr _addr, DiagnosticsSubFunction sf, ModbusData d ):
...@@ -3537,14 +3537,9 @@ std::ostream& ModbusRTU::operator<<(std::ostream& os, FileTransferRetMessage* m ...@@ -3537,14 +3537,9 @@ std::ostream& ModbusRTU::operator<<(std::ostream& os, FileTransferRetMessage* m
return mbPrintMessage(os, (ModbusByte*)m, szModbusHeader + m->szData() ); return mbPrintMessage(os, (ModbusByte*)m, szModbusHeader + m->szData() );
} }
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
std::ostream& ModbusTCP::operator<<(std::ostream& os, MBAPHeader& m ) std::ostream& ModbusTCP::operator<<(std::ostream& os, const MBAPHeader& m )
{ {
// m.swapdata(); return mbPrintMessage(os, (ModbusByte*)(&m), sizeof(m));
for( size_t i = 0; i < sizeof(m); i++ )
os << ((unsigned char*)(&m))[i];
// m.swapdata();
return os;
} }
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
void ModbusTCP::MBAPHeader::swapdata() void ModbusTCP::MBAPHeader::swapdata()
...@@ -3594,3 +3589,11 @@ ModbusRTU::RegID ModbusRTU::genRegID( const ModbusRTU::ModbusData mbreg, const i ...@@ -3594,3 +3589,11 @@ ModbusRTU::RegID ModbusRTU::genRegID( const ModbusRTU::ModbusData mbreg, const i
return max + mbreg + max + UniSetTypes::lcalibrate(fn, 0, fn_max, 0, max, false); return max + mbreg + max + UniSetTypes::lcalibrate(fn, 0, fn_max, 0, max, false);
} }
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
ostream& ModbusTCP::operator<<( ostream& os, const ModbusTCP::ADU& m )
{
os << m.header << "| ";
mbPrintMessage(os, (ModbusByte*)&(m.pdu), szModbusHeader+m.pdu.len);
//return os << m.header << "| " << m.pdu;
return os;
}
// -----------------------------------------------------------------------
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