Commit cdd7d9ea authored by Pavel Vainerman's avatar Pavel Vainerman

(IOBase): ввёл механизм "зависимостей на уровне IOBase".

parent a265be6b
/*! /*!
\page DependsPage Зависимости между датчиками \page DependsPage Зависимости между датчиками
Существует два механизма реализующих зависимость между датчиками:
- \ref pgDep_secIOControl
- \ref pgDep_secIOBase
\section pgDep_secIOControl Зависимость на уровне IOController (SharedMemmory)
Механизм зависимостей реализован в классе IOController. Механизм зависимостей реализован в классе IOController.
Пример записи "зависимости" в configure.xml: Пример записи "зависимости" в configure.xml:
...@@ -20,4 +26,19 @@ ...@@ -20,4 +26,19 @@
ПОКА РЕАЛИЗОВАНА ЗАВИСИМОСТЬ ТОЛЬКО ОТ ОДНОГО ДАТЧИКА! ПОКА РЕАЛИЗОВАНА ЗАВИСИМОСТЬ ТОЛЬКО ОТ ОДНОГО ДАТЧИКА!
т.е. <depend> может быть только один. т.е. <depend> может быть только один.
\section pgDep_secIOBase Зависимость на уровне IOBase
Механизм зависимостей между датчиками на уровне IOBase,
работает на уровне процессов обмена использующих IOBase.
В ним относятся IOControl, ModbusMaster (RTU,TCP) и т.п.
Плюсом данного механизма является, то, что он обеспечивает
для датчика (который зависит от другого) весь набор обработки,
поддерживаемый IOBase - это задержки на срабатывание, фильтры, калибровочные диаграммы и т.п. (см. \ref IOBase).
Чтобы задействовать данный механизм, достаточно у датчика указать следующие поля:
- \b depend="name"- имя датчика от которого зависит данный
- \b depend_value=".." - разрешающее значение (по умолчанию 1).
- \b depend_off_value="..." - значение которое будет иметь датчик, если он "заблокирован". По умолчанию - 0.
Следует иметь ввиду, что этот механизм не действует при сохранении значений, например при помощи uniset-admin,
в отличие от механизма \ref pgDep_secIOControl
*/ */
...@@ -36,6 +36,10 @@ static const int NoSafety = -1; ...@@ -36,6 +36,10 @@ static const int NoSafety = -1;
jar_state(false), jar_state(false),
ondelay_state(false), ondelay_state(false),
offdelay_state(false), offdelay_state(false),
d_id(UniSetTypes::DefaultObjectId),
d_value(0),
d_off_value(0),
d_iotype(UniversalIO::UnknownIOType),
t_ai(UniSetTypes::DefaultObjectId) t_ai(UniSetTypes::DefaultObjectId)
{} {}
...@@ -46,6 +50,8 @@ static const int NoSafety = -1; ...@@ -46,6 +50,8 @@ static const int NoSafety = -1;
bool check_on_delay( bool val ); /*!< реализация задержки на включение */ bool check_on_delay( bool val ); /*!< реализация задержки на включение */
bool check_off_delay( bool val ); /*!< реализация задержки на отключение */ bool check_off_delay( bool val ); /*!< реализация задержки на отключение */
bool check_depend( SMInterface* shm ); /*!< проверка разрешения(зависимости) от другого датчика */
IOController_i::SensorInfo si; IOController_i::SensorInfo si;
UniversalIO::IOTypes stype; /*!< тип канала (DI,DO,AI,AO) */ UniversalIO::IOTypes stype; /*!< тип канала (DI,DO,AI,AO) */
IOController_i::CalibrateInfo cal; /*!< калибровочные параметры */ IOController_i::CalibrateInfo cal; /*!< калибровочные параметры */
...@@ -81,7 +87,14 @@ static const int NoSafety = -1; ...@@ -81,7 +87,14 @@ static const int NoSafety = -1;
bool ondelay_state; /*!< значение для задержки включения */ bool ondelay_state; /*!< значение для задержки включения */
bool offdelay_state; /*!< значение для задержки отключения */ bool offdelay_state; /*!< значение для задержки отключения */
// Зависимость (d - depend)
UniSetTypes::ObjectId d_id; /*!< идентификатор датчика, от которого зависит данный */
IOController::AIOStateList::iterator d_ait; /*! итератор на датчик от которого зависит данный */
IOController::DIOStateList::iterator d_dit; /*! итератор на датчик от которого зависит данный */
long d_value; /*!< разрешающее работу значение датчика от которого зависит данный */
long d_off_value; /*!< блокирующее значение */
UniversalIO::IOTypes d_iotype;
// Порог // Порог
UniSetTypes::ObjectId t_ai; /*!< если данный датчик дискретный, UniSetTypes::ObjectId t_ai; /*!< если данный датчик дискретный,
и является пороговым, то в данном поле и является пороговым, то в данном поле
......
...@@ -92,6 +92,30 @@ bool IOBase::check_off_delay( bool val ) ...@@ -92,6 +92,30 @@ bool IOBase::check_off_delay( bool val )
return offdelay_state; return offdelay_state;
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
bool IOBase::check_depend( SMInterface* shm )
{
if( d_id == DefaultObjectId )
return true;
if( d_iotype == UniversalIO::DigitalInput || d_iotype == UniversalIO::DigitalOutput )
{
if( shm->localGetState(d_dit,d_id) == (bool)d_value )
return true;
return false;
}
if( d_iotype == UniversalIO::AnalogInput || d_iotype == UniversalIO::AnalogOutput )
{
if( shm->localGetValue(d_ait,d_id) == d_value )
return true;
return false;
}
return true;
}
// -----------------------------------------------------------------------------
void IOBase::processingAsAI( IOBase* it, long val, SMInterface* shm, bool force ) void IOBase::processingAsAI( IOBase* it, long val, SMInterface* shm, bool force )
{ {
// проверка на обрыв // проверка на обрыв
...@@ -103,39 +127,45 @@ void IOBase::processingAsAI( IOBase* it, long val, SMInterface* shm, bool force ...@@ -103,39 +127,45 @@ void IOBase::processingAsAI( IOBase* it, long val, SMInterface* shm, bool force
return; return;
} }
if( !it->nofilter && it->df.size() > 1 ) // проверка зависимости
if( !it->check_depend(shm) )
val = it->d_off_value;
else
{ {
if( it->f_median ) if( !it->nofilter && it->df.size() > 1 )
val = it->df.median(val); {
else if( it->f_filter_iir ) if( it->f_median )
val = it->df.filterIIR(val); val = it->df.median(val);
else if( it->f_ls ) else if( it->f_filter_iir )
val = it->df.leastsqr(val); val = it->df.filterIIR(val);
else else if( it->f_ls )
val = it->df.filterRC(val); val = it->df.leastsqr(val);
} else
val = it->df.filterRC(val);
}
if( it->cdiagram ) // задана специальная калибровочная диаграмма if( it->cdiagram ) // задана специальная калибровочная диаграмма
{ {
if( it->craw != val ) if( it->craw != val )
{ {
it->craw = val; it->craw = val;
val = it->cdiagram->getValue(val); val = it->cdiagram->getValue(val);
it->cprev = val; it->cprev = val;
}
else
val = it->cprev; // просто передаём предыдущее значение
} }
else else
val = it->cprev; // просто передаём предыдущее значение {
} IOController_i::CalibrateInfo* cal( &(it->cal) );
else if( cal->maxRaw!=cal->minRaw ) // задана обычная калибровка
{ val = UniSetTypes::lcalibrate(val,cal->minRaw,cal->maxRaw,cal->minCal,cal->maxCal,true);
IOController_i::CalibrateInfo* cal( &(it->cal) ); }
if( cal->maxRaw!=cal->minRaw ) // задана обычная калибровка
val = UniSetTypes::lcalibrate(val,cal->minRaw,cal->maxRaw,cal->minCal,cal->maxCal,true);
}
if( !it->noprecision && it->cal.precision > 0 ) if( !it->noprecision && it->cal.precision > 0 )
val *= lround(pow10(it->cal.precision)); val *= lround(pow10(it->cal.precision));
} // end of 'check_depend'
// если предыдущее значение "обрыв", // если предыдущее значение "обрыв",
// то сбрасываем признак // то сбрасываем признак
...@@ -176,18 +206,24 @@ void IOBase::processingFasAI( IOBase* it, float fval, SMInterface* shm, bool for ...@@ -176,18 +206,24 @@ void IOBase::processingFasAI( IOBase* it, float fval, SMInterface* shm, bool for
return; return;
} }
// Читаем с использованием фильтра... // проверка зависимости
if( !it->nofilter ) if( !it->check_depend(shm) )
val = it->d_off_value;
else
{ {
if( it->df.size() > 1 ) // Читаем с использованием фильтра...
it->df.add(val); if( !it->nofilter )
{
if( it->df.size() > 1 )
it->df.add(val);
val = it->df.filterRC(val); val = it->df.filterRC(val);
} }
IOController_i::CalibrateInfo* cal( &(it->cal) ); IOController_i::CalibrateInfo* cal( &(it->cal) );
if( cal->maxRaw!=cal->minRaw ) // задана обычная калибровка if( cal->maxRaw!=cal->minRaw ) // задана обычная калибровка
val = UniSetTypes::lcalibrate(val,cal->minRaw,cal->maxRaw,cal->minCal,cal->maxCal,true); val = UniSetTypes::lcalibrate(val,cal->minRaw,cal->maxRaw,cal->minCal,cal->maxCal,true);
}
// если предыдущее значение "обрыв", // если предыдущее значение "обрыв",
// то сбрасываем признак // то сбрасываем признак
...@@ -214,18 +250,24 @@ void IOBase::processingFasAI( IOBase* it, float fval, SMInterface* shm, bool for ...@@ -214,18 +250,24 @@ void IOBase::processingFasAI( IOBase* it, float fval, SMInterface* shm, bool for
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
void IOBase::processingAsDI( IOBase* it, bool set, SMInterface* shm, bool force ) void IOBase::processingAsDI( IOBase* it, bool set, SMInterface* shm, bool force )
{ {
// cout << "subdev: " << it->subdev << " chan: " << it->channel << " state=" << set << endl; // проверка зависимости
if( it->invert ) if( !it->check_depend(shm) )
set ^= true; set = (bool)it->d_off_value;
// cout << "subdev: " << it->subdev << " chan: " << it->channel << " (inv)state=" << set << endl; else
{
// Проверяем именно в такой последовательности! // cout << "subdev: " << it->subdev << " chan: " << it->channel << " state=" << set << endl;
set = it->check_jar(set); // фильтр дребезга if( it->invert )
// cout << "subdev: " << it->subdev << " chan: " << it->channel << " (jar)state=" << set << endl; set ^= true;
set = it->check_on_delay(set); // фильтр на срабатывание // cout << "subdev: " << it->subdev << " chan: " << it->channel << " (inv)state=" << set << endl;
// cout << "subdev: " << it->subdev << " chan: " << it->channel << " (on_delay)state=" << set << endl;
set = it->check_off_delay(set); // фильтр на отпускание // Проверяем именно в такой последовательности!
// cout << "subdev: " << it->subdev << " chan: " << it->channel << " (off_delay)state=" << set << endl; set = it->check_jar(set); // фильтр дребезга
// cout << "subdev: " << it->subdev << " chan: " << it->channel << " (jar)state=" << set << endl;
set = it->check_on_delay(set); // фильтр на срабатывание
// cout << "subdev: " << it->subdev << " chan: " << it->channel << " (on_delay)state=" << set << endl;
set = it->check_off_delay(set); // фильтр на отпускание
// cout << "subdev: " << it->subdev << " chan: " << it->channel << " (off_delay)state=" << set << endl;
}
{ {
uniset_spin_lock lock(it->val_lock); uniset_spin_lock lock(it->val_lock);
...@@ -250,6 +292,10 @@ long IOBase::processingAsAO( IOBase* it, SMInterface* shm, bool force ) ...@@ -250,6 +292,10 @@ long IOBase::processingAsAO( IOBase* it, SMInterface* shm, bool force )
uniset_spin_lock lock(it->val_lock); uniset_spin_lock lock(it->val_lock);
long val = it->value; long val = it->value;
// проверка зависимости
if( !it->check_depend(shm) )
return it->d_off_value;
if( force ) if( force )
{ {
if( it->stype == UniversalIO::DigitalInput || it->stype == UniversalIO::DigitalOutput ) if( it->stype == UniversalIO::DigitalInput || it->stype == UniversalIO::DigitalOutput )
...@@ -296,25 +342,32 @@ long IOBase::processingAsAO( IOBase* it, SMInterface* shm, bool force ) ...@@ -296,25 +342,32 @@ long IOBase::processingAsAO( IOBase* it, SMInterface* shm, bool force )
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
bool IOBase::processingAsDO( IOBase* it, SMInterface* shm, bool force ) bool IOBase::processingAsDO( IOBase* it, SMInterface* shm, bool force )
{ {
uniset_spin_lock lock(it->val_lock); // проверка зависимости
bool set = it->value; if( !it->check_depend(shm) )
return (bool)it->d_off_value;
if( force ) uniset_spin_lock lock(it->val_lock);
{ bool set = it->value;
if( it->stype == UniversalIO::DigitalInput || it->stype == UniversalIO::DigitalOutput )
set = shm->localGetState(it->dit,it->si.id); if( force )
else if( it->stype == UniversalIO::AnalogInput || it->stype == UniversalIO::AnalogOutput ) {
set = shm->localGetValue(it->ait,it->si.id) ? true : false; if( it->stype == UniversalIO::DigitalInput || it->stype == UniversalIO::DigitalOutput )
} set = shm->localGetState(it->dit,it->si.id);
else if( it->stype == UniversalIO::AnalogInput || it->stype == UniversalIO::AnalogOutput )
set = shm->localGetValue(it->ait,it->si.id) ? true : false;
}
set = it->invert ? !set : set; set = it->invert ? !set : set;
return set; return set;
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
float IOBase::processingFasAO( IOBase* it, SMInterface* shm, bool force ) float IOBase::processingFasAO( IOBase* it, SMInterface* shm, bool force )
{ {
uniset_spin_lock lock(it->val_lock); // проверка зависимости
if( !it->check_depend(shm) )
return (float)it->d_off_value;
uniset_spin_lock lock(it->val_lock);
long val = it->value; long val = it->value;
if( force ) if( force )
...@@ -453,7 +506,29 @@ bool IOBase::initItem( IOBase* b, UniXML_iterator& it, SMInterface* shm, ...@@ -453,7 +506,29 @@ bool IOBase::initItem( IOBase* b, UniXML_iterator& it, SMInterface* shm,
b->f_filter_iir = false; b->f_filter_iir = false;
shm->initAIterator(b->ait); shm->initAIterator(b->ait);
shm->initAIterator(b->d_ait);
shm->initDIterator(b->dit); shm->initDIterator(b->dit);
shm->initDIterator(b->d_dit);
string d_txt(it.getProp("depend"));
if( !it.getProp("depend").empty() )
{
b->d_id = conf->getSensorID(it.getProp("depend"));
if( b->d_id == DefaultObjectId )
{
if( dlog )
dlog[Debug::CRIT] << myname << "(IOBase::readItem): sensor='"
<< it.getProp("name") << "' err: "
<< " Unknown SensorID for depend='" << it.getProp("depend")
<< endl;
return false;
}
// по умолчанию срабатывание на "1"
b->d_value = it.getProp("depend_value").empty() ? 1 : it.getIntProp("depend_value");
b->d_off_value = it.getIntProp("depend_off_value");
b->d_iotype = conf->getIOType(b->d_id);
}
if( b->stype == UniversalIO::AnalogInput || b->stype == UniversalIO::AnalogOutput ) if( b->stype == UniversalIO::AnalogInput || b->stype == UniversalIO::AnalogOutput )
{ {
......
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