Commit 1c30ab90 authored by Pavel Vainerman's avatar Pavel Vainerman

(ModbusMaster): реализовал отключаемую проверку связи по всем каналам

в ModbusMultiMaster.
parent 01a03deb
......@@ -99,7 +99,7 @@ int main( int argc, char **argv )
<< " timeout=" << tout << " msec "
<< endl;
dlog.addLevel( Debug::type(Debug::CRIT | Debug::WARN | Debug::INFO) );
dlog.addLevel( Debug::ANY );
}
MBTCPServer mbs(myaddr,iaddr,port,verb);
......
......@@ -54,10 +54,10 @@
<DeviceList>
<item addr="0x01" invert="0" respondSensor="RespondRTU_S" timeout="5000" modeSensor="MB1_Mode_AS"/>
</DeviceList>
<SlaveList>
<item ip="127.0.0.1" port="2049" recv_timeout="200"/>
<GateList>
<item ip="127.0.0.1" port="2048" recv_timeout="200"/>
</SlaveList>
<item ip="127.0.0.1" port="2049" recv_timeout="200"/>
</GateList>
</MBMultiMaster1>
<MBSlave1 addr="0x31" aftersend-pause="0" dev="/dev/ttyS0" levels="info,warn,crit" name="MBSlave1" poll_time="200" reply_timeout="60" speed="9600">
......
......@@ -45,10 +45,10 @@ checkThread(0)
checktime = conf->getArgPInt("--" + prefix + "-checktime",it.getProp("checktime"), 5000);
UniXML_iterator it1(it);
if( !it1.find("SlaveList") )
if( !it1.find("GateList") )
{
ostringstream err;
err << myname << "(init): not found <SlaveList>";
err << myname << "(init): not found <GateList>";
dlog[Debug::CRIT] << err.str() << endl;
throw UniSetTypes::SystemError(err.str());
}
......@@ -56,7 +56,7 @@ checkThread(0)
if( !it1.goChildren() )
{
ostringstream err;
err << myname << "(init): empty <SlaveList> ?!";
err << myname << "(init): empty <GateList> ?!";
dlog[Debug::CRIT] << err.str() << endl;
throw UniSetTypes::SystemError(err.str());
}
......@@ -68,7 +68,7 @@ checkThread(0)
if( sinf.ip.empty() )
{
ostringstream err;
err << myname << "(init): ip='' in <SlaveList>";
err << myname << "(init): ip='' in <GateList>";
dlog[Debug::CRIT] << err.str() << endl;
throw UniSetTypes::SystemError(err.str());
}
......@@ -77,7 +77,7 @@ checkThread(0)
if( sinf.port <=0 )
{
ostringstream err;
err << myname << "(init): ERROR: port=''" << sinf.port << " for ip='" << sinf.ip << "' in <SlaveList>";
err << myname << "(init): ERROR: port=''" << sinf.port << " for ip='" << sinf.ip << "' in <GateList>";
dlog[Debug::CRIT] << err.str() << endl;
throw UniSetTypes::SystemError(err.str());
}
......@@ -88,7 +88,7 @@ checkThread(0)
if( sinf.respond_id == DefaultObjectId )
{
ostringstream err;
err << myname << "(init): ERROR: Unknown SensorID for '" << it1.getProp("respond") << "' in <SlaveList>";
err << myname << "(init): ERROR: Unknown SensorID for '" << it1.getProp("respond") << "' in <GateList>";
dlog[Debug::CRIT] << err.str() << endl;
throw UniSetTypes::SystemError(err.str());
}
......@@ -108,6 +108,9 @@ checkThread(0)
n << sinf.ip << ":" << sinf.port;
sinf.myname = n.str();
if( dlog.debugging(Debug::LEVEL9) )
sinf.mbtcp->setLog(dlog);
mblist.push_back(sinf);
if( dlog.debugging(Debug::INFO) )
......@@ -117,13 +120,13 @@ checkThread(0)
if( mblist.empty() )
{
ostringstream err;
err << myname << "(init): empty <SlaveList>!";
err << myname << "(init): empty <GateList>!";
dlog[Debug::CRIT] << err.str() << endl;
throw UniSetTypes::SystemError(err.str());
}
mblist.sort();
mbi = mblist.begin();
mbi = mblist.rbegin();
if( shm->isLocalwork() )
{
......@@ -145,71 +148,97 @@ MBTCPMultiMaster::~MBTCPMultiMaster()
{
delete pollThread;
delete checkThread;
for( MBSlaveList::iterator it=mblist.begin(); it!=mblist.end(); ++it )
for( MBGateList::iterator it=mblist.begin(); it!=mblist.end(); ++it )
{
delete it->mbtcp;
it->mbtcp = 0;
mbi = mblist.end();
mbi = mblist.rend();
}
}
// -----------------------------------------------------------------------------
ModbusClient* MBTCPMultiMaster::initMB( bool reopen )
{
if( mbi!=mblist.end() && mbi->respond )
// просто движемся по кругу (т.к. связь не проверяется)
// движемся в обратном порядке, т.к. сортировка по возрастанию приоритета
if( checktime <=0 )
{
cerr << "******** initMB(0): " << mbi->myname << endl;
mbi++;
if( mbi == mblist.rend() )
mbi = mblist.rbegin();
mbi->init();
mb = mbi->mbtcp;
return mbi->mbtcp;
}
if( mbi != mblist.end() )
mbi->mbtcp->disconnect();
{
uniset_mutex_lock l(tcpMutex,100);
// Если по текущему каналу связь есть, то возвращаем его
if( mbi!=mblist.rend() && mbi->respond )
{
if( mbi->mbtcp->isConnection() || ( !mbi->mbtcp->isConnection() && mbi->init()) )
{
mb = mbi->mbtcp;
return mbi->mbtcp;
}
}
if( mbi != mblist.rend() )
mbi->mbtcp->disconnect();
}
// проходим по списку (в обратном порядке, т.к. самый приоритетный в конце)
for( MBSlaveList::reverse_iterator it=mblist.rbegin(); it!=mblist.rend(); ++it )
for( MBGateList::reverse_iterator it=mblist.rbegin(); it!=mblist.rend(); ++it )
{
if( it->respond )
{
uniset_mutex_lock l(tcpMutex,100);
if( it->respond && it->init() )
{
mbi = it;
mb = mbi->mbtcp;
mbi = it.base();
cerr << "******** initMB(L): " << mbi->myname << endl;
return it->mbtcp;
}
}
cout << myname << "(initMB): return 0..." << endl;
mbi = mblist.end();
mb = 0;
{
uniset_mutex_lock l(tcpMutex,100);
mbi = mblist.rend();
mb = 0;
}
return 0;
}
// -----------------------------------------------------------------------------
bool MBTCPMultiMaster::MBSlaveInfo::check()
{
return mbtcp->checkConnection(ip,port);
return mbtcp->checkConnection(ip,port);
}
// -----------------------------------------------------------------------------
bool MBTCPMultiMaster::MBSlaveInfo::init()
{
try
{
ost::Thread::setException(ost::Thread::throwException);
ost::InetAddress ia(ip.c_str());
mbtcp->connect(ia,port);
// ost::Thread::setException(ost::Thread::throwException);
if( dlog.debugging(Debug::INFO) )
dlog[Debug::INFO] << myname << "(init): connect..." << endl;
mbtcp->connect(ip,port);
// mbtcp->setForceDisconnect(force_disconnect);
if( recv_timeout > 0 )
mbtcp->setTimeout(recv_timeout);
mbtcp->setSleepPause(sleepPause_usec);
mbtcp->setAfterSendPause(aftersend_pause);
// if( !initOK )
{
mbtcp->setSleepPause(sleepPause_usec);
mbtcp->setAfterSendPause(aftersend_pause);
if( dlog.debugging(Debug::INFO) )
dlog[Debug::INFO] << "(init): " << myname << endl;
if( dlog.debugging(Debug::LEVEL9) )
mbtcp->setLog(dlog);
if( mbtcp->isConnection() && dlog.debugging(Debug::INFO) )
dlog[Debug::INFO] << "(init): " << myname << " connect OK" << endl;
return true;
initOK = true;
}
return mbtcp->isConnection();
}
catch( ModbusRTU::mbException& ex )
{
......@@ -222,6 +251,7 @@ bool MBTCPMultiMaster::MBSlaveInfo::init()
dlog[Debug::WARN] << "(init): " << myname << " catch ..." << endl;
}
initOK = false;
return false;
}
// -----------------------------------------------------------------------------
......@@ -231,7 +261,8 @@ void MBTCPMultiMaster::sysCommand( UniSetTypes::SystemMessage *sm )
if( sm->command == SystemMessage::StartUp )
{
pollThread->start();
checkThread->start();
if( checktime > 0 )
checkThread->start();
}
}
// -----------------------------------------------------------------------------
......@@ -267,7 +298,7 @@ void MBTCPMultiMaster::check_thread()
{
while( checkProcActive() )
{
for( MBSlaveList::iterator it=mblist.begin(); it!=mblist.end(); ++it )
for( MBGateList::iterator it=mblist.begin(); it!=mblist.end(); ++it )
{
try
{
......@@ -290,7 +321,11 @@ void MBTCPMultiMaster::check_thread()
}
catch(...){}
it->respond = r;
{
uniset_mutex_lock l(tcpMutex,130);
it->respond = r;
}
}
catch(...){}
......@@ -308,7 +343,7 @@ void MBTCPMultiMaster::check_thread()
void MBTCPMultiMaster::initIterators()
{
MBExchange::initIterators();
for( MBSlaveList::iterator it=mblist.begin(); it!=mblist.end(); ++it )
for( MBGateList::iterator it=mblist.begin(); it!=mblist.end(); ++it )
shm->initDIterator(it->respond_dit);
}
// -----------------------------------------------------------------------------
......@@ -319,9 +354,7 @@ void MBTCPMultiMaster::help_print( int argc, const char* const* argv )
// ---------- init MBTCP ----------
// cout << "--prefix-sm-ready-timeout - время на ожидание старта SM" << endl;
cout << " Настройки протокола TCP: " << endl;
cout << "--prefix-gateway-iaddr hostname,IP - IP опрашиваемого узла" << endl;
cout << "--prefix-gateway-port num - port на опрашиваемом узле" << endl;
cout << "--prefix-persistent-connection 0,1 - Не закрывать соединение на каждом цикле опроса" << endl;
cout << "--prefix-checktime - период проверки связи по каналам (<GateList>)" << endl;
}
// -----------------------------------------------------------------------------
MBTCPMultiMaster* MBTCPMultiMaster::init_mbmaster( int argc, const char* const* argv,
......
......@@ -36,10 +36,10 @@
<item addr="0x01" respondSensor="RTU1_Not_Respond_FS" timeout="2000" invert="1"/>
<item addr="0x02" respondSensor="RTU2_Respond_FS" timeout="2000" invert="0"/>
</DeviceList>
<SlaveList>
<GateList>
<item ip="" port="" respond_id="" priority=""/>
<item ip="" port="" respond_id="" priority=""/>
<SlaveList>
<item ip="" port="" respond_id="" priority="" respond_invert="1"/>
<GateList>
</MBMaster1>
\endcode
Секция <DeviceList> позволяет задать параметры обмена с конкретным RTU-устройством.
......@@ -47,17 +47,18 @@
- \b addr - адрес устройства для которого, задаются параметры
- \b timeout msec - таймаут, для определения отсутствия связи
- \b invert - инвертировать логику. По умолчанию датчик выставляется в "1" при \b наличии связи.
- \b respondSensor - идентификатор датчика связи.
- \b respondSensor - идентификатор датчика связи (DI).
- \b modeSensor - идентификатор датчика режима работы (см. MBExchange::ExchangeMode).
- \b ask_every_reg - 1 - опрашивать ВСЕ регистры подряд, не обращая внимания на timeout. По умолчанию - "0" Т.е. опрос устройства (на текущем шаге цикла опроса), прерывается на первом же регистре, при опросе которого возникнет timeout.
Секция <SlaveList> позволяет задать несколько каналов связи со Slave-устройством. Это удобно для случая, когда Slave имеет
Секция <GateList> позволяет задать несколько каналов связи со Slave-устройством. Это удобно для случая, когда Slave имеет
более одного канала связи с ним (основной и резервный например).
- \b ip - ip-адрес
- \b port - порт
- \b respond - датчик связи по данному каналу (помимо обобщённого)
- \b priority - приоритет канала (чем больше число, тем выше приоритет)
- \b respond_invert - инвертировать датчик связи (DI)
\par Параметры запуска
......@@ -85,7 +86,11 @@
В связи с чем, функция указанная в качестве \b mbfunc игнорируется и подменяется на работающую с многими регистрами.
\b --xxx-poll-time или \b poll_time msec - пауза между опросами. По умолчанию 100 мсек.
\b --xxx-polltime или \b polltime msec - пауза между опросами. По умолчанию 100 мсек.
\b --xxx-checktime или \b checktime msec - пауза между проверками связи по разным каналам. По умолчанию 5000 мсек.
Если задать <=0, то каналы будут просто переключаться по кругу (по timeout-у) в соответсвии с приоритетом (см. <GateList>).
Если >0, то происходит проверка связи (раз в checktime) по всем каналам (см. <GateList>) и в случае потери связи,
происходит переключение на следующий канал, по которому связь есть.
\b --xxx-initPause или \b initPause msec - пауза перед началом работы, после активации. По умолчанию 50 мсек.
......@@ -219,16 +224,13 @@ class MBTCPMultiMaster:
protected:
virtual void sysCommand( UniSetTypes::SystemMessage *sm );
virtual void initIterators();
UniSetTypes::uniset_mutex mbMutex;
int recv_timeout;
virtual ModbusClient* initMB( bool reopen=false );
void poll_thread();
void check_thread();
bool force_disconnect;
UniSetTypes::uniset_mutex mbMutex;
int recv_timeout;
bool force_disconnect;
int checktime;
private:
......@@ -238,7 +240,7 @@ class MBTCPMultiMaster:
{
MBSlaveInfo():ip(""),port(0),mbtcp(0),priority(0),
respond(false),respond_id(UniSetTypes::DefaultObjectId),respond_invert(false),
recv_timeout(200),aftersend_pause(0),sleepPause_usec(100),myname(""){}
recv_timeout(200),aftersend_pause(0),sleepPause_usec(100),myname(""),initOK(false){}
std::string ip;
int port;
......@@ -263,12 +265,14 @@ class MBTCPMultiMaster:
int sleepPause_usec;
std::string myname;
bool initOK;
};
typedef std::list<MBSlaveInfo> MBSlaveList;
typedef std::list<MBSlaveInfo> MBGateList;
MBSlaveList mblist;
MBSlaveList::iterator mbi;
MBGateList mblist;
MBGateList::reverse_iterator mbi;
// т.к. TCP может "зависнуть" на подключении к недоступному узлу
// делаем опрос в отдельном потоке
......
......@@ -54,20 +54,22 @@ mbErrCode ModbusTCPMaster::query( ModbusAddr addr, ModbusMessage& msg,
{
if( iaddr.empty() )
{
dlog[Debug::WARN] << "(query): unknown ip address for server..." << endl;
return erTimeOut; // erHardwareError
if( dlog.debugging(Debug::WARN) )
dlog[Debug::WARN] << iaddr << "(ModbusTCPMaster::query): unknown ip address for server..." << endl;
return erTimeOut; // erHardwareError
}
if( !isConnection() )
{
if( dlog.debugging(Debug::INFO) )
dlog[Debug::INFO] << "(ModbusTCPMaster): no connection.. reconnnect..." << endl;
dlog[Debug::INFO] << iaddr << "(ModbusTCPMaster::query): no connection.. reconnnect..." << endl;
reconnect();
}
if( !isConnection() )
{
dlog[Debug::WARN] << "(query): not connected to server..." << endl;
if( dlog.debugging(Debug::WARN) )
dlog[Debug::WARN] << iaddr << "(ModbusTCPMaster::query): not connected to server..." << endl;
return erTimeOut;
}
......@@ -95,7 +97,7 @@ mbErrCode ModbusTCPMaster::query( ModbusAddr addr, ModbusMessage& msg,
// send TCP header
if( dlog.debugging(Debug::INFO) )
{
dlog[Debug::INFO] << "(ModbusTCPMaster::query): send tcp header(" << sizeof(mh) <<"): ";
dlog[Debug::INFO] << iaddr << "(ModbusTCPMaster::query): send tcp header(" << sizeof(mh) <<"): ";
mbPrintMessage( dlog, (ModbusByte*)(&mh), sizeof(mh));
dlog(Debug::INFO) << endl;
}
......@@ -118,7 +120,8 @@ mbErrCode ModbusTCPMaster::query( ModbusAddr addr, ModbusMessage& msg,
reconnect();
if( !isConnection() )
{
dlog[Debug::WARN] << "(ModbusTCPMaster::query): not connected to server..." << endl;
if( dlog.debugging(Debug::WARN) )
dlog[Debug::WARN] << "(ModbusTCPMaster::query): not connected to server..." << endl;
return erTimeOut;
}
cleanInputStream();
......@@ -223,29 +226,35 @@ mbErrCode ModbusTCPMaster::query( ModbusAddr addr, ModbusMessage& msg,
}
catch( ModbusRTU::mbException& ex )
{
dlog[Debug::WARN] << "(query): " << ex << endl;
if( dlog.debugging(Debug::WARN) )
dlog[Debug::WARN] << "(query): " << ex << endl;
}
catch( SystemError& err )
{
dlog[Debug::WARN] << "(query): " << err << endl;
if( dlog.debugging(Debug::WARN) )
dlog[Debug::WARN] << "(query): " << err << endl;
}
catch( Exception& ex )
{
dlog[Debug::WARN] << "(query): " << ex << endl;
if( dlog.debugging(Debug::WARN) )
dlog[Debug::WARN] << "(query): " << ex << endl;
}
catch( ost::SockException& e )
{
dlog[Debug::WARN] << "(query): tcp error: " << e.getString() << endl;
if( dlog.debugging(Debug::WARN) )
dlog[Debug::WARN] << "(query): tcp error: " << e.getString() << endl;
return erTimeOut;
}
catch( std::exception& e )
{
dlog[Debug::CRIT] << "(query): " << e.what() << std::endl;
if( dlog.debugging(Debug::WARN) )
dlog[Debug::CRIT] << "(query): " << e.what() << std::endl;
return erTimeOut;
}
catch(...)
{
dlog[Debug::WARN] << "(query): cath..." << endl;
if( dlog.debugging(Debug::WARN) )
dlog[Debug::WARN] << "(query): cath..." << endl;
}
return erTimeOut; // erHardwareError
......@@ -307,21 +316,27 @@ void ModbusTCPMaster::reconnect()
}
catch( std::exception& e )
{
ostringstream s;
s << "(ModbusTCPMaster): connection " << s.str() << " error: " << e.what();
dlog[Debug::CRIT] << s.str() << std::endl;
if( dlog.debugging(Debug::CRIT) )
{
ostringstream s;
s << "(ModbusTCPMaster): connection " << s.str() << " error: " << e.what();
dlog[Debug::CRIT] << s.str() << std::endl;
}
}
catch( ... )
{
ostringstream s;
s << "(ModbusTCPMaster): connection " << s.str() << " error: catch ...";
dlog[Debug::CRIT] << s.str() << std::endl;
if( dlog.debugging(Debug::CRIT) )
{
ostringstream s;
s << "(ModbusTCPMaster): connection " << s.str() << " error: catch ...";
dlog[Debug::CRIT] << s.str() << std::endl;
}
}
}
// -------------------------------------------------------------------------
void ModbusTCPMaster::connect( const std::string addr, int port )
{
ost::InetAddress ia(iaddr.c_str());
ost::InetAddress ia(addr.c_str());
connect(ia,port);
}
// -------------------------------------------------------------------------
......@@ -347,7 +362,7 @@ void ModbusTCPMaster::connect( ost::InetAddress addr, int port )
ost::Thread::setException(ost::Thread::throwException);
try
{
tcp = new ost::TCPStream(iaddr.c_str());
tcp = new ost::TCPStream(iaddr.c_str(),ost::Socket::IPV4,536,true,500);
tcp->setTimeout(replyTimeOut_ms);
}
catch( std::exception& e )
......@@ -374,7 +389,7 @@ void ModbusTCPMaster::connect( ost::InetAddress addr, int port )
void ModbusTCPMaster::disconnect()
{
if( dlog.debugging(Debug::INFO) )
dlog[Debug::INFO] << "(ModbusTCPMaster): disconnect." << endl;
dlog[Debug::INFO] << iaddr << "(ModbusTCPMaster): disconnect." << endl;
if( !tcp )
return;
......
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