Commit 316d7772 authored by Pavel Vainerman's avatar Pavel Vainerman Committed by Pavel Vainerman

(modbus): make style

parent 08cccaf0
......@@ -24,1462 +24,1462 @@
namespace uniset
{
// -------------------------------------------------------------------------
using namespace std;
using namespace ModbusRTU;
using namespace uniset;
// -------------------------------------------------------------------------
ModbusClient::ModbusClient():
replyTimeOut_ms(2000),
aftersend_msec(0),
sleepPause_usec(100),
crcNoCheckit(false),
sendMutex("ModbusClient_sendMutex")
{
dlog = make_shared<DebugStream>();
tmProcessing.setTiming(replyTimeOut_ms);
}
// -------------------------------------------------------------------------
ModbusClient::~ModbusClient()
{
}
// -------------------------------------------------------------------------
void ModbusClient::setTimeout( timeout_t msec )
{
replyTimeOut_ms = msec;
}
// -------------------------------------------------------------------------
int ModbusClient::setAfterSendPause( timeout_t msec )
{
timeout_t old = aftersend_msec;
aftersend_msec = msec;
return old;
}
// --------------------------------------------------------------------------------
ReadCoilRetMessage ModbusClient::read01( ModbusAddr addr,
ModbusData start, ModbusData count )
{
ReadCoilMessage msg(addr, start, count);
qbuf = msg.transport_msg();
mbErrCode res = query(addr, qbuf, qreply, replyTimeOut_ms);
if( res == erNoError )
{
ReadCoilRetMessage ret(qreply);
if( ret.bcnt != numBytes(count) )
throw mbException(erBadDataValue);
return ret;
}
throw mbException(res);
}
// --------------------------------------------------------------------------------
ReadInputStatusRetMessage ModbusClient::read02( ModbusAddr addr,
ModbusData start, ModbusData count )
{
ReadInputStatusMessage msg(addr, start, count);
qbuf = msg.transport_msg();
mbErrCode res = query(addr, qbuf, qreply, replyTimeOut_ms);
if( res == erNoError )
{
ReadInputStatusRetMessage ret(qreply);
if( ret.bcnt != numBytes(count) )
throw mbException(erBadDataValue);
return ret;
}
throw mbException(res);
}
// --------------------------------------------------------------------------------
ReadOutputRetMessage ModbusClient::read03( ModbusAddr addr,
ModbusData start, ModbusData count )
{
ReadOutputMessage msg(addr, start, count);
qbuf = msg.transport_msg();
mbErrCode res = query(addr, qbuf, qreply, replyTimeOut_ms);
if( res == erNoError )
{
ReadOutputRetMessage ret(qreply);
if( ret.count != count )
throw mbException(erBadDataValue);
return ret;
}
throw mbException(res);
}
// --------------------------------------------------------------------------------
ReadInputRetMessage ModbusClient::read04( ModbusAddr addr,
ModbusData start, ModbusData count )
{
ReadInputMessage msg(addr, start, count);
qbuf = msg.transport_msg();
mbErrCode res = query(addr, qbuf, qreply, replyTimeOut_ms);
if( res == erNoError )
{
ReadInputRetMessage ret(qreply);
if( ret.count != count )
throw mbException(erBadDataValue);
return ret;
}
throw mbException(res);
}
// --------------------------------------------------------------------------------
ForceSingleCoilRetMessage ModbusClient::write05( ModbusAddr addr,
ModbusData start, bool cmd )
{
ForceSingleCoilMessage msg(addr, start, cmd);
qbuf = msg.transport_msg();
mbErrCode res = query(addr, qbuf, qreply, replyTimeOut_ms);
if( res == erNoError )
{
ForceSingleCoilRetMessage ret(qreply);
if( ret.start != start )
throw mbException(erBadDataValue);
if( ret.cmd() != cmd )
throw mbException(erBadDataValue);
return ret;
}
throw mbException(res);
}
// --------------------------------------------------------------------------------
WriteSingleOutputRetMessage ModbusClient::write06( ModbusAddr addr,
ModbusData start, ModbusData data )
{
WriteSingleOutputMessage msg(addr, start, data);
qbuf = msg.transport_msg();
mbErrCode res = query(addr, qbuf, qreply, replyTimeOut_ms);
if( res == erNoError )
{
WriteSingleOutputRetMessage ret(qreply);
if( ret.start != start )
throw mbException(erBadDataValue);
if( ret.data != data )
throw mbException(erBadDataValue);
return ret;
}
throw mbException(res);
}
// --------------------------------------------------------------------------------
ForceCoilsRetMessage ModbusClient::write0F( ForceCoilsMessage& msg )
{
qbuf = msg.transport_msg();
mbErrCode res = query(msg.addr, qbuf, qreply, replyTimeOut_ms);
if( res == erNoError )
{
ForceCoilsRetMessage ret(qreply);
if( ret.start != msg.start )
throw mbException(erBadDataValue);
if( ret.quant != msg.quant )
throw mbException(erBadDataValue);
return ret;
}
throw mbException(res);
}
// --------------------------------------------------------------------------------
WriteOutputRetMessage ModbusClient::write10( WriteOutputMessage& msg )
{
qbuf = msg.transport_msg();
mbErrCode res = query(msg.addr, qbuf, qreply, replyTimeOut_ms);
if( res == erNoError )
{
WriteOutputRetMessage ret(qreply);
if( ret.start != msg.start )
throw mbException(erBadDataValue);
if( ret.quant != msg.quant )
throw mbException(erBadDataValue);
return ret;
}
throw mbException(res);
}
// --------------------------------------------------------------------------------
DiagnosticRetMessage ModbusClient::diag08( ModbusAddr addr,
DiagnosticsSubFunction subfunc,
ModbusRTU::ModbusData dat )
{
DiagnosticMessage msg(addr, subfunc, dat);
qbuf = msg.transport_msg();
mbErrCode res = query(msg.addr, qbuf, qreply, replyTimeOut_ms);
if( res == erNoError )
{
DiagnosticRetMessage ret(qreply);
if( ret.subf != subfunc )
throw mbException(erBadDataValue);
return ret;
}
throw mbException(res);
}
// --------------------------------------------------------------------------------
ModbusRTU::MEIMessageRetRDI ModbusClient::read4314( ModbusRTU::ModbusAddr addr,
ModbusRTU::ModbusByte devID,
ModbusRTU::ModbusByte objID )
{
MEIMessageRDI msg(addr, devID, objID);
qbuf = msg.transport_msg();
mbErrCode res = query(msg.addr, qbuf, qreply, replyTimeOut_ms);
if( res == erNoError )
{
MEIMessageRetRDI ret(qreply);
if( ret.devID != devID )
throw mbException(erBadDataValue);
if( ret.objID != objID )
throw mbException(erBadDataValue);
return ret;
}
throw mbException(res);
}
// --------------------------------------------------------------------------------
SetDateTimeRetMessage ModbusClient::setDateTime( ModbusAddr addr, ModbusByte hour, ModbusByte min, ModbusByte sec,
ModbusByte day, ModbusByte mon, ModbusByte year,
ModbusByte century )
{
SetDateTimeMessage msg(addr);
msg.hour = hour;
msg.min = min;
msg.sec = sec;
msg.day = day;
msg.mon = mon;
msg.year = year;
msg.century = century;
qbuf = msg.transport_msg();
mbErrCode res = query(addr, qbuf, qreply, replyTimeOut_ms);
if( res == erNoError )
return SetDateTimeRetMessage(qreply);
throw mbException(res);
}
// --------------------------------------------------------------------------------
void ModbusClient::fileTransfer(ModbusAddr addr, ModbusData numfile,
const std::string& save2filename, timeout_t part_timeout_msec )
{
//#warning Необходимо реализовать
// throw mbException(erUnExpectedPacketType);
mbErrCode res = erNoError;
FILE* fdsave = fopen(save2filename.c_str(), "w");
if( fdsave == NULL )
{
if( dlog->is_warn() )
dlog->warn() << "(fileTransfer): fopen '"
<< save2filename << "' with error: "
<< strerror(errno) << endl;
throw mbException(erHardwareError);
}
uint16_t maxpackets = 65535;
uint16_t curpack = 0;
PassiveTimer ptTimeout(part_timeout_msec);
while( curpack < maxpackets && !ptTimeout.checkTime() )
{
try
{
FileTransferRetMessage ret = partOfFileTransfer( addr, numfile, curpack, part_timeout_msec );
if( ret.numfile != numfile )
{
if( dlog->is_warn() )
dlog->warn() << "(fileTransfer): recv nfile=" << ret.numfile
<< " !=numfile(" << numfile << ")" << endl;
continue;
}
if( ret.packet != curpack )
{
if( dlog->is_warn() )
dlog->warn() << "(fileTransfer): recv npack=" << ret.packet
<< " !=curpack(" << curpack << ")" << endl;
continue;
}
maxpackets = ret.numpacks;
if( dlog->is_info() )
dlog->info() << "(fileTransfer): maxpackets="
<< ret.numpacks << " curpack=" << curpack + 1 << endl;
// save data...
if( fwrite(&ret.data, ret.dlen, 1, fdsave) <= 0 )
{
if( dlog->is_warn() )
dlog->warn() << "(fileTransfer): fwrite '"
<< save2filename << "' with error: "
<< strerror(errno) << endl;
res = erHardwareError;
break;
}
ptTimeout.reset();
curpack = ret.packet + 1; // curpack++;
}
catch( mbException& ex )
{
if( ex.err == erBadCheckSum )
continue;
res = ex.err;
break;
}
}
fclose(fdsave);
if( curpack == maxpackets )
return;
if( res == erNoError )
res = erTimeOut;
throw mbException(res);
}
// --------------------------------------------------------------------------------
FileTransferRetMessage ModbusClient::partOfFileTransfer( ModbusAddr addr,
ModbusData idFile, ModbusData numpack,
timeout_t part_timeout_msec )
{
FileTransferMessage msg(addr, idFile, numpack);
qbuf = msg.transport_msg();
mbErrCode res = query(addr, qbuf, qreply, part_timeout_msec);
if( res == erNoError )
return FileTransferRetMessage(qreply);
throw mbException(res);
}
// --------------------------------------------------------------------------------
mbErrCode ModbusClient::recv( ModbusAddr addr, ModbusByte qfunc,
ModbusMessage& rbuf, timeout_t timeout )
{
if( timeout == UniSetTimer::WaitUpTime )
timeout = 15 * 60 * 1000 * 1000; // используем просто большое время (15 минут). Переведя его в наносекунды.
setChannelTimeout(timeout);
PassiveTimer tmAbort(timeout);
size_t bcnt = 0; // receive bytes count
try
{
bool begin = false;
while( !tmAbort.checkTime() )
{
bcnt = getNextData((unsigned char*)(&rbuf.pduhead.addr), sizeof(rbuf.pduhead.addr));
if( bcnt > 0 && ( rbuf.addr() == addr ) ) // || (onBroadcast && rbuf.addr==BroadcastAddr) ) )
{
begin = true;
break;
}
std::this_thread::sleep_for(std::chrono::microseconds(sleepPause_usec));
}
if( !begin )
return erTimeOut;
/*! \todo Подумать Может стоит всё-таки получать весь пакет, а проверять кому он адресован на уровне выше?!
// Lav: конечно стоит, нам же надо буфер чистить
*/
// Проверка кому адресован пакет...
if( rbuf.addr() != addr && rbuf.addr() != BroadcastAddr )
{
ostringstream err;
err << "(recv): BadNodeAddress. my= " << addr2str(addr)
<< " msg.addr=" << addr2str(rbuf.addr());
if( dlog->is_warn() )
dlog->warn() << err.str() << endl;
cleanupChannel();
return erBadReplyNodeAddress;
}
return recv_pdu(qfunc, rbuf, timeout);
}
catch( const uniset::TimeOut& ex )
{
// cout << "(recv): catch TimeOut " << endl;
}
catch( const uniset::CommFailed& ex )
{
if( dlog->is_crit() )
dlog->crit() << "(recv): " << ex << endl;
cleanupChannel();
return erTimeOut;
}
catch( const uniset::Exception& ex ) // SystemError
{
if( dlog->is_crit() )
dlog->crit() << "(recv): " << ex << endl;
cleanupChannel();
return erHardwareError;
}
return erTimeOut;
}
// --------------------------------------------------------------------------------
mbErrCode ModbusClient::recv_pdu( ModbusByte qfunc, ModbusMessage& rbuf, timeout_t timeout )
{
size_t bcnt = 1; // receive bytes count (1 - addr)
try
{
// -----------------------------------
tmProcessing.setTiming(replyTimeOut_ms);
// recv func number
size_t k = getNextData((unsigned char*)(&rbuf.pduhead.func), sizeof(rbuf.pduhead.func));
if( k < sizeof(rbuf.pduhead.func) )
{
if( dlog->is_warn() )
dlog->warn() << "(recv): receive " << k << " bytes < " << sizeof(rbuf.pduhead.func) << endl;
cleanupChannel();
return erInvalidFormat;
}
bcnt += k;
rbuf.dlen = 0;
if( dlog->is_level9() )
dlog->level9() << "(recv): PDU: " << rbuf.pduhead << endl;
// -------------------------------------------------------------------------
using namespace std;
using namespace ModbusRTU;
using namespace uniset;
// -------------------------------------------------------------------------
ModbusClient::ModbusClient():
replyTimeOut_ms(2000),
aftersend_msec(0),
sleepPause_usec(100),
crcNoCheckit(false),
sendMutex("ModbusClient_sendMutex")
{
dlog = make_shared<DebugStream>();
tmProcessing.setTiming(replyTimeOut_ms);
}
// -------------------------------------------------------------------------
ModbusClient::~ModbusClient()
{
}
// -------------------------------------------------------------------------
void ModbusClient::setTimeout( timeout_t msec )
{
replyTimeOut_ms = msec;
}
// -------------------------------------------------------------------------
int ModbusClient::setAfterSendPause( timeout_t msec )
{
timeout_t old = aftersend_msec;
aftersend_msec = msec;
return old;
}
// --------------------------------------------------------------------------------
ReadCoilRetMessage ModbusClient::read01( ModbusAddr addr,
ModbusData start, ModbusData count )
{
ReadCoilMessage msg(addr, start, count);
qbuf = msg.transport_msg();
mbErrCode res = query(addr, qbuf, qreply, replyTimeOut_ms);
if( res == erNoError )
{
ReadCoilRetMessage ret(qreply);
if( ret.bcnt != numBytes(count) )
throw mbException(erBadDataValue);
return ret;
}
throw mbException(res);
}
// --------------------------------------------------------------------------------
ReadInputStatusRetMessage ModbusClient::read02( ModbusAddr addr,
ModbusData start, ModbusData count )
{
ReadInputStatusMessage msg(addr, start, count);
qbuf = msg.transport_msg();
mbErrCode res = query(addr, qbuf, qreply, replyTimeOut_ms);
if( res == erNoError )
{
ReadInputStatusRetMessage ret(qreply);
if( ret.bcnt != numBytes(count) )
throw mbException(erBadDataValue);
return ret;
}
throw mbException(res);
}
// --------------------------------------------------------------------------------
ReadOutputRetMessage ModbusClient::read03( ModbusAddr addr,
ModbusData start, ModbusData count )
{
ReadOutputMessage msg(addr, start, count);
qbuf = msg.transport_msg();
mbErrCode res = query(addr, qbuf, qreply, replyTimeOut_ms);
if( res == erNoError )
{
ReadOutputRetMessage ret(qreply);
if( ret.count != count )
throw mbException(erBadDataValue);
return ret;
}
throw mbException(res);
}
// --------------------------------------------------------------------------------
ReadInputRetMessage ModbusClient::read04( ModbusAddr addr,
ModbusData start, ModbusData count )
{
ReadInputMessage msg(addr, start, count);
qbuf = msg.transport_msg();
mbErrCode res = query(addr, qbuf, qreply, replyTimeOut_ms);
if( res == erNoError )
{
ReadInputRetMessage ret(qreply);
if( ret.count != count )
throw mbException(erBadDataValue);
return ret;
}
throw mbException(res);
}
// --------------------------------------------------------------------------------
ForceSingleCoilRetMessage ModbusClient::write05( ModbusAddr addr,
ModbusData start, bool cmd )
{
ForceSingleCoilMessage msg(addr, start, cmd);
qbuf = msg.transport_msg();
mbErrCode res = query(addr, qbuf, qreply, replyTimeOut_ms);
if( res == erNoError )
{
ForceSingleCoilRetMessage ret(qreply);
if( ret.start != start )
throw mbException(erBadDataValue);
if( ret.cmd() != cmd )
throw mbException(erBadDataValue);
return ret;
}
throw mbException(res);
}
// --------------------------------------------------------------------------------
WriteSingleOutputRetMessage ModbusClient::write06( ModbusAddr addr,
ModbusData start, ModbusData data )
{
WriteSingleOutputMessage msg(addr, start, data);
qbuf = msg.transport_msg();
mbErrCode res = query(addr, qbuf, qreply, replyTimeOut_ms);
if( res == erNoError )
{
WriteSingleOutputRetMessage ret(qreply);
if( ret.start != start )
throw mbException(erBadDataValue);
if( ret.data != data )
throw mbException(erBadDataValue);
return ret;
}
throw mbException(res);
}
// --------------------------------------------------------------------------------
ForceCoilsRetMessage ModbusClient::write0F( ForceCoilsMessage& msg )
{
qbuf = msg.transport_msg();
mbErrCode res = query(msg.addr, qbuf, qreply, replyTimeOut_ms);
if( res == erNoError )
{
ForceCoilsRetMessage ret(qreply);
if( ret.start != msg.start )
throw mbException(erBadDataValue);
if( ret.quant != msg.quant )
throw mbException(erBadDataValue);
return ret;
}
throw mbException(res);
}
// --------------------------------------------------------------------------------
WriteOutputRetMessage ModbusClient::write10( WriteOutputMessage& msg )
{
qbuf = msg.transport_msg();
mbErrCode res = query(msg.addr, qbuf, qreply, replyTimeOut_ms);
if( res == erNoError )
{
WriteOutputRetMessage ret(qreply);
if( ret.start != msg.start )
throw mbException(erBadDataValue);
if( ret.quant != msg.quant )
throw mbException(erBadDataValue);
return ret;
}
throw mbException(res);
}
// --------------------------------------------------------------------------------
DiagnosticRetMessage ModbusClient::diag08( ModbusAddr addr,
DiagnosticsSubFunction subfunc,
ModbusRTU::ModbusData dat )
{
DiagnosticMessage msg(addr, subfunc, dat);
qbuf = msg.transport_msg();
mbErrCode res = query(msg.addr, qbuf, qreply, replyTimeOut_ms);
if( res == erNoError )
{
DiagnosticRetMessage ret(qreply);
if( ret.subf != subfunc )
throw mbException(erBadDataValue);
return ret;
}
throw mbException(res);
}
// --------------------------------------------------------------------------------
ModbusRTU::MEIMessageRetRDI ModbusClient::read4314( ModbusRTU::ModbusAddr addr,
ModbusRTU::ModbusByte devID,
ModbusRTU::ModbusByte objID )
{
MEIMessageRDI msg(addr, devID, objID);
qbuf = msg.transport_msg();
mbErrCode res = query(msg.addr, qbuf, qreply, replyTimeOut_ms);
if( res == erNoError )
{
MEIMessageRetRDI ret(qreply);
if( ret.devID != devID )
throw mbException(erBadDataValue);
if( ret.objID != objID )
throw mbException(erBadDataValue);
return ret;
}
throw mbException(res);
}
// --------------------------------------------------------------------------------
SetDateTimeRetMessage ModbusClient::setDateTime( ModbusAddr addr, ModbusByte hour, ModbusByte min, ModbusByte sec,
ModbusByte day, ModbusByte mon, ModbusByte year,
ModbusByte century )
{
SetDateTimeMessage msg(addr);
msg.hour = hour;
msg.min = min;
msg.sec = sec;
msg.day = day;
msg.mon = mon;
msg.year = year;
msg.century = century;
qbuf = msg.transport_msg();
mbErrCode res = query(addr, qbuf, qreply, replyTimeOut_ms);
if( res == erNoError )
return SetDateTimeRetMessage(qreply);
throw mbException(res);
}
// --------------------------------------------------------------------------------
void ModbusClient::fileTransfer(ModbusAddr addr, ModbusData numfile,
const std::string& save2filename, timeout_t part_timeout_msec )
{
//#warning Необходимо реализовать
// throw mbException(erUnExpectedPacketType);
mbErrCode res = erNoError;
FILE* fdsave = fopen(save2filename.c_str(), "w");
if( fdsave == NULL )
{
if( dlog->is_warn() )
dlog->warn() << "(fileTransfer): fopen '"
<< save2filename << "' with error: "
<< strerror(errno) << endl;
throw mbException(erHardwareError);
}
uint16_t maxpackets = 65535;
uint16_t curpack = 0;
PassiveTimer ptTimeout(part_timeout_msec);
while( curpack < maxpackets && !ptTimeout.checkTime() )
{
try
{
FileTransferRetMessage ret = partOfFileTransfer( addr, numfile, curpack, part_timeout_msec );
if( ret.numfile != numfile )
{
if( dlog->is_warn() )
dlog->warn() << "(fileTransfer): recv nfile=" << ret.numfile
<< " !=numfile(" << numfile << ")" << endl;
continue;
}
if( ret.packet != curpack )
{
if( dlog->is_warn() )
dlog->warn() << "(fileTransfer): recv npack=" << ret.packet
<< " !=curpack(" << curpack << ")" << endl;
continue;
}
maxpackets = ret.numpacks;
if( dlog->is_info() )
dlog->info() << "(fileTransfer): maxpackets="
<< ret.numpacks << " curpack=" << curpack + 1 << endl;
// save data...
if( fwrite(&ret.data, ret.dlen, 1, fdsave) <= 0 )
{
if( dlog->is_warn() )
dlog->warn() << "(fileTransfer): fwrite '"
<< save2filename << "' with error: "
<< strerror(errno) << endl;
res = erHardwareError;
break;
}
ptTimeout.reset();
curpack = ret.packet + 1; // curpack++;
}
catch( mbException& ex )
{
if( ex.err == erBadCheckSum )
continue;
res = ex.err;
break;
}
}
fclose(fdsave);
if( curpack == maxpackets )
return;
if( res == erNoError )
res = erTimeOut;
throw mbException(res);
}
// --------------------------------------------------------------------------------
FileTransferRetMessage ModbusClient::partOfFileTransfer( ModbusAddr addr,
ModbusData idFile, ModbusData numpack,
timeout_t part_timeout_msec )
{
FileTransferMessage msg(addr, idFile, numpack);
qbuf = msg.transport_msg();
mbErrCode res = query(addr, qbuf, qreply, part_timeout_msec);
if( res == erNoError )
return FileTransferRetMessage(qreply);
throw mbException(res);
}
// --------------------------------------------------------------------------------
mbErrCode ModbusClient::recv( ModbusAddr addr, ModbusByte qfunc,
ModbusMessage& rbuf, timeout_t timeout )
{
if( timeout == UniSetTimer::WaitUpTime )
timeout = 15 * 60 * 1000 * 1000; // используем просто большое время (15 минут). Переведя его в наносекунды.
setChannelTimeout(timeout);
PassiveTimer tmAbort(timeout);
size_t bcnt = 0; // receive bytes count
try
{
bool begin = false;
while( !tmAbort.checkTime() )
{
bcnt = getNextData((unsigned char*)(&rbuf.pduhead.addr), sizeof(rbuf.pduhead.addr));
if( bcnt > 0 && ( rbuf.addr() == addr ) ) // || (onBroadcast && rbuf.addr==BroadcastAddr) ) )
{
begin = true;
break;
}
std::this_thread::sleep_for(std::chrono::microseconds(sleepPause_usec));
}
if( !begin )
return erTimeOut;
/*! \todo Подумать Может стоит всё-таки получать весь пакет, а проверять кому он адресован на уровне выше?!
// Lav: конечно стоит, нам же надо буфер чистить
*/
// Проверка кому адресован пакет...
if( rbuf.addr() != addr && rbuf.addr() != BroadcastAddr )
{
ostringstream err;
err << "(recv): BadNodeAddress. my= " << addr2str(addr)
<< " msg.addr=" << addr2str(rbuf.addr());
if( dlog->is_warn() )
dlog->warn() << err.str() << endl;
cleanupChannel();
return erBadReplyNodeAddress;
}
return recv_pdu(qfunc, rbuf, timeout);
}
catch( const uniset::TimeOut& ex )
{
// cout << "(recv): catch TimeOut " << endl;
}
catch( const uniset::CommFailed& ex )
{
if( dlog->is_crit() )
dlog->crit() << "(recv): " << ex << endl;
cleanupChannel();
return erTimeOut;
}
catch( const uniset::Exception& ex ) // SystemError
{
if( dlog->is_crit() )
dlog->crit() << "(recv): " << ex << endl;
cleanupChannel();
return erHardwareError;
}
return erTimeOut;
}
// --------------------------------------------------------------------------------
mbErrCode ModbusClient::recv_pdu( ModbusByte qfunc, ModbusMessage& rbuf, timeout_t timeout )
{
size_t bcnt = 1; // receive bytes count (1 - addr)
try
{
// -----------------------------------
tmProcessing.setTiming(replyTimeOut_ms);
// recv func number
size_t k = getNextData((unsigned char*)(&rbuf.pduhead.func), sizeof(rbuf.pduhead.func));
if( k < sizeof(rbuf.pduhead.func) )
{
if( dlog->is_warn() )
dlog->warn() << "(recv): receive " << k << " bytes < " << sizeof(rbuf.pduhead.func) << endl;
cleanupChannel();
return erInvalidFormat;
}
bcnt += k;
rbuf.dlen = 0;
if( dlog->is_level9() )
dlog->level9() << "(recv): PDU: " << rbuf.pduhead << endl;
// обработка сообщения об ошибке...
if( rbuf.func() == (qfunc | MBErrMask) )
{
rbuf.dlen = ErrorRetMessage::szData();
// обработка сообщения об ошибке...
if( rbuf.func() == (qfunc | MBErrMask) )
{
rbuf.dlen = ErrorRetMessage::szData();
if( crcNoCheckit )
rbuf.dlen -= szCRC;
size_t rlen = getNextData((unsigned char*)(&(rbuf.data)), rbuf.dlen);
if( rlen < rbuf.dlen )
{
if( dlog->is_warn() )
{
dlog->warn() << "(recv:Error): buf: " << rbuf << endl;
dlog->warn() << "(recv:Error)(" << rbuf.func()
<< "): Получили данных меньше чем ждали...(recv="
<< rlen << " < wait=" << rbuf.dlen << ")" << endl;
}
if( crcNoCheckit )
rbuf.dlen -= szCRC;
size_t rlen = getNextData((unsigned char*)(&(rbuf.data)), rbuf.dlen);
if( rlen < rbuf.dlen )
{
if( dlog->is_warn() )
{
dlog->warn() << "(recv:Error): buf: " << rbuf << endl;
dlog->warn() << "(recv:Error)(" << rbuf.func()
<< "): Получили данных меньше чем ждали...(recv="
<< rlen << " < wait=" << rbuf.dlen << ")" << endl;
}
cleanupChannel();
return erInvalidFormat;
}
cleanupChannel();
return erInvalidFormat;
}
bcnt += rlen;
bcnt += rlen;
ErrorRetMessage em(rbuf);
ErrorRetMessage em(rbuf);
if( !crcNoCheckit )
{
ModbusData tcrc = rbuf.pduCRC(bcnt - szCRC);
if( !crcNoCheckit )
{
ModbusData tcrc = rbuf.pduCRC(bcnt - szCRC);
if( tcrc != em.crc )
{
ostringstream err;
err << "(recv:error): bad crc. calc.crc=" << dat2str(tcrc)
<< " msg.crc=" << dat2str(em.crc);
if( tcrc != em.crc )
{
ostringstream err;
err << "(recv:error): bad crc. calc.crc=" << dat2str(tcrc)
<< " msg.crc=" << dat2str(em.crc);
if( dlog->is_warn() )
dlog->warn() << err.str() << endl;
if( dlog->is_warn() )
dlog->warn() << err.str() << endl;
return erBadCheckSum;
}
}
return erBadCheckSum;
}
}
return (mbErrCode)em.ecode;
}
if( qfunc != rbuf.func() )
{
cleanupChannel();
return erUnExpectedPacketType;
}
return (mbErrCode)em.ecode;
}
if( qfunc != rbuf.func() )
{
cleanupChannel();
return erUnExpectedPacketType;
}
// Определяем тип сообщения
switch( rbuf.func() )
{
case fnReadCoilStatus:
rbuf.dlen = ReadCoilRetMessage::szHead();
break;
// Определяем тип сообщения
switch( rbuf.func() )
{
case fnReadCoilStatus:
rbuf.dlen = ReadCoilRetMessage::szHead();
break;
case fnReadInputStatus:
rbuf.dlen = ReadInputStatusRetMessage::szHead();
break;
case fnReadInputStatus:
rbuf.dlen = ReadInputStatusRetMessage::szHead();
break;
case fnReadOutputRegisters:
rbuf.dlen = ReadOutputRetMessage::szHead();
break;
case fnReadOutputRegisters:
rbuf.dlen = ReadOutputRetMessage::szHead();
break;
case fnReadInputRegisters:
rbuf.dlen = ReadInputRetMessage::szHead();
break;
case fnReadInputRegisters:
rbuf.dlen = ReadInputRetMessage::szHead();
break;
case fnForceMultipleCoils:
rbuf.dlen = ForceCoilsRetMessage::szData();
case fnForceMultipleCoils:
rbuf.dlen = ForceCoilsRetMessage::szData();
if( crcNoCheckit )
rbuf.dlen -= szCRC;
if( crcNoCheckit )
rbuf.dlen -= szCRC;
break;
break;
case fnWriteOutputRegisters:
rbuf.dlen = WriteOutputRetMessage::szData();
case fnWriteOutputRegisters:
rbuf.dlen = WriteOutputRetMessage::szData();
if( crcNoCheckit )
rbuf.dlen -= szCRC;
if( crcNoCheckit )
rbuf.dlen -= szCRC;
break;
break;
case fnWriteOutputSingleRegister:
rbuf.dlen = WriteSingleOutputRetMessage::szData();
case fnWriteOutputSingleRegister:
rbuf.dlen = WriteSingleOutputRetMessage::szData();
if( crcNoCheckit )
rbuf.dlen -= szCRC;
if( crcNoCheckit )
rbuf.dlen -= szCRC;
break;
break;
case fnForceSingleCoil:
rbuf.dlen = ForceSingleCoilRetMessage::szData();
case fnForceSingleCoil:
rbuf.dlen = ForceSingleCoilRetMessage::szData();
if( crcNoCheckit )
rbuf.dlen -= szCRC;
if( crcNoCheckit )
rbuf.dlen -= szCRC;
break;
break;
case fnDiagnostics:
rbuf.dlen = DiagnosticRetMessage::szHead();
break;
case fnDiagnostics:
rbuf.dlen = DiagnosticRetMessage::szHead();
break;
case fnMEI:
rbuf.dlen = MEIMessageRetRDI::szHead();
break;
case fnMEI:
rbuf.dlen = MEIMessageRetRDI::szHead();
break;
case fnSetDateTime:
rbuf.dlen = SetDateTimeRetMessage::szData();
case fnSetDateTime:
rbuf.dlen = SetDateTimeRetMessage::szData();
if( crcNoCheckit )
rbuf.dlen -= szCRC;
if( crcNoCheckit )
rbuf.dlen -= szCRC;
break;
break;
case fnFileTransfer:
rbuf.dlen = FileTransferRetMessage::szHead();
break;
case fnFileTransfer:
rbuf.dlen = FileTransferRetMessage::szHead();
break;
/*
case fnJournalCommand:
rbuf.len = JournalCommandMessage::szData();
break;
/*
case fnJournalCommand:
rbuf.len = JournalCommandMessage::szData();
break;
case fnRemoteService:
rbuf.len = RemoteServiceMessage::szHead();
break;
*/
default:
cleanupChannel();
return erUnExpectedPacketType;
}
case fnRemoteService:
rbuf.len = RemoteServiceMessage::szHead();
break;
*/
default:
cleanupChannel();
return erUnExpectedPacketType;
}
// Получаем остальную часть сообщения
size_t rlen = getNextData((unsigned char*)(rbuf.data), rbuf.dlen);
if( rlen < rbuf.dlen )
{
// rbuf.len = bcnt + rlen - szModbusHeader;
if( dlog->is_warn() )
{
dlog->warn() << "(recv): buf: " << rbuf << endl;
dlog->warn() << "(recv)(" << rbuf.func()
<< "): Получили данных меньше чем ждали...(recv="
<< rlen << " < wait=" << rbuf.dlen << ")" << endl;
}
// Получаем остальную часть сообщения
size_t rlen = getNextData((unsigned char*)(rbuf.data), rbuf.dlen);
if( rlen < rbuf.dlen )
{
// rbuf.len = bcnt + rlen - szModbusHeader;
if( dlog->is_warn() )
{
dlog->warn() << "(recv): buf: " << rbuf << endl;
dlog->warn() << "(recv)(" << rbuf.func()
<< "): Получили данных меньше чем ждали...(recv="
<< rlen << " < wait=" << rbuf.dlen << ")" << endl;
}
cleanupChannel();
return erInvalidFormat;
}
cleanupChannel();
return erInvalidFormat;
}
bcnt += rlen;
bcnt += rlen;
// получаем остальное...
if( rbuf.func() == fnReadCoilStatus )
{
int szDataLen = ReadCoilRetMessage::getDataLen(rbuf) + szCRC;
// получаем остальное...
if( rbuf.func() == fnReadCoilStatus )
{
int szDataLen = ReadCoilRetMessage::getDataLen(rbuf) + szCRC;
if( crcNoCheckit )
szDataLen -= szCRC;
if( crcNoCheckit )
szDataLen -= szCRC;
// Мы получили только предварительный загловок
// Теперь необходимо дополучить данные
// (c позиции rlen, т.к. часть уже получили)
int rlen1 = getNextData((unsigned char*)(&(rbuf.data[rlen])), szDataLen);
// Мы получили только предварительный загловок
// Теперь необходимо дополучить данные
// (c позиции rlen, т.к. часть уже получили)
int rlen1 = getNextData((unsigned char*)(&(rbuf.data[rlen])), szDataLen);
if( rlen1 < szDataLen )
{
rbuf.dlen = bcnt + rlen1 - szModbusHeader;
if( rlen1 < szDataLen )
{
rbuf.dlen = bcnt + rlen1 - szModbusHeader;
if( dlog->is_warn() )
{
dlog->warn() << "(0x01): buf: " << rbuf << endl;
dlog->warn() << "(0x01)("
<< (int)rbuf.func() << "):(fnReadCoilStatus) "
<< "Получили данных меньше чем ждали...("
<< rlen1 << " < " << szDataLen << ")" << endl;
}
cleanupChannel();
return erInvalidFormat;
}
bcnt += rlen1;
rbuf.dlen = bcnt - szModbusHeader;
ReadCoilRetMessage mRead(rbuf);
if( dlog->is_info() )
dlog->info() << "(0x01)(fnReadCoilStatus): recv buf: " << rbuf << endl;
if( crcNoCheckit )
return erNoError;
// Проверяем контрольную сумму
// от начала(включая заголовок)
// и до конца (исключив последний элемент содержащий CRC)
// int mlen = szModbusHeader + mWrite.szHead()+ mWrite.bcnt;
ModbusData tcrc = rbuf.pduCRC(bcnt - szCRC);
if( tcrc != mRead.crc )
{
ostringstream err;
err << "(0x01)(fnReadCoilStatus): bad crc. calc.crc=" << dat2str(tcrc)
<< " msg.crc=" << dat2str(mRead.crc);
if( dlog->is_warn() )
dlog->warn() << err.str() << endl;
return erBadCheckSum;
}
return erNoError;
}
else if( rbuf.func() == fnReadInputStatus )
{
int szDataLen = ReadInputStatusRetMessage::getDataLen(rbuf) + szCRC;
if( crcNoCheckit )
szDataLen -= szCRC;
// Мы получили только предварительный загловок
// Теперь необходимо дополучить данные
// (c позиции rlen, т.к. часть уже получили)
int rlen1 = getNextData((unsigned char*)(&(rbuf.data[rlen])), szDataLen);
if( rlen1 < szDataLen )
{
rbuf.dlen = bcnt + rlen1 - szModbusHeader;
if( dlog->is_warn() )
{
dlog->warn() << "(0x02): buf: " << rbuf << endl;
dlog->warn() << "(0x02)("
<< (int)rbuf.func() << "):(fnReadInputStatus) "
<< "Получили данных меньше чем ждали...("
<< rlen1 << " < " << szDataLen << ")" << endl;
}
cleanupChannel();
return erInvalidFormat;
}
bcnt += rlen1;
rbuf.dlen = bcnt - szModbusHeader;
ReadInputStatusRetMessage mRead(rbuf);
if( dlog->is_info() )
dlog->info() << "(0x02)(fnReadInputStatus): recv buf: " << rbuf << endl;
if( crcNoCheckit )
return erNoError;
// Проверяем контрольную сумму
// от начала(включая заголовок)
// и до конца (исключив последний элемент содержащий CRC)
// int mlen = szModbusHeader + mWrite.szHead()+ mWrite.bcnt;
ModbusData tcrc = rbuf.pduCRC(bcnt - szCRC);
if( tcrc != mRead.crc )
{
ostringstream err;
err << "(recv:fnReadInputStatus): bad crc. calc.crc=" << dat2str(tcrc)
<< " msg.crc=" << dat2str(mRead.crc);
if( dlog->is_warn() )
dlog->warn() << err.str() << endl;
return erBadCheckSum;
}
return erNoError;
}
else if( rbuf.func() == fnReadInputRegisters )
{
int szDataLen = ReadInputRetMessage::getDataLen(rbuf) + szCRC;
if( crcNoCheckit )
szDataLen -= szCRC;
// Мы получили только предварительный загловок
// Теперь необходимо дополучить данные
// (c позиции rlen, т.к. часть уже получили)
int rlen1 = getNextData((unsigned char*)(&(rbuf.data[rlen])), szDataLen);
if( rlen1 < szDataLen )
{
rbuf.dlen = bcnt + rlen1 - szModbusHeader;
if( dlog->is_warn() )
{
dlog->warn() << "(0x04): buf: " << rbuf << endl;
dlog->warn() << "(0x04)("
<< (int)rbuf.func() << "):(fnReadInputRegisters) "
<< "Получили данных меньше чем ждали...("
<< rlen1 << " < " << szDataLen << ")" << endl;
}
cleanupChannel();
return erInvalidFormat;
}
bcnt += rlen1;
rbuf.dlen = bcnt - szModbusHeader;
ReadInputRetMessage mRead(rbuf);
if( dlog->is_info() )
dlog->info() << "(recv)(fnReadInputRegisters): recv buf: " << rbuf << endl;
if( crcNoCheckit )
return erNoError;
// Проверяем контрольную сумму
// от начала(включая заголовок)
// и до конца (исключив последний элемент содержащий CRC)
// int mlen = szModbusHeader + mWrite.szHead()+ mWrite.bcnt;
ModbusData tcrc = rbuf.pduCRC(bcnt - szCRC);
if( tcrc != mRead.crc )
{
ostringstream err;
err << "(recv:fnReadInputRegisters): bad crc. calc.crc=" << dat2str(tcrc)
<< " msg.crc=" << dat2str(mRead.crc);
if( dlog->is_warn() )
dlog->warn() << err.str() << endl;
return erBadCheckSum;
}
return erNoError;
}
else if( rbuf.func() == fnReadOutputRegisters )
{
int szDataLen = ReadOutputRetMessage::getDataLen(rbuf) + szCRC;
if( crcNoCheckit )
szDataLen -= szCRC;
// Мы получили только предварительный загловок
// Теперь необходимо дополучить данные
// (c позиции rlen, т.к. часть уже получили)
int rlen1 = getNextData((unsigned char*)(&(rbuf.data[rlen])), szDataLen);
if( rlen1 < szDataLen )
{
rbuf.dlen = bcnt + rlen1 - szModbusHeader;
if( dlog->is_warn() )
{
dlog->warn() << "(0x03): buf: " << rbuf << endl;
dlog->warn() << "(0x03)("
<< (int)rbuf.func() << "):(fnReadInputRegisters) "
<< "Получили данных меньше чем ждали...("
<< rlen1 << " < " << szDataLen << ")" << endl;
}
cleanupChannel();
return erInvalidFormat;
}
bcnt += rlen1;
rbuf.dlen = bcnt - szModbusHeader;
ReadOutputRetMessage mRead(rbuf);
if( dlog->is_info() )
dlog->info() << "(recv)(fnReadOutputRegisters): recv buf: " << rbuf << endl;
if( crcNoCheckit )
return erNoError;
// Проверяем контрольную сумму
// от начала(включая заголовок)
// и до конца (исключив последний элемент содержащий CRC)
// int mlen = szModbusHeader + mWrite.szHead()+ mWrite.bcnt;
ModbusData tcrc = rbuf.pduCRC(bcnt - szCRC);
if( tcrc != mRead.crc )
{
ostringstream err;
err << "(recv:fnReadOutputRegisters): bad crc. calc.crc=" << dat2str(tcrc)
<< " msg.crc=" << dat2str(mRead.crc);
if( dlog->is_warn() )
dlog->warn() << err.str() << endl;
return erBadCheckSum;
}
return erNoError;
}
else if( rbuf.func() == fnForceMultipleCoils )
{
rbuf.dlen = bcnt - szModbusHeader;
ForceCoilsRetMessage mWrite(rbuf);
if( dlog->is_info() )
dlog->info() << "(0x0F): recv buf: " << rbuf << endl;
if( crcNoCheckit )
return erNoError;
// Проверяем контрольную сумму
// от начала(включая заголовок)
// и до конца (исключив последний элемент содержащий CRC)
// int mlen = szModbusHeader + mWrite.szHead()+ mWrite.bcnt;
ModbusData tcrc = rbuf.pduCRC(bcnt - szCRC);
if( tcrc != mWrite.crc )
{
ostringstream err;
err << "(0x0F): bad crc. calc.crc=" << dat2str(tcrc)
<< " msg.crc=" << dat2str(mWrite.crc);
dlog->warn() << err.str() << endl;
return erBadCheckSum;
}
return erNoError;
}
else if( rbuf.func() == fnWriteOutputRegisters )
{
rbuf.dlen = bcnt - szModbusHeader;
WriteOutputRetMessage mWrite(rbuf);
if( dlog->is_info() )
dlog->info() << "(0x10): recv buf: " << rbuf << endl;
if( crcNoCheckit )
return erNoError;
// Проверяем контрольную сумму
// от начала(включая заголовок)
// и до конца (исключив последний элемент содержащий CRC)
// int mlen = szModbusHeader + mWrite.szHead()+ mWrite.bcnt;
ModbusData tcrc = rbuf.pduCRC(bcnt - szCRC);
if( tcrc != mWrite.crc )
{
ostringstream err;
err << "(0x10): bad crc. calc.crc=" << dat2str(tcrc)
<< " msg.crc=" << dat2str(mWrite.crc);
dlog->warn() << err.str() << endl;
return erBadCheckSum;
}
return erNoError;
}
else if( rbuf.func() == fnWriteOutputSingleRegister )
{
WriteSingleOutputRetMessage mWrite(rbuf);
if( dlog->is_info() )
dlog->info() << "(0x06): recv buf: " << rbuf << endl;
if( crcNoCheckit )
return erNoError;
// Проверяем контрольную сумму
// от начала(включая заголовок)
// и до конца (исключив последний элемент содержащий CRC)
// int mlen = szModbusHeader + mWrite.szHead() + mWrite.bcnt;
ModbusData tcrc = rbuf.pduCRC(bcnt - szCRC);
if( tcrc != mWrite.crc )
{
ostringstream err;
err << "(0x06): bad crc. calc.crc=" << dat2str(tcrc)
<< " msg.crc=" << dat2str(mWrite.crc);
dlog->warn() << err.str() << endl;
return erBadCheckSum;
}
return erNoError;
}
else if( rbuf.func() == fnForceSingleCoil )
{
ForceSingleCoilRetMessage mWrite(rbuf);
if( dlog->is_info() )
dlog->info() << "(0x05): recv buf: " << rbuf << endl;
if( crcNoCheckit )
return erNoError;
// Проверяем контрольную сумму
// от начала(включая заголовок)
// и до конца (исключив последний элемент содержащий CRC)
// int mlen = szModbusHeader + mWrite.szHead() + mWrite.bcnt;
ModbusData tcrc = rbuf.pduCRC(bcnt - szCRC);
if( tcrc != mWrite.crc )
{
ostringstream err;
err << "(0x05): bad crc. calc.crc=" << dat2str(tcrc)
<< " msg.crc=" << dat2str(mWrite.crc);
dlog->warn() << err.str() << endl;
return erBadCheckSum;
}
return erNoError;
}
else if( rbuf.func() == fnDiagnostics )
{
int szDataLen = DiagnosticRetMessage::getDataLen(rbuf) + szCRC;
if( crcNoCheckit )
szDataLen -= szCRC;
// Мы получили только предварительный загловок
// Теперь необходимо дополучить данные
// (c позиции rlen, т.к. часть уже получили)
int rlen1 = getNextData((unsigned char*)(&(rbuf.data[rlen])), szDataLen);
if( rlen1 < szDataLen )
{
rbuf.dlen = bcnt + rlen1 - szModbusHeader;
if( dlog->is_warn() )
{
dlog->warn() << "(0x08): buf: " << rbuf << endl;
dlog->warn() << "(0x08)("
<< (int)rbuf.func() << "):(fnDiagnostics) "
<< "Получили данных меньше чем ждали...("
<< rlen1 << " < " << szDataLen << ")" << endl;
}
cleanupChannel();
return erInvalidFormat;
}
bcnt += rlen1;
rbuf.dlen = bcnt - szModbusHeader;
DiagnosticRetMessage mDiag(rbuf);
if( dlog->is_info() )
dlog->info() << "(recv)(fnDiagnostics): recv buf: " << rbuf << endl;
if( crcNoCheckit )
return erNoError;
// Проверяем контрольную сумму
// от начала(включая заголовок)
// и до конца (исключив последний элемент содержащий CRC)
// int mlen = szModbusHeader + mWrite.szHead()+ mWrite.bcnt;
ModbusData tcrc = rbuf.pduCRC(bcnt - szCRC);
if( tcrc != mDiag.crc )
{
ostringstream err;
err << "(recv:fnDiagnostics): bad crc. calc.crc=" << dat2str(tcrc)
<< " msg.crc=" << dat2str(mDiag.crc);
if( dlog->is_warn() )
dlog->warn() << err.str() << endl;
return erBadCheckSum;
}
return erNoError;
}
else if( rbuf.func() == fnMEI )
{
MEIMessageRetRDI mPreRDI;
mPreRDI.pre_init(rbuf);
if( mPreRDI.objNum > 0 )
{
size_t onum = 0;
while( (rlen + 2) < sizeof(rbuf.data) && onum < mPreRDI.objNum )
{
// сперва получаем два байта, для определения длины последующих данных
size_t szDataLen = 2; // object id + len
size_t rlen1 = getNextData((unsigned char*)(&(rbuf.data[rlen])), szDataLen);
if( rlen1 < szDataLen )
{
rbuf.dlen = bcnt + rlen1 - szModbusHeader;
if( dlog->is_warn() )
{
dlog->warn() << "(0x2B/0x0E): buf: " << rbuf << endl;
dlog->warn() << "(0x2B/0x0E)("
<< (int)rbuf.func() << "):(fnMEI) "
<< "Получили данных меньше чем ждали...("
<< rlen1 << " < " << szDataLen << ")" << endl;
}
cleanupChannel();
return erInvalidFormat;
}
rlen += szDataLen;
bcnt += szDataLen;
// теперь получаем собственно данные
szDataLen = rbuf.data[rlen - 1]; // последний (предыдущий) байт - это длина данных
rlen1 = getNextData((unsigned char*)(&(rbuf.data[rlen])), szDataLen);
if( rlen1 < szDataLen )
{
rbuf.dlen = bcnt + rlen1 - szModbusHeader;
if( dlog->is_warn() )
{
dlog->warn() << "(0x2B/0x0E): buf: " << rbuf << endl;
dlog->warn() << "(0x2B/0x0E)("
<< (int)rbuf.func() << "):(fnMEI) "
<< "Получили данных меньше чем ждали...("
<< rlen1 << " < " << szDataLen << ")" << endl;
}
cleanupChannel();
return erInvalidFormat;
}
rlen += szDataLen;
bcnt += szDataLen;
onum++;
}
}
rbuf.dlen = bcnt - szModbusHeader;
if( crcNoCheckit )
{
if( dlog->is_info() )
dlog->info() << "(recv)(fnMEI): recv buf: " << rbuf << endl;
return erNoError;
}
// теперь получаем CRC
size_t rlen1 = getNextData((unsigned char*)(&(rbuf.data[rlen])), szCRC);
if( rlen1 < szCRC )
{
rbuf.dlen = bcnt + rlen1 - szModbusHeader;
if( dlog->is_warn() )
{
dlog->warn() << "(0x2B/0x0E): buf: " << rbuf << endl;
dlog->warn() << "(0x2B/0x0E)("
<< (int)rbuf.func() << "):(fnMEI) "
<< "(CRC): Получили данных меньше чем ждали...("
<< rlen1 << " < " << szCRC << ")" << endl;
}
cleanupChannel();
return erInvalidFormat;
}
bcnt += rlen1;
rbuf.dlen = bcnt - szModbusHeader;
if( dlog->is_info() )
dlog->info() << "(recv)(fnMEI): recv buf: " << rbuf << endl;
MEIMessageRetRDI mRDI(rbuf);
// Проверяем контрольную сумму
// от начала(включая заголовок)
// и до конца (исключив последний элемент содержащий CRC)
// int mlen = szModbusHeader + mWrite.szHead()+ mWrite.bcnt;
ModbusData tcrc = rbuf.pduCRC(bcnt - szCRC);
if( tcrc != mRDI.crc )
{
ostringstream err;
err << "(recv:fnMEI): bad crc. calc.crc=" << dat2str(tcrc)
<< " msg.crc=" << dat2str(mRDI.crc);
if( dlog->is_warn() )
dlog->warn() << err.str() << endl;
return erBadCheckSum;
}
return erNoError;
}
else if( rbuf.func() == fnSetDateTime )
{
SetDateTimeRetMessage mSet(rbuf);
if( dlog->is_info() )
dlog->info() << "(0x50): recv buf: " << rbuf << endl;
if( !crcNoCheckit )
{
// Проверяем контрольную сумму
// от начала(включая заголовок) и до конца (исключив последний элемент содержащий CRC)
ModbusData tcrc = rbuf.pduCRC(bcnt - szCRC);
if( tcrc != mSet.crc )
{
ostringstream err;
err << "(0x50): bad crc. calc.crc=" << dat2str(tcrc)
<< " msg.crc=" << dat2str(mSet.crc);
if( dlog->is_warn() )
dlog->warn() << err.str() << endl;
return erBadCheckSum;
}
}
if( !mSet.checkFormat() )
{
if( dlog->is_warn() )
dlog->warn() << "(0x50): некорректные значения..." << endl;
return erBadDataValue; // return erInvalidFormat;
}
return erNoError;
}
else if( rbuf.func() == fnFileTransfer )
{
int szDataLen = FileTransferRetMessage::getDataLen(rbuf) + szCRC;
if( crcNoCheckit )
szDataLen -= szCRC;
// Мы получили только предварительный загловок
// Теперь необходимо дополучить данные
// (c позиции rlen, т.к. часть уже получили)
int rlen1 = getNextData((unsigned char*)(&(rbuf.data[rlen])), szDataLen);
if( rlen1 < szDataLen )
{
rbuf.dlen = bcnt + rlen1 - szModbusHeader;
if( dlog->is_warn() )
{
dlog->warn() << "(0x66): buf: " << rbuf << endl;
dlog->warn() << "(0x66)("
<< rbuf.func() << "):(fnFileTransfer) "
<< "Получили данных меньше чем ждали...("
<< rlen1 << " < " << szDataLen << ")" << endl;
}
cleanupChannel();
return erInvalidFormat;
}
bcnt += rlen1;
rbuf.dlen = bcnt - szModbusHeader;
if( dlog->is_warn() )
{
dlog->warn() << "(0x01): buf: " << rbuf << endl;
dlog->warn() << "(0x01)("
<< (int)rbuf.func() << "):(fnReadCoilStatus) "
<< "Получили данных меньше чем ждали...("
<< rlen1 << " < " << szDataLen << ")" << endl;
}
cleanupChannel();
return erInvalidFormat;
}
bcnt += rlen1;
rbuf.dlen = bcnt - szModbusHeader;
ReadCoilRetMessage mRead(rbuf);
if( dlog->is_info() )
dlog->info() << "(0x01)(fnReadCoilStatus): recv buf: " << rbuf << endl;
if( crcNoCheckit )
return erNoError;
// Проверяем контрольную сумму
// от начала(включая заголовок)
// и до конца (исключив последний элемент содержащий CRC)
// int mlen = szModbusHeader + mWrite.szHead()+ mWrite.bcnt;
ModbusData tcrc = rbuf.pduCRC(bcnt - szCRC);
if( tcrc != mRead.crc )
{
ostringstream err;
err << "(0x01)(fnReadCoilStatus): bad crc. calc.crc=" << dat2str(tcrc)
<< " msg.crc=" << dat2str(mRead.crc);
if( dlog->is_warn() )
dlog->warn() << err.str() << endl;
return erBadCheckSum;
}
return erNoError;
}
else if( rbuf.func() == fnReadInputStatus )
{
int szDataLen = ReadInputStatusRetMessage::getDataLen(rbuf) + szCRC;
if( crcNoCheckit )
szDataLen -= szCRC;
// Мы получили только предварительный загловок
// Теперь необходимо дополучить данные
// (c позиции rlen, т.к. часть уже получили)
int rlen1 = getNextData((unsigned char*)(&(rbuf.data[rlen])), szDataLen);
if( rlen1 < szDataLen )
{
rbuf.dlen = bcnt + rlen1 - szModbusHeader;
if( dlog->is_warn() )
{
dlog->warn() << "(0x02): buf: " << rbuf << endl;
dlog->warn() << "(0x02)("
<< (int)rbuf.func() << "):(fnReadInputStatus) "
<< "Получили данных меньше чем ждали...("
<< rlen1 << " < " << szDataLen << ")" << endl;
}
cleanupChannel();
return erInvalidFormat;
}
bcnt += rlen1;
rbuf.dlen = bcnt - szModbusHeader;
ReadInputStatusRetMessage mRead(rbuf);
if( dlog->is_info() )
dlog->info() << "(0x02)(fnReadInputStatus): recv buf: " << rbuf << endl;
if( crcNoCheckit )
return erNoError;
// Проверяем контрольную сумму
// от начала(включая заголовок)
// и до конца (исключив последний элемент содержащий CRC)
// int mlen = szModbusHeader + mWrite.szHead()+ mWrite.bcnt;
ModbusData tcrc = rbuf.pduCRC(bcnt - szCRC);
if( tcrc != mRead.crc )
{
ostringstream err;
err << "(recv:fnReadInputStatus): bad crc. calc.crc=" << dat2str(tcrc)
<< " msg.crc=" << dat2str(mRead.crc);
if( dlog->is_warn() )
dlog->warn() << err.str() << endl;
return erBadCheckSum;
}
return erNoError;
}
else if( rbuf.func() == fnReadInputRegisters )
{
int szDataLen = ReadInputRetMessage::getDataLen(rbuf) + szCRC;
if( crcNoCheckit )
szDataLen -= szCRC;
// Мы получили только предварительный загловок
// Теперь необходимо дополучить данные
// (c позиции rlen, т.к. часть уже получили)
int rlen1 = getNextData((unsigned char*)(&(rbuf.data[rlen])), szDataLen);
if( rlen1 < szDataLen )
{
rbuf.dlen = bcnt + rlen1 - szModbusHeader;
if( dlog->is_warn() )
{
dlog->warn() << "(0x04): buf: " << rbuf << endl;
dlog->warn() << "(0x04)("
<< (int)rbuf.func() << "):(fnReadInputRegisters) "
<< "Получили данных меньше чем ждали...("
<< rlen1 << " < " << szDataLen << ")" << endl;
}
cleanupChannel();
return erInvalidFormat;
}
bcnt += rlen1;
rbuf.dlen = bcnt - szModbusHeader;
ReadInputRetMessage mRead(rbuf);
if( dlog->is_info() )
dlog->info() << "(recv)(fnReadInputRegisters): recv buf: " << rbuf << endl;
if( crcNoCheckit )
return erNoError;
// Проверяем контрольную сумму
// от начала(включая заголовок)
// и до конца (исключив последний элемент содержащий CRC)
// int mlen = szModbusHeader + mWrite.szHead()+ mWrite.bcnt;
ModbusData tcrc = rbuf.pduCRC(bcnt - szCRC);
if( tcrc != mRead.crc )
{
ostringstream err;
err << "(recv:fnReadInputRegisters): bad crc. calc.crc=" << dat2str(tcrc)
<< " msg.crc=" << dat2str(mRead.crc);
if( dlog->is_warn() )
dlog->warn() << err.str() << endl;
return erBadCheckSum;
}
return erNoError;
}
else if( rbuf.func() == fnReadOutputRegisters )
{
int szDataLen = ReadOutputRetMessage::getDataLen(rbuf) + szCRC;
if( crcNoCheckit )
szDataLen -= szCRC;
// Мы получили только предварительный загловок
// Теперь необходимо дополучить данные
// (c позиции rlen, т.к. часть уже получили)
int rlen1 = getNextData((unsigned char*)(&(rbuf.data[rlen])), szDataLen);
if( rlen1 < szDataLen )
{
rbuf.dlen = bcnt + rlen1 - szModbusHeader;
if( dlog->is_warn() )
{
dlog->warn() << "(0x03): buf: " << rbuf << endl;
dlog->warn() << "(0x03)("
<< (int)rbuf.func() << "):(fnReadInputRegisters) "
<< "Получили данных меньше чем ждали...("
<< rlen1 << " < " << szDataLen << ")" << endl;
}
cleanupChannel();
return erInvalidFormat;
}
bcnt += rlen1;
rbuf.dlen = bcnt - szModbusHeader;
ReadOutputRetMessage mRead(rbuf);
if( dlog->is_info() )
dlog->info() << "(recv)(fnReadOutputRegisters): recv buf: " << rbuf << endl;
if( crcNoCheckit )
return erNoError;
// Проверяем контрольную сумму
// от начала(включая заголовок)
// и до конца (исключив последний элемент содержащий CRC)
// int mlen = szModbusHeader + mWrite.szHead()+ mWrite.bcnt;
ModbusData tcrc = rbuf.pduCRC(bcnt - szCRC);
if( tcrc != mRead.crc )
{
ostringstream err;
err << "(recv:fnReadOutputRegisters): bad crc. calc.crc=" << dat2str(tcrc)
<< " msg.crc=" << dat2str(mRead.crc);
if( dlog->is_warn() )
dlog->warn() << err.str() << endl;
return erBadCheckSum;
}
return erNoError;
}
else if( rbuf.func() == fnForceMultipleCoils )
{
rbuf.dlen = bcnt - szModbusHeader;
ForceCoilsRetMessage mWrite(rbuf);
if( dlog->is_info() )
dlog->info() << "(0x0F): recv buf: " << rbuf << endl;
if( crcNoCheckit )
return erNoError;
// Проверяем контрольную сумму
// от начала(включая заголовок)
// и до конца (исключив последний элемент содержащий CRC)
// int mlen = szModbusHeader + mWrite.szHead()+ mWrite.bcnt;
ModbusData tcrc = rbuf.pduCRC(bcnt - szCRC);
if( tcrc != mWrite.crc )
{
ostringstream err;
err << "(0x0F): bad crc. calc.crc=" << dat2str(tcrc)
<< " msg.crc=" << dat2str(mWrite.crc);
dlog->warn() << err.str() << endl;
return erBadCheckSum;
}
return erNoError;
}
else if( rbuf.func() == fnWriteOutputRegisters )
{
rbuf.dlen = bcnt - szModbusHeader;
WriteOutputRetMessage mWrite(rbuf);
if( dlog->is_info() )
dlog->info() << "(0x10): recv buf: " << rbuf << endl;
if( crcNoCheckit )
return erNoError;
// Проверяем контрольную сумму
// от начала(включая заголовок)
// и до конца (исключив последний элемент содержащий CRC)
// int mlen = szModbusHeader + mWrite.szHead()+ mWrite.bcnt;
ModbusData tcrc = rbuf.pduCRC(bcnt - szCRC);
if( tcrc != mWrite.crc )
{
ostringstream err;
err << "(0x10): bad crc. calc.crc=" << dat2str(tcrc)
<< " msg.crc=" << dat2str(mWrite.crc);
dlog->warn() << err.str() << endl;
return erBadCheckSum;
}
return erNoError;
}
else if( rbuf.func() == fnWriteOutputSingleRegister )
{
WriteSingleOutputRetMessage mWrite(rbuf);
if( dlog->is_info() )
dlog->info() << "(0x06): recv buf: " << rbuf << endl;
if( crcNoCheckit )
return erNoError;
// Проверяем контрольную сумму
// от начала(включая заголовок)
// и до конца (исключив последний элемент содержащий CRC)
// int mlen = szModbusHeader + mWrite.szHead() + mWrite.bcnt;
ModbusData tcrc = rbuf.pduCRC(bcnt - szCRC);
if( tcrc != mWrite.crc )
{
ostringstream err;
err << "(0x06): bad crc. calc.crc=" << dat2str(tcrc)
<< " msg.crc=" << dat2str(mWrite.crc);
dlog->warn() << err.str() << endl;
return erBadCheckSum;
}
return erNoError;
}
else if( rbuf.func() == fnForceSingleCoil )
{
ForceSingleCoilRetMessage mWrite(rbuf);
if( dlog->is_info() )
dlog->info() << "(0x05): recv buf: " << rbuf << endl;
if( crcNoCheckit )
return erNoError;
// Проверяем контрольную сумму
// от начала(включая заголовок)
// и до конца (исключив последний элемент содержащий CRC)
// int mlen = szModbusHeader + mWrite.szHead() + mWrite.bcnt;
ModbusData tcrc = rbuf.pduCRC(bcnt - szCRC);
if( tcrc != mWrite.crc )
{
ostringstream err;
err << "(0x05): bad crc. calc.crc=" << dat2str(tcrc)
<< " msg.crc=" << dat2str(mWrite.crc);
dlog->warn() << err.str() << endl;
return erBadCheckSum;
}
return erNoError;
}
else if( rbuf.func() == fnDiagnostics )
{
int szDataLen = DiagnosticRetMessage::getDataLen(rbuf) + szCRC;
if( crcNoCheckit )
szDataLen -= szCRC;
// Мы получили только предварительный загловок
// Теперь необходимо дополучить данные
// (c позиции rlen, т.к. часть уже получили)
int rlen1 = getNextData((unsigned char*)(&(rbuf.data[rlen])), szDataLen);
if( rlen1 < szDataLen )
{
rbuf.dlen = bcnt + rlen1 - szModbusHeader;
if( dlog->is_warn() )
{
dlog->warn() << "(0x08): buf: " << rbuf << endl;
dlog->warn() << "(0x08)("
<< (int)rbuf.func() << "):(fnDiagnostics) "
<< "Получили данных меньше чем ждали...("
<< rlen1 << " < " << szDataLen << ")" << endl;
}
cleanupChannel();
return erInvalidFormat;
}
bcnt += rlen1;
rbuf.dlen = bcnt - szModbusHeader;
DiagnosticRetMessage mDiag(rbuf);
if( dlog->is_info() )
dlog->info() << "(recv)(fnDiagnostics): recv buf: " << rbuf << endl;
if( crcNoCheckit )
return erNoError;
// Проверяем контрольную сумму
// от начала(включая заголовок)
// и до конца (исключив последний элемент содержащий CRC)
// int mlen = szModbusHeader + mWrite.szHead()+ mWrite.bcnt;
ModbusData tcrc = rbuf.pduCRC(bcnt - szCRC);
if( tcrc != mDiag.crc )
{
ostringstream err;
err << "(recv:fnDiagnostics): bad crc. calc.crc=" << dat2str(tcrc)
<< " msg.crc=" << dat2str(mDiag.crc);
if( dlog->is_warn() )
dlog->warn() << err.str() << endl;
return erBadCheckSum;
}
return erNoError;
}
else if( rbuf.func() == fnMEI )
{
MEIMessageRetRDI mPreRDI;
mPreRDI.pre_init(rbuf);
if( mPreRDI.objNum > 0 )
{
size_t onum = 0;
while( (rlen + 2) < sizeof(rbuf.data) && onum < mPreRDI.objNum )
{
// сперва получаем два байта, для определения длины последующих данных
size_t szDataLen = 2; // object id + len
size_t rlen1 = getNextData((unsigned char*)(&(rbuf.data[rlen])), szDataLen);
if( rlen1 < szDataLen )
{
rbuf.dlen = bcnt + rlen1 - szModbusHeader;
if( dlog->is_warn() )
{
dlog->warn() << "(0x2B/0x0E): buf: " << rbuf << endl;
dlog->warn() << "(0x2B/0x0E)("
<< (int)rbuf.func() << "):(fnMEI) "
<< "Получили данных меньше чем ждали...("
<< rlen1 << " < " << szDataLen << ")" << endl;
}
cleanupChannel();
return erInvalidFormat;
}
rlen += szDataLen;
bcnt += szDataLen;
// теперь получаем собственно данные
szDataLen = rbuf.data[rlen - 1]; // последний (предыдущий) байт - это длина данных
rlen1 = getNextData((unsigned char*)(&(rbuf.data[rlen])), szDataLen);
if( rlen1 < szDataLen )
{
rbuf.dlen = bcnt + rlen1 - szModbusHeader;
if( dlog->is_warn() )
{
dlog->warn() << "(0x2B/0x0E): buf: " << rbuf << endl;
dlog->warn() << "(0x2B/0x0E)("
<< (int)rbuf.func() << "):(fnMEI) "
<< "Получили данных меньше чем ждали...("
<< rlen1 << " < " << szDataLen << ")" << endl;
}
cleanupChannel();
return erInvalidFormat;
}
rlen += szDataLen;
bcnt += szDataLen;
onum++;
}
}
rbuf.dlen = bcnt - szModbusHeader;
if( crcNoCheckit )
{
if( dlog->is_info() )
dlog->info() << "(recv)(fnMEI): recv buf: " << rbuf << endl;
return erNoError;
}
// теперь получаем CRC
size_t rlen1 = getNextData((unsigned char*)(&(rbuf.data[rlen])), szCRC);
if( rlen1 < szCRC )
{
rbuf.dlen = bcnt + rlen1 - szModbusHeader;
if( dlog->is_warn() )
{
dlog->warn() << "(0x2B/0x0E): buf: " << rbuf << endl;
dlog->warn() << "(0x2B/0x0E)("
<< (int)rbuf.func() << "):(fnMEI) "
<< "(CRC): Получили данных меньше чем ждали...("
<< rlen1 << " < " << szCRC << ")" << endl;
}
cleanupChannel();
return erInvalidFormat;
}
bcnt += rlen1;
rbuf.dlen = bcnt - szModbusHeader;
if( dlog->is_info() )
dlog->info() << "(recv)(fnMEI): recv buf: " << rbuf << endl;
MEIMessageRetRDI mRDI(rbuf);
// Проверяем контрольную сумму
// от начала(включая заголовок)
// и до конца (исключив последний элемент содержащий CRC)
// int mlen = szModbusHeader + mWrite.szHead()+ mWrite.bcnt;
ModbusData tcrc = rbuf.pduCRC(bcnt - szCRC);
if( tcrc != mRDI.crc )
{
ostringstream err;
err << "(recv:fnMEI): bad crc. calc.crc=" << dat2str(tcrc)
<< " msg.crc=" << dat2str(mRDI.crc);
if( dlog->is_warn() )
dlog->warn() << err.str() << endl;
return erBadCheckSum;
}
return erNoError;
}
else if( rbuf.func() == fnSetDateTime )
{
SetDateTimeRetMessage mSet(rbuf);
if( dlog->is_info() )
dlog->info() << "(0x50): recv buf: " << rbuf << endl;
if( !crcNoCheckit )
{
// Проверяем контрольную сумму
// от начала(включая заголовок) и до конца (исключив последний элемент содержащий CRC)
ModbusData tcrc = rbuf.pduCRC(bcnt - szCRC);
if( tcrc != mSet.crc )
{
ostringstream err;
err << "(0x50): bad crc. calc.crc=" << dat2str(tcrc)
<< " msg.crc=" << dat2str(mSet.crc);
if( dlog->is_warn() )
dlog->warn() << err.str() << endl;
return erBadCheckSum;
}
}
if( !mSet.checkFormat() )
{
if( dlog->is_warn() )
dlog->warn() << "(0x50): некорректные значения..." << endl;
return erBadDataValue; // return erInvalidFormat;
}
return erNoError;
}
else if( rbuf.func() == fnFileTransfer )
{
int szDataLen = FileTransferRetMessage::getDataLen(rbuf) + szCRC;
if( crcNoCheckit )
szDataLen -= szCRC;
// Мы получили только предварительный загловок
// Теперь необходимо дополучить данные
// (c позиции rlen, т.к. часть уже получили)
int rlen1 = getNextData((unsigned char*)(&(rbuf.data[rlen])), szDataLen);
if( rlen1 < szDataLen )
{
rbuf.dlen = bcnt + rlen1 - szModbusHeader;
if( dlog->is_warn() )
{
dlog->warn() << "(0x66): buf: " << rbuf << endl;
dlog->warn() << "(0x66)("
<< rbuf.func() << "):(fnFileTransfer) "
<< "Получили данных меньше чем ждали...("
<< rlen1 << " < " << szDataLen << ")" << endl;
}
cleanupChannel();
return erInvalidFormat;
}
bcnt += rlen1;
rbuf.dlen = bcnt - szModbusHeader;
FileTransferRetMessage mFT(rbuf);
if( dlog->is_info() )
dlog->info() << "(0x66): recv buf: " << rbuf << endl;
if( crcNoCheckit )
return erNoError;
// Проверяем контрольную сумму
// от начала(включая заголовок)
// и до конца (исключив последний элемент содержащий CRC)
// int mlen = szModbusHeader + mWrite.szHead()+ mWrite.bcnt;
ModbusData tcrc = rbuf.pduCRC(bcnt - szCRC);
if( tcrc != mFT.crc )
{
ostringstream err;
err << "(0x66): bad crc. calc.crc=" << dat2str(tcrc)
<< " msg.crc=" << dat2str(mFT.crc);
if( dlog->is_warn() )
dlog->warn() << err.str() << endl;
FileTransferRetMessage mFT(rbuf);
if( dlog->is_info() )
dlog->info() << "(0x66): recv buf: " << rbuf << endl;
if( crcNoCheckit )
return erNoError;
// Проверяем контрольную сумму
// от начала(включая заголовок)
// и до конца (исключив последний элемент содержащий CRC)
// int mlen = szModbusHeader + mWrite.szHead()+ mWrite.bcnt;
ModbusData tcrc = rbuf.pduCRC(bcnt - szCRC);
if( tcrc != mFT.crc )
{
ostringstream err;
err << "(0x66): bad crc. calc.crc=" << dat2str(tcrc)
<< " msg.crc=" << dat2str(mFT.crc);
if( dlog->is_warn() )
dlog->warn() << err.str() << endl;
return erBadCheckSum;
}
return erNoError;
}
return erBadCheckSum;
}
return erNoError;
}
#if 0
else if( rbuf.func() == fnJournalCommand )
{
JournalCommandMessage mRead(rbuf);
if( dlog->is_info() )
dlog->info() << "(0x65): recv buf: " << rbuf << endl;
if( crcNoCheckit )
return erNoError;
// Проверяем контрольную сумму
// от начала(включая заголовок) и до конца (исключив последний элемент содержащий CRC)
// ModbusData tcrc = checkCRC((ModbusByte*)(&rbuf.pduhead),sizeof(ReadOutputMessage)-szCRC);
ModbusData tcrc = rbuf.pduCRC(bcnt - szCRC);
if( tcrc != mRead.crc )
{
ostringstream err;
err << "(0x65): bad crc. calc.crc=" << dat2str(tcrc)
<< " msg.crc=" << dat2str(mRead.crc);
dlog->warn() << err.str() << endl;
return erBadCheckSum;
}
return erNoError;
}
else if( rbuf.func() == fnRemoteService )
{
int szDataLen = RemoteServiceMessage::getDataLen(rbuf) + szCRC;
if( crcNoCheckit )
szDataLen -= szCRC;
// Мы получили только предварительный загловок
// Теперь необходимо дополучить данные
// (c позиции rlen, т.к. часть уже получили)
int rlen1 = getNextData((unsigned char*)(&(rbuf.data[rlen])), szDataLen);
if( rlen1 < szDataLen )
{
rbuf.len = bcnt + rlen1 - szModbusHeader;
dlog->warn() << "(0x53): buf: " << rbuf << endl;
dlog->warn() << "(0x53)("
<< rbuf.func() << "):(fnWriteOutputRegisters) "
<< "Получили данных меньше чем ждали...("
<< rlen1 << " < " << szDataLen << ")" << endl;
cleanupChannel();
return erInvalidFormat;
}
bcnt += rlen1;
rbuf.len = bcnt - szModbusHeader;
RemoteServiceMessage mRServ(rbuf);
if( dlog->is_info() )
dlog->info() << "(0x53): recv buf: " << rbuf << endl;
if( crcNoCheckit )
return erNoError;
// Проверяем контрольную сумму
// от начала(включая заголовок)
// и до конца (исключив последний элемент содержащий CRC)
// int mlen = szModbusHeader + mWrite.szHead()+ mWrite.bcnt;
ModbusData tcrc = rbuf.pduCRC(bcnt - szCRC);
if( tcrc != mRServ.crc )
{
ostringstream err;
err << "(0x53): bad crc. calc.crc=" << dat2str(tcrc)
<< " msg.crc=" << dat2str(mRServ.crc);
dlog->warn() << err.str() << endl;
return erBadCheckSum;
}
return erNoError;
}
else if( rbuf.func() == fnJournalCommand )
{
JournalCommandMessage mRead(rbuf);
if( dlog->is_info() )
dlog->info() << "(0x65): recv buf: " << rbuf << endl;
if( crcNoCheckit )
return erNoError;
// Проверяем контрольную сумму
// от начала(включая заголовок) и до конца (исключив последний элемент содержащий CRC)
// ModbusData tcrc = checkCRC((ModbusByte*)(&rbuf.pduhead),sizeof(ReadOutputMessage)-szCRC);
ModbusData tcrc = rbuf.pduCRC(bcnt - szCRC);
if( tcrc != mRead.crc )
{
ostringstream err;
err << "(0x65): bad crc. calc.crc=" << dat2str(tcrc)
<< " msg.crc=" << dat2str(mRead.crc);
dlog->warn() << err.str() << endl;
return erBadCheckSum;
}
return erNoError;
}
else if( rbuf.func() == fnRemoteService )
{
int szDataLen = RemoteServiceMessage::getDataLen(rbuf) + szCRC;
if( crcNoCheckit )
szDataLen -= szCRC;
// Мы получили только предварительный загловок
// Теперь необходимо дополучить данные
// (c позиции rlen, т.к. часть уже получили)
int rlen1 = getNextData((unsigned char*)(&(rbuf.data[rlen])), szDataLen);
if( rlen1 < szDataLen )
{
rbuf.len = bcnt + rlen1 - szModbusHeader;
dlog->warn() << "(0x53): buf: " << rbuf << endl;
dlog->warn() << "(0x53)("
<< rbuf.func() << "):(fnWriteOutputRegisters) "
<< "Получили данных меньше чем ждали...("
<< rlen1 << " < " << szDataLen << ")" << endl;
cleanupChannel();
return erInvalidFormat;
}
bcnt += rlen1;
rbuf.len = bcnt - szModbusHeader;
RemoteServiceMessage mRServ(rbuf);
if( dlog->is_info() )
dlog->info() << "(0x53): recv buf: " << rbuf << endl;
if( crcNoCheckit )
return erNoError;
// Проверяем контрольную сумму
// от начала(включая заголовок)
// и до конца (исключив последний элемент содержащий CRC)
// int mlen = szModbusHeader + mWrite.szHead()+ mWrite.bcnt;
ModbusData tcrc = rbuf.pduCRC(bcnt - szCRC);
if( tcrc != mRServ.crc )
{
ostringstream err;
err << "(0x53): bad crc. calc.crc=" << dat2str(tcrc)
<< " msg.crc=" << dat2str(mRServ.crc);
dlog->warn() << err.str() << endl;
return erBadCheckSum;
}
return erNoError;
}
#endif // not standart commands
else
{
// А как мы сюда добрались?!!!!!!
cleanupChannel();
return erUnExpectedPacketType;
}
}
catch( mbException& ex )
{
if( dlog->is_crit() )
dlog->crit() << "(recv): " << ex << endl;
return ex.err;
}
catch( const uniset::TimeOut& ex )
{
// cout << "(recv): catch TimeOut " << endl;
}
catch( const uniset::CommFailed& ex )
{
if( dlog->is_crit() )
dlog->crit() << "(recv): " << ex << endl;
return erTimeOut;
}
catch( const uniset::Exception& ex ) // SystemError
{
if( dlog->is_crit() )
dlog->crit() << "(recv): " << ex << endl;
return erHardwareError;
}
return erTimeOut;
}
// -------------------------------------------------------------------------
mbErrCode ModbusClient::send( ModbusMessage& msg )
{
if( msg.len() > msg.maxSizeOfMessage() )
{
if( dlog->is_warn() )
dlog->warn() << "(ModbusClient::send): message len=" << msg.len()
<< " > MAXLEN=" << msg.maxSizeOfMessage() << endl;
return erPacketTooLong;
}
if( dlog->is_info() )
dlog->info() << "(ModbusClient::send): [" << msg.len() << " bytes]: " << msg << endl;
try
{
size_t len = msg.len(); // т.к. swapHead() поменяет
msg.swapHead();
sendData(msg.buf(), len);
msg.swapHead();
}
catch( mbException& ex )
{
if( dlog->is_crit() )
dlog->crit() << "(send): " << ex << endl;
msg.swapHead();
return ex.err;
}
catch( const uniset::Exception& ex ) // SystemError
{
if( dlog->is_crit() )
dlog->crit() << "(send): " << ex << endl;
msg.swapHead();
return erHardwareError;
}
// Пауза, чтобы не ловить свою посылку
if( aftersend_msec > 0 )
msleep(aftersend_msec);
return erNoError;
}
// -------------------------------------------------------------------------
void ModbusClient::initLog( std::shared_ptr<uniset::Configuration> conf,
const std::string& lname, const string& logfile )
{
conf->initLogStream(dlog, lname);
if( !logfile.empty() )
dlog->logFile( logfile );
}
// -------------------------------------------------------------------------
void ModbusClient::setLog( std::shared_ptr<DebugStream> l )
{
this->dlog = l;
}
// -------------------------------------------------------------------------
void ModbusClient::printProcessingTime()
{
if( dlog->is_info() )
{
dlog->info() << "(processingTime): "
<< tmProcessing.getCurrent() << " [мсек]" << endl;
}
}
// -------------------------------------------------------------------------
else
{
// А как мы сюда добрались?!!!!!!
cleanupChannel();
return erUnExpectedPacketType;
}
}
catch( mbException& ex )
{
if( dlog->is_crit() )
dlog->crit() << "(recv): " << ex << endl;
return ex.err;
}
catch( const uniset::TimeOut& ex )
{
// cout << "(recv): catch TimeOut " << endl;
}
catch( const uniset::CommFailed& ex )
{
if( dlog->is_crit() )
dlog->crit() << "(recv): " << ex << endl;
return erTimeOut;
}
catch( const uniset::Exception& ex ) // SystemError
{
if( dlog->is_crit() )
dlog->crit() << "(recv): " << ex << endl;
return erHardwareError;
}
return erTimeOut;
}
// -------------------------------------------------------------------------
mbErrCode ModbusClient::send( ModbusMessage& msg )
{
if( msg.len() > msg.maxSizeOfMessage() )
{
if( dlog->is_warn() )
dlog->warn() << "(ModbusClient::send): message len=" << msg.len()
<< " > MAXLEN=" << msg.maxSizeOfMessage() << endl;
return erPacketTooLong;
}
if( dlog->is_info() )
dlog->info() << "(ModbusClient::send): [" << msg.len() << " bytes]: " << msg << endl;
try
{
size_t len = msg.len(); // т.к. swapHead() поменяет
msg.swapHead();
sendData(msg.buf(), len);
msg.swapHead();
}
catch( mbException& ex )
{
if( dlog->is_crit() )
dlog->crit() << "(send): " << ex << endl;
msg.swapHead();
return ex.err;
}
catch( const uniset::Exception& ex ) // SystemError
{
if( dlog->is_crit() )
dlog->crit() << "(send): " << ex << endl;
msg.swapHead();
return erHardwareError;
}
// Пауза, чтобы не ловить свою посылку
if( aftersend_msec > 0 )
msleep(aftersend_msec);
return erNoError;
}
// -------------------------------------------------------------------------
void ModbusClient::initLog( std::shared_ptr<uniset::Configuration> conf,
const std::string& lname, const string& logfile )
{
conf->initLogStream(dlog, lname);
if( !logfile.empty() )
dlog->logFile( logfile );
}
// -------------------------------------------------------------------------
void ModbusClient::setLog( std::shared_ptr<DebugStream> l )
{
this->dlog = l;
}
// -------------------------------------------------------------------------
void ModbusClient::printProcessingTime()
{
if( dlog->is_info() )
{
dlog->info() << "(processingTime): "
<< tmProcessing.getCurrent() << " [мсек]" << endl;
}
}
// -------------------------------------------------------------------------
} // end of namespace uniset
......@@ -21,146 +21,146 @@
// -------------------------------------------------------------------------
namespace uniset
{
// -------------------------------------------------------------------------
using namespace std;
using namespace ModbusRTU;
using namespace uniset;
// -------------------------------------------------------------------------
static ComPort::Speed checkSpeed[] =
{
ComPort::ComSpeed9600,
ComPort::ComSpeed19200,
ComPort::ComSpeed38400,
ComPort::ComSpeed57600,
ComPort::ComSpeed4800,
ComPort::ComSpeed115200,
ComPort::ComSpeed0
};
// -------------------------------------------------------------------------
ModbusAddr ModbusHelpers::autodetectSlave( ModbusClient* m,
ModbusAddr beg, ModbusAddr end,
ModbusData reg,
SlaveFunctionCode fn )
{
if( beg > end )
{
ModbusAddr tmp = beg;
beg = end;
end = tmp;
}
// -------------------------------------------------------------------------
using namespace std;
using namespace ModbusRTU;
using namespace uniset;
// -------------------------------------------------------------------------
static ComPort::Speed checkSpeed[] =
{
ComPort::ComSpeed9600,
ComPort::ComSpeed19200,
ComPort::ComSpeed38400,
ComPort::ComSpeed57600,
ComPort::ComSpeed4800,
ComPort::ComSpeed115200,
ComPort::ComSpeed0
};
// -------------------------------------------------------------------------
ModbusAddr ModbusHelpers::autodetectSlave( ModbusClient* m,
ModbusAddr beg, ModbusAddr end,
ModbusData reg,
SlaveFunctionCode fn )
{
if( beg > end )
{
ModbusAddr tmp = beg;
beg = end;
end = tmp;
}
for( ModbusAddr a = beg; a <= end; a++ )
{
try
{
if( fn == fnReadInputRegisters )
{
m->read04(a, reg, 1);
}
else if( fn == fnReadInputStatus )
{
m->read02(a, reg, 1);
}
else if( fn == fnReadCoilStatus )
{
m->read01(a, reg, 1);
}
else if( fn == fnReadOutputRegisters )
{
m->read03(a, reg, 1);
}
else
throw mbException(erOperationFailed);
for( ModbusAddr a = beg; a <= end; a++ )
{
try
{
if( fn == fnReadInputRegisters )
{
m->read04(a, reg, 1);
}
else if( fn == fnReadInputStatus )
{
m->read02(a, reg, 1);
}
else if( fn == fnReadCoilStatus )
{
m->read01(a, reg, 1);
}
else if( fn == fnReadOutputRegisters )
{
m->read03(a, reg, 1);
}
else
throw mbException(erOperationFailed);
return a;
}
catch( ModbusRTU::mbException& ex )
{
if( ex.err < erInternalErrorCode )
return a; // узел ответил ошибкой (но связь то есть)
}
catch(...) {}
return a;
}
catch( ModbusRTU::mbException& ex )
{
if( ex.err < erInternalErrorCode )
return a; // узел ответил ошибкой (но связь то есть)
}
catch(...) {}
if( (beg == 0xff) || (end == 0xff) )
break;
}
if( (beg == 0xff) || (end == 0xff) )
break;
}
throw TimeOut();
}
// -------------------------------------------------------------------------
throw TimeOut();
}
// -------------------------------------------------------------------------
ModbusAddr ModbusHelpers::autodetectSlave( std::string dev, ComPort::Speed s, int tout,
ModbusAddr beg, ModbusAddr end,
ModbusData reg,
SlaveFunctionCode fn )
{
ModbusRTUMaster mb(dev);
mb.setSpeed(s);
mb.setTimeout(tout);
return autodetectSlave( &mb, beg, end, reg, fn );
}
// -------------------------------------------------------------------------
ModbusAddr ModbusHelpers::autodetectSlave( std::string dev, ComPort::Speed s, int tout,
ModbusAddr beg, ModbusAddr end,
ModbusData reg,
SlaveFunctionCode fn )
{
ModbusRTUMaster mb(dev);
mb.setSpeed(s);
mb.setTimeout(tout);
return autodetectSlave( &mb, beg, end, reg, fn );
}
// -------------------------------------------------------------------------
ComPort::Speed ModbusHelpers::autodetectSpeed( ModbusRTUMaster* m, ModbusAddr slave,
ModbusData reg, SlaveFunctionCode fn )
{
ComPort::Speed cur = m->getSpeed();
ComPort::Speed s = ComPort::ComSpeed0;
ComPort::Speed ModbusHelpers::autodetectSpeed( ModbusRTUMaster* m, ModbusAddr slave,
ModbusData reg, SlaveFunctionCode fn )
{
ComPort::Speed cur = m->getSpeed();
ComPort::Speed s = ComPort::ComSpeed0;
for( unsigned int i = 0; checkSpeed[i] != ComPort::ComSpeed0; i++ )
{
try
{
m->setSpeed( checkSpeed[i] );
for( unsigned int i = 0; checkSpeed[i] != ComPort::ComSpeed0; i++ )
{
try
{
m->setSpeed( checkSpeed[i] );
if( fn == fnReadInputRegisters )
{
m->read04(slave, reg, 1);
}
else if( fn == fnReadInputStatus )
{
m->read02(slave, reg, 1);
}
else if( fn == fnReadCoilStatus )
{
m->read01(slave, reg, 1);
}
else if( fn == fnReadOutputRegisters )
{
m->read03(slave, reg, 1);
}
else
throw mbException(erOperationFailed);
if( fn == fnReadInputRegisters )
{
m->read04(slave, reg, 1);
}
else if( fn == fnReadInputStatus )
{
m->read02(slave, reg, 1);
}
else if( fn == fnReadCoilStatus )
{
m->read01(slave, reg, 1);
}
else if( fn == fnReadOutputRegisters )
{
m->read03(slave, reg, 1);
}
else
throw mbException(erOperationFailed);
s = checkSpeed[i];
break;
}
catch( ModbusRTU::mbException& ex )
{
if( ex.err < erInternalErrorCode )
{
s = checkSpeed[i];
break; // узел ответил ошибкой (но связь то есть)
}
}
catch(...) {}
}
s = checkSpeed[i];
break;
}
catch( ModbusRTU::mbException& ex )
{
if( ex.err < erInternalErrorCode )
{
s = checkSpeed[i];
break; // узел ответил ошибкой (но связь то есть)
}
}
catch(...) {}
}
m->setSpeed(cur);
m->setSpeed(cur);
if( s != ComPort::ComSpeed0 )
return s;
if( s != ComPort::ComSpeed0 )
return s;
throw TimeOut();
}
// -------------------------------------------------------------------------
ComPort::Speed ModbusHelpers::autodetectSpeed( std::string dev, ModbusRTU::ModbusAddr slave, int tout,
ModbusData reg, SlaveFunctionCode fn )
{
ModbusRTUMaster mb(dev);
mb.setTimeout(tout);
return autodetectSpeed( &mb, slave, reg, fn );
}
// -------------------------------------------------------------------------
throw TimeOut();
}
// -------------------------------------------------------------------------
ComPort::Speed ModbusHelpers::autodetectSpeed( std::string dev, ModbusRTU::ModbusAddr slave, int tout,
ModbusData reg, SlaveFunctionCode fn )
{
ModbusRTUMaster mb(dev);
mb.setTimeout(tout);
return autodetectSpeed( &mb, slave, reg, fn );
}
// -------------------------------------------------------------------------
} // end of namespace uniset
......@@ -24,113 +24,113 @@
// -------------------------------------------------------------------------
namespace uniset
{
// -------------------------------------------------------------------------
using namespace std;
using namespace ModbusRTU;
using namespace uniset;
// -------------------------------------------------------------------------
using namespace std;
using namespace ModbusRTU;
using namespace uniset;
// -------------------------------------------------------------------------
ModbusRTUMaster::ModbusRTUMaster( const string& dev, bool use485, bool tr_ctl ):
port(NULL),
myport(true)
{
if( use485 )
{
// -------------------------------------------------------------------------
ModbusRTUMaster::ModbusRTUMaster( const string& dev, bool use485, bool tr_ctl ):
port(NULL),
myport(true)
{
if( use485 )
{
#ifndef DISABLE_COMPORT_485F
ComPort485F* cp;
ComPort485F* cp;
if( dev == "/dev/ttyS2" )
cp = new ComPort485F(dev, 5, tr_ctl);
else if( dev == "/dev/ttyS3" )
cp = new ComPort485F(dev, 6, tr_ctl);
else
throw Exception("Open ComPort FAILED! dev must be /dev/ttyS2 or /dev/tytS3");
if( dev == "/dev/ttyS2" )
cp = new ComPort485F(dev, 5, tr_ctl);
else if( dev == "/dev/ttyS3" )
cp = new ComPort485F(dev, 6, tr_ctl);
else
throw Exception("Open ComPort FAILED! dev must be /dev/ttyS2 or /dev/tytS3");
port = cp;
port = cp;
#else
throw Exception("Open ComPort485F FAILED! DISABLE_COMPORT_485F");
throw Exception("Open ComPort485F FAILED! DISABLE_COMPORT_485F");
#endif // #ifndef DISABLE_COMPORT_485F
}
else
port = new ComPort(dev);
}
else
port = new ComPort(dev);
port->setSpeed(ComPort::ComSpeed38400);
port->setParity(ComPort::NoParity);
port->setCharacterSize(ComPort::CSize8);
port->setStopBits(ComPort::OneBit);
port->setWaiting(true);
port->setTimeout(replyTimeOut_ms);
// port->setBlocking(false);
}
// -------------------------------------------------------------------------
ModbusRTUMaster::ModbusRTUMaster( ComPort* com ):
port(com),
myport(false)
{
if( !port )
throw Exception("comport=NULL!!");
port->setSpeed(ComPort::ComSpeed38400);
port->setParity(ComPort::NoParity);
port->setCharacterSize(ComPort::CSize8);
port->setStopBits(ComPort::OneBit);
port->setWaiting(true);
port->setTimeout(replyTimeOut_ms);
// port->setBlocking(false);
}
// -------------------------------------------------------------------------
ModbusRTUMaster::ModbusRTUMaster( ComPort* com ):
port(com),
myport(false)
{
if( !port )
throw Exception("comport=NULL!!");
port->setSpeed(ComPort::ComSpeed38400);
port->setParity(ComPort::NoParity);
port->setCharacterSize(ComPort::CSize8);
port->setStopBits(ComPort::OneBit);
port->setWaiting(true);
port->setTimeout(replyTimeOut_ms);
// port->setBlocking(false);
}
// -------------------------------------------------------------------------
ModbusRTUMaster::~ModbusRTUMaster()
{
if( myport )
delete port;
}
// -------------------------------------------------------------------------
void ModbusRTUMaster::cleanupChannel()
{
if( port )
port->cleanupChannel();
}
// -------------------------------------------------------------------------
void ModbusRTUMaster::setSpeed( ComPort::Speed s )
{
if( port != NULL )
port->setSpeed(s);
}
// --------------------------------------------------------------------------------
void ModbusRTUMaster::setSpeed( const std::string& s )
{
if( port != NULL )
port->setSpeed(s);
}
// --------------------------------------------------------------------------------
ComPort::Speed ModbusRTUMaster::getSpeed()
{
if( port == NULL )
return ComPort::ComSpeed0;
port->setSpeed(ComPort::ComSpeed38400);
port->setParity(ComPort::NoParity);
port->setCharacterSize(ComPort::CSize8);
port->setStopBits(ComPort::OneBit);
port->setWaiting(true);
port->setTimeout(replyTimeOut_ms);
// port->setBlocking(false);
}
// -------------------------------------------------------------------------
ModbusRTUMaster::~ModbusRTUMaster()
{
if( myport )
delete port;
}
// -------------------------------------------------------------------------
void ModbusRTUMaster::cleanupChannel()
{
if( port )
port->cleanupChannel();
}
// -------------------------------------------------------------------------
void ModbusRTUMaster::setSpeed( ComPort::Speed s )
{
if( port != NULL )
port->setSpeed(s);
}
// --------------------------------------------------------------------------------
void ModbusRTUMaster::setSpeed( const std::string& s )
{
if( port != NULL )
port->setSpeed(s);
}
// --------------------------------------------------------------------------------
ComPort::Speed ModbusRTUMaster::getSpeed()
{
if( port == NULL )
return ComPort::ComSpeed0;
return port->getSpeed();
}
// -------------------------------------------------------------------------
ComPort::Parity ModbusRTUMaster::getParity()
{
if( port != NULL)
port->getParity();
return port->getSpeed();
}
// -------------------------------------------------------------------------
ComPort::Parity ModbusRTUMaster::getParity()
{
if( port != NULL)
port->getParity();
return ComPort::NoParity;
}
return ComPort::NoParity;
}
// -------------------------------------------------------------------------
void ModbusRTUMaster::setParity( ComPort::Parity parity )
{
if( port != NULL)
port->setParity(parity);
}
// -------------------------------------------------------------------------
void ModbusRTUMaster::setCharacterSize( ComPort::CharacterSize csize )
{
if( port != NULL)
port->setCharacterSize(csize);
}
// -------------------------------------------------------------------------
void ModbusRTUMaster::setParity( ComPort::Parity parity )
{
if( port != NULL)
port->setParity(parity);
}
// -------------------------------------------------------------------------
void ModbusRTUMaster::setCharacterSize( ComPort::CharacterSize csize )
{
if( port != NULL)
port->setCharacterSize(csize);
}
// -------------------------------------------------------------------------
ComPort::CharacterSize ModbusRTUMaster::getCharacterSize()
{
if( port != NULL)
......@@ -147,56 +147,56 @@ namespace uniset
return ComPort::OneBit;
}
// -------------------------------------------------------------------------
void ModbusRTUMaster::setStopBits( ComPort::StopBits sBit )
{
if( port != NULL)
port->setStopBits(sBit);
}
// -------------------------------------------------------------------------
timeout_t ModbusRTUMaster::getTimeout() const
{
if( port == NULL )
return 0;
void ModbusRTUMaster::setStopBits( ComPort::StopBits sBit )
{
if( port != NULL)
port->setStopBits(sBit);
}
// -------------------------------------------------------------------------
timeout_t ModbusRTUMaster::getTimeout() const
{
if( port == NULL )
return 0;
return port->getTimeout();
}
// -------------------------------------------------------------------------
size_t ModbusRTUMaster::getNextData( unsigned char* buf, size_t len )
{
// if( !port ) return 0;
return port->receiveBlock(buf, len);
}
// --------------------------------------------------------------------------------
void ModbusRTUMaster::setChannelTimeout( timeout_t msec )
{
if( port )
port->setTimeout(msec);
}
// --------------------------------------------------------------------------------
mbErrCode ModbusRTUMaster::sendData(unsigned char* buf, size_t len )
{
try
{
port->sendBlock(buf, len);
}
catch( const uniset::Exception& ex ) // SystemError
{
dlog->crit() << "(send): " << ex << endl;
return erHardwareError;
}
return port->getTimeout();
}
// -------------------------------------------------------------------------
size_t ModbusRTUMaster::getNextData( unsigned char* buf, size_t len )
{
// if( !port ) return 0;
return port->receiveBlock(buf, len);
}
// --------------------------------------------------------------------------------
void ModbusRTUMaster::setChannelTimeout( timeout_t msec )
{
if( port )
port->setTimeout(msec);
}
// --------------------------------------------------------------------------------
mbErrCode ModbusRTUMaster::sendData(unsigned char* buf, size_t len )
{
try
{
port->sendBlock(buf, len);
}
catch( const uniset::Exception& ex ) // SystemError
{
dlog->crit() << "(send): " << ex << endl;
return erHardwareError;
}
return erNoError;
}
// -------------------------------------------------------------------------
mbErrCode ModbusRTUMaster::query( ModbusAddr addr, ModbusMessage& msg,
ModbusMessage& reply, timeout_t timeout )
{
mbErrCode res = send(msg);
return erNoError;
}
// -------------------------------------------------------------------------
mbErrCode ModbusRTUMaster::query( ModbusAddr addr, ModbusMessage& msg,
ModbusMessage& reply, timeout_t timeout )
{
mbErrCode res = send(msg);
if( res != erNoError )
return res;
if( res != erNoError )
return res;
return recv(addr, msg.pduhead.func, reply, timeout);
}
// --------------------------------------------------------------------------------
return recv(addr, msg.pduhead.func, reply, timeout);
}
// --------------------------------------------------------------------------------
} // end of namespace uniset
......@@ -25,199 +25,199 @@
// -------------------------------------------------------------------------
namespace uniset
{
// -------------------------------------------------------------------------
using namespace std;
using namespace ModbusRTU;
using namespace uniset;
// -------------------------------------------------------------------------
ModbusRTUSlave::ModbusRTUSlave( const string& dev, bool use485, bool tr_ctl ):
port(NULL),
myport(true)
{
if( use485 )
{
// -------------------------------------------------------------------------
using namespace std;
using namespace ModbusRTU;
using namespace uniset;
// -------------------------------------------------------------------------
ModbusRTUSlave::ModbusRTUSlave( const string& dev, bool use485, bool tr_ctl ):
port(NULL),
myport(true)
{
if( use485 )
{
#ifndef DISABLE_COMPORT_485F
ComPort485F* cp;
ComPort485F* cp;
if( dev == "/dev/ttyS2" )
cp = new ComPort485F(dev, 5, tr_ctl);
else if( dev == "/dev/ttyS3" )
cp = new ComPort485F(dev, 6, tr_ctl);
else
throw Exception("Open ComPort FAILED! dev must be /dev/ttyS2 or /dev/tytS3");
if( dev == "/dev/ttyS2" )
cp = new ComPort485F(dev, 5, tr_ctl);
else if( dev == "/dev/ttyS3" )
cp = new ComPort485F(dev, 6, tr_ctl);
else
throw Exception("Open ComPort FAILED! dev must be /dev/ttyS2 or /dev/tytS3");
port = cp;
port = cp;
#else
throw Exception("Open ComPort485F FAILED! DISABLE_COMPORT_485F");
throw Exception("Open ComPort485F FAILED! DISABLE_COMPORT_485F");
#endif // #ifndef DISABLE_COMPORT_485F
}
else
port = new ComPort(dev);
port->setSpeed(ComPort::ComSpeed38400);
port->setParity(ComPort::NoParity);
port->setCharacterSize(ComPort::CSize8);
port->setStopBits(ComPort::OneBit);
port->setWaiting(true);
port->setTimeout(recvTimeOut_ms);
// port->setBlocking(false);
}
// -------------------------------------------------------------------------
ModbusRTUSlave::ModbusRTUSlave( ComPort* com ):
port(com),
myport(false)
{
port->setSpeed(ComPort::ComSpeed38400);
port->setParity(ComPort::NoParity);
port->setCharacterSize(ComPort::CSize8);
port->setStopBits(ComPort::OneBit);
port->setWaiting(true);
port->setTimeout(recvTimeOut_ms);
// port->setBlocking(false);
}
// -------------------------------------------------------------------------
ModbusRTUSlave::~ModbusRTUSlave()
{
if( myport )
delete port;
}
// -------------------------------------------------------------------------
// --------------------------------------------------------------------------------
ComPort::Speed ModbusRTUSlave::getSpeed()
{
if( port == NULL )
return ComPort::ComSpeed0;
return port->getSpeed();
}
}
else
port = new ComPort(dev);
port->setSpeed(ComPort::ComSpeed38400);
port->setParity(ComPort::NoParity);
port->setCharacterSize(ComPort::CSize8);
port->setStopBits(ComPort::OneBit);
port->setWaiting(true);
port->setTimeout(recvTimeOut_ms);
// port->setBlocking(false);
}
// -------------------------------------------------------------------------
ModbusRTUSlave::ModbusRTUSlave( ComPort* com ):
port(com),
myport(false)
{
port->setSpeed(ComPort::ComSpeed38400);
port->setParity(ComPort::NoParity);
port->setCharacterSize(ComPort::CSize8);
port->setStopBits(ComPort::OneBit);
port->setWaiting(true);
port->setTimeout(recvTimeOut_ms);
// port->setBlocking(false);
}
// -------------------------------------------------------------------------
ModbusRTUSlave::~ModbusRTUSlave()
{
if( myport )
delete port;
}
// -------------------------------------------------------------------------
// --------------------------------------------------------------------------------
ComPort::Speed ModbusRTUSlave::getSpeed()
{
if( port == NULL )
return ComPort::ComSpeed0;
return port->getSpeed();
}
// -------------------------------------------------------------------------
void ModbusRTUSlave::setCharSize( ComPort::CharacterSize s )
{
if( port != NULL )
port->setCharacterSize(s);
}
// -------------------------------------------------------------------------
// -------------------------------------------------------------------------
void ModbusRTUSlave::setStopBits( ComPort::StopBits b )
{
if( port != NULL )
port->setStopBits(b);
}
// -------------------------------------------------------------------------
void ModbusRTUSlave::setParity( ComPort::Parity p )
{
if( port != NULL )
port->setParity(p);
}
// -------------------------------------------------------------------------
void ModbusRTUSlave::setParity( const std::string& p )
{
setParity(ComPort::getParity(p));
}
void ModbusRTUSlave::setParity( ComPort::Parity p )
{
if( port != NULL )
port->setParity(p);
}
// -------------------------------------------------------------------------
void ModbusRTUSlave::setParity( const std::string& p )
{
setParity(ComPort::getParity(p));
}
// -------------------------------------------------------------------------
void ModbusRTUSlave::setSpeed( ComPort::Speed s )
{
if( port != NULL )
port->setSpeed(s);
}
// --------------------------------------------------------------------------------
void ModbusRTUSlave::setSpeed( const std::string& s )
{
if( port != NULL )
port->setSpeed(s);
}
// --------------------------------------------------------------------------------
size_t ModbusRTUSlave::getNextData( unsigned char* buf, int len )
{
// if( !port ) return 0;
return port->receiveBlock(buf, len);
}
// --------------------------------------------------------------------------------
void ModbusRTUSlave::setChannelTimeout( timeout_t msec )
{
if( msec == UniSetTimer::WaitUpTime )
port->setTimeout(15 * 60 * 1000); // используем просто большое время (15 минут)
else
port->setTimeout(msec);
}
// --------------------------------------------------------------------------------
mbErrCode ModbusRTUSlave::sendData( unsigned char* buf, int len )
{
try
{
port->sendBlock(buf, len);
}
catch( const uniset::Exception& ex ) // SystemError
{
if( dlog->is_crit() )
dlog->crit() << "(send): " << ex << endl;
return erHardwareError;
}
return erNoError;
}
// -------------------------------------------------------------------------
void ModbusRTUSlave::terminate()
{
try
{
}
catch(...) {}
}
// -------------------------------------------------------------------------
bool ModbusRTUSlave::isActive() const
{
return false;
}
// -------------------------------------------------------------------------
mbErrCode ModbusRTUSlave::realReceive(const std::unordered_set<ModbusAddr>& vmbaddr, timeout_t timeout )
{
if( !recvMutex.try_lock_for( std::chrono::milliseconds(timeout)) )
{
if( dlog->is_crit() )
dlog->crit() << "(ModbusRTUSlave::receive): Don`t lock recvMutex.." << endl;
return erTimeOut;
}
std::lock_guard<std::timed_mutex> lk(recvMutex, std::adopt_lock);
ModbusMessage buf;
mbErrCode res = erBadReplyNodeAddress;
do
{
res = recv(vmbaddr, buf, timeout);
if( res != erNoError && res != erBadReplyNodeAddress )
{
// Если ошибка подразумевает посылку ответа с сообщением об ошибке
// то посылаем
if( res < erInternalErrorCode )
{
ErrorRetMessage em( buf.addr(), buf.func(), res );
buf = em.transport_msg();
send(buf);
printProcessingTime();
}
if( aftersend_msec > 0 )
msleep(aftersend_msec);
return res;
}
// если полученный пакет адресован
// не данному узлу (и не широковещательный)
// то ждать следующий...
}
while( res == erBadReplyNodeAddress );
return processing(buf);
}
// -------------------------------------------------------------------------
void ModbusRTUSlave::setSpeed( ComPort::Speed s )
{
if( port != NULL )
port->setSpeed(s);
}
// --------------------------------------------------------------------------------
void ModbusRTUSlave::setSpeed( const std::string& s )
{
if( port != NULL )
port->setSpeed(s);
}
// --------------------------------------------------------------------------------
size_t ModbusRTUSlave::getNextData( unsigned char* buf, int len )
{
// if( !port ) return 0;
return port->receiveBlock(buf, len);
}
// --------------------------------------------------------------------------------
void ModbusRTUSlave::setChannelTimeout( timeout_t msec )
{
if( msec == UniSetTimer::WaitUpTime )
port->setTimeout(15 * 60 * 1000); // используем просто большое время (15 минут)
else
port->setTimeout(msec);
}
// --------------------------------------------------------------------------------
mbErrCode ModbusRTUSlave::sendData( unsigned char* buf, int len )
{
try
{
port->sendBlock(buf, len);
}
catch( const uniset::Exception& ex ) // SystemError
{
if( dlog->is_crit() )
dlog->crit() << "(send): " << ex << endl;
return erHardwareError;
}
return erNoError;
}
// -------------------------------------------------------------------------
void ModbusRTUSlave::terminate()
{
try
{
}
catch(...) {}
}
// -------------------------------------------------------------------------
bool ModbusRTUSlave::isActive() const
{
return false;
}
// -------------------------------------------------------------------------
mbErrCode ModbusRTUSlave::realReceive(const std::unordered_set<ModbusAddr>& vmbaddr, timeout_t timeout )
{
if( !recvMutex.try_lock_for( std::chrono::milliseconds(timeout)) )
{
if( dlog->is_crit() )
dlog->crit() << "(ModbusRTUSlave::receive): Don`t lock recvMutex.." << endl;
return erTimeOut;
}
std::lock_guard<std::timed_mutex> lk(recvMutex, std::adopt_lock);
ModbusMessage buf;
mbErrCode res = erBadReplyNodeAddress;
do
{
res = recv(vmbaddr, buf, timeout);
if( res != erNoError && res != erBadReplyNodeAddress )
{
// Если ошибка подразумевает посылку ответа с сообщением об ошибке
// то посылаем
if( res < erInternalErrorCode )
{
ErrorRetMessage em( buf.addr(), buf.func(), res );
buf = em.transport_msg();
send(buf);
printProcessingTime();
}
if( aftersend_msec > 0 )
msleep(aftersend_msec);
return res;
}
// если полученный пакет адресован
// не данному узлу (и не широковещательный)
// то ждать следующий...
}
while( res == erBadReplyNodeAddress );
return processing(buf);
}
// -------------------------------------------------------------------------
} // end of namespace uniset
......@@ -18,174 +18,174 @@
// -------------------------------------------------------------------------
namespace uniset
{
// -------------------------------------------------------------------------
using namespace ModbusRTU;
using namespace std;
// -------------------------------------------------------------------------
ModbusRTUSlaveSlot::ModbusRTUSlaveSlot( const std::string& dev, bool use485, bool tr_ctl ):
ModbusRTUSlave(dev, use485, tr_ctl)
{
}
// -------------------------------------------------------------------------
ModbusRTUSlaveSlot::ModbusRTUSlaveSlot( ComPort* c ):
ModbusRTUSlave(c)
{
}
// -------------------------------------------------------------------------
ModbusRTUSlaveSlot::~ModbusRTUSlaveSlot()
{
}
// -------------------------------------------------------------------------
mbErrCode ModbusRTUSlaveSlot::readCoilStatus( ReadCoilMessage& query,
ReadCoilRetMessage& reply )
{
if( !slReadCoil )
return erOperationFailed;
return slReadCoil(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusRTUSlaveSlot::readInputStatus( ReadInputStatusMessage& query,
ReadInputStatusRetMessage& reply )
{
if( !slReadInputStatus )
return erOperationFailed;
return slReadInputStatus(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusRTUSlaveSlot::readOutputRegisters( ReadOutputMessage& query,
ReadOutputRetMessage& reply )
{
if( !slReadOutputs )
return erOperationFailed;
return slReadOutputs(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusRTUSlaveSlot::readInputRegisters( ReadInputMessage& query,
ReadInputRetMessage& reply )
{
if( !slReadInputs )
return erOperationFailed;
return slReadInputs(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusRTUSlaveSlot::forceMultipleCoils( ForceCoilsMessage& query,
ForceCoilsRetMessage& reply )
{
if( !slForceCoils )
return erOperationFailed;
return slForceCoils(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusRTUSlaveSlot::writeOutputRegisters( WriteOutputMessage& query,
WriteOutputRetMessage& reply )
{
if( !slWriteOutputs )
return erOperationFailed;
return slWriteOutputs(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusRTUSlaveSlot::diagnostics( DiagnosticMessage& query,
DiagnosticRetMessage& reply )
{
if( !slDiagnostics )
return erOperationFailed;
return slDiagnostics(query, reply);
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode ModbusRTUSlaveSlot::read4314( ModbusRTU::MEIMessageRDI& query,
ModbusRTU::MEIMessageRetRDI& reply )
{
if( !slMEIRDI )
return erOperationFailed;
return slMEIRDI(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusRTUSlaveSlot::forceSingleCoil( ForceSingleCoilMessage& query,
ForceSingleCoilRetMessage& reply )
{
if( !slForceSingleCoil )
return erOperationFailed;
return slForceSingleCoil(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusRTUSlaveSlot::writeOutputSingleRegister( WriteSingleOutputMessage& query,
WriteSingleOutputRetMessage& reply )
{
if( !slWriteSingleOutputs )
return erOperationFailed;
return slWriteSingleOutputs(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusRTUSlaveSlot::journalCommand( JournalCommandMessage& query,
JournalCommandRetMessage& reply )
{
if( !slJournalCommand )
return erOperationFailed;
return slJournalCommand(query, reply);
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode ModbusRTUSlaveSlot::setDateTime( ModbusRTU::SetDateTimeMessage& query,
ModbusRTU::SetDateTimeRetMessage& reply )
{
if( !slSetDateTime )
return erOperationFailed;
return slSetDateTime(query, reply);
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode ModbusRTUSlaveSlot::remoteService( ModbusRTU::RemoteServiceMessage& query,
ModbusRTU::RemoteServiceRetMessage& reply )
{
if( !slRemoteService )
return erOperationFailed;
return slRemoteService(query, reply);
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode ModbusRTUSlaveSlot::fileTransfer( ModbusRTU::FileTransferMessage& query,
ModbusRTU::FileTransferRetMessage& reply )
{
if( !slFileTransfer )
return erOperationFailed;
return slFileTransfer(query, reply);
}
// -------------------------------------------------------------------------
void ModbusRTUSlaveSlot::terminate()
{
try
{
ModbusRTUSlave::terminate();
}
catch(...) {}
}
// -------------------------------------------------------------------------
ComPort* ModbusRTUSlaveSlot::getComPort()
{
return port;
}
// -------------------------------------------------------------------------
// -------------------------------------------------------------------------
using namespace ModbusRTU;
using namespace std;
// -------------------------------------------------------------------------
ModbusRTUSlaveSlot::ModbusRTUSlaveSlot( const std::string& dev, bool use485, bool tr_ctl ):
ModbusRTUSlave(dev, use485, tr_ctl)
{
}
// -------------------------------------------------------------------------
ModbusRTUSlaveSlot::ModbusRTUSlaveSlot( ComPort* c ):
ModbusRTUSlave(c)
{
}
// -------------------------------------------------------------------------
ModbusRTUSlaveSlot::~ModbusRTUSlaveSlot()
{
}
// -------------------------------------------------------------------------
mbErrCode ModbusRTUSlaveSlot::readCoilStatus( ReadCoilMessage& query,
ReadCoilRetMessage& reply )
{
if( !slReadCoil )
return erOperationFailed;
return slReadCoil(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusRTUSlaveSlot::readInputStatus( ReadInputStatusMessage& query,
ReadInputStatusRetMessage& reply )
{
if( !slReadInputStatus )
return erOperationFailed;
return slReadInputStatus(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusRTUSlaveSlot::readOutputRegisters( ReadOutputMessage& query,
ReadOutputRetMessage& reply )
{
if( !slReadOutputs )
return erOperationFailed;
return slReadOutputs(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusRTUSlaveSlot::readInputRegisters( ReadInputMessage& query,
ReadInputRetMessage& reply )
{
if( !slReadInputs )
return erOperationFailed;
return slReadInputs(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusRTUSlaveSlot::forceMultipleCoils( ForceCoilsMessage& query,
ForceCoilsRetMessage& reply )
{
if( !slForceCoils )
return erOperationFailed;
return slForceCoils(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusRTUSlaveSlot::writeOutputRegisters( WriteOutputMessage& query,
WriteOutputRetMessage& reply )
{
if( !slWriteOutputs )
return erOperationFailed;
return slWriteOutputs(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusRTUSlaveSlot::diagnostics( DiagnosticMessage& query,
DiagnosticRetMessage& reply )
{
if( !slDiagnostics )
return erOperationFailed;
return slDiagnostics(query, reply);
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode ModbusRTUSlaveSlot::read4314( ModbusRTU::MEIMessageRDI& query,
ModbusRTU::MEIMessageRetRDI& reply )
{
if( !slMEIRDI )
return erOperationFailed;
return slMEIRDI(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusRTUSlaveSlot::forceSingleCoil( ForceSingleCoilMessage& query,
ForceSingleCoilRetMessage& reply )
{
if( !slForceSingleCoil )
return erOperationFailed;
return slForceSingleCoil(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusRTUSlaveSlot::writeOutputSingleRegister( WriteSingleOutputMessage& query,
WriteSingleOutputRetMessage& reply )
{
if( !slWriteSingleOutputs )
return erOperationFailed;
return slWriteSingleOutputs(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusRTUSlaveSlot::journalCommand( JournalCommandMessage& query,
JournalCommandRetMessage& reply )
{
if( !slJournalCommand )
return erOperationFailed;
return slJournalCommand(query, reply);
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode ModbusRTUSlaveSlot::setDateTime( ModbusRTU::SetDateTimeMessage& query,
ModbusRTU::SetDateTimeRetMessage& reply )
{
if( !slSetDateTime )
return erOperationFailed;
return slSetDateTime(query, reply);
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode ModbusRTUSlaveSlot::remoteService( ModbusRTU::RemoteServiceMessage& query,
ModbusRTU::RemoteServiceRetMessage& reply )
{
if( !slRemoteService )
return erOperationFailed;
return slRemoteService(query, reply);
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode ModbusRTUSlaveSlot::fileTransfer( ModbusRTU::FileTransferMessage& query,
ModbusRTU::FileTransferRetMessage& reply )
{
if( !slFileTransfer )
return erOperationFailed;
return slFileTransfer(query, reply);
}
// -------------------------------------------------------------------------
void ModbusRTUSlaveSlot::terminate()
{
try
{
ModbusRTUSlave::terminate();
}
catch(...) {}
}
// -------------------------------------------------------------------------
ComPort* ModbusRTUSlaveSlot::getComPort()
{
return port;
}
// -------------------------------------------------------------------------
} // end of namespace uniset
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -18,92 +18,92 @@
// -------------------------------------------------------------------------
namespace uniset
{
// -------------------------------------------------------------------------
using namespace ModbusRTU;
using namespace std;
// -------------------------------------------------------------------------
ModbusServerSlot::ModbusServerSlot()
{
}
// -------------------------------------------------------------------------
ModbusServerSlot::~ModbusServerSlot()
{
// -------------------------------------------------------------------------
using namespace ModbusRTU;
using namespace std;
// -------------------------------------------------------------------------
ModbusServerSlot::ModbusServerSlot()
{
}
// -------------------------------------------------------------------------
ModbusServerSlot::~ModbusServerSlot()
{
}
// -------------------------------------------------------------------------
void ModbusServerSlot::connectReadCoil( ReadCoilSlot sl )
{
slReadCoil = sl;
}
// -------------------------------------------------------------------------
void ModbusServerSlot::connectReadInputStatus( ReadInputStatusSlot sl )
{
slReadInputStatus = sl;
}
// -------------------------------------------------------------------------
}
// -------------------------------------------------------------------------
void ModbusServerSlot::connectReadCoil( ReadCoilSlot sl )
{
slReadCoil = sl;
}
// -------------------------------------------------------------------------
void ModbusServerSlot::connectReadInputStatus( ReadInputStatusSlot sl )
{
slReadInputStatus = sl;
}
// -------------------------------------------------------------------------
void ModbusServerSlot::connectReadOutput( ReadOutputSlot sl )
{
slReadOutputs = sl;
}
// -------------------------------------------------------------------------
void ModbusServerSlot::connectReadInput( ReadInputSlot sl )
{
slReadInputs = sl;
}
// -------------------------------------------------------------------------
void ModbusServerSlot::connectForceCoils( ForceCoilsSlot sl )
{
slForceCoils = sl;
}
// -------------------------------------------------------------------------
void ModbusServerSlot::connectWriteOutput( WriteOutputSlot sl )
{
slWriteOutputs = sl;
}
void ModbusServerSlot::connectReadOutput( ReadOutputSlot sl )
{
slReadOutputs = sl;
}
// -------------------------------------------------------------------------
void ModbusServerSlot::connectReadInput( ReadInputSlot sl )
{
slReadInputs = sl;
}
// -------------------------------------------------------------------------
void ModbusServerSlot::connectForceCoils( ForceCoilsSlot sl )
{
slForceCoils = sl;
}
// -------------------------------------------------------------------------
void ModbusServerSlot::connectWriteOutput( WriteOutputSlot sl )
{
slWriteOutputs = sl;
}
// ------------------------------------------------------------------------
void ModbusServerSlot::connectWriteSingleOutput( WriteSingleOutputSlot sl )
{
slWriteSingleOutputs = sl;
}
// ------------------------------------------------------------------------
void ModbusServerSlot::connectWriteSingleOutput( WriteSingleOutputSlot sl )
{
slWriteSingleOutputs = sl;
}
// -------------------------------------------------------------------------
void ModbusServerSlot::connectDiagnostics( DiagnosticsSlot sl )
{
slDiagnostics = sl;
}
// -------------------------------------------------------------------------
void ModbusServerSlot::connectMEIRDI( MEIRDISlot sl )
{
slMEIRDI = sl;
}
// -------------------------------------------------------------------------
void ModbusServerSlot::connectForceSingleCoil( ForceSingleCoilSlot sl )
{
slForceSingleCoil = sl;
}
// -------------------------------------------------------------------------
// -------------------------------------------------------------------------
void ModbusServerSlot::connectDiagnostics( DiagnosticsSlot sl )
{
slDiagnostics = sl;
}
// -------------------------------------------------------------------------
void ModbusServerSlot::connectMEIRDI( MEIRDISlot sl )
{
slMEIRDI = sl;
}
// -------------------------------------------------------------------------
void ModbusServerSlot::connectForceSingleCoil( ForceSingleCoilSlot sl )
{
slForceSingleCoil = sl;
}
// -------------------------------------------------------------------------
void ModbusServerSlot::connectJournalCommand( JournalCommandSlot sl )
{
slJournalCommand = sl;
}
void ModbusServerSlot::connectJournalCommand( JournalCommandSlot sl )
{
slJournalCommand = sl;
}
// -------------------------------------------------------------------------
void ModbusServerSlot::connectSetDateTime( SetDateTimeSlot sl )
{
slSetDateTime = sl;
}
// -------------------------------------------------------------------------
void ModbusServerSlot::connectRemoteService( RemoteServiceSlot sl )
{
slRemoteService = sl;
}
// -------------------------------------------------------------------------
void ModbusServerSlot::connectFileTransfer( FileTransferSlot sl )
{
slFileTransfer = sl;
}
// -------------------------------------------------------------------------
// -------------------------------------------------------------------------
void ModbusServerSlot::connectSetDateTime( SetDateTimeSlot sl )
{
slSetDateTime = sl;
}
// -------------------------------------------------------------------------
void ModbusServerSlot::connectRemoteService( RemoteServiceSlot sl )
{
slRemoteService = sl;
}
// -------------------------------------------------------------------------
void ModbusServerSlot::connectFileTransfer( FileTransferSlot sl )
{
slFileTransfer = sl;
}
// -------------------------------------------------------------------------
} // end of namespace uniset
......@@ -20,257 +20,257 @@
// -------------------------------------------------------------------------
namespace uniset
{
// -------------------------------------------------------------------------
using namespace std;
using namespace ModbusRTU;
// -------------------------------------------------------------------------
// -------------------------------------------------------------------------
using namespace std;
using namespace ModbusRTU;
// -------------------------------------------------------------------------
#define USE_BUFFER_FOR_READ 1
#define DEFAULT_BUFFER_SIZE_FOR_READ 255
// -------------------------------------------------------------------------
size_t ModbusTCPCore::readNextData(UTCPStream* tcp,
std::queue<unsigned char>& qrecv, size_t max )
{
if( !tcp ) // || !tcp->available() )
return 0;
// -------------------------------------------------------------------------
size_t ModbusTCPCore::readNextData(UTCPStream* tcp,
std::queue<unsigned char>& qrecv, size_t max )
{
if( !tcp ) // || !tcp->available() )
return 0;
size_t i = 0;
bool commfail = false;
size_t i = 0;
bool commfail = false;
#ifdef USE_BUFFER_FOR_READ
max = std::max(max, (size_t)DEFAULT_BUFFER_SIZE_FOR_READ);
max = std::max(max, (size_t)DEFAULT_BUFFER_SIZE_FOR_READ);
char* buf = new char[max];
char* buf = new char[max];
try
{
ssize_t l = tcp->receiveBytes(buf, max);
try
{
ssize_t l = tcp->receiveBytes(buf, max);
if( l > 0 )
{
for( ssize_t k = 0; k < l; k++ )
qrecv.push(buf[k]);
if( l > 0 )
{
for( ssize_t k = 0; k < l; k++ )
qrecv.push(buf[k]);
i = l;
}
i = l;
}
// канал закрыт!
if( l == 0 )
commfail = true;
}
catch( Poco::TimeoutException& ex )
{
// канал закрыт!
if( l == 0 )
commfail = true;
}
catch( Poco::TimeoutException& ex )
{
}
catch( Poco::Net::NetException& e )
{
commfail = true;
}
}
catch( Poco::Net::NetException& e )
{
commfail = true;
}
delete [] buf;
delete [] buf;
#else
try
{
for( ; i < max; i++ )
{
// (не оптимально): читаем один символ за раз..
unsigned char c;
ssize_t l = tcp->readData(&c, sizeof(c), 0, t);
if( l == 0 )
{
commfail = true;
break;
}
if( l < 0 )
break;
qrecv.push(c);
}
}
catch( ost::SockException& e )
{
}
try
{
for( ; i < max; i++ )
{
// (не оптимально): читаем один символ за раз..
unsigned char c;
ssize_t l = tcp->readData(&c, sizeof(c), 0, t);
if( l == 0 )
{
commfail = true;
break;
}
if( l < 0 )
break;
qrecv.push(c);
}
}
catch( ost::SockException& e )
{
}
#endif
if( commfail )
throw uniset::CommFailed();
return i;
}
// ------------------------------------------------------------------------
size_t ModbusTCPCore::getNextData(UTCPStream* tcp,
std::queue<unsigned char>& qrecv,
unsigned char* buf, size_t len)
{
if( qrecv.empty() || qrecv.size() < len )
{
if( !tcp ) // || !tcp->available() )
return 0;
if( len <= 0 )
len = 7;
try
{
size_t ret = ModbusTCPCore::readNextData(tcp, qrecv, len);
if( ret == 0 )
return 0;
}
catch( uniset::CommFailed& ex )
{
if( qrecv.empty() )
return 0;
}
}
size_t i = 0;
for( ; i < len && !qrecv.empty(); i++ )
{
buf[i] = qrecv.front();
qrecv.pop();
}
return i;
}
// -------------------------------------------------------------------------
size_t ModbusTCPCore::readDataFD( int fd, std::queue<unsigned char>& qrecv, size_t max , size_t attempts )
{
bool commfail = false;
if( commfail )
throw uniset::CommFailed();
return i;
}
// ------------------------------------------------------------------------
size_t ModbusTCPCore::getNextData(UTCPStream* tcp,
std::queue<unsigned char>& qrecv,
unsigned char* buf, size_t len)
{
if( qrecv.empty() || qrecv.size() < len )
{
if( !tcp ) // || !tcp->available() )
return 0;
if( len <= 0 )
len = 7;
try
{
size_t ret = ModbusTCPCore::readNextData(tcp, qrecv, len);
if( ret == 0 )
return 0;
}
catch( uniset::CommFailed& ex )
{
if( qrecv.empty() )
return 0;
}
}
size_t i = 0;
for( ; i < len && !qrecv.empty(); i++ )
{
buf[i] = qrecv.front();
qrecv.pop();
}
return i;
}
// -------------------------------------------------------------------------
size_t ModbusTCPCore::readDataFD( int fd, std::queue<unsigned char>& qrecv, size_t max, size_t attempts )
{
bool commfail = false;
#ifdef USE_BUFFER_FOR_READ
max = std::max(max, (size_t)DEFAULT_BUFFER_SIZE_FOR_READ);
max = std::max(max, (size_t)DEFAULT_BUFFER_SIZE_FOR_READ);
char* buf = new char[max];
char* buf = new char[max];
ssize_t l = 0;
size_t cnt = 0;
ssize_t l = 0;
size_t cnt = 0;
for( size_t a = 0; a < attempts; a++ )
{
l = ::read(fd, buf, max);
for( size_t a = 0; a < attempts; a++ )
{
l = ::read(fd, buf, max);
if( l > 0 )
{
for( int k = 0; k < l; k++ )
qrecv.push(buf[k]);
if( l > 0 )
{
for( int k = 0; k < l; k++ )
qrecv.push(buf[k]);
cnt += l;
cnt += l;
if( cnt >= max )
break;
}
if( cnt >= max )
break;
}
// канал закрыт!
if( l == 0 )
commfail = true;
}
// канал закрыт!
if( l == 0 )
commfail = true;
}
delete [] buf;
delete [] buf;
#else
size_t i = 0;
size_t i = 0;
for( size_t a = 0; a < attempts; a++ )
{
for( ; i < max; i++ )
{
// (не оптимально): читаем один символ за раз..
unsigned char c;
ssize_t l = ::read(fd, &c, sizeof(c));
for( size_t a = 0; a < attempts; a++ )
{
for( ; i < max; i++ )
{
// (не оптимально): читаем один символ за раз..
unsigned char c;
ssize_t l = ::read(fd, &c, sizeof(c));
if( l == 0 )
{
commfail = true;
break;
}
if( l == 0 )
{
commfail = true;
break;
}
if( l < 0 )
break;
if( l < 0 )
break;
qrecv.push(c);
}
}
qrecv.push(c);
}
}
#endif
if( commfail )
throw uniset::CommFailed();
return std::min(qrecv.size(), max);
}
// ------------------------------------------------------------------------
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( len == 0 )
len = 7;
try
{
size_t ret = ModbusTCPCore::readDataFD(fd, qrecv, len, attempts);
if( ret == 0 && qrecv.empty() )
return 0;
}
catch( uniset::CommFailed& ex )
{
if( qrecv.empty() )
return 0;
}
}
size_t i = 0;
for( ; i < len && !qrecv.empty(); i++ )
{
buf[i] = qrecv.front();
qrecv.pop();
}
return i;
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPCore::sendData(UTCPStream* tcp, unsigned char* buf, size_t len )
{
if( !tcp ) // || !tcp->available() )
return erTimeOut;
try
{
ssize_t l = tcp->sendBytes(buf, len);
if( l == len )
return erNoError;
}
catch( Poco::Net::NetException& e )
{
// cerr << "(send): " << e.getString() << ": " << e.getSystemErrorString() << endl;
}
catch(...)
{
// cerr << "(send): cath..." << endl;
}
return erHardwareError;
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPCore::sendDataFD( int fd, unsigned char* buf, size_t len )
{
ssize_t l = ::write(fd, buf, len);
if( l == len )
return erNoError;
return erHardwareError;
}
// -------------------------------------------------------------------------
if( commfail )
throw uniset::CommFailed();
return std::min(qrecv.size(), max);
}
// ------------------------------------------------------------------------
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( len == 0 )
len = 7;
try
{
size_t ret = ModbusTCPCore::readDataFD(fd, qrecv, len, attempts);
if( ret == 0 && qrecv.empty() )
return 0;
}
catch( uniset::CommFailed& ex )
{
if( qrecv.empty() )
return 0;
}
}
size_t i = 0;
for( ; i < len && !qrecv.empty(); i++ )
{
buf[i] = qrecv.front();
qrecv.pop();
}
return i;
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPCore::sendData(UTCPStream* tcp, unsigned char* buf, size_t len )
{
if( !tcp ) // || !tcp->available() )
return erTimeOut;
try
{
ssize_t l = tcp->sendBytes(buf, len);
if( l == len )
return erNoError;
}
catch( Poco::Net::NetException& e )
{
// cerr << "(send): " << e.getString() << ": " << e.getSystemErrorString() << endl;
}
catch(...)
{
// cerr << "(send): cath..." << endl;
}
return erHardwareError;
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPCore::sendDataFD( int fd, unsigned char* buf, size_t len )
{
ssize_t l = ::write(fd, buf, len);
if( l == len )
return erNoError;
return erHardwareError;
}
// -------------------------------------------------------------------------
} // end of namespace uniset
......@@ -25,503 +25,503 @@
// -------------------------------------------------------------------------
namespace uniset
{
// -------------------------------------------------------------------------
using namespace std;
using namespace ModbusRTU;
using namespace uniset;
using namespace Poco;
// -------------------------------------------------------------------------
ModbusTCPMaster::ModbusTCPMaster():
tcp(nullptr),
nTransaction(0),
iaddr(""),
force_disconnect(true)
{
setCRCNoCheckit(true);
// dlog->level(Debug::ANY);
}
// -------------------------------------------------------------------------
ModbusTCPMaster::~ModbusTCPMaster()
{
if( isConnection() )
disconnect();
}
// -------------------------------------------------------------------------
size_t ModbusTCPMaster::getNextData( unsigned char* buf, size_t len )
{
return ModbusTCPCore::getNextData(tcp.get(), qrecv, buf, len );
}
// -------------------------------------------------------------------------
void ModbusTCPMaster::setChannelTimeout( timeout_t msec )
{
if( !tcp )
return;
Poco::Timespan tm = UniSetTimer::millisecToPoco(msec);
Poco::Timespan old = tcp->getReceiveTimeout();;
if( old.totalMicroseconds() == tm.totalMicroseconds() )
return;
tcp->setReceiveTimeout(tm);
int oldKeepAlive = keepAliveTimeout;
keepAliveTimeout = (msec > 1000 ? msec / 1000 : 1);
// т.к. каждый раз не вызывать дорогой системный вызов
// смотрим меняется ли значение
if( oldKeepAlive != keepAliveTimeout )
tcp->setKeepAliveParams(keepAliveTimeout);
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPMaster::sendData( unsigned char* buf, size_t len )
{
return ModbusTCPCore::sendData(tcp.get(), buf, len);
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPMaster::query( ModbusAddr addr, ModbusMessage& msg,
ModbusMessage& reply, timeout_t timeout_msec )
{
try
{
if( iaddr.empty() )
{
if( dlog->is_warn() )
dlog->warn() << iaddr << "(ModbusTCPMaster::query): unknown ip address for server..." << endl;
return erTimeOut; // erHardwareError
}
if( !isConnection() )
{
if( dlog->is_info() )
dlog->info() << iaddr << "(ModbusTCPMaster::query): no connection.. reconnnect..." << endl;
reconnect();
}
if( !isConnection() )
{
if( dlog->is_warn() )
dlog->warn() << iaddr << "(ModbusTCPMaster::query): not connected to server..." << endl;
return erTimeOut;
}
assert(timeout_msec);
ptTimeout.setTiming(timeout_msec);
tcp->setReceiveTimeout( UniSetTimer::millisecToPoco(timeout_msec) );
msg.makeMBAPHeader(++nTransaction, crcNoCheckit);
for( size_t i = 0; i < 2; i++ )
{
if( tcp->poll(UniSetTimer::millisecToPoco(timeout_msec), Poco::Net::Socket::SELECT_WRITE) )
{
mbErrCode res = send(msg);
if( res != erNoError )
return res;
break;
}
if( dlog->is_info() )
dlog->info() << "(ModbusTCPMaster::query): no write pending.. reconnnect.." << endl;
reconnect();
if( !isConnection() )
{
if( dlog->is_warn() )
dlog->warn() << "(ModbusTCPMaster::query): not connected to server..." << endl;
return erTimeOut;
}
cleanInputStream();
if( dlog->is_info() )
dlog->info() << "(ModbusTCPMaster::query): no write pending.. reconnnect OK" << endl;
}
if( timeout_msec != UniSetTimer::WaitUpTime )
{
timeout_msec = ptTimeout.getLeft(timeout_msec);
if( timeout_msec == 0 )
return erTimeOut;
ptTimeout.setTiming(timeout_msec);
}
// чистим очередь
// cleanInputStream();
while( !qrecv.empty() )
qrecv.pop();
//tcp->sync();
if( tcp->poll(UniSetTimer::millisecToPoco(timeout_msec), Poco::Net::Socket::SELECT_READ ) )
{
size_t ret = 0;
while( !ptTimeout.checkTime() )
{
ret = getNextData((unsigned char*)(&reply.mbaphead), sizeof(reply.mbaphead));
if( ret == sizeof(reply.mbaphead) )
break;
}
if( ret > 0 && dlog->is_info() )
{
dlog->info() << "(ModbusTCPMaster::query): recv tcp header(" << ret << "): ";
mbPrintMessage( dlog->info(false), (ModbusByte*)(&reply.mbaphead), sizeof(reply.mbaphead));
dlog->info(false) << endl;
}
if( ret < sizeof(reply.mbaphead) )
{
if( dlog->is_warn() )
{
try
{
Poco::Net::SocketAddress ia = tcp->peerAddress();
dlog->warn() << "(ModbusTCPMaster::query): ret=" << ret
<< " < rmh=" << sizeof(reply.mbaphead)
<< " perr: " << ia.host().toString() << ":" << ia.port()
<< endl;
}
catch( const Poco::Net::NetException& ex )
{
if( dlog->is_warn() )
dlog->warn() << "(query): tcp error: " << ex.displayText() << endl;
}
}
cleanInputStream();
if( tcp )
tcp->forceDisconnect();
return erTimeOut; // return erHardwareError;
}
reply.swapHead();
if( dlog->is_level9() )
dlog->level9() << "(ModbusTCPMaster::query): ADU len=" << reply.aduLen()
<< endl;
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( reply.pID() != 0 )
{
cleanInputStream();
return erBadReplyNodeAddress;
}
//
timeout_msec = ptTimeout.getLeft(timeout_msec);
if( timeout_msec <= 0 )
{
if( dlog->is_warn() )
dlog->warn() << "(ModbusTCPMaster::query): processing reply timeout.." << endl;
return erTimeOut; // return erHardwareError;
}
//msg.aduhead = reply.aduhead;
mbErrCode res = recv(addr, msg.func(), reply, timeout_msec);
if( force_disconnect )
{
if( dlog->is_info() )
dlog->info() << "(query): disconnect.." << endl;
// при штатном обмене..лучше дождаться конца "посылки"..
// поэтому применяем disconnect(), а не forceDisconnect()
// (с учётом выставленной опции setLinger(true))
if( tcp )
tcp->disconnect();
}
return res;
}
if( dlog->is_info() )
dlog->info() << "(query): input pending timeout=" << timeout_msec << endl;
if( force_disconnect )
{
if( dlog->is_info() )
dlog->info() << "(query): force disconnect.." << endl;
// cleanInputStream();
if( tcp )
tcp->forceDisconnect();
}
return erTimeOut;
}
catch( ModbusRTU::mbException& ex )
{
if( dlog->is_warn() )
dlog->warn() << "(query): " << ex << endl;
}
catch( SystemError& err )
{
if( dlog->is_warn() )
dlog->warn() << "(query): " << err << endl;
}
catch( const uniset::CommFailed& ex )
{
if( dlog->is_crit() )
dlog->crit() << "(query): " << ex << endl;
if( tcp )
tcp->forceDisconnect();
}
catch( const Poco::Net::NetException& e )
{
if( dlog->is_warn() )
dlog->warn() << "(query): tcp error: " << e.displayText() << endl;
}
catch( const uniset::Exception& ex )
{
if( dlog->is_warn() )
dlog->warn() << "(query): " << ex << endl;
}
catch( const std::exception& e )
{
if( dlog->is_warn() )
dlog->warn() << "(query): " << e.what() << std::endl;
}
return erTimeOut; // erHardwareError
}
// -------------------------------------------------------------------------
void ModbusTCPMaster::cleanInputStream()
{
unsigned char buf[100];
int ret = 0;
try
{
do
{
ret = getNextData(buf, sizeof(buf));
}
while( ret > 0);
}
catch( ... ) {}
}
// -------------------------------------------------------------------------
void ModbusTCPMaster::cleanupChannel()
{
cleanInputStream();
}
// -------------------------------------------------------------------------
string ModbusTCPMaster::getAddress() const
{
return iaddr;
}
// -------------------------------------------------------------------------
int ModbusTCPMaster::getPort() const
{
return port;
}
// -------------------------------------------------------------------------
void ModbusTCPMaster::setReadTimeout( timeout_t msec )
{
readTimeout = msec;
}
// -------------------------------------------------------------------------
timeout_t ModbusTCPMaster::getReadTimeout() const
{
return readTimeout;
}
// -------------------------------------------------------------------------
bool ModbusTCPMaster::checkConnection( const std::string& ip, int port, int timeout_msec )
{
try
{
ostringstream s;
s << ip << ":" << port;
// Проверяем просто попыткой создать соединение..
UTCPStream t;
t.create(ip, port, timeout_msec);
t.setKeepAliveParams( (timeout_msec > 1000 ? timeout_msec / 1000 : 1), 1, 1);
t.setNoDelay(true);
//t.shutdown();
t.close();
return true;
}
catch(...)
{
}
return false;
}
// -------------------------------------------------------------------------
void ModbusTCPMaster::setForceDisconnect( bool s )
{
force_disconnect = s;
}
// -------------------------------------------------------------------------
bool ModbusTCPMaster::reconnect()
{
if( dlog->is_info() )
dlog->info() << "(ModbusTCPMaster): reconnect " << iaddr << ":" << port << endl;
if( tcp )
{
tcp->forceDisconnect();
tcp = nullptr;
}
return connect(iaddr, port, true);
}
// -------------------------------------------------------------------------
bool ModbusTCPMaster::connect( const std::string& addr, int _port, bool closeOldConnection ) noexcept
{
try
{
Net::SocketAddress sa(addr, _port);
return connect(sa, _port, closeOldConnection);
}
catch( const std::exception& e )
{
if( dlog->debugging(Debug::CRIT) )
{
ostringstream s;
s << "(ModbusTCPMaster): connect " << iaddr << ":" << port << " error: " << e.what();
dlog->crit() << s.str() << std::endl;
}
}
if( closeOldConnection && tcp )
{
forceDisconnect();
tcp = nullptr;
}
return false;
}
// -------------------------------------------------------------------------
bool ModbusTCPMaster::connect( const Poco::Net::SocketAddress& addr, int _port, bool closeOldConnection ) noexcept
{
if( tcp )
{
if( !closeOldConnection )
return false;
//disconnect();
forceDisconnect();
tcp = nullptr;
}
iaddr = addr.host().toString();
port = _port;
if( dlog->is_info() )
dlog->info() << "(ModbusTCPMaster): connect to " << iaddr << ":" << port << endl;
try
{
tcp = make_shared<UTCPStream>();
tcp->create(iaddr, port, 500);
//tcp->connect(addr,500);
tcp->setReceiveTimeout(UniSetTimer::millisecToPoco(replyTimeOut_ms));
tcp->setKeepAlive(true); // tcp->setKeepAliveParams((replyTimeOut_ms > 1000 ? replyTimeOut_ms / 1000 : 1));
tcp->setNoDelay(true);
return true;
}
catch( Poco::TimeoutException& ex)
{
if( dlog->debugging(Debug::CRIT) )
{
ostringstream s;
s << "(ModbusTCPMaster): create connection " << iaddr << ":" << port << " timeout exception";
dlog->crit() << s.str() << std::endl;
}
}
catch( Poco::Net::NetException& ex)
{
if( dlog->debugging(Debug::CRIT) )
{
ostringstream s;
s << "(ModbusTCPMaster): create connection " << iaddr << ":" << port << " error: " << ex.displayText();
dlog->crit() << s.str() << std::endl;
}
}
catch( const std::exception& e )
{
if( dlog->debugging(Debug::CRIT) )
{
ostringstream s;
s << "(ModbusTCPMaster): connection " << iaddr << ":" << port << " error: " << e.what();
dlog->crit() << s.str() << std::endl;
}
}
catch( ... )
{
if( dlog->debugging(Debug::CRIT) )
{
ostringstream s;
s << "(ModbusTCPMaster): connection " << iaddr << ":" << port << " error: catch ...";
dlog->crit() << s.str() << std::endl;
}
}
tcp = nullptr;
return false;
}
// -------------------------------------------------------------------------
void ModbusTCPMaster::disconnect()
{
if( dlog->is_info() )
dlog->info() << iaddr << "(ModbusTCPMaster): disconnect (" << iaddr << ":" << port << ")." << endl;
if( !tcp )
return;
tcp->disconnect(); // close();
tcp = nullptr;
}
// -------------------------------------------------------------------------
void ModbusTCPMaster::forceDisconnect()
{
if( dlog->is_info() )
dlog->info() << iaddr << "(ModbusTCPMaster): FORCE disconnect (" << iaddr << ":" << port << ")." << endl;
if( !tcp )
return;
tcp->forceDisconnect();
tcp = nullptr;
}
// -------------------------------------------------------------------------
bool ModbusTCPMaster::isConnection() const
{
return tcp && tcp->isConnected();
}
// -------------------------------------------------------------------------
// -------------------------------------------------------------------------
using namespace std;
using namespace ModbusRTU;
using namespace uniset;
using namespace Poco;
// -------------------------------------------------------------------------
ModbusTCPMaster::ModbusTCPMaster():
tcp(nullptr),
nTransaction(0),
iaddr(""),
force_disconnect(true)
{
setCRCNoCheckit(true);
// dlog->level(Debug::ANY);
}
// -------------------------------------------------------------------------
ModbusTCPMaster::~ModbusTCPMaster()
{
if( isConnection() )
disconnect();
}
// -------------------------------------------------------------------------
size_t ModbusTCPMaster::getNextData( unsigned char* buf, size_t len )
{
return ModbusTCPCore::getNextData(tcp.get(), qrecv, buf, len );
}
// -------------------------------------------------------------------------
void ModbusTCPMaster::setChannelTimeout( timeout_t msec )
{
if( !tcp )
return;
Poco::Timespan tm = UniSetTimer::millisecToPoco(msec);
Poco::Timespan old = tcp->getReceiveTimeout();;
if( old.totalMicroseconds() == tm.totalMicroseconds() )
return;
tcp->setReceiveTimeout(tm);
int oldKeepAlive = keepAliveTimeout;
keepAliveTimeout = (msec > 1000 ? msec / 1000 : 1);
// т.к. каждый раз не вызывать дорогой системный вызов
// смотрим меняется ли значение
if( oldKeepAlive != keepAliveTimeout )
tcp->setKeepAliveParams(keepAliveTimeout);
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPMaster::sendData( unsigned char* buf, size_t len )
{
return ModbusTCPCore::sendData(tcp.get(), buf, len);
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPMaster::query( ModbusAddr addr, ModbusMessage& msg,
ModbusMessage& reply, timeout_t timeout_msec )
{
try
{
if( iaddr.empty() )
{
if( dlog->is_warn() )
dlog->warn() << iaddr << "(ModbusTCPMaster::query): unknown ip address for server..." << endl;
return erTimeOut; // erHardwareError
}
if( !isConnection() )
{
if( dlog->is_info() )
dlog->info() << iaddr << "(ModbusTCPMaster::query): no connection.. reconnnect..." << endl;
reconnect();
}
if( !isConnection() )
{
if( dlog->is_warn() )
dlog->warn() << iaddr << "(ModbusTCPMaster::query): not connected to server..." << endl;
return erTimeOut;
}
assert(timeout_msec);
ptTimeout.setTiming(timeout_msec);
tcp->setReceiveTimeout( UniSetTimer::millisecToPoco(timeout_msec) );
msg.makeMBAPHeader(++nTransaction, crcNoCheckit);
for( size_t i = 0; i < 2; i++ )
{
if( tcp->poll(UniSetTimer::millisecToPoco(timeout_msec), Poco::Net::Socket::SELECT_WRITE) )
{
mbErrCode res = send(msg);
if( res != erNoError )
return res;
break;
}
if( dlog->is_info() )
dlog->info() << "(ModbusTCPMaster::query): no write pending.. reconnnect.." << endl;
reconnect();
if( !isConnection() )
{
if( dlog->is_warn() )
dlog->warn() << "(ModbusTCPMaster::query): not connected to server..." << endl;
return erTimeOut;
}
cleanInputStream();
if( dlog->is_info() )
dlog->info() << "(ModbusTCPMaster::query): no write pending.. reconnnect OK" << endl;
}
if( timeout_msec != UniSetTimer::WaitUpTime )
{
timeout_msec = ptTimeout.getLeft(timeout_msec);
if( timeout_msec == 0 )
return erTimeOut;
ptTimeout.setTiming(timeout_msec);
}
// чистим очередь
// cleanInputStream();
while( !qrecv.empty() )
qrecv.pop();
//tcp->sync();
if( tcp->poll(UniSetTimer::millisecToPoco(timeout_msec), Poco::Net::Socket::SELECT_READ ) )
{
size_t ret = 0;
while( !ptTimeout.checkTime() )
{
ret = getNextData((unsigned char*)(&reply.mbaphead), sizeof(reply.mbaphead));
if( ret == sizeof(reply.mbaphead) )
break;
}
if( ret > 0 && dlog->is_info() )
{
dlog->info() << "(ModbusTCPMaster::query): recv tcp header(" << ret << "): ";
mbPrintMessage( dlog->info(false), (ModbusByte*)(&reply.mbaphead), sizeof(reply.mbaphead));
dlog->info(false) << endl;
}
if( ret < sizeof(reply.mbaphead) )
{
if( dlog->is_warn() )
{
try
{
Poco::Net::SocketAddress ia = tcp->peerAddress();
dlog->warn() << "(ModbusTCPMaster::query): ret=" << ret
<< " < rmh=" << sizeof(reply.mbaphead)
<< " perr: " << ia.host().toString() << ":" << ia.port()
<< endl;
}
catch( const Poco::Net::NetException& ex )
{
if( dlog->is_warn() )
dlog->warn() << "(query): tcp error: " << ex.displayText() << endl;
}
}
cleanInputStream();
if( tcp )
tcp->forceDisconnect();
return erTimeOut; // return erHardwareError;
}
reply.swapHead();
if( dlog->is_level9() )
dlog->level9() << "(ModbusTCPMaster::query): ADU len=" << reply.aduLen()
<< endl;
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( reply.pID() != 0 )
{
cleanInputStream();
return erBadReplyNodeAddress;
}
//
timeout_msec = ptTimeout.getLeft(timeout_msec);
if( timeout_msec <= 0 )
{
if( dlog->is_warn() )
dlog->warn() << "(ModbusTCPMaster::query): processing reply timeout.." << endl;
return erTimeOut; // return erHardwareError;
}
//msg.aduhead = reply.aduhead;
mbErrCode res = recv(addr, msg.func(), reply, timeout_msec);
if( force_disconnect )
{
if( dlog->is_info() )
dlog->info() << "(query): disconnect.." << endl;
// при штатном обмене..лучше дождаться конца "посылки"..
// поэтому применяем disconnect(), а не forceDisconnect()
// (с учётом выставленной опции setLinger(true))
if( tcp )
tcp->disconnect();
}
return res;
}
if( dlog->is_info() )
dlog->info() << "(query): input pending timeout=" << timeout_msec << endl;
if( force_disconnect )
{
if( dlog->is_info() )
dlog->info() << "(query): force disconnect.." << endl;
// cleanInputStream();
if( tcp )
tcp->forceDisconnect();
}
return erTimeOut;
}
catch( ModbusRTU::mbException& ex )
{
if( dlog->is_warn() )
dlog->warn() << "(query): " << ex << endl;
}
catch( SystemError& err )
{
if( dlog->is_warn() )
dlog->warn() << "(query): " << err << endl;
}
catch( const uniset::CommFailed& ex )
{
if( dlog->is_crit() )
dlog->crit() << "(query): " << ex << endl;
if( tcp )
tcp->forceDisconnect();
}
catch( const Poco::Net::NetException& e )
{
if( dlog->is_warn() )
dlog->warn() << "(query): tcp error: " << e.displayText() << endl;
}
catch( const uniset::Exception& ex )
{
if( dlog->is_warn() )
dlog->warn() << "(query): " << ex << endl;
}
catch( const std::exception& e )
{
if( dlog->is_warn() )
dlog->warn() << "(query): " << e.what() << std::endl;
}
return erTimeOut; // erHardwareError
}
// -------------------------------------------------------------------------
void ModbusTCPMaster::cleanInputStream()
{
unsigned char buf[100];
int ret = 0;
try
{
do
{
ret = getNextData(buf, sizeof(buf));
}
while( ret > 0);
}
catch( ... ) {}
}
// -------------------------------------------------------------------------
void ModbusTCPMaster::cleanupChannel()
{
cleanInputStream();
}
// -------------------------------------------------------------------------
string ModbusTCPMaster::getAddress() const
{
return iaddr;
}
// -------------------------------------------------------------------------
int ModbusTCPMaster::getPort() const
{
return port;
}
// -------------------------------------------------------------------------
void ModbusTCPMaster::setReadTimeout( timeout_t msec )
{
readTimeout = msec;
}
// -------------------------------------------------------------------------
timeout_t ModbusTCPMaster::getReadTimeout() const
{
return readTimeout;
}
// -------------------------------------------------------------------------
bool ModbusTCPMaster::checkConnection( const std::string& ip, int port, int timeout_msec )
{
try
{
ostringstream s;
s << ip << ":" << port;
// Проверяем просто попыткой создать соединение..
UTCPStream t;
t.create(ip, port, timeout_msec);
t.setKeepAliveParams( (timeout_msec > 1000 ? timeout_msec / 1000 : 1), 1, 1);
t.setNoDelay(true);
//t.shutdown();
t.close();
return true;
}
catch(...)
{
}
return false;
}
// -------------------------------------------------------------------------
void ModbusTCPMaster::setForceDisconnect( bool s )
{
force_disconnect = s;
}
// -------------------------------------------------------------------------
bool ModbusTCPMaster::reconnect()
{
if( dlog->is_info() )
dlog->info() << "(ModbusTCPMaster): reconnect " << iaddr << ":" << port << endl;
if( tcp )
{
tcp->forceDisconnect();
tcp = nullptr;
}
return connect(iaddr, port, true);
}
// -------------------------------------------------------------------------
bool ModbusTCPMaster::connect( const std::string& addr, int _port, bool closeOldConnection ) noexcept
{
try
{
Net::SocketAddress sa(addr, _port);
return connect(sa, _port, closeOldConnection);
}
catch( const std::exception& e )
{
if( dlog->debugging(Debug::CRIT) )
{
ostringstream s;
s << "(ModbusTCPMaster): connect " << iaddr << ":" << port << " error: " << e.what();
dlog->crit() << s.str() << std::endl;
}
}
if( closeOldConnection && tcp )
{
forceDisconnect();
tcp = nullptr;
}
return false;
}
// -------------------------------------------------------------------------
bool ModbusTCPMaster::connect( const Poco::Net::SocketAddress& addr, int _port, bool closeOldConnection ) noexcept
{
if( tcp )
{
if( !closeOldConnection )
return false;
//disconnect();
forceDisconnect();
tcp = nullptr;
}
iaddr = addr.host().toString();
port = _port;
if( dlog->is_info() )
dlog->info() << "(ModbusTCPMaster): connect to " << iaddr << ":" << port << endl;
try
{
tcp = make_shared<UTCPStream>();
tcp->create(iaddr, port, 500);
//tcp->connect(addr,500);
tcp->setReceiveTimeout(UniSetTimer::millisecToPoco(replyTimeOut_ms));
tcp->setKeepAlive(true); // tcp->setKeepAliveParams((replyTimeOut_ms > 1000 ? replyTimeOut_ms / 1000 : 1));
tcp->setNoDelay(true);
return true;
}
catch( Poco::TimeoutException& ex)
{
if( dlog->debugging(Debug::CRIT) )
{
ostringstream s;
s << "(ModbusTCPMaster): create connection " << iaddr << ":" << port << " timeout exception";
dlog->crit() << s.str() << std::endl;
}
}
catch( Poco::Net::NetException& ex)
{
if( dlog->debugging(Debug::CRIT) )
{
ostringstream s;
s << "(ModbusTCPMaster): create connection " << iaddr << ":" << port << " error: " << ex.displayText();
dlog->crit() << s.str() << std::endl;
}
}
catch( const std::exception& e )
{
if( dlog->debugging(Debug::CRIT) )
{
ostringstream s;
s << "(ModbusTCPMaster): connection " << iaddr << ":" << port << " error: " << e.what();
dlog->crit() << s.str() << std::endl;
}
}
catch( ... )
{
if( dlog->debugging(Debug::CRIT) )
{
ostringstream s;
s << "(ModbusTCPMaster): connection " << iaddr << ":" << port << " error: catch ...";
dlog->crit() << s.str() << std::endl;
}
}
tcp = nullptr;
return false;
}
// -------------------------------------------------------------------------
void ModbusTCPMaster::disconnect()
{
if( dlog->is_info() )
dlog->info() << iaddr << "(ModbusTCPMaster): disconnect (" << iaddr << ":" << port << ")." << endl;
if( !tcp )
return;
tcp->disconnect(); // close();
tcp = nullptr;
}
// -------------------------------------------------------------------------
void ModbusTCPMaster::forceDisconnect()
{
if( dlog->is_info() )
dlog->info() << iaddr << "(ModbusTCPMaster): FORCE disconnect (" << iaddr << ":" << port << ")." << endl;
if( !tcp )
return;
tcp->forceDisconnect();
tcp = nullptr;
}
// -------------------------------------------------------------------------
bool ModbusTCPMaster::isConnection() const
{
return tcp && tcp->isConnected();
}
// -------------------------------------------------------------------------
} // end of namespace uniset
......@@ -23,451 +23,460 @@
// -------------------------------------------------------------------------
namespace uniset
{
// -------------------------------------------------------------------------
using namespace std;
using namespace ModbusRTU;
using namespace uniset;
// -------------------------------------------------------------------------
ModbusTCPServer::ModbusTCPServer( const std::string& ia, int _port ):
port(_port),
iaddr(ia),
myname(""),
ignoreAddr(false),
maxSessions(10),
sessCount(0),
sessTimeout(10000)
{
setCRCNoCheckit(true);
{
ostringstream s;
s << iaddr << ":" << port;
myname = s.str();
}
io.set<ModbusTCPServer, &ModbusTCPServer::ioAccept>(this);
ioTimer.set<ModbusTCPServer, &ModbusTCPServer::onTimer>(this);
sockTimeout.set<ModbusTCPServer, &ModbusTCPServer::onSocketTimeout>(this);
asyncResetSockTimeout.set<ModbusTCPServer, &ModbusTCPServer::onSocketResetTimeout>(this);
}
// -------------------------------------------------------------------------
ModbusTCPServer::~ModbusTCPServer()
{
}
// -------------------------------------------------------------------------
void ModbusTCPServer::setMaxSessions( size_t num )
{
if( num < sessCount )
{
std::lock_guard<std::mutex> l(sMutex);
int k = sessCount - num;
int d = 0;
for( SessionList::reverse_iterator i = slist.rbegin(); d < k && i != slist.rend(); ++i, d++ )
(*i).reset();
sessCount = num;
}
maxSessions = num;
}
// -------------------------------------------------------------------------
size_t ModbusTCPServer::getMaxSessions() const noexcept
{
return maxSessions;
}
// -------------------------------------------------------------------------
size_t ModbusTCPServer::getCountSessions() const noexcept
{
return sessCount;
}
// -------------------------------------------------------------------------
void ModbusTCPServer::setSessionTimeout( timeout_t msec )
{
sessTimeout = msec;
}
// -------------------------------------------------------------------------
timeout_t ModbusTCPServer::getSessionTimeout() const noexcept
{
return sessTimeout;
}
// -------------------------------------------------------------------------
bool ModbusTCPServer::run( const std::unordered_set<ModbusAddr>& _vmbaddr )
{
vmbaddr = _vmbaddr;
return evrun();
}
// -------------------------------------------------------------------------
bool ModbusTCPServer::async_run( const std::unordered_set<ModbusAddr>& _vmbaddr )
{
vmbaddr = _vmbaddr;
return async_evrun();
}
// -------------------------------------------------------------------------
bool ModbusTCPServer::isActive() const
{
return evIsActive() && sock;
}
// -------------------------------------------------------------------------
void ModbusTCPServer::createSocket()
{
try
{
// -------------------------------------------------------------------------
using namespace std;
using namespace ModbusRTU;
using namespace uniset;
// -------------------------------------------------------------------------
ModbusTCPServer::ModbusTCPServer( const std::string& ia, int _port ):
port(_port),
iaddr(ia),
myname(""),
ignoreAddr(false),
maxSessions(10),
sessCount(0),
sessTimeout(10000)
{
setCRCNoCheckit(true);
{
ostringstream s;
s << iaddr << ":" << port;
myname = s.str();
}
io.set<ModbusTCPServer, &ModbusTCPServer::ioAccept>(this);
ioTimer.set<ModbusTCPServer, &ModbusTCPServer::onTimer>(this);
sockTimeout.set<ModbusTCPServer, &ModbusTCPServer::onSocketTimeout>(this);
asyncResetSockTimeout.set<ModbusTCPServer, &ModbusTCPServer::onSocketResetTimeout>(this);
}
// -------------------------------------------------------------------------
ModbusTCPServer::~ModbusTCPServer()
{
}
// -------------------------------------------------------------------------
void ModbusTCPServer::setMaxSessions( size_t num )
{
if( num < sessCount )
{
std::lock_guard<std::mutex> l(sMutex);
int k = sessCount - num;
int d = 0;
for( SessionList::reverse_iterator i = slist.rbegin(); d < k && i != slist.rend(); ++i, d++ )
(*i).reset();
sessCount = num;
}
maxSessions = num;
}
// -------------------------------------------------------------------------
size_t ModbusTCPServer::getMaxSessions() const noexcept
{
return maxSessions;
}
// -------------------------------------------------------------------------
size_t ModbusTCPServer::getCountSessions() const noexcept
{
return sessCount;
}
// -------------------------------------------------------------------------
void ModbusTCPServer::setSessionTimeout( timeout_t msec )
{
sessTimeout = msec;
}
// -------------------------------------------------------------------------
timeout_t ModbusTCPServer::getSessionTimeout() const noexcept
{
return sessTimeout;
}
// -------------------------------------------------------------------------
bool ModbusTCPServer::run( const std::unordered_set<ModbusAddr>& _vmbaddr )
{
vmbaddr = _vmbaddr;
return evrun();
}
// -------------------------------------------------------------------------
bool ModbusTCPServer::async_run( const std::unordered_set<ModbusAddr>& _vmbaddr )
{
vmbaddr = _vmbaddr;
return async_evrun();
}
// -------------------------------------------------------------------------
bool ModbusTCPServer::isActive() const
{
return evIsActive() && sock;
}
// -------------------------------------------------------------------------
void ModbusTCPServer::createSocket()
{
try
{
auto tmpSock = make_shared<UTCPSocket>(iaddr, port);
if( sock )
sock.reset();
sock = tmpSock;
}
catch( const Poco::Net::NetException& ex )
{
ostringstream err;
err << "(ModbusTCPServer::createSocket): connect " << iaddr << ":" << port << " err: " << ex.what();
dlog->crit() << err.str() << endl;
throw uniset::SystemError(err.str());
}
catch( const std::exception& ex )
{
ostringstream err;
sock = tmpSock;
}
catch( const Poco::Net::NetException& ex )
{
ostringstream err;
err << "(ModbusTCPServer::createSocket): connect " << iaddr << ":" << port << " err: " << ex.what();
dlog->crit() << err.str() << endl;
throw uniset::SystemError(err.str());
}
catch( const std::exception& ex )
{
ostringstream err;
err << "(ModbusTCPServer::createSocket): connect " << iaddr << ":" << port << " err: " << ex.what();
dlog->crit() << err.str() << endl;
throw uniset::SystemError(err.str());
}
sock->setBlocking(false);
}
// -------------------------------------------------------------------------
void ModbusTCPServer::evprepare()
{
dlog->crit() << err.str() << endl;
throw uniset::SystemError(err.str());
}
sock->setBlocking(false);
}
// -------------------------------------------------------------------------
void ModbusTCPServer::evprepare()
{
createSocket();
io.set(loop);
io.start(sock->getSocket(), ev::READ);
io.set(loop);
io.start(sock->getSocket(), ev::READ);
asyncResetSockTimeout.set(loop);
asyncResetSockTimeout.start();
asyncResetSockTimeout.set(loop);
asyncResetSockTimeout.start();
ioTimer.set(loop);
if( tmTime_msec != UniSetTimer::WaitUpTime )
ioTimer.start(0, tmTime);
ioTimer.set(loop);
if( tmTime_msec != UniSetTimer::WaitUpTime )
ioTimer.start(0, tmTime);
sockTimeout.set(loop);
if( socketTimeout_msec > 0 && socketTimeout_msec != UniSetTimer::WaitUpTime )
sockTimeout.start(0, tmSockTimeout);
}
// -------------------------------------------------------------------------
void ModbusTCPServer::terminate()
{
evstop();
}
// -------------------------------------------------------------------------
void ModbusTCPServer::evfinish()
{
if( !io.is_active() )
return;
if( dlog->is_info() )
dlog->info() << myname << "(ModbusTCPServer): terminate..." << endl;
ioTimer.stop();
io.stop();
sockTimeout.stop();
asyncResetSockTimeout.stop();
auto lst(slist);
// Копируем сперва себе список сессий..
// т.к при вызове terminate()
// у Session будет вызван сигнал "final"
// который приведёт к вызову sessionFinished()..
// в котором этот список будет меняться (удалится сессия из списка)
for( const auto& s : lst )
{
try
{
s->terminate();
}
catch( std::exception& ex ) {}
}
}
// -------------------------------------------------------------------------
void ModbusTCPServer::sessionFinished( const ModbusTCPSession* s )
{
std::lock_guard<std::mutex> l(sMutex);
for( auto i = slist.begin(); i != slist.end(); ++i )
{
if( (*i).get() == s )
{
slist.erase(i);
sessCount--;
asyncResetSockTimeout.send();
return;
}
}
}
// -------------------------------------------------------------------------
void ModbusTCPServer::getSessions( Sessions& lst )
{
std::lock_guard<std::mutex> l(sMutex);
for( const auto& i : slist )
lst.emplace_back( i->getClientAddress(), i->getAskCount() );
}
// -------------------------------------------------------------------------
string ModbusTCPServer::getInetAddress() const noexcept
{
return iaddr;
}
// -------------------------------------------------------------------------
int ModbusTCPServer::getInetPort() const noexcept
{
return port;
}
// -------------------------------------------------------------------------
size_t ModbusTCPServer::getConnectionCount() const noexcept
{
return connCount;
}
// -------------------------------------------------------------------------
ModbusTCPServer::TimerSignal ModbusTCPServer::signal_timer()
{
return m_timer_signal;
}
// -------------------------------------------------------------------------
void ModbusTCPServer::setTimer( timeout_t msec )
{
tmTime_msec = msec;
if( msec == UniSetTimer::WaitUpTime )
{
tmTime = 0;
if( ioTimer.is_active() )
ioTimer.stop();
}
else
{
tmTime = (double)msec / 1000.;
if( ioTimer.is_active() )
ioTimer.start( 0, tmTime );
}
}
// -------------------------------------------------------------------------
timeout_t ModbusTCPServer::getTimer() const noexcept
{
return tmTime_msec;
}
// -------------------------------------------------------------------------
void ModbusTCPServer::setSocketTimeout( timeout_t msec )
{
socketTimeout_msec = msec;
if( msec == UniSetTimer::WaitUpTime || msec == 0 )
{
socketTimeout_msec = 0;
if( sockTimeout.is_active() )
sockTimeout.stop();
}
else
{
tmSockTimeout = (double)msec / 1000.;
if( sockTimeout.is_active() )
sockTimeout.start( 0, tmSockTimeout );
}
}
// ------------------------------------------------------------------------
timeout_t ModbusTCPServer::getSocketTimeout() const noexcept
{
return socketTimeout_msec;
}
// -------------------------------------------------------------------------
void ModbusTCPServer::iowait( timeout_t msec )
{
ptWait.setTiming(msec);
while( !ptWait.checkTime() )
io.loop.iteration();
}
// -------------------------------------------------------------------------
void ModbusTCPServer::ioAccept(ev::io& watcher, int revents)
{
if (EV_ERROR & revents)
{
if( dlog->is_crit() )
dlog->crit() << myname << "(ModbusTCPServer::ioAccept): invalid event" << endl;
return;
}
if( !evIsActive() )
{
if( dlog->is_crit() )
dlog->crit() << myname << "(ModbusTCPServer::ioAccept): terminate work.." << endl;
sock->close();
return;
}
if( sessCount >= maxSessions )
{
if( dlog->is_crit() )
dlog->crit() << myname << "(ModbusTCPServer::ioAccept): session limit(" << maxSessions << ")" << endl;
sock->close();
return;
}
if( dlog->is_info() )
dlog->info() << myname << "(ModbusTCPServer): new connection.." << endl;
try
{
Poco::Net::StreamSocket ss = sock->acceptConnection();
connCount++;
if( sockTimeout.is_active() )
sockTimeout.again();
auto s = make_shared<ModbusTCPSession>(ss, vmbaddr, sessTimeout);
s->connectReadCoil( sigc::mem_fun(this, &ModbusTCPServer::readCoilStatus) );
s->connectReadInputStatus( sigc::mem_fun(this, &ModbusTCPServer::readInputStatus) );
s->connectReadOutput( sigc::mem_fun(this, &ModbusTCPServer::readOutputRegisters) );
s->connectReadInput( sigc::mem_fun(this, &ModbusTCPServer::readInputRegisters) );
s->connectForceSingleCoil( sigc::mem_fun(this, &ModbusTCPServer::forceSingleCoil) );
s->connectForceCoils( sigc::mem_fun(this, &ModbusTCPServer::forceMultipleCoils) );
s->connectWriteOutput( sigc::mem_fun(this, &ModbusTCPServer::writeOutputRegisters) );
s->connectWriteSingleOutput( sigc::mem_fun(this, &ModbusTCPServer::writeOutputSingleRegister) );
s->connectMEIRDI( sigc::mem_fun(this, &ModbusTCPServer::read4314) );
s->connectSetDateTime( sigc::mem_fun(this, &ModbusTCPServer::setDateTime) );
s->connectDiagnostics( sigc::mem_fun(this, &ModbusTCPServer::diagnostics) );
s->connectFileTransfer( sigc::mem_fun(this, &ModbusTCPServer::fileTransfer) );
s->connectJournalCommand( sigc::mem_fun(this, &ModbusTCPServer::journalCommand) );
s->connectRemoteService( sigc::mem_fun(this, &ModbusTCPServer::remoteService) );
s->connectFileTransfer( sigc::mem_fun(this, &ModbusTCPServer::fileTransfer) );
s->setAfterSendPause(aftersend_msec);
s->setReplyTimeout(replyTimeout_ms);
s->setRecvTimeout(recvTimeOut_ms);
s->setSleepPause(sleepPause_msec);
s->setCleanBeforeSend(cleanBeforeSend);
s->setSessionTimeout( (double)sessTimeout / 1000. );
s->signal_post_receive().connect( sigc::mem_fun(this, &ModbusTCPServer::postReceiveEvent) );
s->signal_pre_receive().connect( sigc::mem_fun(this, &ModbusTCPServer::preReceiveEvent) );
s->setLog(dlog);
s->connectFinalSession( sigc::mem_fun(this, &ModbusTCPServer::sessionFinished) );
{
std::lock_guard<std::mutex> l(sMutex);
slist.push_back(s);
}
s->run(loop);
sessCount++;
}
catch( std::exception& ex )
{
if( dlog->is_crit() )
dlog->crit() << myname << "(ModbusTCPServer): new connection error: " << ex.what() << endl;
}
}
// -------------------------------------------------------------------------
void ModbusTCPServer::onTimer( ev::timer& t, int revents )
{
if (EV_ERROR & revents)
{
if( dlog->is_crit() )
dlog->crit() << myname << "(ModbusTCPServer::ioTimer): invalid event" << endl;
return;
}
try
{
m_timer_signal.emit();
}
catch( std::exception& ex )
{
if( dlog->is_crit() )
dlog->crit() << myname << "(onTimer): " << ex.what() << endl;
}
}
// -------------------------------------------------------------------------
void ModbusTCPServer::onSocketResetTimeout( ev::async& watcher, int revents ) noexcept
{
if( EV_ERROR & revents )
{
if( dlog->is_crit() )
dlog->crit() << myname << "(ModbusTCPServer::onSocketResetTimeout): invalid event" << endl;
return;
}
if( dlog->is_info() )
dlog->info() << myname << "(ModbusTCPServer::onSocketResetTimeout): reset socket timeout.." << endl;
if( sockTimeout.is_active() )
sockTimeout.again();
}
// -------------------------------------------------------------------------
void ModbusTCPServer::onSocketTimeout( ev::timer& t, int revents )
{
if (EV_ERROR & revents)
{
if( dlog->is_crit() )
dlog->crit() << myname << "(ModbusTCPServer::onSocketTimeout): invalid event" << endl;
return;
}
{
std::lock_guard<std::mutex> l(sMutex);
if( !slist.empty())
{
if( dlog->is_info() )
dlog->info() << myname << "(ModbusTCPServer::onSocketTimeout): check socket [OK].." << endl;
t.again();
return;
}
}
if( dlog->is_warn() )
dlog->warn() << myname << "(ModbusTCPServer::onSocketTimeout): no connections.. recreate socket.." << endl;
try
{
createSocket();
if( io.is_active() )
io.stop();
io.start(sock->getSocket(), ev::READ);
}
catch( std::exception& ex )
{
if( dlog->is_crit() )
dlog->crit() << myname << "(ModbusTCPServer::onSocketTimeout): recreate socket ERROR: " << ex.what() << endl;
}
t.again();
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPServer::realReceive( const std::unordered_set<ModbusAddr>& vaddr, timeout_t msecTimeout )
{
return ModbusRTU::erOperationFailed;
}
// -------------------------------------------------------------------------
void ModbusTCPServer::postReceiveEvent( mbErrCode res )
{
m_post_signal.emit(res);
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPServer::preReceiveEvent(const std::unordered_set<ModbusAddr> vaddr, timeout_t tout)
{
if( m_pre_signal.empty() )
return ModbusRTU::erNoError;
return m_pre_signal.emit(vaddr, tout);
}
// -------------------------------------------------------------------------
}
// -------------------------------------------------------------------------
void ModbusTCPServer::terminate()
{
evstop();
}
// -------------------------------------------------------------------------
void ModbusTCPServer::evfinish()
{
if( !io.is_active() )
return;
if( dlog->is_info() )
dlog->info() << myname << "(ModbusTCPServer): terminate..." << endl;
ioTimer.stop();
io.stop();
sockTimeout.stop();
asyncResetSockTimeout.stop();
auto lst(slist);
// Копируем сперва себе список сессий..
// т.к при вызове terminate()
// у Session будет вызван сигнал "final"
// который приведёт к вызову sessionFinished()..
// в котором этот список будет меняться (удалится сессия из списка)
for( const auto& s : lst )
{
try
{
s->terminate();
}
catch( std::exception& ex ) {}
}
}
// -------------------------------------------------------------------------
void ModbusTCPServer::sessionFinished( const ModbusTCPSession* s )
{
std::lock_guard<std::mutex> l(sMutex);
for( auto i = slist.begin(); i != slist.end(); ++i )
{
if( (*i).get() == s )
{
slist.erase(i);
sessCount--;
asyncResetSockTimeout.send();
return;
}
}
}
// -------------------------------------------------------------------------
void ModbusTCPServer::getSessions( Sessions& lst )
{
std::lock_guard<std::mutex> l(sMutex);
for( const auto& i : slist )
lst.emplace_back( i->getClientAddress(), i->getAskCount() );
}
// -------------------------------------------------------------------------
string ModbusTCPServer::getInetAddress() const noexcept
{
return iaddr;
}
// -------------------------------------------------------------------------
int ModbusTCPServer::getInetPort() const noexcept
{
return port;
}
// -------------------------------------------------------------------------
size_t ModbusTCPServer::getConnectionCount() const noexcept
{
return connCount;
}
// -------------------------------------------------------------------------
ModbusTCPServer::TimerSignal ModbusTCPServer::signal_timer()
{
return m_timer_signal;
}
// -------------------------------------------------------------------------
void ModbusTCPServer::setTimer( timeout_t msec )
{
tmTime_msec = msec;
if( msec == UniSetTimer::WaitUpTime )
{
tmTime = 0;
if( ioTimer.is_active() )
ioTimer.stop();
}
else
{
tmTime = (double)msec / 1000.;
if( ioTimer.is_active() )
ioTimer.start( 0, tmTime );
}
}
// -------------------------------------------------------------------------
timeout_t ModbusTCPServer::getTimer() const noexcept
{
return tmTime_msec;
}
// -------------------------------------------------------------------------
void ModbusTCPServer::setSocketTimeout( timeout_t msec )
{
socketTimeout_msec = msec;
if( msec == UniSetTimer::WaitUpTime || msec == 0 )
{
socketTimeout_msec = 0;
if( sockTimeout.is_active() )
sockTimeout.stop();
}
else
{
tmSockTimeout = (double)msec / 1000.;
if( sockTimeout.is_active() )
sockTimeout.start( 0, tmSockTimeout );
}
}
// ------------------------------------------------------------------------
timeout_t ModbusTCPServer::getSocketTimeout() const noexcept
{
return socketTimeout_msec;
}
// -------------------------------------------------------------------------
void ModbusTCPServer::iowait( timeout_t msec )
{
ptWait.setTiming(msec);
while( !ptWait.checkTime() )
io.loop.iteration();
}
// -------------------------------------------------------------------------
void ModbusTCPServer::ioAccept(ev::io& watcher, int revents)
{
if (EV_ERROR & revents)
{
if( dlog->is_crit() )
dlog->crit() << myname << "(ModbusTCPServer::ioAccept): invalid event" << endl;
return;
}
if( !evIsActive() )
{
if( dlog->is_crit() )
dlog->crit() << myname << "(ModbusTCPServer::ioAccept): terminate work.." << endl;
sock->close();
return;
}
if( sessCount >= maxSessions )
{
if( dlog->is_crit() )
dlog->crit() << myname << "(ModbusTCPServer::ioAccept): session limit(" << maxSessions << ")" << endl;
sock->close();
return;
}
if( dlog->is_info() )
dlog->info() << myname << "(ModbusTCPServer): new connection.." << endl;
try
{
Poco::Net::StreamSocket ss = sock->acceptConnection();
connCount++;
if( sockTimeout.is_active() )
sockTimeout.again();
auto s = make_shared<ModbusTCPSession>(ss, vmbaddr, sessTimeout);
s->connectReadCoil( sigc::mem_fun(this, &ModbusTCPServer::readCoilStatus) );
s->connectReadInputStatus( sigc::mem_fun(this, &ModbusTCPServer::readInputStatus) );
s->connectReadOutput( sigc::mem_fun(this, &ModbusTCPServer::readOutputRegisters) );
s->connectReadInput( sigc::mem_fun(this, &ModbusTCPServer::readInputRegisters) );
s->connectForceSingleCoil( sigc::mem_fun(this, &ModbusTCPServer::forceSingleCoil) );
s->connectForceCoils( sigc::mem_fun(this, &ModbusTCPServer::forceMultipleCoils) );
s->connectWriteOutput( sigc::mem_fun(this, &ModbusTCPServer::writeOutputRegisters) );
s->connectWriteSingleOutput( sigc::mem_fun(this, &ModbusTCPServer::writeOutputSingleRegister) );
s->connectMEIRDI( sigc::mem_fun(this, &ModbusTCPServer::read4314) );
s->connectSetDateTime( sigc::mem_fun(this, &ModbusTCPServer::setDateTime) );
s->connectDiagnostics( sigc::mem_fun(this, &ModbusTCPServer::diagnostics) );
s->connectFileTransfer( sigc::mem_fun(this, &ModbusTCPServer::fileTransfer) );
s->connectJournalCommand( sigc::mem_fun(this, &ModbusTCPServer::journalCommand) );
s->connectRemoteService( sigc::mem_fun(this, &ModbusTCPServer::remoteService) );
s->connectFileTransfer( sigc::mem_fun(this, &ModbusTCPServer::fileTransfer) );
s->setAfterSendPause(aftersend_msec);
s->setReplyTimeout(replyTimeout_ms);
s->setRecvTimeout(recvTimeOut_ms);
s->setSleepPause(sleepPause_msec);
s->setCleanBeforeSend(cleanBeforeSend);
s->setSessionTimeout( (double)sessTimeout / 1000. );
s->signal_post_receive().connect( sigc::mem_fun(this, &ModbusTCPServer::postReceiveEvent) );
s->signal_pre_receive().connect( sigc::mem_fun(this, &ModbusTCPServer::preReceiveEvent) );
s->setLog(dlog);
s->connectFinalSession( sigc::mem_fun(this, &ModbusTCPServer::sessionFinished) );
{
std::lock_guard<std::mutex> l(sMutex);
slist.push_back(s);
}
s->run(loop);
sessCount++;
}
catch( std::exception& ex )
{
if( dlog->is_crit() )
dlog->crit() << myname << "(ModbusTCPServer): new connection error: " << ex.what() << endl;
}
}
// -------------------------------------------------------------------------
void ModbusTCPServer::onTimer( ev::timer& t, int revents )
{
if (EV_ERROR & revents)
{
if( dlog->is_crit() )
dlog->crit() << myname << "(ModbusTCPServer::ioTimer): invalid event" << endl;
return;
}
try
{
m_timer_signal.emit();
}
catch( std::exception& ex )
{
if( dlog->is_crit() )
dlog->crit() << myname << "(onTimer): " << ex.what() << endl;
}
}
// -------------------------------------------------------------------------
void ModbusTCPServer::onSocketResetTimeout( ev::async& watcher, int revents ) noexcept
{
if( EV_ERROR & revents )
{
if( dlog->is_crit() )
dlog->crit() << myname << "(ModbusTCPServer::onSocketResetTimeout): invalid event" << endl;
return;
}
if( dlog->is_info() )
dlog->info() << myname << "(ModbusTCPServer::onSocketResetTimeout): reset socket timeout.." << endl;
if( sockTimeout.is_active() )
sockTimeout.again();
}
// -------------------------------------------------------------------------
void ModbusTCPServer::onSocketTimeout( ev::timer& t, int revents )
{
if (EV_ERROR & revents)
{
if( dlog->is_crit() )
dlog->crit() << myname << "(ModbusTCPServer::onSocketTimeout): invalid event" << endl;
return;
}
{
std::lock_guard<std::mutex> l(sMutex);
if( !slist.empty())
{
if( dlog->is_info() )
dlog->info() << myname << "(ModbusTCPServer::onSocketTimeout): check socket [OK].." << endl;
t.again();
return;
}
}
if( dlog->is_warn() )
dlog->warn() << myname << "(ModbusTCPServer::onSocketTimeout): no connections.. recreate socket.." << endl;
try
{
createSocket();
if( io.is_active() )
io.stop();
io.start(sock->getSocket(), ev::READ);
}
catch( std::exception& ex )
{
if( dlog->is_crit() )
dlog->crit() << myname << "(ModbusTCPServer::onSocketTimeout): recreate socket ERROR: " << ex.what() << endl;
}
t.again();
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPServer::realReceive( const std::unordered_set<ModbusAddr>& vaddr, timeout_t msecTimeout )
{
return ModbusRTU::erOperationFailed;
}
// -------------------------------------------------------------------------
void ModbusTCPServer::postReceiveEvent( mbErrCode res )
{
m_post_signal.emit(res);
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPServer::preReceiveEvent(const std::unordered_set<ModbusAddr> vaddr, timeout_t tout)
{
if( m_pre_signal.empty() )
return ModbusRTU::erNoError;
return m_pre_signal.emit(vaddr, tout);
}
// -------------------------------------------------------------------------
} // end of namespace uniset
......@@ -18,163 +18,163 @@
// -------------------------------------------------------------------------
namespace uniset
{
// -------------------------------------------------------------------------
using namespace ModbusRTU;
using namespace std;
// -------------------------------------------------------------------------
ModbusTCPServerSlot::ModbusTCPServerSlot(const string& ia, int port ):
ModbusTCPServer(ia, port)
{
}
// -------------------------------------------------------------------------
ModbusTCPServerSlot::~ModbusTCPServerSlot()
{
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPServerSlot::readCoilStatus( ReadCoilMessage& query,
ReadCoilRetMessage& reply )
{
if( !slReadCoil )
return erOperationFailed;
return slReadCoil(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPServerSlot::readInputStatus( ReadInputStatusMessage& query,
ReadInputStatusRetMessage& reply )
{
if( !slReadInputStatus )
return erOperationFailed;
return slReadInputStatus(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPServerSlot::readOutputRegisters( ReadOutputMessage& query,
ReadOutputRetMessage& reply )
{
if( !slReadOutputs )
return erOperationFailed;
return slReadOutputs(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPServerSlot::readInputRegisters( ReadInputMessage& query,
ReadInputRetMessage& reply )
{
if( !slReadInputs )
return erOperationFailed;
return slReadInputs(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPServerSlot::forceMultipleCoils( ForceCoilsMessage& query,
ForceCoilsRetMessage& reply )
{
if( !slForceCoils )
return erOperationFailed;
return slForceCoils(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPServerSlot::writeOutputRegisters( WriteOutputMessage& query,
WriteOutputRetMessage& reply )
{
if( !slWriteOutputs )
return erOperationFailed;
return slWriteOutputs(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPServerSlot::diagnostics( DiagnosticMessage& query,
DiagnosticRetMessage& reply )
{
if( !slDiagnostics )
return erOperationFailed;
return slDiagnostics(query, reply);
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode ModbusTCPServerSlot::read4314( ModbusRTU::MEIMessageRDI& query,
ModbusRTU::MEIMessageRetRDI& reply )
{
if( !slMEIRDI )
return erOperationFailed;
return slMEIRDI(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPServerSlot::forceSingleCoil( ForceSingleCoilMessage& query,
ForceSingleCoilRetMessage& reply )
{
if( !slForceSingleCoil )
return erOperationFailed;
return slForceSingleCoil(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPServerSlot::writeOutputSingleRegister( WriteSingleOutputMessage& query,
WriteSingleOutputRetMessage& reply )
{
if( !slWriteSingleOutputs )
return erOperationFailed;
return slWriteSingleOutputs(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPServerSlot::journalCommand( JournalCommandMessage& query,
JournalCommandRetMessage& reply )
{
if( !slJournalCommand )
return erOperationFailed;
return slJournalCommand(query, reply);
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode ModbusTCPServerSlot::setDateTime( ModbusRTU::SetDateTimeMessage& query,
ModbusRTU::SetDateTimeRetMessage& reply )
{
if( !slSetDateTime )
return erOperationFailed;
return slSetDateTime(query, reply);
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode ModbusTCPServerSlot::remoteService( ModbusRTU::RemoteServiceMessage& query,
ModbusRTU::RemoteServiceRetMessage& reply )
{
if( !slRemoteService )
return erOperationFailed;
return slRemoteService(query, reply);
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode ModbusTCPServerSlot::fileTransfer( ModbusRTU::FileTransferMessage& query,
ModbusRTU::FileTransferRetMessage& reply )
{
if( !slFileTransfer )
return erOperationFailed;
return slFileTransfer(query, reply);
}
// -------------------------------------------------------------------------
void ModbusTCPServerSlot::terminate()
{
try
{
ModbusTCPServer::terminate();
}
catch( std::exception& ex ) {}
}
// -------------------------------------------------------------------------
// -------------------------------------------------------------------------
using namespace ModbusRTU;
using namespace std;
// -------------------------------------------------------------------------
ModbusTCPServerSlot::ModbusTCPServerSlot(const string& ia, int port ):
ModbusTCPServer(ia, port)
{
}
// -------------------------------------------------------------------------
ModbusTCPServerSlot::~ModbusTCPServerSlot()
{
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPServerSlot::readCoilStatus( ReadCoilMessage& query,
ReadCoilRetMessage& reply )
{
if( !slReadCoil )
return erOperationFailed;
return slReadCoil(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPServerSlot::readInputStatus( ReadInputStatusMessage& query,
ReadInputStatusRetMessage& reply )
{
if( !slReadInputStatus )
return erOperationFailed;
return slReadInputStatus(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPServerSlot::readOutputRegisters( ReadOutputMessage& query,
ReadOutputRetMessage& reply )
{
if( !slReadOutputs )
return erOperationFailed;
return slReadOutputs(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPServerSlot::readInputRegisters( ReadInputMessage& query,
ReadInputRetMessage& reply )
{
if( !slReadInputs )
return erOperationFailed;
return slReadInputs(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPServerSlot::forceMultipleCoils( ForceCoilsMessage& query,
ForceCoilsRetMessage& reply )
{
if( !slForceCoils )
return erOperationFailed;
return slForceCoils(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPServerSlot::writeOutputRegisters( WriteOutputMessage& query,
WriteOutputRetMessage& reply )
{
if( !slWriteOutputs )
return erOperationFailed;
return slWriteOutputs(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPServerSlot::diagnostics( DiagnosticMessage& query,
DiagnosticRetMessage& reply )
{
if( !slDiagnostics )
return erOperationFailed;
return slDiagnostics(query, reply);
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode ModbusTCPServerSlot::read4314( ModbusRTU::MEIMessageRDI& query,
ModbusRTU::MEIMessageRetRDI& reply )
{
if( !slMEIRDI )
return erOperationFailed;
return slMEIRDI(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPServerSlot::forceSingleCoil( ForceSingleCoilMessage& query,
ForceSingleCoilRetMessage& reply )
{
if( !slForceSingleCoil )
return erOperationFailed;
return slForceSingleCoil(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPServerSlot::writeOutputSingleRegister( WriteSingleOutputMessage& query,
WriteSingleOutputRetMessage& reply )
{
if( !slWriteSingleOutputs )
return erOperationFailed;
return slWriteSingleOutputs(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPServerSlot::journalCommand( JournalCommandMessage& query,
JournalCommandRetMessage& reply )
{
if( !slJournalCommand )
return erOperationFailed;
return slJournalCommand(query, reply);
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode ModbusTCPServerSlot::setDateTime( ModbusRTU::SetDateTimeMessage& query,
ModbusRTU::SetDateTimeRetMessage& reply )
{
if( !slSetDateTime )
return erOperationFailed;
return slSetDateTime(query, reply);
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode ModbusTCPServerSlot::remoteService( ModbusRTU::RemoteServiceMessage& query,
ModbusRTU::RemoteServiceRetMessage& reply )
{
if( !slRemoteService )
return erOperationFailed;
return slRemoteService(query, reply);
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode ModbusTCPServerSlot::fileTransfer( ModbusRTU::FileTransferMessage& query,
ModbusRTU::FileTransferRetMessage& reply )
{
if( !slFileTransfer )
return erOperationFailed;
return slFileTransfer(query, reply);
}
// -------------------------------------------------------------------------
void ModbusTCPServerSlot::terminate()
{
try
{
ModbusTCPServer::terminate();
}
catch( std::exception& ex ) {}
}
// -------------------------------------------------------------------------
} // end of namespace uniset
......@@ -29,567 +29,567 @@
// -------------------------------------------------------------------------
namespace uniset
{
// -------------------------------------------------------------------------
using namespace std;
using namespace ModbusRTU;
using namespace uniset;
// -------------------------------------------------------------------------
ModbusTCPSession::~ModbusTCPSession()
{
cancelled = true;
if( io.is_active() )
io.stop();
if( ioTimeout.is_active() )
ioTimeout.stop();
}
// -------------------------------------------------------------------------
ModbusTCPSession::ModbusTCPSession(const Poco::Net::StreamSocket& s, const std::unordered_set<ModbusAddr>& a, timeout_t timeout ):
vaddr(a),
timeout(timeout),
peername(""),
caddr(""),
cancelled(false)
{
try
{
sock = make_shared<UTCPStream>(s);
// если стремиться к "оптимизации по скорости"
// то getpeername "медленная" операция и может стоит от неё отказаться.
Poco::Net::SocketAddress iaddr = sock->peerAddress();
if( iaddr.host().toString().empty() )
{
ostringstream err;
err << "(ModbusTCPSession): unknonwn ip(0.0.0.0) client disconnected?!";
if( dlog->is_crit() )
dlog->crit() << err.str() << endl;
sock.reset();
throw SystemError(err.str());
}
caddr = iaddr.host().toString();
ostringstream s;
s << caddr << ":" << iaddr.port();
peername = s.str();
}
catch( const Poco::Net::NetException& ex )
{
if( dlog->is_crit() )
dlog->crit() << "(ModbusTCPSession): err: " << ex.displayText() << endl;
sock.reset();
throw SystemError(ex.message());
}
sock->setBlocking(false); // fcntl(sfd, F_SETFL, fcntl(sfd, F_GETFL, 0) | O_NONBLOCK);
setCRCNoCheckit(true);
timeout_t tout = timeout / 1000;
if( tout <= 0 )
tout = 3;
io.set<ModbusTCPSession, &ModbusTCPSession::callback>(this);
ioTimeout.set<ModbusTCPSession, &ModbusTCPSession::onTimeout>(this);
}
// -------------------------------------------------------------------------
void ModbusTCPSession::setSessionTimeout( double t )
{
sessTimeout = t;
if( t <= 0 )
ioTimeout.stop();
else if( ioTimeout.is_active() )
ioTimeout.start(t);
}
// -------------------------------------------------------------------------
void ModbusTCPSession::iowait( timeout_t msec )
{
ptWait.setTiming(msec);
while( !ptWait.checkTime() )
io.loop.iteration();
}
// -------------------------------------------------------------------------
void ModbusTCPSession::run( ev::loop_ref& loop )
{
if( dlog->is_info() )
dlog->info() << peername << "(run): run session.." << endl;
io.set(loop);
io.start(sock->getSocket(), ev::READ);
ioTimeout.set(loop);
if( sessTimeout > 0 )
ioTimeout.start(sessTimeout);
}
// -------------------------------------------------------------------------
bool ModbusTCPSession::isActive() const
{
return io.is_active();
}
// -------------------------------------------------------------------------
void ModbusTCPSession::callback( ev::io& watcher, int revents )
{
if( EV_ERROR & revents )
{
if( dlog->is_crit() )
dlog->crit() << peername << "(callback): EVENT ERROR.." << endl;
return;
}
if (revents & EV_READ)
readEvent(watcher);
if (revents & EV_WRITE)
writeEvent(watcher);
if( qsend.empty() )
io.set(ev::READ);
else
io.set(ev::READ | ev::WRITE);
if( cancelled )
{
if( dlog->is_info() )
dlog->info() << peername << ": stop session... disconnect.." << endl;
terminate();
}
else if( sessTimeout > 0 )
ioTimeout.start(sessTimeout); // restart timer..
}
// -------------------------------------------------------------------------
void ModbusTCPSession::onTimeout( ev::timer& t, int revents )
{
if( dlog->is_info() )
dlog->info() << peername << ": timeout connection activity..(terminate session)" << endl;
t.stop();
terminate();
}
// -------------------------------------------------------------------------
void ModbusTCPSession::readEvent( ev::io& watcher )
{
if( receive(vaddr, timeout) == erSessionClosed )
cancelled = true;
}
// -------------------------------------------------------------------------
void ModbusTCPSession::writeEvent( ev::io& watcher )
{
if( qsend.empty() )
return;
UTCPCore::Buffer* buffer = qsend.front();
ssize_t ret = write(watcher.fd, buffer->dpos(), buffer->nbytes());
if( ret < 0 )
{
if( dlog->is_warn() )
dlog->warn() << peername << "(writeEvent): write to socket error: " << strerror(errno) << endl;
return;
}
buffer->pos += ret;
if( buffer->nbytes() == 0 )
{
qsend.pop();
delete buffer;
}
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode ModbusTCPSession::realReceive( const std::unordered_set<ModbusAddr>& vmbaddr, timeout_t msec )
{
ModbusRTU::mbErrCode res = erTimeOut;
ptTimeout.setTiming(msec);
try
{
buf.clear();
res = tcp_processing(buf.mbaphead);
if( res != erNoError )
return res;
if( msec != UniSetTimer::WaitUpTime )
{
msec = ptTimeout.getLeft(msec);
if( msec == 0 ) // времени для ответа не осталось..
return erTimeOut;
}
if( qrecv.empty() )
return erTimeOut;
if( cancelled )
return erSessionClosed;
// запоминаем принятый заголовок,
// для формирования ответа (см. make_adu_header)
curQueryHeader = buf.mbaphead;
if( dlog->is_level9() )
dlog->level9() << "(ModbusTCPSession::recv): ADU len=" << curQueryHeader.len << endl;
res = recv( vmbaddr, buf, msec );
if( cancelled )
return erSessionClosed;
if( res != erNoError ) // && res!=erBadReplyNodeAddress )
{
if( res < erInternalErrorCode )
{
ErrorRetMessage em( buf.addr(), buf.func(), res );
buf = em.transport_msg();
send(buf);
printProcessingTime();
}
else if( aftersend_msec > 0 )
iowait(aftersend_msec);
return res;
}
if( msec != UniSetTimer::WaitUpTime )
{
msec = ptTimeout.getLeft(msec);
if( msec == 0 )
return erTimeOut;
}
if( cancelled )
return erSessionClosed;
// processing message...
res = processing(buf);
}
catch( uniset::CommFailed& ex )
{
cancelled = true;
return erSessionClosed;
}
return res;
}
// -------------------------------------------------------------------------
void ModbusTCPSession::final()
{
slFin(this);
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPSession::sendData( unsigned char* buf, int len )
{
qsend.emplace( new UTCPCore::Buffer(buf, len) );
return erNoError;
}
// -------------------------------------------------------------------------
size_t ModbusTCPSession::getNextData( unsigned char* buf, int len )
{
ssize_t res = ModbusTCPCore::getDataFD( sock->getSocket(), qrecv, buf, len );
try
{
if( res > 0 )
return res;
if( res < 0 )
{
int errnum = errno;
if( errnum != EAGAIN && dlog->is_warn() )
dlog->warn() << peername << "(getNextData): read from socket error(" << errnum << "): " << strerror(errnum) << endl;
return 0;
}
}
catch( const uniset::CommFailed& ex ){}
if( !cancelled && dlog->is_info() )
dlog->info() << peername << "(getNextData): client disconnected" << endl;
cancelled = true;
return 0;
}
// --------------------------------------------------------------------------------
mbErrCode ModbusTCPSession::tcp_processing( ModbusRTU::MBAPHeader& mhead )
{
// чистим очередь
while( !qrecv.empty() )
qrecv.pop();
size_t len = getNextData((unsigned char*)(&mhead), sizeof(mhead));
//size_t len = ModbusTCPCore::getDataFD( sfd, qrecv, (unsigned char*)(&mhead), sizeof(mhead) );
if( len < sizeof(mhead) )
{
if( len == 0 )
return erSessionClosed;
return erInvalidFormat;
}
mhead.swapdata();
if( dlog->is_level9() )
{
dlog->level9() << peername << "(tcp_processing): recv tcp header(" << len << "): ";
mbPrintMessage( dlog->level9(false), (ModbusByte*)(&mhead), sizeof(mhead));
dlog->level9(false) << endl;
}
// check header
if( mhead.pID != 0 )
return erUnExpectedPacketType; // erTimeOut;
if( mhead.len == 0 )
{
if( dlog->is_warn() )
dlog->warn() << "(ModbusTCPServer::tcp_processing): BAD FORMAT: len=0!" << endl;
return erInvalidFormat;
}
if( mhead.len > ModbusRTU::MAXLENPACKET )
{
if( dlog->is_warn() )
dlog->warn() << "(ModbusTCPServer::tcp_processing): len(" << (int)mhead.len
<< ") < MAXLENPACKET(" << ModbusRTU::MAXLENPACKET << ")" << endl;
return erInvalidFormat;
}
pt.setTiming(10);
try
{
do
{
len = ModbusTCPCore::readDataFD( sock->getSocket(), qrecv, mhead.len );
if( len == 0 )
io.loop.iteration();
}
while( len == 0 && !pt.checkTime() );
}
catch( const uniset::CommFailed& ex ){}
if( len < mhead.len )
{
if( dlog->is_warn() )
dlog->warn() << peername << "(tcp_processing): len(" << (int)len
<< ") < mhead.len(" << (int)mhead.len << ")" << endl;
return erInvalidFormat;
}
return erNoError;
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode ModbusTCPSession::post_send_request( ModbusRTU::ModbusMessage& request )
{
return erNoError;
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPSession::make_adu_header( ModbusMessage& req )
{
req.makeMBAPHeader(curQueryHeader.tID, isCRCNoCheckit(), curQueryHeader.pID);
return erNoError;
}
// -------------------------------------------------------------------------
void ModbusTCPSession::cleanInputStream()
{
unsigned char tmpbuf[100];
size_t ret = 0;
do
{
ret = getNextData(tmpbuf, sizeof(tmpbuf));
}
while( ret > 0);
}
// -------------------------------------------------------------------------
void ModbusTCPSession::cleanupChannel()
{
cleanInputStream();
}
// -------------------------------------------------------------------------
void ModbusTCPSession::terminate()
{
if( dlog->is_info() )
dlog->info() << peername << "(terminate)..." << endl;
cancelled = true;
io.stop();
ioTimeout.stop();
ModbusServer::terminate();
sock.reset(); // close..
final(); // после этого вызова возможно данный объект будет разрушен!
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPSession::readCoilStatus( ReadCoilMessage& query,
ReadCoilRetMessage& reply )
{
if( !slReadCoil )
return erOperationFailed;
return slReadCoil(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPSession::readInputStatus( ReadInputStatusMessage& query,
ReadInputStatusRetMessage& reply )
{
if( !slReadInputStatus )
return erOperationFailed;
return slReadInputStatus(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPSession::readOutputRegisters( ReadOutputMessage& query,
ReadOutputRetMessage& reply )
{
if( !slReadOutputs )
return erOperationFailed;
return slReadOutputs(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPSession::readInputRegisters( ReadInputMessage& query,
ReadInputRetMessage& reply )
{
if( !slReadInputs )
return erOperationFailed;
return slReadInputs(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPSession::forceMultipleCoils( ForceCoilsMessage& query,
ForceCoilsRetMessage& reply )
{
if( !slForceCoils )
return erOperationFailed;
return slForceCoils(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPSession::writeOutputRegisters( WriteOutputMessage& query,
WriteOutputRetMessage& reply )
{
if( !slWriteOutputs )
return erOperationFailed;
return slWriteOutputs(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPSession::diagnostics( DiagnosticMessage& query,
DiagnosticRetMessage& reply )
{
if( !slDiagnostics )
return erOperationFailed;
return slDiagnostics(query, reply);
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode ModbusTCPSession::read4314( ModbusRTU::MEIMessageRDI& query,
ModbusRTU::MEIMessageRetRDI& reply )
{
if( !slMEIRDI )
return erOperationFailed;
return slMEIRDI(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPSession::forceSingleCoil( ForceSingleCoilMessage& query,
ForceSingleCoilRetMessage& reply )
{
if( !slForceSingleCoil )
return erOperationFailed;
return slForceSingleCoil(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPSession::writeOutputSingleRegister( WriteSingleOutputMessage& query,
WriteSingleOutputRetMessage& reply )
{
if( !slWriteSingleOutputs )
return erOperationFailed;
return slWriteSingleOutputs(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPSession::journalCommand( JournalCommandMessage& query,
JournalCommandRetMessage& reply )
{
if( !slJournalCommand )
return erOperationFailed;
return slJournalCommand(query, reply);
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode ModbusTCPSession::setDateTime( ModbusRTU::SetDateTimeMessage& query,
ModbusRTU::SetDateTimeRetMessage& reply )
{
if( !slSetDateTime )
return erOperationFailed;
return slSetDateTime(query, reply);
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode ModbusTCPSession::remoteService( ModbusRTU::RemoteServiceMessage& query,
ModbusRTU::RemoteServiceRetMessage& reply )
{
if( !slRemoteService )
return erOperationFailed;
return slRemoteService(query, reply);
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode ModbusTCPSession::fileTransfer( ModbusRTU::FileTransferMessage& query,
ModbusRTU::FileTransferRetMessage& reply )
{
if( !slFileTransfer )
return erOperationFailed;
return slFileTransfer(query, reply);
}
// -------------------------------------------------------------------------
void ModbusTCPSession::setChannelTimeout( timeout_t msec )
{
setSessionTimeout(msec);
}
// -------------------------------------------------------------------------
void ModbusTCPSession::connectFinalSession( FinalSlot sl )
{
slFin = sl;
}
// -------------------------------------------------------------------------
string ModbusTCPSession::getClientAddress() const
{
return caddr;
}
// -------------------------------------------------------------------------
// -------------------------------------------------------------------------
using namespace std;
using namespace ModbusRTU;
using namespace uniset;
// -------------------------------------------------------------------------
ModbusTCPSession::~ModbusTCPSession()
{
cancelled = true;
if( io.is_active() )
io.stop();
if( ioTimeout.is_active() )
ioTimeout.stop();
}
// -------------------------------------------------------------------------
ModbusTCPSession::ModbusTCPSession(const Poco::Net::StreamSocket& s, const std::unordered_set<ModbusAddr>& a, timeout_t timeout ):
vaddr(a),
timeout(timeout),
peername(""),
caddr(""),
cancelled(false)
{
try
{
sock = make_shared<UTCPStream>(s);
// если стремиться к "оптимизации по скорости"
// то getpeername "медленная" операция и может стоит от неё отказаться.
Poco::Net::SocketAddress iaddr = sock->peerAddress();
if( iaddr.host().toString().empty() )
{
ostringstream err;
err << "(ModbusTCPSession): unknonwn ip(0.0.0.0) client disconnected?!";
if( dlog->is_crit() )
dlog->crit() << err.str() << endl;
sock.reset();
throw SystemError(err.str());
}
caddr = iaddr.host().toString();
ostringstream s;
s << caddr << ":" << iaddr.port();
peername = s.str();
}
catch( const Poco::Net::NetException& ex )
{
if( dlog->is_crit() )
dlog->crit() << "(ModbusTCPSession): err: " << ex.displayText() << endl;
sock.reset();
throw SystemError(ex.message());
}
sock->setBlocking(false); // fcntl(sfd, F_SETFL, fcntl(sfd, F_GETFL, 0) | O_NONBLOCK);
setCRCNoCheckit(true);
timeout_t tout = timeout / 1000;
if( tout <= 0 )
tout = 3;
io.set<ModbusTCPSession, &ModbusTCPSession::callback>(this);
ioTimeout.set<ModbusTCPSession, &ModbusTCPSession::onTimeout>(this);
}
// -------------------------------------------------------------------------
void ModbusTCPSession::setSessionTimeout( double t )
{
sessTimeout = t;
if( t <= 0 )
ioTimeout.stop();
else if( ioTimeout.is_active() )
ioTimeout.start(t);
}
// -------------------------------------------------------------------------
void ModbusTCPSession::iowait( timeout_t msec )
{
ptWait.setTiming(msec);
while( !ptWait.checkTime() )
io.loop.iteration();
}
// -------------------------------------------------------------------------
void ModbusTCPSession::run( ev::loop_ref& loop )
{
if( dlog->is_info() )
dlog->info() << peername << "(run): run session.." << endl;
io.set(loop);
io.start(sock->getSocket(), ev::READ);
ioTimeout.set(loop);
if( sessTimeout > 0 )
ioTimeout.start(sessTimeout);
}
// -------------------------------------------------------------------------
bool ModbusTCPSession::isActive() const
{
return io.is_active();
}
// -------------------------------------------------------------------------
void ModbusTCPSession::callback( ev::io& watcher, int revents )
{
if( EV_ERROR & revents )
{
if( dlog->is_crit() )
dlog->crit() << peername << "(callback): EVENT ERROR.." << endl;
return;
}
if (revents & EV_READ)
readEvent(watcher);
if (revents & EV_WRITE)
writeEvent(watcher);
if( qsend.empty() )
io.set(ev::READ);
else
io.set(ev::READ | ev::WRITE);
if( cancelled )
{
if( dlog->is_info() )
dlog->info() << peername << ": stop session... disconnect.." << endl;
terminate();
}
else if( sessTimeout > 0 )
ioTimeout.start(sessTimeout); // restart timer..
}
// -------------------------------------------------------------------------
void ModbusTCPSession::onTimeout( ev::timer& t, int revents )
{
if( dlog->is_info() )
dlog->info() << peername << ": timeout connection activity..(terminate session)" << endl;
t.stop();
terminate();
}
// -------------------------------------------------------------------------
void ModbusTCPSession::readEvent( ev::io& watcher )
{
if( receive(vaddr, timeout) == erSessionClosed )
cancelled = true;
}
// -------------------------------------------------------------------------
void ModbusTCPSession::writeEvent( ev::io& watcher )
{
if( qsend.empty() )
return;
UTCPCore::Buffer* buffer = qsend.front();
ssize_t ret = write(watcher.fd, buffer->dpos(), buffer->nbytes());
if( ret < 0 )
{
if( dlog->is_warn() )
dlog->warn() << peername << "(writeEvent): write to socket error: " << strerror(errno) << endl;
return;
}
buffer->pos += ret;
if( buffer->nbytes() == 0 )
{
qsend.pop();
delete buffer;
}
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode ModbusTCPSession::realReceive( const std::unordered_set<ModbusAddr>& vmbaddr, timeout_t msec )
{
ModbusRTU::mbErrCode res = erTimeOut;
ptTimeout.setTiming(msec);
try
{
buf.clear();
res = tcp_processing(buf.mbaphead);
if( res != erNoError )
return res;
if( msec != UniSetTimer::WaitUpTime )
{
msec = ptTimeout.getLeft(msec);
if( msec == 0 ) // времени для ответа не осталось..
return erTimeOut;
}
if( qrecv.empty() )
return erTimeOut;
if( cancelled )
return erSessionClosed;
// запоминаем принятый заголовок,
// для формирования ответа (см. make_adu_header)
curQueryHeader = buf.mbaphead;
if( dlog->is_level9() )
dlog->level9() << "(ModbusTCPSession::recv): ADU len=" << curQueryHeader.len << endl;
res = recv( vmbaddr, buf, msec );
if( cancelled )
return erSessionClosed;
if( res != erNoError ) // && res!=erBadReplyNodeAddress )
{
if( res < erInternalErrorCode )
{
ErrorRetMessage em( buf.addr(), buf.func(), res );
buf = em.transport_msg();
send(buf);
printProcessingTime();
}
else if( aftersend_msec > 0 )
iowait(aftersend_msec);
return res;
}
if( msec != UniSetTimer::WaitUpTime )
{
msec = ptTimeout.getLeft(msec);
if( msec == 0 )
return erTimeOut;
}
if( cancelled )
return erSessionClosed;
// processing message...
res = processing(buf);
}
catch( uniset::CommFailed& ex )
{
cancelled = true;
return erSessionClosed;
}
return res;
}
// -------------------------------------------------------------------------
void ModbusTCPSession::final()
{
slFin(this);
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPSession::sendData( unsigned char* buf, int len )
{
qsend.emplace( new UTCPCore::Buffer(buf, len) );
return erNoError;
}
// -------------------------------------------------------------------------
size_t ModbusTCPSession::getNextData( unsigned char* buf, int len )
{
ssize_t res = ModbusTCPCore::getDataFD( sock->getSocket(), qrecv, buf, len );
try
{
if( res > 0 )
return res;
if( res < 0 )
{
int errnum = errno;
if( errnum != EAGAIN && dlog->is_warn() )
dlog->warn() << peername << "(getNextData): read from socket error(" << errnum << "): " << strerror(errnum) << endl;
return 0;
}
}
catch( const uniset::CommFailed& ex ) {}
if( !cancelled && dlog->is_info() )
dlog->info() << peername << "(getNextData): client disconnected" << endl;
cancelled = true;
return 0;
}
// --------------------------------------------------------------------------------
mbErrCode ModbusTCPSession::tcp_processing( ModbusRTU::MBAPHeader& mhead )
{
// чистим очередь
while( !qrecv.empty() )
qrecv.pop();
size_t len = getNextData((unsigned char*)(&mhead), sizeof(mhead));
//size_t len = ModbusTCPCore::getDataFD( sfd, qrecv, (unsigned char*)(&mhead), sizeof(mhead) );
if( len < sizeof(mhead) )
{
if( len == 0 )
return erSessionClosed;
return erInvalidFormat;
}
mhead.swapdata();
if( dlog->is_level9() )
{
dlog->level9() << peername << "(tcp_processing): recv tcp header(" << len << "): ";
mbPrintMessage( dlog->level9(false), (ModbusByte*)(&mhead), sizeof(mhead));
dlog->level9(false) << endl;
}
// check header
if( mhead.pID != 0 )
return erUnExpectedPacketType; // erTimeOut;
if( mhead.len == 0 )
{
if( dlog->is_warn() )
dlog->warn() << "(ModbusTCPServer::tcp_processing): BAD FORMAT: len=0!" << endl;
return erInvalidFormat;
}
if( mhead.len > ModbusRTU::MAXLENPACKET )
{
if( dlog->is_warn() )
dlog->warn() << "(ModbusTCPServer::tcp_processing): len(" << (int)mhead.len
<< ") < MAXLENPACKET(" << ModbusRTU::MAXLENPACKET << ")" << endl;
return erInvalidFormat;
}
pt.setTiming(10);
try
{
do
{
len = ModbusTCPCore::readDataFD( sock->getSocket(), qrecv, mhead.len );
if( len == 0 )
io.loop.iteration();
}
while( len == 0 && !pt.checkTime() );
}
catch( const uniset::CommFailed& ex ) {}
if( len < mhead.len )
{
if( dlog->is_warn() )
dlog->warn() << peername << "(tcp_processing): len(" << (int)len
<< ") < mhead.len(" << (int)mhead.len << ")" << endl;
return erInvalidFormat;
}
return erNoError;
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode ModbusTCPSession::post_send_request( ModbusRTU::ModbusMessage& request )
{
return erNoError;
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPSession::make_adu_header( ModbusMessage& req )
{
req.makeMBAPHeader(curQueryHeader.tID, isCRCNoCheckit(), curQueryHeader.pID);
return erNoError;
}
// -------------------------------------------------------------------------
void ModbusTCPSession::cleanInputStream()
{
unsigned char tmpbuf[100];
size_t ret = 0;
do
{
ret = getNextData(tmpbuf, sizeof(tmpbuf));
}
while( ret > 0);
}
// -------------------------------------------------------------------------
void ModbusTCPSession::cleanupChannel()
{
cleanInputStream();
}
// -------------------------------------------------------------------------
void ModbusTCPSession::terminate()
{
if( dlog->is_info() )
dlog->info() << peername << "(terminate)..." << endl;
cancelled = true;
io.stop();
ioTimeout.stop();
ModbusServer::terminate();
sock.reset(); // close..
final(); // после этого вызова возможно данный объект будет разрушен!
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPSession::readCoilStatus( ReadCoilMessage& query,
ReadCoilRetMessage& reply )
{
if( !slReadCoil )
return erOperationFailed;
return slReadCoil(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPSession::readInputStatus( ReadInputStatusMessage& query,
ReadInputStatusRetMessage& reply )
{
if( !slReadInputStatus )
return erOperationFailed;
return slReadInputStatus(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPSession::readOutputRegisters( ReadOutputMessage& query,
ReadOutputRetMessage& reply )
{
if( !slReadOutputs )
return erOperationFailed;
return slReadOutputs(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPSession::readInputRegisters( ReadInputMessage& query,
ReadInputRetMessage& reply )
{
if( !slReadInputs )
return erOperationFailed;
return slReadInputs(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPSession::forceMultipleCoils( ForceCoilsMessage& query,
ForceCoilsRetMessage& reply )
{
if( !slForceCoils )
return erOperationFailed;
return slForceCoils(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPSession::writeOutputRegisters( WriteOutputMessage& query,
WriteOutputRetMessage& reply )
{
if( !slWriteOutputs )
return erOperationFailed;
return slWriteOutputs(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPSession::diagnostics( DiagnosticMessage& query,
DiagnosticRetMessage& reply )
{
if( !slDiagnostics )
return erOperationFailed;
return slDiagnostics(query, reply);
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode ModbusTCPSession::read4314( ModbusRTU::MEIMessageRDI& query,
ModbusRTU::MEIMessageRetRDI& reply )
{
if( !slMEIRDI )
return erOperationFailed;
return slMEIRDI(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPSession::forceSingleCoil( ForceSingleCoilMessage& query,
ForceSingleCoilRetMessage& reply )
{
if( !slForceSingleCoil )
return erOperationFailed;
return slForceSingleCoil(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPSession::writeOutputSingleRegister( WriteSingleOutputMessage& query,
WriteSingleOutputRetMessage& reply )
{
if( !slWriteSingleOutputs )
return erOperationFailed;
return slWriteSingleOutputs(query, reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPSession::journalCommand( JournalCommandMessage& query,
JournalCommandRetMessage& reply )
{
if( !slJournalCommand )
return erOperationFailed;
return slJournalCommand(query, reply);
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode ModbusTCPSession::setDateTime( ModbusRTU::SetDateTimeMessage& query,
ModbusRTU::SetDateTimeRetMessage& reply )
{
if( !slSetDateTime )
return erOperationFailed;
return slSetDateTime(query, reply);
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode ModbusTCPSession::remoteService( ModbusRTU::RemoteServiceMessage& query,
ModbusRTU::RemoteServiceRetMessage& reply )
{
if( !slRemoteService )
return erOperationFailed;
return slRemoteService(query, reply);
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode ModbusTCPSession::fileTransfer( ModbusRTU::FileTransferMessage& query,
ModbusRTU::FileTransferRetMessage& reply )
{
if( !slFileTransfer )
return erOperationFailed;
return slFileTransfer(query, reply);
}
// -------------------------------------------------------------------------
void ModbusTCPSession::setChannelTimeout( timeout_t msec )
{
setSessionTimeout(msec);
}
// -------------------------------------------------------------------------
void ModbusTCPSession::connectFinalSession( FinalSlot sl )
{
slFin = sl;
}
// -------------------------------------------------------------------------
string ModbusTCPSession::getClientAddress() const
{
return caddr;
}
// -------------------------------------------------------------------------
} // end of namespace uniset
This source diff could not be displayed because it is too large. You can view the blob instead.
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