Commit 36591cd7 authored by Pavel Vainerman's avatar Pavel Vainerman

(Modbus): добавил возможность задать для каждого устройства

датчик "управления обменом"(modeSensor), чтобы процессом можно было управлять "снаружи" (вплоть до отключения обмена).
parent 97887904
......@@ -7,7 +7,7 @@
Name: libuniset
Version: 1.6
Release: alt11
Release: alt12
Summary: UniSet - library for building distributed industrial control systems
......@@ -319,6 +319,9 @@ mv -f %buildroot%python_sitelibdir_noarch/* %buildroot%python_sitelibdir/%oname
%exclude %_pkgconfigdir/libUniSet.pc
%changelog
* Thu Sep 19 2013 Pavel Vainerman <pv@altlinux.ru> 1.6-alt12
- (Modbus): Added ability to set the sensor mode (modeSensor) for each device
* Thu Jun 13 2013 Pavel Vainerman <pv@altlinux.ru> 1.6-alt11
- fixed after cppcheck checking
......
......@@ -45,9 +45,9 @@
<item name="UniExchange2" node="Node2"/>
<item id="3001" node_id="Node2"/>
</UniExchange>
<MBMaster1 addr="0x31" iaddr="127.0.0.1" levels="info,warn,crit" name="MBMaster1" poll_time="200" port="30000" reply_timeout="60">
<MBMaster1 iaddr="127.0.0.1" levels="info,warn,crit" name="MBMaster1" poll_time="200" port="30000" reply_timeout="60">
<DeviceList>
<item addr="0x02" invert="0" respondSensor="RespondRTU_S" timeout="5000"/>
<item addr="0x01" invert="0" respondSensor="RespondRTU_S" timeout="5000" modeSensor="MB1_Mode_AS"/>
</DeviceList>
</MBMaster1>
<MBSlave1 addr="0x31" aftersend-pause="0" dev="/dev/ttyS0" levels="info,warn,crit" name="MBSlave1" poll_time="200" reply_timeout="60" speed="9600">
......@@ -103,7 +103,7 @@
</MBSlave1>
<RTUExchange name="RTUExchange">
<DeviceList>
<item addr="0x01" invert="0" respondSensor="RespondRTU_S" timeout="5000"/>
<item addr="0x01" invert="0" respondSensor="RespondRTU_S" modeSensor="MB1_Mode_AS" timeout="5000"/>
</DeviceList>
</RTUExchange>
<UDPExchange name="UDPExchange"/>
......@@ -136,7 +136,7 @@
<!-- ************************ Датчики ********************** -->
<sensors name="Sensors">
<item db_ignore="1" default="1" id="1" iotype="DI" name="Input1_S" priority="Medium" textname="Команда 1"/>
<item id="2" iotype="DI" mbaddr="0x01" mbfunc="0x04" mbreg="0x02" mbtype="rtu" name="Input2_S" priority="Medium" rs="2" textname="Команда 2"/>
<item id="2" iotype="DI" mbaddr="0x01" mbfunc="0x06" mbreg="0x02" nbit="11" mbtype="rtu" name="Input2_S" priority="Medium" rs="4" textname="Команда 2"/>
<item id="3" iotype="DI" mbtcp="1" mbtcp_mbaddr="0x02" mbtcp_mbfunc="0x03" mbtcp_mbreg="0x02" mbtcp_mbtype="rtu" name="Input3_S" priority="Medium" textname="Команда 3"/>
<item id="4" iotype="DI" mbaddr="0x02" mbfunc="0x04" mbreg="0x02" mbtype="rtu" name="Input4_S" priority="Medium" rs="2" textname="Команда 4"/>
<item id="5" iotype="DI" name="Input5_S" priority="Medium" textname="Команда 5" udp="2"/>
......@@ -178,6 +178,12 @@
<item id="32" iotype="AI" mbtcp_mbaddr="1" mbtcp_mbfunc="0x04" mbtcp_mbreg="43" mbtcp_mbtype="rtu" mbtcp_vtype="I2" name="performance1" noprecision="1" precision="6" rs="mbmaster" textname="Производительность танка 1"/>
<item id="33" iotype="DI" name="Message1" priority="Medium" textname="Текст сообщения 1"/>
<item id="34" iotype="AI" name="MB1_Mode_AS" priority="Medium" textname="ModbusExchange Mode"/>
<item id="50" iotype="DI" mbaddr="0x01" mbfunc="0x06" mbreg="0x02" nbit="0" mbtype="rtu" name="Input50_S" priority="Medium" rs="5" textname="Команда 2"/>
<item id="51" iotype="DI" mbaddr="0x01" mbfunc="0x03" mbreg="0x01" ntit="1" mbtype="rtu" name="Input51_S" priority="Medium" rs="5" textname="Команда 2"/>
<item id="52" iotype="DI" mbaddr="0x01" mbfunc="0x06" mbreg="0x02" nbit="1" mbtype="rtu" name="Input52_S" priority="Medium" rs="5" textname="Команда 2"/>
<item id="53" iotype="DI" mbaddr="0x01" mbfunc="0x03" mbreg="0x01" nbit="2" mbtype="rtu" name="Input53_S" priority="Medium" rs="5" textname="Команда 2"/>
</sensors>
<thresholds name="thresholds">
<sensor iotype="AI" name="AI_AS">
......
......@@ -302,6 +302,7 @@ void MBExchange::initIterators()
{
RTUDevice* d(it1->second);
shm->initDIterator(d->resp_dit);
shm->initAIterator(d->mode_ait);
for( MBExchange::RegMap::iterator it=d->regmap.begin(); it!=d->regmap.end(); ++it )
{
for( PList::iterator it2=it->second->slst.begin();it2!=it->second->slst.end(); ++it2 )
......@@ -313,9 +314,20 @@ void MBExchange::initIterators()
}
}
// -----------------------------------------------------------------------------
bool MBExchange::checkUpdateSM( bool wrFunc )
bool MBExchange::checkUpdateSM( bool wrFunc, long mdev )
{
if( wrFunc && exchangeMode == emReadOnly )
if( exchangeMode == emSkipExchange || mdev == emSkipExchange )
{
if( wrFunc )
return true; // данные для посылки, должны обновляться всегда (чтобы быть актуальными)
if( dlog.debugging(Debug::LEVEL3) )
dlog[Debug::LEVEL3] << "(checkUpdateSM):"
<< " skip... mode='emSkipExchange' " << endl;
return false;
}
if( wrFunc && (exchangeMode == emReadOnly || mdev == emReadOnly) )
{
if( dlog.debugging(Debug::LEVEL3) )
dlog[Debug::LEVEL3] << "(checkUpdateSM):"
......@@ -323,7 +335,7 @@ bool MBExchange::checkUpdateSM( bool wrFunc )
return false;
}
if( !wrFunc && exchangeMode == emWriteOnly )
if( !wrFunc && (exchangeMode == emWriteOnly || mdev == emWriteOnly) )
{
if( dlog.debugging(Debug::LEVEL3) )
dlog[Debug::LEVEL3] << "(checkUpdateSM):"
......@@ -331,7 +343,7 @@ bool MBExchange::checkUpdateSM( bool wrFunc )
return false;
}
if( wrFunc && exchangeMode == emSkipSaveToSM )
if( wrFunc && (exchangeMode == emSkipSaveToSM || mdev == emSkipSaveToSM) )
{
if( dlog.debugging(Debug::LEVEL3) )
dlog[Debug::LEVEL3] << "(checkUpdateSM):"
......@@ -764,6 +776,15 @@ bool MBExchange::pollRTU( RTUDevice* dev, RegMap::iterator& it )
{
RegInfo* p(it->second);
if( dev->mode == emSkipExchange )
{
if( dlog.debugging(Debug::LEVEL3) )
dlog[Debug::LEVEL3] << myname << "(pollRTU): SKIP EXCHANGE (mode=emSkipExchange) "
<< " mbaddr=" << ModbusRTU::addr2str(dev->mbaddr)
<< endl;
return true;
}
if( dlog.debugging(Debug::LEVEL3) )
{
dlog[Debug::LEVEL3] << myname << "(pollRTU): poll "
......@@ -964,6 +985,40 @@ void MBExchange::updateSM()
{
RTUDevice* d(it1->second);
if( d->mode_id != DefaultObjectId )
{
try
{
if( !shm->isLocalwork() )
d->mode = shm->localGetValue(d->mode_ait,d->mode_id);
}
catch(IOController_i::NameNotFound &ex)
{
dlog[Debug::LEVEL3] << myname << "(updateSM):(NameNotFound) " << ex.err << endl;
}
catch(IOController_i::IOBadParam& ex )
{
dlog[Debug::LEVEL3] << myname << "(updateSM):(IOBadParam) " << ex.err << endl;
}
catch(IONotifyController_i::BadRange )
{
dlog[Debug::LEVEL3] << myname << "(updateSM): (BadRange)..." << endl;
}
catch( Exception& ex )
{
dlog[Debug::LEVEL3] << myname << "(updateSM): " << ex << endl;
}
catch(CORBA::SystemException& ex)
{
dlog[Debug::LEVEL3] << myname << "(updateSM): CORBA::SystemException: "
<< ex.NP_minorString() << endl;
}
catch(...)
{
dlog[Debug::LEVEL3] << myname << "(updateSM): check modeSensor..catch ..." << endl;
}
}
// обновление датчиков связи происходит в другом потоке
// чтобы не зависеть от TCP таймаутов
// см. updateRespondSensors()
......@@ -1031,7 +1086,7 @@ void MBExchange::updateRSProperty( RSProperty* p, bool write_only )
if( !save && write_only )
return;
if( !checkUpdateSM(save) )
if( !checkUpdateSM(save,r->dev->mode) )
return;
// если требуется инициализация и она ещё не произведена,
......@@ -1345,32 +1400,14 @@ void MBExchange::updateRSProperty( RSProperty* p, bool write_only )
void MBExchange::updateMTR( RegMap::iterator& rit )
{
RegInfo* r(rit->second);
using namespace ModbusRTU;
bool save = isWriteFunction( r->mbfunc );
if( save && exchangeMode == emReadOnly )
{
if( dlog.debugging(Debug::LEVEL3) )
dlog[Debug::LEVEL3] << myname << "(updateMTR):"
<< " skip... mode=emReadOnly " << endl;
if( !r || !r->dev )
return;
}
if( !save && exchangeMode == emWriteOnly )
{
if( dlog.debugging(Debug::LEVEL3) )
dlog[Debug::LEVEL3] << myname << "(updateMTR):"
<< " skip... mode=emWriteOnly " << endl;
return;
}
using namespace ModbusRTU;
bool save = isWriteFunction( r->mbfunc );
if( save && exchangeMode == emSkipSaveToSM )
{
if( dlog.debugging(Debug::LEVEL3) )
dlog[Debug::LEVEL3] << myname << "(updateMTR):"
<< " skip... mode=emSkipSaveToSM " << endl;
if( !checkUpdateSM(save,r->dev->mode) )
return;
}
{
for( PList::iterator it=r->slst.begin(); it!=r->slst.end(); ++it )
......@@ -1608,7 +1645,15 @@ void MBExchange::updateRTU188( RegMap::iterator& rit )
return;
}
if( save && exchangeMode == emReadOnly )
if( exchangeMode == emSkipExchange || r->dev->mode == emSkipExchange )
{
if( dlog.debugging(Debug::LEVEL3) )
dlog[Debug::LEVEL3] << myname << "(updateRTU188):"
<< " skip... mode=emSkipExchange " << endl;
return;
}
if( save && (exchangeMode == emReadOnly || r->dev->mode == emReadOnly) )
{
if( dlog.debugging(Debug::LEVEL3) )
dlog[Debug::LEVEL3] << myname << "(updateRTU188):"
......@@ -1616,7 +1661,7 @@ void MBExchange::updateRTU188( RegMap::iterator& rit )
return;
}
if( !save && exchangeMode == emWriteOnly )
if( !save && ( exchangeMode == emWriteOnly || r->dev->mode == emWriteOnly) )
{
if( dlog.debugging(Debug::LEVEL3) )
dlog[Debug::LEVEL3] << myname << "(updateRTU188):"
......@@ -1624,7 +1669,7 @@ void MBExchange::updateRTU188( RegMap::iterator& rit )
return;
}
if( save && exchangeMode == emSkipSaveToSM )
if( save && ( exchangeMode == emSkipSaveToSM || r->dev->mode == emSkipSaveToSM) )
{
if( dlog.debugging(Debug::LEVEL3) )
dlog[Debug::LEVEL3] << myname << "(updateRT188):"
......@@ -2331,7 +2376,25 @@ bool MBExchange::initDeviceInfo( RTUDeviceMap& m, ModbusRTU::ModbusAddr a, UniXM
d->second->resp_id = conf->getSensorID(s);
if( d->second->resp_id == DefaultObjectId )
{
dlog[Debug::CRIT] << myname << "(initDeviceInfo): not found ID for noRespondSensor=" << s << endl;
dlog[Debug::CRIT] << myname << "(initDeviceInfo): not found ID for respondSensor=" << s << endl;
return false;
}
}
string mod(it.getProp("modeSensor"));
if( !mod.empty() )
{
d->second->mode_id = conf->getSensorID(mod);
if( d->second->mode_id == DefaultObjectId )
{
dlog[Debug::CRIT] << myname << "(initDeviceInfo): not found ID for modeSensor=" << mod << endl;
return false;
}
UniversalIO::IOTypes m_iotype = conf->getIOType(d->second->mode_id);
if( m_iotype != UniversalIO::AnalogInput )
{
dlog[Debug::CRIT] << myname << "(initDeviceInfo): modeSensor='" << mod << "' must be 'AI'" << endl;
return false;
}
}
......@@ -2453,6 +2516,8 @@ void MBExchange::sysCommand( UniSetTypes::SystemMessage *sm )
initOutput();
}
updateSM();
askTimer(tmExchange,polltime);
break;
}
......@@ -2528,9 +2593,6 @@ void MBExchange::askSensors( UniversalIO::UIOCommand cmd )
throw SystemError(err.str());
}
if( force_out )
return;
try
{
if( sidExchangeMode != DefaultObjectId )
......@@ -2548,6 +2610,24 @@ void MBExchange::askSensors( UniversalIO::UIOCommand cmd )
for( MBExchange::RTUDeviceMap::iterator it1=rmap.begin(); it1!=rmap.end(); ++it1 )
{
RTUDevice* d(it1->second);
try
{
if( d->mode_id != DefaultObjectId )
shm->askSensor(d->mode_id,cmd);
}
catch( UniSetTypes::Exception& ex )
{
dlog[Debug::WARN] << myname << "(askSensors): " << ex << std::endl;
}
catch(...)
{
dlog[Debug::WARN] << myname << "(askSensors): (mode_id=" << d->mode_id << ").. catch..." << std::endl;
}
if( force_out )
return;
for( MBExchange::RegMap::iterator it=d->regmap.begin(); it!=d->regmap.end(); ++it )
{
if( !isWriteFunction(it->second->mbfunc) )
......@@ -2565,7 +2645,7 @@ void MBExchange::askSensors( UniversalIO::UIOCommand cmd )
}
catch(...)
{
dlog[Debug::WARN] << myname << "(askSensors): catch..." << std::endl;
dlog[Debug::WARN] << myname << "(askSensors): id=" << i->si.id << " catch..." << std::endl;
}
}
}
......@@ -2574,20 +2654,24 @@ void MBExchange::askSensors( UniversalIO::UIOCommand cmd )
// ------------------------------------------------------------------------------------------
void MBExchange::sensorInfo( UniSetTypes::SensorMessage* sm )
{
if( force_out )
return;
if( sm->id == sidExchangeMode )
{
exchangeMode = sm->value;
if( dlog.debugging(Debug::LEVEL3) )
dlog[Debug::LEVEL3] << myname << "(sensorInfo): exchange MODE=" << sm->value << std::endl;
return;
//return; // этот датчик может встречаться и в списке обмена.. поэтому делать return нельзя.
}
for( MBExchange::RTUDeviceMap::iterator it1=rmap.begin(); it1!=rmap.end(); ++it1 )
{
RTUDevice* d(it1->second);
if( sm->id == d->mode_id )
d->mode = sm->value;
if( force_out )
continue;
for( MBExchange::RegMap::iterator it=d->regmap.begin(); it!=d->regmap.end(); ++it )
{
if( !isWriteFunction(it->second->mbfunc) )
......@@ -2669,8 +2753,11 @@ void MBExchange::poll()
{
RTUDevice* d(it1->second);
if( dlog.debugging(Debug::INFO) )
dlog[Debug::INFO] << myname << "(poll): ask addr=" << ModbusRTU::addr2str(d->mbaddr)
if( d->mode_id != DefaultObjectId && d->mode == emSkipExchange )
continue;
if( dlog.debugging(Debug::LEVEL3) )
dlog[Debug::LEVEL3] << myname << "(poll): ask addr=" << ModbusRTU::addr2str(d->mbaddr)
<< " regs=" << d->regmap.size() << endl;
d->resp_real = false;
......
......@@ -39,10 +39,11 @@ class MBExchange:
/*! Режимы работы процесса обмена */
enum ExchangeMode
{
emNone, /*!< нормальная работа (по умолчанию) */
emWriteOnly, /*!< "только посылка данных" (работают только write-функции) */
emReadOnly, /*!< "только чтение" (работают только read-функции) */
emSkipSaveToSM /*!< не писать данные в SM (при этом работают и read и write функции */
emNone=0, /*!< нормальная работа (по умолчанию) */
emWriteOnly=1, /*!< "только посылка данных" (работают только write-функции) */
emReadOnly=2, /*!< "только чтение" (работают только read-функции) */
emSkipSaveToSM=3, /*!< не писать данные в SM (при этом работают и read и write функции */
emSkipExchange=4 /*!< отключить обмен */
};
friend std::ostream& operator<<( std::ostream& os, const ExchangeMode& em );
......@@ -145,6 +146,8 @@ class MBExchange:
resp_real(false),
resp_init(false),
ask_every_reg(false),
mode_id(UniSetTypes::DefaultObjectId),
mode(emNone),
speed(ComPort::ComSpeed38400),
rtu(0)
{
......@@ -166,6 +169,9 @@ class MBExchange:
bool resp_real;
bool resp_init;
bool ask_every_reg;
UniSetTypes::ObjectId mode_id;
IOController::AIOStateList::iterator mode_ait;
long mode; // режим работы с устройством (см. ExchangeMode)
// return TRUE if state changed
bool checkRespond();
......@@ -241,7 +247,7 @@ class MBExchange:
void updateRSProperty( RSProperty* p, bool write_only=false );
virtual void updateRespondSensors();
bool checkUpdateSM( bool wrFunc );
bool checkUpdateSM( bool wrFunc, long devMode );
bool checkPoll( bool wrFunc );
bool checkProcActive();
......
......@@ -44,6 +44,7 @@
- \b timeout msec - таймаут, для определения отсутствия связи
- \b invert - инвертировать логику. По умолчанию датчик выставляется в "1" при \b наличии связи.
- \b respondSensor - идентификатор датчика связи.
- \b modeSensor - идентификатор датчика режима работы (см. MBExchange::ExchangeMode).
- \b ask_every_reg - 1 - опрашивать ВСЕ регистры подряд, не обращая внимания на timeout. По умолчанию - "0" Т.е. опрос устройства (на текущем шаге цикла опроса), прерывается на первом же регистре, при опросе которого возникнет timeout.
\par Параметры запуска
......@@ -171,6 +172,7 @@
- \b emSkipSaveToSM - "не записывать данные в SM", это особый режим, похожий на \b emWriteOnly,
но отличие в том, что при этом режиме ведётся полноценый обмен (и read и write),
только реально данные не записываются в SharedMemory(SM).
- \b emSkipExchnage - отключить обмен (при этом данные "из SM" обновляются).
Режимы переключаются при помощи датчика, который можно задать либо аргументом командной строки
\b --prefix-exchange-mode-id либо в конф. файле параметром \b echangeModeID="". Константы определяющие режимы объявлены в MBTCPMaster::ExchangeMode.
......
......@@ -209,6 +209,9 @@ void RTUExchange::poll()
{
RTUDevice* d(it1->second);
if( d->mode_id != DefaultObjectId && d->mode == emSkipExchange )
continue;
if( d->speed != s )
{
s = d->speed;
......@@ -220,9 +223,9 @@ void RTUExchange::poll()
if( !d->rtu )
continue;
if( dlog.debugging(Debug::INFO) )
if( dlog.debugging(Debug::LEVEL3) )
{
dlog[Debug::INFO] << myname << "(pollRTU188): poll RTU188 "
dlog[Debug::LEVEL3] << myname << "(pollRTU188): poll RTU188 "
<< " mbaddr=" << ModbusRTU::addr2str(d->mbaddr)
<< endl;
}
......@@ -250,8 +253,8 @@ void RTUExchange::poll()
}
else
{
if( dlog.debugging(Debug::INFO) )
dlog[Debug::INFO] << myname << "(poll): ask addr=" << ModbusRTU::addr2str(d->mbaddr)
if( dlog.debugging(Debug::LEVEL3) )
dlog[Debug::LEVEL3] << myname << "(poll): ask addr=" << ModbusRTU::addr2str(d->mbaddr)
<< " regs=" << d->regmap.size() << endl;
d->resp_real = false;
......
......@@ -6,12 +6,12 @@ uniset-start.sh -f ./uniset-rtuexchange --confile test.xml \
--rs-name RTUExchange \
--rs-speed 115200 \
--rs-filter-field rs \
--rs-filter-value 2 \
--rs-filter-value 4 \
--dlog-add-levels info,crit,warn,level4,level3 \
--rs-force 0 \
--rs-force-out 0 \
--rs-polltime 500 \
--rs-set-prop-prefix rs_\
--rs-set-prop-prefix \
#,level3
# --rs-force 1 \
......@@ -5,14 +5,18 @@
--mbtcp-name MBMaster1 \
--smemory-id SharedMemory \
--dlog-add-levels info,crit,warn,level4,level3 \
--mbtcp-set-prop-prefix \
--mbtcp-filter-field rs \
--mbtcp-filter-value 1 \
--mbtcp-filter-value 5 \
--mbtcp-gateway-iaddr 127.0.0.1 \
--mbtcp-gateway-port 2048 \
--mbtcp-recv-timeout 5000 \
--mbtcp-force-disconnect 1 \
--mbtcp-polltime 3000 \
--mbtcp-exchange-mode-id MB1_Mode_AS \
--mbtcp-set-prop-prefix rs_
--mbtcp-force-out 1 \
$*
#--mbtcp-exchange-mode-id MB1_Mode_AS \
#--mbtcp-filter-field mbtcp --mbtcp-filter-value 1
#--mbtcp-set-prop-prefix rs_ \
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