You need to sign in or sign up before continuing.
Commit f065b491 authored by Pavel Vainerman's avatar Pavel Vainerman

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

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