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

(UNetUDP): исправлена критическая ошибка в переключении каналов между собой,

добавлена возможность указать датчик, показывающий по какому каналу (1,2) идёт работа.
parent 246af23e
......@@ -12,7 +12,7 @@
Name: libuniset2
Version: 2.0
Release: alt22
Release: alt23
Summary: UniSet - library for building distributed industrial control systems
......@@ -409,12 +409,15 @@ mv -f %buildroot%python_sitelibdir_noarch/* %buildroot%python_sitelibdir/%oname
# ..
%changelog
* Thu Mar 19 2015 Pavel Vainerman <pv@altlinux.ru> 2.0-alt23
- unetudp: fxied critial bug in "switching channels" (thank`s Alexey Surov)
* Mon Mar 16 2015 Pavel Vainerman <pv@altlinux.ru> 2.0-alt22
- codegen: add dumpIO(), str(), strval() functions (debug helpers)
* Thu Mar 12 2015 Pavel Vainerman <pv@altlinux.ru> 2.0-alt21
- codegen: adjustment documentation
- unetudp: add tests, minor optimization (thank`s uzum)
- unetudp: add tests, minor optimization (thank`s Alexey Vinogradov)
* Fri Mar 06 2015 Pavel Vainerman <pv@altlinux.ru> 2.0-alt20
- (modbustcpmaster): minor fixes in error messages
......
......@@ -331,14 +331,14 @@ MyClass_SK.cc: myclass.src.xml
...
\endcode
- \b string \b str( ObjectId,showLinkName) - вывод названия указанного входа или выхода в формате "in_input1_s(Sensor1_S)". Если
- \b string \b str(ObjectId,showLinkName) - вывод названия указанного входа или выхода в формате "in_input1_s(Sensor1_S)". Если
showLinkName=false, то будет сформирована строка "in_input1_s". Пример использования:
\code
..
myinfo << str(input1_s) << endl;
\endcode
- \b string \b strval( ObjectId,showLinkName) - вывод названия и текущего значения указанного входа или выхода в формате "in_input1_s(Sensor1_S)=1". Если
- \b string \b strval(ObjectId,showLinkName) - вывод названия и текущего значения указанного входа или выхода в формате "in_input1_s(Sensor1_S)=1". Если
showLinkName=false, то будет сформирована строка "in_input1_s=1". Пример использования:
\code
..
......
......@@ -237,6 +237,20 @@ no_sender(false)
}
}
string s_numchannel_id(n_it.getProp("unet_numchannel_id"));
UniSetTypes::ObjectId numchannel_id = UniSetTypes::DefaultObjectId;
if( !s_numchannel_id.empty() )
{
numchannel_id = conf->getSensorID(s_numchannel_id);
if( numchannel_id == UniSetTypes::DefaultObjectId )
{
ostringstream err;
err << myname << ": Unknown NumChannelID.. Not found id for '" << s_numchannel_id << "'" << endl;
dcrit << myname << "(init): " << err.str() << endl;
throw SystemError(err.str());
}
}
dinfo << myname << "(init): (node='" << n << "') add receiver "
<< h2 << ":" << p2 << endl;
auto r = make_shared<UNetReceiver>(h,p,shm);
......@@ -291,6 +305,7 @@ no_sender(false)
ReceiverInfo ri(r,r2);
ri.setRespondID(resp_comm_id,resp_invert);
ri.setLostPacketsID(lp_comm_id);
ri.setChannelNumID(numchannel_id);
recvlist.push_back(ri);
}
......@@ -446,6 +461,24 @@ void UNetExchange::ReceiverInfo::step( const std::shared_ptr<SMInterface> shm, c
{
dcrit << myname << "(ReceiverInfo::step): (lostpackets): " << ex << std::endl;
}
try
{
if( sidChannelNum != DefaultObjectId )
{
long c = 0;
if( r1 && !r1->isLockUpdate() )
c = 1;
if( r2 && !r2->isLockUpdate() )
c = 2;
shm->localSetValue(itChannelNum,sidChannelNum,c,shm->ID());
}
}
catch( const Exception& ex )
{
dcrit << myname << "(ReceiverInfo::step): (channelnum): " << ex << std::endl;
}
}
// -----------------------------------------------------------------------------
void UNetExchange::sysCommand( const UniSetTypes::SystemMessage *sm )
......@@ -669,17 +702,15 @@ std::shared_ptr<UNetExchange> UNetExchange::init_unetexchange( int argc, const c
// -----------------------------------------------------------------------------
void UNetExchange::receiverEvent( const shared_ptr<UNetReceiver>& r, UNetReceiver::Event ev )
{
// пока, что другие события нас не интересуют
if( ev != UNetReceiver::evTimeout )
return;
for( auto &it: recvlist )
{
if( it.r1 == r )
{
// если нет второго канала
// то и переключать некуда
if( !it.r2 )
if( ev == UNetReceiver::evTimeout )
{
// если нет второго канала или нет связи
// то и переключать не надо
if( !it.r2 || !it.r2->isRecvOK() )
return;
// пропала связь по первому каналу...
......@@ -687,20 +718,62 @@ void UNetExchange::receiverEvent( const shared_ptr<UNetReceiver>& r, UNetReceive
it.r1->setLockUpdate(true);
it.r2->setLockUpdate(false);
dinfo << myname << "(event): " << r->getName()
dlog8 << myname << "(event): " << r->getName()
<< ": timeout for channel1.. select channel 2" << endl;
}
else if( ev == UNetReceiver::evOK )
{
// если связь восстановилась..
// проверяем, а что там со вторым каналом
// если у него связи нет, то забираем себе..
if( !it.r2 || !it.r2->isRecvOK() )
{
it.r1->setLockUpdate(false);
if( it.r2 )
it.r2->setLockUpdate(true);
dlog8 << myname << "(event): " << r->getName()
<< ": link failed for channel2.. select again channel1.." << endl;
}
}
return;
}
if( it.r2 == r )
{
if( ev == UNetReceiver::evTimeout )
{
// если первого канала нет или нет связи
// то и переключать не надо
if( !it.r1 || !it.r1->isRecvOK() )
return;
// пропала связь по второму каналу...
// переключаемся на первый
it.r1->setLockUpdate(false);
it.r2->setLockUpdate(true);
dinfo << myname << "(event): " << r->getName()
dlog8 << myname << "(event): " << r->getName()
<< ": timeout for channel2.. select channel 1" << endl;
}
else if( ev == UNetReceiver::evOK )
{
// если связь восстановилась..
// проверяем, а что там со первым каналом
// если у него связи нет, то забираем себе..
if( !it.r1 || !it.r1->isRecvOK() )
{
if( it.r1 )
it.r1->setLockUpdate(true);
it.r2->setLockUpdate(false);
dlog8 << myname << "(event): " << r->getName()
<< ": link failed for channel1.. select again channel2.." << endl;
}
}
return;
}
}
......
......@@ -142,14 +142,16 @@ class UNetExchange:
ReceiverInfo():r1(nullptr),r2(nullptr),
sidRespond(UniSetTypes::DefaultObjectId),
respondInvert(false),
sidLostPackets(UniSetTypes::DefaultObjectId)
sidLostPackets(UniSetTypes::DefaultObjectId),
sidChannelNum(UniSetTypes::DefaultObjectId)
{}
ReceiverInfo( const std::shared_ptr<UNetReceiver>& _r1, const std::shared_ptr<UNetReceiver>& _r2 ):
r1(_r1),r2(_r2),
sidRespond(UniSetTypes::DefaultObjectId),
respondInvert(false),
sidLostPackets(UniSetTypes::DefaultObjectId)
sidLostPackets(UniSetTypes::DefaultObjectId),
sidChannelNum(UniSetTypes::DefaultObjectId)
{}
std::shared_ptr<UNetReceiver> r1; /*!< приём по первому каналу */
......@@ -163,21 +165,26 @@ class UNetExchange:
respondInvert = invert;
}
inline void setLostPacketsID( UniSetTypes::ObjectId id ){ sidLostPackets = id; }
inline void setChannelNumID( UniSetTypes::ObjectId id ){ sidChannelNum = id; }
inline void initIterators( const std::shared_ptr<SMInterface> shm )
{
shm->initIterator(itLostPackets);
shm->initIterator(itRespond);
shm->initIterator(itChannelNum);
}
// Сводная информация по двум каналам
// сумма потерянных пакетов и наличие связи
// хотя бы по одному каналу
// хотя бы по одному каналу, номер рабочего канала
// ( реализацию см. ReceiverInfo::step() )
UniSetTypes::ObjectId sidRespond;
IOController::IOStateList::iterator itRespond;
bool respondInvert;
UniSetTypes::ObjectId sidLostPackets;
IOController::IOStateList::iterator itLostPackets;
UniSetTypes::ObjectId sidChannelNum;
IOController::IOStateList::iterator itChannelNum;
};
typedef std::deque<ReceiverInfo> ReceiverList;
......
......@@ -67,6 +67,7 @@ class UNetReceiver:
// блокировать сохранение данных в SM
void setLockUpdate( bool st );
inline bool isLockUpdate(){ return lockUpdate; }
void resetTimeout();
......
......@@ -26,6 +26,8 @@ static int s_numpack = 1;
static ObjectId node2_respond_s = 12;
static ObjectId node2_lostpackets_as = 13;
static int maxDifferense = 5; // см. unetudp-test-configure.xml --unet-maxdifferense
static int recvTimeout = 1000; // --unet-recv-timeout
static ObjectId node1_numchannel_as = 14;
// -----------------------------------------------------------------------------
void InitTest()
{
......@@ -417,3 +419,21 @@ TEST_CASE("[UNetUDP]: bad packet number","[unetudp][badnumber]")
REQUIRE( ui->getValue(8) == 160 );
}
// -----------------------------------------------------------------------------
TEST_CASE("[UNetUDP]: switching channels","[unetudp][chswitch]")
{
InitTest();
UniSetUDP::UDPMessage pack;
pack.addAData(8,70);
send(pack);
msleep(120);
REQUIRE( ui->getValue(8) == 70 );
// К сожалению в текущей реализации тестов
// обмена по второму каналу нет
// поэтому проверить переключение нет возможности
// остаётся только проверить, что мы не "ушли" с первого канала
// т.к. на втором нет связи и мы не должны на него переключаться
msleep(recvTimeout*2);
REQUIRE( ui->getValue(node1_numchannel_as) == 1 );
}
// -----------------------------------------------------------------------------
......@@ -32,11 +32,11 @@
</settings>
<ObjectsMap idfromfile="1">
<nodes port="2809" unet_broadcast_ip="127.255.255.255">
<nodes port="2809" unet_broadcast_ip="127.255.255.255" unet_broadcast_ip2="badip">
<item id="3000" ip="127.0.0.1" name="localhost" textname="Локальный узел" unet_ignore="0" unet_port="3000"/>
<item id="3001" ip="127.0.0.1" name="localhost1" textname="Локальный узел" unet_ignore="1" unet_port="3001"/>
<item id="3002" ip="192.168.56.10" name="Node1" textname="Node1" unet_ignore="0" unet_ip="192.168.56.255" unet_respond_id="Node1_Respond_S" unet_respond_invert="1"/>
<item id="3003" ip="192.168.56.11" name="Node2" textname="Node2" unet_ignore="0" unet_ip="192.168.56.255" unet_respond_id="Node2_Respond_S" unet_lostpackets_id="Node2_LostPackets_AS"/>
<item id="3003" ip="192.168.56.11" name="Node2" textname="Node2" unet_ignore="0" unet_ip="192.168.56.255" unet_respond_id="Node2_Respond_S" unet_lostpackets_id="Node2_LostPackets_AS" unet_numchannel_id="Node2_NumChannel_AS"/>
</nodes>
<!-- ************************ Датчики ********************** -->
<sensors name="Sensors">
......@@ -55,6 +55,7 @@
<item id="11" iotype="DI" name="DI4_S" textname="DI sensor 4"/>
<item id="12" iotype="DI" name="Node2_Respond_S" textname="Node2 respond"/>
<item id="13" iotype="AI" name="Node2_LostPackets_AS" textname="Node2 lost packets"/>
<item id="14" iotype="AI" name="Node2_NumChannel_AS" textname="Node2 num channel"/>
</sensors>
<thresholds name="thresholds"/>
......
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