add scalarAlarmSupport

This commit is contained in:
mrkraimer
2019-06-04 14:21:38 -04:00
parent b052e28788
commit 6c91249340
9 changed files with 371 additions and 30 deletions

View File

@ -17,6 +17,7 @@ INC += pv/removeRecord.h
INC += pv/numericRecord.h INC += pv/numericRecord.h
INC += pv/pvSupport.h INC += pv/pvSupport.h
INC += pv/controlSupport.h INC += pv/controlSupport.h
INC += pv/scalarAlarmSupport.h
include $(PVDATABASE_SRC)/copy/Makefile include $(PVDATABASE_SRC)/copy/Makefile
include $(PVDATABASE_SRC)/database/Makefile include $(PVDATABASE_SRC)/database/Makefile
include $(PVDATABASE_SRC)/pvAccess/Makefile include $(PVDATABASE_SRC)/pvAccess/Makefile

View File

@ -45,20 +45,22 @@ public:
*/ */
virtual ~ControlSupport(); virtual ~ControlSupport();
/** /**
* @brief Optional initialization method. * @brief Connects to contol fields.
* *
* A derived method <b>Must</b> call initControlSupport. * @param pvValue The field to support.
* @param pvSupport Support specific fields.
* @return <b>true</b> for success and <b>false</b> for failure. * @return <b>true</b> for success and <b>false</b> for failure.
*/ */
virtual bool init(); virtual bool init(
epics::pvData::PVFieldPtr const & pvValue,
epics::pvData::PVFieldPtr const & pvSupport);
/** /**
* @brief Optional method for derived class. * @brief Honors control fields.
*
* *
*/ */
virtual void process(); virtual void process();
/** /**
* @brief Optional method for derived class. * @brief If implementing minSteps it sets isMinStep to false.
* *
*/ */
virtual void reset(); virtual void reset();

View File

@ -15,6 +15,7 @@
#include <pv/channelProviderLocal.h> #include <pv/channelProviderLocal.h>
#include <pv/controlSupport.h> #include <pv/controlSupport.h>
#include <pv/scalarAlarmSupport.h>
namespace epics { namespace pvDatabase { namespace epics { namespace pvDatabase {
@ -23,10 +24,10 @@ class NumericRecord;
typedef std::tr1::shared_ptr<NumericRecord> NumericRecordPtr; typedef std::tr1::shared_ptr<NumericRecord> NumericRecordPtr;
/** /**
* @brief support for control and valueAlarm for a numeric scalar record * @brief support for control and scalarAlarm for a numeric scalar record
* *
* This is support for a record with a top level field that has type scalar. * This is support for a record with a top level field that has type scalar.
* It provides support for control and valueAlarm * It provides support for control and scalarAlarm
*/ */
class epicsShareClass NumericRecord : class epicsShareClass NumericRecord :
public PVRecord public PVRecord
@ -56,6 +57,7 @@ private:
std::string const & recordName, std::string const & recordName,
epics::pvData::PVStructurePtr const & pvStructure); epics::pvData::PVStructurePtr const & pvStructure);
ControlSupportPtr controlSupport; ControlSupportPtr controlSupport;
ScalarAlarmSupportPtr scalarAlarmSupport;
epics::pvData::PVBooleanPtr pvReset; epics::pvData::PVBooleanPtr pvReset;
}; };

View File

@ -51,10 +51,15 @@ public:
/** /**
* @brief Optional initialization method. * @brief Optional initialization method.
* *
* A derived method <b>Must</b> call initPVSupport. * Called after PVRecord is created but before record is installed into PVDatabase.
*
* @param pvValue The field to support.
* @param pvSupport Support specific fields.
* @return <b>true</b> for success and <b>false</b> for failure. * @return <b>true</b> for success and <b>false</b> for failure.
*/ */
virtual bool init() {return true;} virtual bool init(
epics::pvData::PVFieldPtr const & pvValue,
epics::pvData::PVFieldPtr const & pvSupport) {return true;}
/** /**
* @brief Optional method for derived class. * @brief Optional method for derived class.
* *
@ -62,13 +67,10 @@ public:
*/ */
virtual void start() {} virtual void start() {}
/** /**
* @brief Optional method for derived class. * @brief Virtual method for derived class.
* *
* It is the method that makes a record smart. * It is the method that implements support.
* If it encounters errors it should raise alarms and/or * It is called each time the record is processed.
* call the <b>message</b> method provided by the base class.
* If the pvStructure has a top level timeStamp,
* the base class sets the timeStamp to the current time.
*/ */
virtual void process() = 0; virtual void process() = 0;
/** /**

107
src/pv/scalarAlarmSupport.h Normal file
View File

@ -0,0 +1,107 @@
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2019.06.01
*/
#ifndef SCALARALARMSUPPORT_H
#define SCALARALARMSUPPORT_H
#ifdef epicsExportSharedSymbols
# define pvdatabaseEpicsExportSharedSymbols
# undef epicsExportSharedSymbols
#endif
#include <pv/pvDatabase.h>
#include <pv/pvSupport.h>
#include <pv/alarm.h>
#include <pv/pvAlarm.h>
#ifdef pvdatabaseEpicsExportSharedSymbols
# define epicsExportSharedSymbols
# undef pvdatabaseEpicsExportSharedSymbols
#endif
#include <shareLib.h>
#include <pv/pvStructureCopy.h>
namespace epics { namespace pvDatabase {
class ScalarAlarmSupport;
typedef std::tr1::shared_ptr<ScalarAlarmSupport> ScalarAlarmSupportPtr;
/**
* @brief Base interface for a ScalarAlarmSupport.
*
*/
class epicsShareClass ScalarAlarmSupport :
PVSupport
{
public:
POINTER_DEFINITIONS(ScalarAlarmSupport);
/**
* The Destructor.
*/
virtual ~ScalarAlarmSupport();
/**
* @brief Connects to contol fields.
*
* @param pvValue The field to support.
* @param pvSupport Support specific fields.
* @return <b>true</b> for success and <b>false</b> for failure.
*/
virtual bool init(
epics::pvData::PVFieldPtr const & pvValue,
epics::pvData::PVStructurePtr const & pvAlarm,
epics::pvData::PVFieldPtr const & pvSupport);
/**
* @brief Honors scalarAlarm fields.
*
*/
virtual void process();
/**
* @brief If implementing minSteps it sets isMinStep to false.
*
*/
virtual void reset();
static ScalarAlarmSupportPtr create(PVRecordPtr const & pvRecord);
static epics::pvData::StructureConstPtr scalarAlarm();
private:
static epics::pvData::StructureConstPtr scalarAlarmField;
ScalarAlarmSupport(PVRecordPtr const & pvRecord);
enum {
range_Lolo = 0,
range_Low,
range_Normal,
range_High,
range_Hihi,
range_Invalid,
range_Undefined
} AlarmRange;
void setAlarm(
epics::pvData::PVStructurePtr const & pvAlarm,
int alarmRange);
PVRecordPtr pvRecord;
int prevAlarmRange;
epics::pvData::PVScalarPtr pvValue;
epics::pvData::PVStructurePtr pvAlarm;
epics::pvData::PVStructurePtr pvScalarAlarm;
epics::pvData::PVBooleanPtr pvActive;
epics::pvData::PVDoublePtr pvLowAlarmLimit;
epics::pvData::PVDoublePtr pvLowWarningLimit;
epics::pvData::PVDoublePtr pvHighWarningLimit;
epics::pvData::PVDoublePtr pvHighAlarmLimit;
epics::pvData::PVDoublePtr pvHysteresis;
double requestedValue;
double currentValue;
bool isHystersis;
};
}}
#endif /* SCALARALARMSUPPORT_H */

View File

@ -12,6 +12,7 @@
#include <pv/convert.h> #include <pv/convert.h>
#include <pv/standardField.h> #include <pv/standardField.h>
#include <pv/controlSupport.h> #include <pv/controlSupport.h>
#include <pv/scalarAlarmSupport.h>
#define epicsExportSharedSymbols #define epicsExportSharedSymbols
@ -42,7 +43,7 @@ NumericRecordPtr NumericRecord::create(
add("timeStamp",standardField->timeStamp()) -> add("timeStamp",standardField->timeStamp()) ->
add("display",standardField->display()) -> add("display",standardField->display()) ->
add("control",standardField->control()) -> add("control",standardField->control()) ->
add("valueAlarm",standardField->doubleAlarm()) -> add("scalarAlarm",ScalarAlarmSupport::scalarAlarm()) ->
createStructure(); createStructure();
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(topStructure); PVStructurePtr pvStructure = pvDataCreate->createPVStructure(topStructure);
NumericRecordPtr pvRecord( NumericRecordPtr pvRecord(
@ -62,8 +63,16 @@ bool NumericRecord::init()
{ {
initPVRecord(); initPVRecord();
PVRecordPtr pvRecord = shared_from_this(); PVRecordPtr pvRecord = shared_from_this();
PVStructurePtr pvStructure(getPVStructure());
controlSupport = ControlSupport::create(pvRecord); controlSupport = ControlSupport::create(pvRecord);
bool result = controlSupport->init(); bool result = controlSupport->init(
pvStructure->getSubField("value"),pvStructure->getSubField("control"));
if(!result) return false;
scalarAlarmSupport = ScalarAlarmSupport::create(pvRecord);
result = scalarAlarmSupport->init(
pvStructure->getSubField("value"),
pvStructure->getSubField<PVStructure>("alarm"),
pvStructure->getSubField("scalarAlarm"));
if(!result) return false; if(!result) return false;
pvReset = getPVStructure()->getSubField<PVBoolean>("reset"); pvReset = getPVStructure()->getSubField<PVBoolean>("reset");
return true; return true;
@ -74,8 +83,10 @@ void NumericRecord::process()
if(pvReset->get()==true) { if(pvReset->get()==true) {
pvReset->put(false); pvReset->put(false);
controlSupport->reset(); controlSupport->reset();
scalarAlarmSupport->reset();
} else { } else {
controlSupport->process(); controlSupport->process();
scalarAlarmSupport->process();
} }
PVRecord::process(); PVRecord::process();
} }

View File

@ -3,3 +3,4 @@
SRC_DIRS += $(PVDATABASE_SRC)/support SRC_DIRS += $(PVDATABASE_SRC)/support
LIBSRCS += controlSupport.cpp LIBSRCS += controlSupport.cpp
LIBSRCS += scalarAlarmSupport.cpp

View File

@ -39,10 +39,8 @@ ControlSupport::ControlSupport(PVRecordPtr const & pvRecord)
: pvRecord(pvRecord) : pvRecord(pvRecord)
{} {}
bool ControlSupport::init() bool ControlSupport::init(PVFieldPtr const & pv,PVFieldPtr const & pvsup)
{ {
PVStructurePtr pvStructure = pvRecord->getPVStructure();
PVFieldPtr pv(pvStructure->getSubField("value"));
if(pv) { if(pv) {
if(pv->getField()->getType()==epics::pvData::scalar) { if(pv->getField()->getType()==epics::pvData::scalar) {
ScalarConstPtr s = static_pointer_cast<const Scalar>(pv->getField()); ScalarConstPtr s = static_pointer_cast<const Scalar>(pv->getField());
@ -56,14 +54,21 @@ bool ControlSupport::init()
<< " failed because not numeric scalar\n"; << " failed because not numeric scalar\n";
return false; return false;
} }
pvControl = static_pointer_cast<PVStructure>(pvsup);
if(pvControl) {
pvLimitLow = pvControl->getSubField<PVDouble>("limitLow");
pvLimitHigh = pvControl->getSubField<PVDouble>("limitHigh");
pvMinStep = pvControl->getSubField<PVDouble>("minStep");
}
if(!pvControl || !pvLimitLow || !pvLimitHigh || !pvMinStep) {
cout << "ControlSupport for record " << pvRecord->getRecordName()
<< " failed because pvSupport not a valid control structure\n";
return false;
}
ConvertPtr convert = getConvert(); ConvertPtr convert = getConvert();
requestedValue = convert->toDouble(pvValue); requestedValue = convert->toDouble(pvValue);
currentValue = requestedValue; currentValue = requestedValue;
isMinStep = false; isMinStep = false;
pvControl = pvStructure->getSubField<PVStructure>("control");
pvLimitLow = pvControl->getSubField<PVDouble>("limitLow");
pvLimitHigh = pvControl->getSubField<PVDouble>("limitHigh");
pvMinStep = pvControl->getSubField<PVDouble>("minStep");
return true; return true;
} }
@ -71,11 +76,6 @@ void ControlSupport::process()
{ {
ConvertPtr convert = getConvert(); ConvertPtr convert = getConvert();
double value = convert->toDouble(pvValue); double value = convert->toDouble(pvValue);
cout << "value " << value
<< " requestedValue " << requestedValue
<< " currentValue " << currentValue
<< " isMinStep " << (isMinStep ? "true" : "false")
<< "\n";
if(value==requestedValue&&value==currentValue) return; if(value==requestedValue&&value==currentValue) return;
if(!isMinStep) requestedValue = value; if(!isMinStep) requestedValue = value;
double limitLow = pvLimitLow->get(); double limitLow = pvLimitLow->get();

View File

@ -0,0 +1,215 @@
/* scalarAlarmSupport.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2019.06.01
*/
#include <pv/pvDatabase.h>
#include <pv/pvSupport.h>
#include <pv/convert.h>
#include <pv/standardField.h>
#include <pv/alarm.h>
#include <pv/pvAlarm.h>
#define epicsExportSharedSymbols
#include <pv/scalarAlarmSupport.h>
using std::tr1::static_pointer_cast;
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace std;
namespace epics { namespace pvDatabase {
ScalarAlarmSupport::~ScalarAlarmSupport()
{
cout << "ScalarAlarmSupport::~ScalarAlarmSupport()\n";
}
epics::pvData::StructureConstPtr ScalarAlarmSupport::scalarAlarmField =
FieldBuilder::begin()
->setId("scalarAlarm_t")
->add("active", pvBoolean)
->add("lowAlarmLimit", pvDouble)
->add("lowWarningLimit", pvDouble)
->add("highWarningLimit", pvDouble)
->add("highAlarmLimit", pvDouble)
->add("hysteresis", pvDouble)
->createStructure();
epics::pvData::StructureConstPtr ScalarAlarmSupport::scalarAlarm()
{
return scalarAlarmField;
}
ScalarAlarmSupportPtr ScalarAlarmSupport::create(PVRecordPtr const & pvRecord)
{
ScalarAlarmSupportPtr support(new ScalarAlarmSupport(pvRecord));
return support;
}
ScalarAlarmSupport::ScalarAlarmSupport(PVRecordPtr const & pvRecord)
: pvRecord(pvRecord),
prevAlarmRange(range_Undefined)
{}
bool ScalarAlarmSupport::init(
PVFieldPtr const & pvval,
PVStructurePtr const & pvalarm,
PVFieldPtr const & pvsup)
{
if(pvval->getField()->getType()==epics::pvData::scalar) {
ScalarConstPtr s = static_pointer_cast<const Scalar>(pvval->getField());
if(ScalarTypeFunc::isNumeric(s->getScalarType())) {
pvValue = static_pointer_cast<PVScalar>(pvval);
}
}
if(!pvValue) {
cout << "ScalarAlarmSupport for record " << pvRecord->getRecordName()
<< " failed because not numeric scalar\n";
return false;
}
pvScalarAlarm = static_pointer_cast<PVStructure>(pvsup);
if(pvScalarAlarm) {
pvActive = pvScalarAlarm->getSubField<PVBoolean>("active");
pvLowAlarmLimit = pvScalarAlarm->getSubField<PVDouble>("lowAlarmLimit");
pvLowWarningLimit = pvScalarAlarm->getSubField<PVDouble>("lowWarningLimit");
pvHighWarningLimit = pvScalarAlarm->getSubField<PVDouble>("highWarningLimit");
pvHighAlarmLimit = pvScalarAlarm->getSubField<PVDouble>("highAlarmLimit");
pvHysteresis = pvScalarAlarm->getSubField<PVDouble>("hysteresis");
}
if(!pvScalarAlarm
|| !pvActive
|| !pvLowAlarmLimit || !pvLowWarningLimit
|| !pvLowWarningLimit || !pvHighAlarmLimit
|| !pvHysteresis)
{
cout << "ScalarAlarmSupport for record " << pvRecord->getRecordName()
<< " failed because pvSupport not a valid scalarAlarm structure\n";
return false;
}
pvAlarm = pvalarm;
ConvertPtr convert = getConvert();
requestedValue = convert->toDouble(pvValue);
currentValue = requestedValue;
isHystersis = false;
setAlarm(pvAlarm,range_Undefined);
return true;
}
void ScalarAlarmSupport::process()
{
ConvertPtr convert = getConvert();
double value = convert->toDouble(pvValue);
double lowAlarmLimit = pvLowAlarmLimit->get();
double lowWarningLimit = pvLowWarningLimit->get();
double highWarningLimit = pvHighWarningLimit->get();
double highAlarmLimit = pvHighAlarmLimit->get();
double hysteresis = pvHysteresis->get();
int alarmRange = range_Normal;
if(highAlarmLimit>lowAlarmLimit) {
if(value>=highAlarmLimit) {
alarmRange = range_Hihi;
} else if(value<=lowAlarmLimit) {
alarmRange = range_Lolo;
}
}
if(alarmRange==range_Normal && (pvHighWarningLimit>pvLowWarningLimit)) {
if(value>=highWarningLimit) {
alarmRange = range_High;
} else if(value<=lowWarningLimit) {
alarmRange = range_Low;
}
}
cout << "ScalarAlarmSupport::process() alarmRange " << alarmRange
<< " prevAlarmRange " << prevAlarmRange << "\n";
if(alarmRange!=prevAlarmRange) setAlarm(pvAlarm,alarmRange);
prevAlarmRange = alarmRange;
}
void ScalarAlarmSupport::reset()
{
isHystersis = false;
}
void ScalarAlarmSupport::setAlarm(
epics::pvData::PVStructurePtr const & pva,
int alarmRange)
{
Alarm alarm;
PVAlarm pvAlarm;
if(!pvAlarm.attach(pva)) throw std::logic_error("bad alarm field");
epics::pvData::AlarmStatus status(epics::pvData::noStatus);
epics::pvData::AlarmSeverity severity(epics::pvData::noAlarm);
string message;
switch (alarmRange) {
case range_Lolo :
{
severity = epics::pvData::majorAlarm;
status = epics::pvData::recordStatus;
message = "major low alarm";
break;
}
case range_Low :
{
severity = epics::pvData::minorAlarm;
status = epics::pvData::recordStatus;
message = "minor low alarm";
break;
}
case range_Normal :
{
break;
}
case range_High :
{
severity = epics::pvData::minorAlarm;
status = epics::pvData::recordStatus;
message = "minor high alarm";
break;
}
case range_Hihi :
{
severity = epics::pvData::majorAlarm;
status = epics::pvData::recordStatus;
message = "major high alarm";
break;
}
case range_Invalid :
{
severity = epics::pvData::invalidAlarm;
status = epics::pvData::recordStatus;
message = "invalid alarm";
break;
}
case range_Undefined :
{
severity = epics::pvData::undefinedAlarm;
status = epics::pvData::recordStatus;
message = "undefined alarm";
break;
}
default:
{
severity = epics::pvData::undefinedAlarm;
status = epics::pvData::recordStatus;
message = "bad alarm definition";
break;
}
}
alarm.setStatus(status);
alarm.setSeverity(severity);
alarm.setMessage(message);
pvAlarm.set(alarm);
}
}}