Commit 19906299 authored by Pavel Vainerman's avatar Pavel Vainerman

(ModbusMaster): рефакторинг: переписан механизм определения пропажи связи

с опрашиваемым устройством.
parent 86bdc3e4
......@@ -495,7 +495,7 @@ std::ostream& operator<<( std::ostream& os, MBExchange::RTUDevice& d )
os << "addr=" << ModbusRTU::addr2str(d.mbaddr)
<< " type=" << d.dtype
<< " respond_id=" << d.resp_id
<< " respond_timeout=" << d.resp_ptTimeout.getInterval()
<< " respond_timeout=" << d.resp_Delay.getOffDelay()
<< " respond_state=" << d.resp_state
<< " respond_invert=" << d.resp_invert
<< endl;
......@@ -2672,8 +2672,9 @@ bool MBExchange::initDeviceInfo( RTUDeviceMap& m, ModbusRTU::ModbusAddr a, UniXM
}
dinfo << myname << "(initDeviceInfo): add addr=" << ModbusRTU::addr2str(a) << endl;
int tout = it.getPIntProp("timeout", 5000);
d->second->resp_ptTimeout.setTiming(tout);
int tout = it.getPIntProp("timeout", ptTimeout.getInterval() );
d->second->resp_Delay.set(0,tout); // ставим время на отпускание.. см. checkRespond()
d->second->resp_invert = it.getIntProp("invert");
return true;
}
......@@ -2945,12 +2946,6 @@ bool MBExchange::poll()
uniset_rwmutex_wrlock l(pollMutex);
pollActivated = false;
mb = initMB(false);
if( !mb )
{
for( auto it = rmap.begin(); it != rmap.end(); ++it )
it->second->resp_real = false;
}
}
if( !checkProcActive() )
......@@ -2985,7 +2980,7 @@ bool MBExchange::poll()
dlog3 << myname << "(poll): ask addr=" << ModbusRTU::addr2str(d->mbaddr)
<< " regs=" << d->regmap.size() << endl;
d->resp_real = false;
int prev_numreply = d->numreply.load();
for( auto it = d->regmap.begin(); it != d->regmap.end(); ++it )
{
......@@ -2993,38 +2988,28 @@ bool MBExchange::poll()
return false;
if( exchangeMode == emSkipExchange )
{
d->resp_real = false;
continue;
}
try
{
if( d->dtype == MBExchange::dtRTU || d->dtype == MBExchange::dtMTR )
{
if( pollRTU(d, it) )
d->resp_real = true;
d->numreply++;
}
}
catch( ModbusRTU::mbException& ex )
{
// if( d->resp_real )
// {
dlog3 << myname << "(poll): FAILED ask addr=" << ModbusRTU::addr2str(d->mbaddr)
<< " reg=" << ModbusRTU::dat2str(it->second->mbreg)
<< " for sensors: ";
print_plist(dlog()->level3(), it->second->slst)
<< endl << " err: " << ex << endl;
// d->resp_real = false;
if( ex.err == ModbusRTU::erTimeOut && !d->ask_every_reg )
break;
if( ex.err == ModbusRTU::erNoError )
d->resp_real = true;
}
if( d->resp_real )
if( d->numreply != prev_numreply )
allNotRespond = false;
if( it == d->regmap.end() )
......@@ -3085,52 +3070,26 @@ bool MBExchange::RTUDevice::checkRespond()
{
bool prev = resp_state;
if( resp_ptTimeout.getInterval() <= 0 )
{
resp_state = resp_real;
return (prev != resp_state);
}
if( resp_trTimeout.hi(resp_state && !resp_real) || resp_real )
resp_ptTimeout.reset();
resp_state = resp_Delay.check( prev_numreply!=numreply );
if( resp_real )
resp_state = true;
else if( resp_state && !resp_real && resp_ptTimeout.checkTime() )
resp_state = false;
prev_numreply.store(numreply);
// если ещё не инициализировали значение в SM
// то возвращаем true, чтобы оно принудительно сохранилось
if( !resp_init )
{
resp_state = resp_real;
resp_init = true;
prev = resp_state;
return true;
}
return ( prev != resp_state );
return (prev!=resp_state);
}
// -----------------------------------------------------------------------------
void MBExchange::updateRespondSensors()
{
bool chanTimeout = false;
{
uniset_rwmutex_rlock l(pollMutex);
chanTimeout = pollActivated && ptTimeout.checkTime();
}
for( auto it1 = rmap.begin(); it1 != rmap.end(); ++it1 )
for( const auto& it1: rmap )
{
RTUDevice* d(it1->second);
if( chanTimeout )
d->resp_real = false;
RTUDevice* d(it1.second);
dlog4 << myname << ": check respond addr=" << ModbusRTU::addr2str(d->mbaddr)
<< " respond_id=" << d->resp_id
<< " real=" << d->resp_real
<< " state=" << d->resp_state
<< " [timeout=" << d->resp_Delay.getOffDelay()
<< " numreply=" << d->numreply
<< " prev_numreply=" << d->prev_numreply
<< " ]"
<< endl;
if( d->checkRespond() && d->resp_id != DefaultObjectId )
......
......@@ -9,6 +9,7 @@
#include "IONotifyController.h"
#include "UniSetObject_LT.h"
#include "PassiveTimer.h"
#include "DelayTimer.h"
#include "Trigger.h"
#include "Mutex.h"
#include "Calibration.h"
......@@ -156,15 +157,14 @@ class MBExchange:
resp_id(UniSetTypes::DefaultObjectId),
resp_state(false),
resp_invert(false),
resp_real(false),
resp_init(false),
numreply(0),
prev_numreply(0),
ask_every_reg(false),
mode_id(UniSetTypes::DefaultObjectId),
mode(emNone),
speed(ComPort::ComSpeed38400),
rtu(0)
{
resp_trTimeout.change(false);
}
bool respnond;
......@@ -173,15 +173,19 @@ class MBExchange:
DeviceType dtype; /*!< тип устройства */
// resp - respond..(контроль наличия связи)
UniSetTypes::ObjectId resp_id;
IOController::IOStateList::iterator resp_it;
PassiveTimer resp_ptTimeout;
Trigger resp_trTimeout;
DelayTimer resp_Delay; // таймер для формирования задержки на отпускание (пропадание связи)
bool resp_state;
bool resp_invert;
bool resp_real;
bool resp_init;
bool ask_every_reg;
std::atomic<unsigned int> numreply; // количество успешных запросов..
std::atomic<unsigned int> prev_numreply;
//
bool ask_every_reg; /*!< опрашивать ли каждый регистр, независимо от результата опроса предыдущего. По умолчанию false - прервать опрос при первом же timeout */
// режим работы
UniSetTypes::ObjectId mode_id;
IOController::IOStateList::iterator mode_it;
long mode; // режим работы с устройством (см. ExchangeMode)
......
......@@ -184,12 +184,6 @@ bool RTUExchange::poll()
uniset_rwmutex_wrlock l(pollMutex);
pollActivated = false;
mb = initMB(false);
if( !mb )
{
for( auto& it : rmap )
it.second->resp_real = false;
}
}
if( !checkProcActive() )
......@@ -228,6 +222,7 @@ bool RTUExchange::poll()
mbrtu->setSpeed(d->speed);
}
int prev_numreply = d->numreply;
if( d->dtype == MBExchange::dtRTU188 )
{
if( !d->rtu )
......@@ -243,15 +238,14 @@ bool RTUExchange::poll()
mb->cleanupChannel();
d->rtu->poll(mbrtu);
d->resp_real = true;
d->numreply++;
}
catch( ModbusRTU::mbException& ex )
{
if( d->resp_real )
if( d->numreply != d->prev_numreply )
{
dlog3 << myname << "(poll): FAILED ask addr=" << ModbusRTU::addr2str(d->mbaddr)
<< " -> " << ex << endl;
d->resp_real = false;
}
}
}
......@@ -260,8 +254,6 @@ bool RTUExchange::poll()
dlog3 << myname << "(poll): ask addr=" << ModbusRTU::addr2str(d->mbaddr)
<< " regs=" << d->regmap.size() << endl;
d->resp_real = false;
for( auto it = d->regmap.begin(); it != d->regmap.end(); ++it )
{
try
......@@ -272,21 +264,16 @@ bool RTUExchange::poll()
mb->cleanupChannel();
if( pollRTU(d, it) )
d->resp_real = true;
d->numreply++;
}
}
catch( ModbusRTU::mbException& ex )
{
// if( d->resp_real )
// {
dlog3 << myname << "(poll): FAILED ask addr=" << ModbusRTU::addr2str(d->mbaddr)
<< " reg=" << ModbusRTU::dat2str(it->second->mbreg)
<< " for sensors: ";
print_plist(dlog()->level3(), it->second->slst);
dlog()->level3() << " err: " << ex << endl;
// d->resp_real = false;
// }
}
if( it == d->regmap.end() )
......@@ -297,7 +284,7 @@ bool RTUExchange::poll()
}
}
if( d->resp_real )
if( d->numreply != prev_numreply )
allNotRespond = false;
}
......
......@@ -512,6 +512,20 @@ TEST_CASE("MBTCPMaster: exchangeMode", "[modbus][exchangemode][mbmaster][mbtcpma
}
}
// -----------------------------------------------------------------------------
TEST_CASE("MBTCPMaster: check respond resnsor", "[modbus][respond][mbmaster][mbtcpmaster]")
{
InitTest();
mbs->disableExchange(false);
msleep(1100);
CHECK( ui->getValue(slaveNotRespond) == 0 );
mbs->disableExchange(true);
msleep(1100);
CHECK( ui->getValue(slaveNotRespond) == 1 );
mbs->disableExchange(false);
msleep(1100);
CHECK( ui->getValue(slaveNotRespond) == 0 );
}
// -----------------------------------------------------------------------------
TEST_CASE("MBTCPMaster: iobase functions", "[modbus][iobase][mbmaster][mbtcpmaster]")
{
WARN("Test of 'iobase functions'..not yet.. ");
......
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