merged record-updates branch

This commit is contained in:
Andrew Johnson
2012-06-22 17:58:12 -05:00
30 changed files with 2073 additions and 1166 deletions

View File

@@ -15,6 +15,40 @@ EPICS Base 3.15.0.x releases are not intended for use in production systems.</p>
<h2 align="center">Changes between 3.14.x and 3.15.0.x</h2>
<!-- Insert new items immediately below here ... -->
<h3>Alarm filtering added to input record types</h3>
<p>The record types ai, calc, longin and mbbi have a new alarm filter added to
them. This provides a low-pass filter that can be used to delay the reporting of
alarms caused by the input level passing the HIGH, HIHI, LOW or LOLO values. The
filter is controlled with a new AFTC field that sets the filter's time constant.
The default value for this field is zero, which keeps the record's original
alarm behaviour.</p>
<p>The record must be scanned often enough for the filtering action to work
effectively and the alarm severity can only change when the record is processed,
but that processing does not have to be regular; the filter uses the time since
the record last processed in its calculation. Setting AFTC to a positive number
of seconds will delay the record going into or out of a minor alarm severity or
from minor to major severity until the input signal has been in that range for
that number of seconds.</p>
<h3>Post events on Waveform record's NORD field</h3>
<p>When the record type or soft device support modify the NORD field of a
waveform record they now also post a DBE_VALUE and DBE_LOG event, signalling the
array length change to any clients monitoring the NORD field. Input device
support routines should be modified to do this as well.</p>
<h3>Attributes of Non-VAL Fields</h3>
<p>Non-VAL fields now report meaningful information for precision, units,
graphic limits, control limits, and alarm limits instead of simply using
PREC, EGU, HOPR, LOPR, DRVL, DRVH, HIHI, HIGH, LOW, and LOLO. All delay
fields have a default precision of 2 digits, units "s" and control limits
of 0 to 100,000 seconds (these precision and limit values can be changed
for each record type as a whole at runtime by updating a registered global
variable). Input fields like A-L of the calc record read their metadata
from the corresponding INPn link if possible.</p>
<h4>epicsStdioRedirect.h merged into epicsStdio.h</h4>
<p>The definitions from the header file epicsStdioRedirect.h have been moved

View File

@@ -20,6 +20,7 @@
#include "alarm.h"
#include "dbDefs.h"
#include "dbAccess.h"
#include "dbEvent.h"
#include "recGbl.h"
#include "devSup.h"
#include "waveformRecord.h"
@@ -75,6 +76,7 @@ static long read_wf(waveformRecord *prec)
if (prec->tsel.type == CONSTANT &&
prec->tse == epicsTimeEventDeviceTime)
dbGetTimeStamp(&prec->inp, &prec->time);
db_post_events(prec, &prec->nord, DBE_VALUE | DBE_LOG);
}
return 0;

View File

@@ -53,14 +53,14 @@ static long special(DBADDR *, int);
static long cvt_dbaddr(DBADDR *);
static long get_array_info(DBADDR *, long *, long *);
static long put_array_info(DBADDR *, long );
#define get_units NULL
static long get_units(DBADDR *, char *);
static long get_precision(DBADDR *, long *);
#define get_enum_str NULL
#define get_enum_strs NULL
#define put_enum_str NULL
#define get_graphic_double NULL
#define get_control_double NULL
#define get_alarm_double NULL
static long get_graphic_double(DBADDR *, struct dbr_grDouble *);
static long get_control_double(DBADDR *, struct dbr_ctrlDouble *);
static long get_alarm_double(DBADDR *, struct dbr_alDouble *);
rset aSubRSET = {
RSETNUMBER,
@@ -330,15 +330,116 @@ static long fetch_values(aSubRecord *prec)
return 0;
}
static long get_precision(DBADDR *paddr, long *precision)
#define indexof(field) aSubRecord##field
static long get_inlinkNumber(int fieldIndex) {
if (fieldIndex >= indexof(A) && fieldIndex <= indexof(U))
return fieldIndex - indexof(A);
return -1;
}
static long get_outlinkNumber(int fieldIndex) {
if (fieldIndex >= indexof(VALA) && fieldIndex <= indexof(VALU))
return fieldIndex - indexof(VALA);
return -1;
}
static long get_units(DBADDR *paddr, char *units)
{
aSubRecord *prec = (aSubRecord *)paddr->precord;
int linkNumber;
*precision = prec->prec;
recGblGetPrec(paddr, precision);
linkNumber = get_inlinkNumber(dbGetFieldIndex(paddr));
if (linkNumber >= 0) {
dbGetUnits(&prec->inpa + linkNumber, units, DB_UNITS_SIZE);
return 0;
}
linkNumber = get_outlinkNumber(dbGetFieldIndex(paddr));
if (linkNumber >= 0) {
dbGetUnits(&prec->outa + linkNumber, units, DB_UNITS_SIZE);
}
return 0;
}
static long get_precision(DBADDR *paddr, long *pprecision)
{
aSubRecord *prec = (aSubRecord *)paddr->precord;
int fieldIndex = dbGetFieldIndex(paddr);
int linkNumber;
short precision;
*pprecision = prec->prec;
linkNumber = get_inlinkNumber(fieldIndex);
if (linkNumber >= 0) {
if (dbGetPrecision(&prec->inpa + linkNumber, &precision) == 0)
*pprecision = precision;
return 0;
}
linkNumber = get_outlinkNumber(fieldIndex);
if (linkNumber >= 0) {
if (dbGetPrecision(&prec->outa + linkNumber, &precision) == 0)
*pprecision = precision;
return 0;
}
recGblGetPrec(paddr, pprecision);
return 0;
}
static long get_graphic_double(DBADDR *paddr, struct dbr_grDouble *pgd)
{
aSubRecord *prec = (aSubRecord *)paddr->precord;
int fieldIndex = dbGetFieldIndex(paddr);
int linkNumber;
linkNumber = get_inlinkNumber(fieldIndex);
if (linkNumber >= 0) {
dbGetGraphicLimits(&prec->inpa + linkNumber,
&pgd->lower_disp_limit,
&pgd->upper_disp_limit);
return 0;
}
linkNumber = get_outlinkNumber(fieldIndex);
if (linkNumber >= 0) {
dbGetGraphicLimits(&prec->outa + linkNumber,
&pgd->lower_disp_limit,
&pgd->upper_disp_limit);
}
return 0;
}
static long get_control_double(DBADDR *paddr, struct dbr_ctrlDouble *pcd)
{
recGblGetControlDouble(paddr,pcd);
return 0;
}
static long get_alarm_double(DBADDR *paddr, struct dbr_alDouble *pad)
{
aSubRecord *prec = (aSubRecord *)paddr->precord;
int fieldIndex = dbGetFieldIndex(paddr);
int linkNumber;
linkNumber = get_inlinkNumber(fieldIndex);
if (linkNumber >= 0) {
dbGetAlarmLimits(&prec->inpa + linkNumber,
&pad->lower_alarm_limit,
&pad->lower_warning_limit,
&pad->upper_warning_limit,
&pad->upper_alarm_limit);
return 0;
}
linkNumber = get_outlinkNumber(fieldIndex);
if (linkNumber >= 0) {
dbGetAlarmLimits(&prec->outa + linkNumber,
&pad->lower_alarm_limit,
&pad->lower_warning_limit,
&pad->upper_warning_limit,
&pad->upper_alarm_limit);
return 0;
}
recGblGetAlarmDouble(paddr, pad);
return 0;
}
static void monitor(aSubRecord *prec)
{

View File

@@ -109,7 +109,7 @@ static long init_record(aaiRecord *prec, int pass)
recGblRecordError(S_dev_noDSET, prec, "aai: init_record");
return S_dev_noDSET;
}
if (pass == 0) {
if (prec->nelm <= 0)
prec->nelm = 1;
@@ -120,12 +120,12 @@ static long init_record(aaiRecord *prec, int pass)
} else {
prec->nord = 0;
}
/* we must call pdset->init_record in pass 0
because it may set prec->bptr which must
not change after links are established before pass 1
*/
if (pdset->init_record) {
/* init_record may set the bptr to point to the data */
if ((status = pdset->init_record(prec)))
@@ -141,7 +141,7 @@ static long init_record(aaiRecord *prec, int pass)
/* SIML must be a CONSTANT or a PV_LINK or a DB_LINK */
if (prec->siml.type == CONSTANT) {
recGblInitConstantLink(&prec->siml,DBF_USHORT,&prec->simm);
recGblInitConstantLink(&prec->siml,DBF_USHORT,&prec->simm);
}
/* must have read_aai function defined */
@@ -210,11 +210,20 @@ static long put_array_info(DBADDR *paddr, long nNew)
return 0;
}
#define indexof(field) aaiRecord##field
static long get_units(DBADDR *paddr, char *units)
{
aaiRecord *prec = (aaiRecord *)paddr->precord;
strncpy(units, prec->egu, DB_UNITS_SIZE);
switch (dbGetFieldIndex(paddr)) {
case indexof(VAL):
if (prec->ftvl == DBF_STRING || prec->ftvl == DBF_ENUM)
break;
case indexof(HOPR):
case indexof(LOPR):
strncpy(units,prec->egu,DB_UNITS_SIZE);
}
return 0;
}
@@ -223,8 +232,8 @@ static long get_precision(DBADDR *paddr, long *precision)
aaiRecord *prec = (aaiRecord *)paddr->precord;
*precision = prec->prec;
if (paddr->pfield == prec->bptr) return 0;
recGblGetPrec(paddr, precision);
if (dbGetFieldIndex(paddr) != indexof(VAL))
recGblGetPrec(paddr, precision);
return 0;
}
@@ -232,10 +241,18 @@ static long get_graphic_double(DBADDR *paddr, struct dbr_grDouble *pgd)
{
aaiRecord *prec = (aaiRecord *)paddr->precord;
if (paddr->pfield == prec->bptr) {
pgd->upper_disp_limit = prec->hopr;
pgd->lower_disp_limit = prec->lopr;
} else recGblGetGraphicDouble(paddr, pgd);
switch (dbGetFieldIndex(paddr)) {
case indexof(VAL):
pgd->upper_disp_limit = prec->hopr;
pgd->lower_disp_limit = prec->lopr;
break;
case indexof(NORD):
pgd->upper_disp_limit = prec->nelm;
pgd->lower_disp_limit = 0;
break;
default:
recGblGetGraphicDouble(paddr, pgd);
}
return 0;
}
@@ -243,10 +260,18 @@ static long get_control_double(DBADDR *paddr, struct dbr_ctrlDouble *pcd)
{
aaiRecord *prec = (aaiRecord *)paddr->precord;
if (paddr->pfield == prec->bptr) {
pcd->upper_ctrl_limit = prec->hopr;
pcd->lower_ctrl_limit = prec->lopr;
} else recGblGetControlDouble(paddr, pcd);
switch (dbGetFieldIndex(paddr)) {
case indexof(VAL):
pcd->upper_ctrl_limit = prec->hopr;
pcd->lower_ctrl_limit = prec->lopr;
break;
case indexof(NORD):
pcd->upper_ctrl_limit = prec->nelm;
pcd->lower_ctrl_limit = 0;
break;
default:
recGblGetControlDouble(paddr, pcd);
}
return 0;
}

View File

@@ -109,7 +109,7 @@ static long init_record(aaoRecord *prec, int pass)
recGblRecordError(S_dev_noDSET, prec, "aao: init_record");
return S_dev_noDSET;
}
if (pass == 0) {
if (prec->nelm <= 0)
prec->nelm = 1;
@@ -120,12 +120,12 @@ static long init_record(aaoRecord *prec, int pass)
} else {
prec->nord = 0;
}
/* we must call pdset->init_record in pass 0
because it may set prec->bptr which must
not change after links are established before pass 1
*/
if (pdset->init_record) {
/* init_record may set the bptr to point to the data */
if ((status = pdset->init_record(prec)))
@@ -138,12 +138,12 @@ static long init_record(aaoRecord *prec, int pass)
}
return 0;
}
/* SIML must be a CONSTANT or a PV_LINK or a DB_LINK */
if (prec->siml.type == CONSTANT) {
recGblInitConstantLink(&prec->siml,DBF_USHORT,&prec->simm);
recGblInitConstantLink(&prec->siml,DBF_USHORT,&prec->simm);
}
/* must have write_aao function defined */
if (pdset->number < 5 || pdset->write_aao == NULL) {
recGblRecordError(S_dev_missingSup, prec, "aao: init_record");
@@ -210,11 +210,20 @@ static long put_array_info(DBADDR *paddr, long nNew)
return 0;
}
#define indexof(field) aaoRecord##field
static long get_units(DBADDR *paddr, char *units)
{
aaoRecord *prec = (aaoRecord *)paddr->precord;
strncpy(units, prec->egu, DB_UNITS_SIZE);
switch (dbGetFieldIndex(paddr)) {
case indexof(VAL):
if (prec->ftvl == DBF_STRING || prec->ftvl == DBF_ENUM)
break;
case indexof(HOPR):
case indexof(LOPR):
strncpy(units,prec->egu,DB_UNITS_SIZE);
}
return 0;
}
@@ -223,8 +232,8 @@ static long get_precision(DBADDR *paddr, long *precision)
aaoRecord *prec = (aaoRecord *)paddr->precord;
*precision = prec->prec;
if (paddr->pfield == (void *)prec->bptr) return 0;
recGblGetPrec(paddr, precision);
if (dbGetFieldIndex(paddr) != indexof(VAL))
recGblGetPrec(paddr, precision);
return 0;
}
@@ -232,10 +241,18 @@ static long get_graphic_double(DBADDR *paddr, struct dbr_grDouble *pgd)
{
aaoRecord *prec = (aaoRecord *)paddr->precord;
if (paddr->pfield == prec->bptr) {
pgd->upper_disp_limit = prec->hopr;
pgd->lower_disp_limit = prec->lopr;
} else recGblGetGraphicDouble(paddr,pgd);
switch (dbGetFieldIndex(paddr)) {
case indexof(VAL):
pgd->upper_disp_limit = prec->hopr;
pgd->lower_disp_limit = prec->lopr;
break;
case indexof(NORD):
pgd->upper_disp_limit = prec->nelm;
pgd->lower_disp_limit = 0;
break;
default:
recGblGetGraphicDouble(paddr, pgd);
}
return 0;
}
@@ -243,10 +260,18 @@ static long get_control_double(DBADDR *paddr, struct dbr_ctrlDouble *pcd)
{
aaoRecord *prec = (aaoRecord *)paddr->precord;
if(paddr->pfield == prec->bptr){
pcd->upper_ctrl_limit = prec->hopr;
pcd->lower_ctrl_limit = prec->lopr;
} else recGblGetControlDouble(paddr,pcd);
switch (dbGetFieldIndex(paddr)) {
case indexof(VAL):
pcd->upper_ctrl_limit = prec->hopr;
pcd->lower_ctrl_limit = prec->lopr;
break;
case indexof(NORD):
pcd->upper_ctrl_limit = prec->nelm;
pcd->lower_ctrl_limit = 0;
break;
default:
recGblGetControlDouble(paddr, pcd);
}
return 0;
}

View File

@@ -41,6 +41,9 @@
#undef GEN_SIZE_OFFSET
#include "epicsExport.h"
/* Hysterisis for alarm filtering: 1-1/e */
#define THRESHOLD 0.6321
/* Create RSET - Record Support Entry Table*/
#define report NULL
#define initialize NULL
@@ -94,12 +97,7 @@ typedef struct aidset { /* analog input dset */
}aidset;
/*Following from timing system */
/*
extern unsigned int gts_trigger_counter;
*/
static void checkAlarms(aiRecord *prec);
static void checkAlarms(aiRecord *prec, epicsTimeStamp *lastTime);
static void convert(aiRecord *prec);
static void monitor(aiRecord *prec);
static long readValue(aiRecord *prec);
@@ -158,12 +156,15 @@ static long process(void *precord)
aidset *pdset = (aidset *)(prec->dset);
long status;
unsigned char pact=prec->pact;
epicsTimeStamp timeLast;
if( (pdset==NULL) || (pdset->read_ai==NULL) ) {
prec->pact=TRUE;
recGblRecordError(S_dev_missingSup,(void *)prec,"read_ai");
return(S_dev_missingSup);
}
timeLast = prec->time;
status=readValue(prec); /* read the new value */
/* check if device support set pact */
if ( !pact && prec->pact ) return(0);
@@ -174,7 +175,7 @@ static long process(void *precord)
else if (status==2) status=0;
/* check for alarms */
checkAlarms(prec);
checkAlarms(prec,&timeLast);
/* check event list */
monitor(prec);
/* process the forward scan link record */
@@ -217,11 +218,22 @@ static long special(DBADDR *paddr,int after)
}
}
#define indexof(field) aiRecord##field
static long get_units(DBADDR *paddr, char *units)
{
aiRecord *prec=(aiRecord *)paddr->precord;
strncpy(units,prec->egu,DB_UNITS_SIZE);
if(paddr->pfldDes->field_type == DBF_DOUBLE) {
switch (dbGetFieldIndex(paddr)) {
case indexof(ASLO):
case indexof(AOFF):
case indexof(SMOO):
break;
default:
strncpy(units,prec->egu,DB_UNITS_SIZE);
}
}
return(0);
}
@@ -230,7 +242,7 @@ static long get_precision(DBADDR *paddr, long *precision)
aiRecord *prec=(aiRecord *)paddr->precord;
*precision = prec->prec;
if(paddr->pfield == (void *)&prec->val) return(0);
if (dbGetFieldIndex(paddr) == indexof(VAL)) return(0);
recGblGetPrec(paddr,precision);
return(0);
}
@@ -238,43 +250,54 @@ static long get_precision(DBADDR *paddr, long *precision)
static long get_graphic_double(DBADDR *paddr,struct dbr_grDouble *pgd)
{
aiRecord *prec=(aiRecord *)paddr->precord;
int fieldIndex = dbGetFieldIndex(paddr);
if(fieldIndex == aiRecordVAL
|| fieldIndex == aiRecordHIHI
|| fieldIndex == aiRecordHIGH
|| fieldIndex == aiRecordLOW
|| fieldIndex == aiRecordLOLO
|| fieldIndex == aiRecordHOPR
|| fieldIndex == aiRecordLOPR) {
pgd->upper_disp_limit = prec->hopr;
pgd->lower_disp_limit = prec->lopr;
} else recGblGetGraphicDouble(paddr,pgd);
switch (dbGetFieldIndex(paddr)) {
case indexof(VAL):
case indexof(HIHI):
case indexof(HIGH):
case indexof(LOW):
case indexof(LOLO):
case indexof(LALM):
case indexof(ALST):
case indexof(MLST):
case indexof(SVAL):
pgd->upper_disp_limit = prec->hopr;
pgd->lower_disp_limit = prec->lopr;
break;
default:
recGblGetGraphicDouble(paddr,pgd);
}
return(0);
}
static long get_control_double(DBADDR *paddr,struct dbr_ctrlDouble *pcd)
{
aiRecord *prec=(aiRecord *)paddr->precord;
int fieldIndex = dbGetFieldIndex(paddr);
if(fieldIndex == aiRecordVAL
|| fieldIndex == aiRecordHIHI
|| fieldIndex == aiRecordHIGH
|| fieldIndex == aiRecordLOW
|| fieldIndex == aiRecordLOLO) {
pcd->upper_ctrl_limit = prec->hopr;
pcd->lower_ctrl_limit = prec->lopr;
} else recGblGetControlDouble(paddr,pcd);
switch (dbGetFieldIndex(paddr)) {
case indexof(VAL):
case indexof(HIHI):
case indexof(HIGH):
case indexof(LOW):
case indexof(LOLO):
case indexof(LALM):
case indexof(ALST):
case indexof(MLST):
case indexof(SVAL):
pcd->upper_ctrl_limit = prec->hopr;
pcd->lower_ctrl_limit = prec->lopr;
break;
default:
recGblGetControlDouble(paddr,pcd);
}
return(0);
}
static long get_alarm_double(DBADDR *paddr,struct dbr_alDouble *pad)
{
aiRecord *prec=(aiRecord *)paddr->precord;
int fieldIndex = dbGetFieldIndex(paddr);
if(fieldIndex == aiRecordVAL) {
if (dbGetFieldIndex(paddr) == indexof(VAL)) {
pad->upper_alarm_limit = prec->hhsv ? prec->hihi : epicsNAN;
pad->upper_warning_limit = prec->hsv ? prec->high : epicsNAN;
pad->lower_warning_limit = prec->lsv ? prec->low : epicsNAN;
@@ -283,60 +306,114 @@ static long get_alarm_double(DBADDR *paddr,struct dbr_alDouble *pad)
return(0);
}
static void checkAlarms(aiRecord *prec)
static void checkAlarms(aiRecord *prec, epicsTimeStamp *lastTime)
{
double val, hyst, lalm;
double alev;
enum {
range_Lolo = 1,
range_Low,
range_Normal,
range_High,
range_Hihi
} alarmRange;
static const epicsEnum16 range_stat[] = {
SOFT_ALARM, LOLO_ALARM, LOW_ALARM,
NO_ALARM, HIGH_ALARM, HIHI_ALARM
};
double val, hyst, lalm, alev, aftc, afvl;
epicsEnum16 asev;
if (prec->udf) {
recGblSetSevr(prec, UDF_ALARM, INVALID_ALARM);
prec->afvl = 0;
return;
}
val = prec->val;
val = prec->val;
hyst = prec->hyst;
lalm = prec->lalm;
/* alarm condition hihi */
asev = prec->hhsv;
alev = prec->hihi;
if (asev && (val >= alev || ((lalm == alev) && (val >= alev - hyst)))) {
if (recGblSetSevr(prec, HIHI_ALARM, asev))
prec->lalm = alev;
return;
/* check VAL against alarm limits */
if ((asev = prec->hhsv) &&
(val >= (alev = prec->hihi) ||
((lalm == alev) && (val >= alev - hyst))))
alarmRange = range_Hihi;
else
if ((asev = prec->llsv) &&
(val <= (alev = prec->lolo) ||
((lalm == alev) && (val <= alev + hyst))))
alarmRange = range_Lolo;
else
if ((asev = prec->hsv) &&
(val >= (alev = prec->high) ||
((lalm == alev) && (val >= alev - hyst))))
alarmRange = range_High;
else
if ((asev = prec->lsv) &&
(val <= (alev = prec->low) ||
((lalm == alev) && (val <= alev + hyst))))
alarmRange = range_Low;
else {
alev = val;
asev = NO_ALARM;
alarmRange = range_Normal;
}
/* alarm condition lolo */
asev = prec->llsv;
alev = prec->lolo;
if (asev && (val <= alev || ((lalm == alev) && (val <= alev + hyst)))) {
if (recGblSetSevr(prec, LOLO_ALARM, asev))
prec->lalm = alev;
return;
}
aftc = prec->aftc;
afvl = 0;
/* alarm condition high */
asev = prec->hsv;
alev = prec->high;
if (asev && (val >= alev || ((lalm == alev) && (val >= alev - hyst)))) {
if (recGblSetSevr(prec, HIGH_ALARM, asev))
prec->lalm = alev;
return;
}
if (aftc > 0) {
/* Apply level filtering */
afvl = prec->afvl;
if (afvl == 0) {
afvl = (double)alarmRange;
} else {
double t = epicsTimeDiffInSeconds(&prec->time, lastTime);
double alpha = aftc / (t + aftc);
/* alarm condition low */
asev = prec->lsv;
alev = prec->low;
if (asev && (val <= alev || ((lalm == alev) && (val <= alev + hyst)))) {
if (recGblSetSevr(prec, LOW_ALARM, asev))
prec->lalm = alev;
return;
}
/* The sign of afvl indicates whether the result should be
* rounded up or down. This gives the filter hysteresis.
* If afvl > 0 the floor() function rounds to a lower alarm
* level, otherwise to a higher.
*/
afvl = alpha * afvl +
((afvl > 0) ? (1 - alpha) : (alpha - 1)) * alarmRange;
if (afvl - floor(afvl) > THRESHOLD)
afvl = -afvl; /* reverse rounding */
/* we get here only if val is out of alarm by at least hyst */
prec->lalm = val;
return;
alarmRange = abs((int)floor(afvl));
switch (alarmRange) {
case range_Hihi:
asev = prec->hhsv;
alev = prec->hihi;
break;
case range_High:
asev = prec->hsv;
alev = prec->high;
break;
case range_Normal:
asev = NO_ALARM;
break;
case range_Low:
asev = prec->lsv;
alev = prec->low;
break;
case range_Lolo:
asev = prec->llsv;
alev = prec->lolo;
break;
}
}
}
prec->afvl = afvl;
if (asev) {
/* Report alarm condition, store LALM for future HYST calculations */
if (recGblSetSevr(prec, range_stat[alarmRange], asev))
prec->lalm = alev;
} else {
/* No alarm condition, reset LALM */
prec->lalm = val;
}
}
static void convert(aiRecord *prec)

View File

@@ -138,6 +138,11 @@ recordtype(ai) {
promptgroup(GUI_ALARMS)
interest(1)
}
field(AFTC,DBF_DOUBLE) {
prompt("Alarm Filter Time Constant")
promptgroup(GUI_ALARMS)
interest(1)
}
field(ADEL,DBF_DOUBLE) {
prompt("Archive Deadband")
promptgroup(GUI_DISPLAY)
@@ -153,6 +158,11 @@ recordtype(ai) {
special(SPC_NOMOD)
interest(3)
}
field(AFVL,DBF_DOUBLE) {
prompt("Alarm Filter Value")
special(SPC_NOMOD)
interest(3)
}
field(ALST,DBF_DOUBLE) {
prompt("Last Value Archived")
special(SPC_NOMOD)

View File

@@ -276,11 +276,21 @@ static long special(DBADDR *paddr, int after)
}
}
#define indexof(field) aoRecord##field
static long get_units(DBADDR * paddr,char *units)
{
aoRecord *prec=(aoRecord *)paddr->precord;
strncpy(units,prec->egu,DB_UNITS_SIZE);
if(paddr->pfldDes->field_type == DBF_DOUBLE) {
switch (dbGetFieldIndex(paddr)) {
case indexof(ASLO):
case indexof(AOFF):
break;
default:
strncpy(units,prec->egu,DB_UNITS_SIZE);
}
}
return(0);
}
@@ -289,10 +299,14 @@ static long get_precision(DBADDR *paddr,long *precision)
aoRecord *prec=(aoRecord *)paddr->precord;
*precision = prec->prec;
if(paddr->pfield == (void *)&prec->val
|| paddr->pfield == (void *)&prec->oval
|| paddr->pfield == (void *)&prec->pval) return(0);
recGblGetPrec(paddr,precision);
switch (dbGetFieldIndex(paddr)) {
case indexof(VAL):
case indexof(OVAL):
case indexof(PVAL):
break;
default:
recGblGetPrec(paddr,precision);
}
return(0);
}
@@ -300,16 +314,24 @@ static long get_graphic_double(DBADDR *paddr,struct dbr_grDouble *pgd)
{
aoRecord *prec=(aoRecord *)paddr->precord;
if(paddr->pfield==(void *)&prec->val
|| paddr->pfield==(void *)&prec->hihi
|| paddr->pfield==(void *)&prec->high
|| paddr->pfield==(void *)&prec->low
|| paddr->pfield==(void *)&prec->lolo
|| paddr->pfield==(void *)&prec->oval
|| paddr->pfield==(void *)&prec->pval){
pgd->upper_disp_limit = prec->hopr;
pgd->lower_disp_limit = prec->lopr;
} else recGblGetGraphicDouble(paddr,pgd);
switch (dbGetFieldIndex(paddr)) {
case indexof(VAL):
case indexof(OVAL):
case indexof(PVAL):
case indexof(HIHI):
case indexof(HIGH):
case indexof(LOW):
case indexof(LOLO):
case indexof(LALM):
case indexof(ALST):
case indexof(MLST):
case indexof(IVOV):
pgd->upper_disp_limit = prec->hopr;
pgd->lower_disp_limit = prec->lopr;
break;
default:
recGblGetGraphicDouble(paddr,pgd);
}
return(0);
}
@@ -317,23 +339,30 @@ static long get_control_double(DBADDR *paddr, struct dbr_ctrlDouble *pcd)
{
aoRecord *prec=(aoRecord *)paddr->precord;
if(paddr->pfield==(void *)&prec->val
|| paddr->pfield==(void *)&prec->hihi
|| paddr->pfield==(void *)&prec->high
|| paddr->pfield==(void *)&prec->low
|| paddr->pfield==(void *)&prec->lolo
|| paddr->pfield==(void *)&prec->oval
|| paddr->pfield==(void *)&prec->pval){
pcd->upper_ctrl_limit = prec->drvh;
pcd->lower_ctrl_limit = prec->drvl;
} else recGblGetControlDouble(paddr,pcd);
switch (dbGetFieldIndex(paddr)) {
case indexof(VAL):
case indexof(OVAL):
case indexof(PVAL):
case indexof(HIHI):
case indexof(HIGH):
case indexof(LOW):
case indexof(LOLO):
case indexof(LALM):
case indexof(ALST):
case indexof(MLST):
pcd->upper_ctrl_limit = prec->drvh;
pcd->lower_ctrl_limit = prec->drvl;
break;
default:
recGblGetControlDouble(paddr,pcd);
}
return(0);
}
static long get_alarm_double(DBADDR *paddr, struct dbr_alDouble *pad)
{
aoRecord *prec=(aoRecord *)paddr->precord;
if(paddr->pfield==(void *)&prec->val){
if(dbGetFieldIndex(paddr) == indexof(VAL)){
pad->upper_alarm_limit = prec->hhsv ? prec->hihi : epicsNAN;
pad->upper_warning_limit = prec->hsv ? prec->high : epicsNAN;
pad->lower_warning_limit = prec->lsv ? prec->low : epicsNAN;

View File

@@ -51,13 +51,13 @@ static long process(boRecord *);
#define cvt_dbaddr NULL
#define get_array_info NULL
#define put_array_info NULL
#define get_units NULL
static long get_units(DBADDR *, char *);
static long get_precision(DBADDR *, long *);
static long get_enum_str(DBADDR *, char *);
static long get_enum_strs(DBADDR *, struct dbr_enumStrs *);
static long put_enum_str(DBADDR *, char *);
#define get_graphic_double NULL
#define get_control_double NULL
static long get_control_double(DBADDR *, struct dbr_ctrlDouble *);
#define get_alarm_double NULL
rset boRSET={
@@ -82,6 +82,11 @@ rset boRSET={
};
epicsExportAddress(rset,boRSET);
int boHIGHprecision = 2;
epicsExportAddress(int, boHIGHprecision);
double boHIGHlimit = 100000;
epicsExportAddress(double, boHIGHlimit);
struct bodset { /* binary output dset */
long number;
DEVSUPFUN dev_report;
@@ -268,12 +273,31 @@ static long process(boRecord *prec)
return(status);
}
#define indexof(field) boRecord##field
static long get_units(DBADDR *paddr, char *units)
{
if(dbGetFieldIndex(paddr) == indexof(HIGH))
strcpy(units, "s");
return(0);
}
static long get_precision(DBADDR *paddr, long *precision)
{
boRecord *prec=(boRecord *)paddr->precord;
if(dbGetFieldIndex(paddr) == indexof(HIGH))
*precision = boHIGHprecision;
else
recGblGetPrec(paddr,precision);
return(0);
}
if(paddr->pfield == (void *)&prec->high) *precision=2;
else recGblGetPrec(paddr,precision);
static long get_control_double(DBADDR *paddr,struct dbr_ctrlDouble *pcd)
{
if(dbGetFieldIndex(paddr) == indexof(HIGH)) {
pcd->lower_ctrl_limit = 0.0;
pcd->upper_ctrl_limit = boHIGHlimit;
} else
recGblGetControlDouble(paddr,pcd);
return(0);
}
@@ -285,7 +309,7 @@ static long get_enum_str(DBADDR *paddr, char *pstring)
index = dbGetFieldIndex(paddr);
if(index!=boRecordVAL) {
if(index!=indexof(VAL)) {
strcpy(pstring,"Illegal_Value");
} else if(*pfield==0) {
strncpy(pstring,prec->znam,sizeof(prec->znam));

View File

@@ -149,3 +149,6 @@ recordtype(bo) {
interest(2)
}
}
variable(boHIGHprecision, int)
variable(boHIGHlimit, double)

View File

@@ -37,6 +37,9 @@
#undef GEN_SIZE_OFFSET
#include "epicsExport.h"
/* Hysterisis for alarm filtering: 1-1/e */
#define THRESHOLD 0.6321
/* Create RSET - Record Support Entry Table */
#define report NULL
@@ -54,32 +57,32 @@ static long get_precision(DBADDR *paddr, long *precision);
#define get_enum_strs NULL
#define put_enum_str NULL
static long get_graphic_double(DBADDR *paddr, struct dbr_grDouble *pgd);
static long get_ctrl_double(DBADDR *paddr, struct dbr_ctrlDouble *pcd);
static long get_control_double(DBADDR *paddr, struct dbr_ctrlDouble *pcd);
static long get_alarm_double(DBADDR *paddr, struct dbr_alDouble *pad);
rset calcRSET={
RSETNUMBER,
report,
initialize,
init_record,
process,
special,
get_value,
cvt_dbaddr,
get_array_info,
put_array_info,
get_units,
get_precision,
get_enum_str,
get_enum_strs,
put_enum_str,
get_graphic_double,
get_ctrl_double,
get_alarm_double
RSETNUMBER,
report,
initialize,
init_record,
process,
special,
get_value,
cvt_dbaddr,
get_array_info,
put_array_info,
get_units,
get_precision,
get_enum_str,
get_enum_strs,
put_enum_str,
get_graphic_double,
get_control_double,
get_alarm_double
};
epicsExportAddress(rset, calcRSET);
static void checkAlarms(calcRecord *prec);
static void checkAlarms(calcRecord *prec, epicsTimeStamp *timeLast);
static void monitor(calcRecord *prec);
static int fetch_values(calcRecord *prec);
@@ -96,30 +99,35 @@ static long init_record(calcRecord *prec, int pass)
plink = &prec->inpa;
pvalue = &prec->a;
for (i = 0; i < CALCPERFORM_NARGS; i++, plink++, pvalue++) {
if (plink->type == CONSTANT) {
recGblInitConstantLink(plink, DBF_DOUBLE, pvalue);
}
if (plink->type == CONSTANT) {
recGblInitConstantLink(plink, DBF_DOUBLE, pvalue);
}
}
if (postfix(prec->calc, prec->rpcl, &error_number)) {
recGblRecordError(S_db_badField, (void *)prec,
"calc: init_record: Illegal CALC field");
errlogPrintf("%s.CALC: %s in expression \"%s\"\n",
prec->name, calcErrorStr(error_number), prec->calc);
recGblRecordError(S_db_badField, (void *)prec,
"calc: init_record: Illegal CALC field");
errlogPrintf("%s.CALC: %s in expression \"%s\"\n",
prec->name, calcErrorStr(error_number), prec->calc);
}
return 0;
}
static long process(calcRecord *prec)
{
epicsTimeStamp timeLast;
prec->pact = TRUE;
if (fetch_values(prec)==0) {
if (calcPerform(&prec->a, &prec->val, prec->rpcl)) {
recGblSetSevr(prec, CALC_ALARM, INVALID_ALARM);
} else prec->udf = isnan(prec->val);
if (fetch_values(prec) == 0) {
if (calcPerform(&prec->a, &prec->val, prec->rpcl)) {
recGblSetSevr(prec, CALC_ALARM, INVALID_ALARM);
} else
prec->udf = isnan(prec->val);
}
timeLast = prec->time;
recGblGetTimeStamp(prec);
/* check for alarms */
checkAlarms(prec);
checkAlarms(prec, &timeLast);
/* check event list */
monitor(prec);
/* process the forward scan link record */
@@ -135,24 +143,41 @@ static long special(DBADDR *paddr, int after)
if (!after) return 0;
if (paddr->special == SPC_CALC) {
if (postfix(prec->calc, prec->rpcl, &error_number)) {
recGblRecordError(S_db_badField, (void *)prec,
"calc: Illegal CALC field");
errlogPrintf("%s.CALC: %s in expression \"%s\"\n",
prec->name, calcErrorStr(error_number), prec->calc);
return S_db_badField;
}
return 0;
if (postfix(prec->calc, prec->rpcl, &error_number)) {
recGblRecordError(S_db_badField, (void *)prec,
"calc: Illegal CALC field");
errlogPrintf("%s.CALC: %s in expression \"%s\"\n",
prec->name, calcErrorStr(error_number), prec->calc);
return S_db_badField;
}
return 0;
}
recGblDbaddrError(S_db_badChoice, paddr, "calc::special - bad special value!");
return S_db_badChoice;
}
#define indexof(field) calcRecord##field
static long get_linkNumber(int fieldIndex) {
if (fieldIndex >= indexof(A) && fieldIndex <= indexof(L))
return fieldIndex - indexof(A);
if (fieldIndex >= indexof(LA) && fieldIndex <= indexof(LL))
return fieldIndex - indexof(LA);
return -1;
}
static long get_units(DBADDR *paddr, char *units)
{
calcRecord *prec = (calcRecord *)paddr->precord;
int linkNumber;
strncpy(units, prec->egu, DB_UNITS_SIZE);
if(paddr->pfldDes->field_type == DBF_DOUBLE) {
linkNumber = get_linkNumber(dbGetFieldIndex(paddr));
if (linkNumber >= 0)
dbGetUnits(&prec->inpa + linkNumber, units, DB_UNITS_SIZE);
else
strncpy(units,prec->egu,DB_UNITS_SIZE);
}
return 0;
}
@@ -160,98 +185,122 @@ static long get_precision(DBADDR *paddr, long *pprecision)
{
calcRecord *prec = (calcRecord *)paddr->precord;
int fieldIndex = dbGetFieldIndex(paddr);
int linkNumber;
*pprecision = prec->prec;
if (fieldIndex != calcRecordVAL)
recGblGetPrec(paddr, pprecision);
if (fieldIndex == indexof(VAL)) {
return 0;
}
linkNumber = get_linkNumber(fieldIndex);
if (linkNumber >= 0) {
short precision;
if (dbGetPrecision(&prec->inpa + linkNumber, &precision) == 0)
*pprecision = precision;
else
*pprecision = 15;
} else
recGblGetPrec(paddr, pprecision);
return 0;
}
static long get_graphic_double(DBADDR *paddr, struct dbr_grDouble *pgd)
{
calcRecord *prec = (calcRecord *)paddr->precord;
if (paddr->pfield == (void *)&prec->val ||
paddr->pfield == (void *)&prec->hihi ||
paddr->pfield == (void *)&prec->high ||
paddr->pfield == (void *)&prec->low ||
paddr->pfield == (void *)&prec->lolo) {
pgd->upper_disp_limit = prec->hopr;
pgd->lower_disp_limit = prec->lopr;
return 0;
int fieldIndex = dbGetFieldIndex(paddr);
int linkNumber;
switch (fieldIndex) {
case indexof(VAL):
case indexof(HIHI):
case indexof(HIGH):
case indexof(LOW):
case indexof(LOLO):
case indexof(LALM):
case indexof(ALST):
case indexof(MLST):
pgd->lower_disp_limit = prec->lopr;
pgd->upper_disp_limit = prec->hopr;
break;
default:
linkNumber = get_linkNumber(fieldIndex);
if (linkNumber >= 0) {
dbGetGraphicLimits(&prec->inpa + linkNumber,
&pgd->lower_disp_limit,
&pgd->upper_disp_limit);
} else
recGblGetGraphicDouble(paddr,pgd);
}
if (paddr->pfield >= (void *)&prec->a &&
paddr->pfield <= (void *)&prec->l) {
pgd->upper_disp_limit = prec->hopr;
pgd->lower_disp_limit = prec->lopr;
return 0;
}
if (paddr->pfield >= (void *)&prec->la &&
paddr->pfield <= (void *)&prec->ll) {
pgd->upper_disp_limit = prec->hopr;
pgd->lower_disp_limit = prec->lopr;
return 0;
}
recGblGetGraphicDouble(paddr, pgd);
return 0;
}
static long get_ctrl_double(DBADDR *paddr, struct dbr_ctrlDouble *pcd)
static long get_control_double(DBADDR *paddr, struct dbr_ctrlDouble *pcd)
{
calcRecord *prec = (calcRecord *)paddr->precord;
if (paddr->pfield == (void *)&prec->val ||
paddr->pfield == (void *)&prec->hihi ||
paddr->pfield == (void *)&prec->high ||
paddr->pfield == (void *)&prec->low ||
paddr->pfield == (void *)&prec->lolo) {
pcd->upper_ctrl_limit = prec->hopr;
pcd->lower_ctrl_limit = prec->lopr;
return 0;
switch (dbGetFieldIndex(paddr)) {
case indexof(VAL):
case indexof(HIHI):
case indexof(HIGH):
case indexof(LOW):
case indexof(LOLO):
case indexof(LALM):
case indexof(ALST):
case indexof(MLST):
pcd->lower_ctrl_limit = prec->lopr;
pcd->upper_ctrl_limit = prec->hopr;
break;
default:
recGblGetControlDouble(paddr,pcd);
}
if (paddr->pfield >= (void *)&prec->a &&
paddr->pfield <= (void *)&prec->l) {
pcd->upper_ctrl_limit = prec->hopr;
pcd->lower_ctrl_limit = prec->lopr;
return 0;
}
if (paddr->pfield >= (void *)&prec->la &&
paddr->pfield <= (void *)&prec->ll) {
pcd->upper_ctrl_limit = prec->hopr;
pcd->lower_ctrl_limit = prec->lopr;
return 0;
}
recGblGetControlDouble(paddr, pcd);
return 0;
}
static long get_alarm_double(DBADDR *paddr, struct dbr_alDouble *pad)
{
calcRecord *prec = (calcRecord *)paddr->precord;
int fieldIndex = dbGetFieldIndex(paddr);
int linkNumber;
if (paddr->pfield == (void *)&prec->val) {
pad->upper_alarm_limit = prec->hhsv ? prec->hihi : epicsNAN;
pad->upper_warning_limit = prec->hsv ? prec->high : epicsNAN;
pad->lower_warning_limit = prec->lsv ? prec->low : epicsNAN;
if (fieldIndex == indexof(VAL)) {
pad->lower_alarm_limit = prec->llsv ? prec->lolo : epicsNAN;
pad->lower_warning_limit = prec->lsv ? prec->low : epicsNAN;
pad->upper_warning_limit = prec->hsv ? prec->high : epicsNAN;
pad->upper_alarm_limit = prec->hhsv ? prec->hihi : epicsNAN;
} else {
recGblGetAlarmDouble(paddr, pad);
linkNumber = get_linkNumber(fieldIndex);
if (linkNumber >= 0) {
dbGetAlarmLimits(&prec->inpa + linkNumber,
&pad->lower_alarm_limit,
&pad->lower_warning_limit,
&pad->upper_warning_limit,
&pad->upper_alarm_limit);
} else
recGblGetAlarmDouble(paddr, pad);
}
return 0;
}
static void checkAlarms(calcRecord *prec)
static void checkAlarms(calcRecord *prec, epicsTimeStamp *timeLast)
{
double val, hyst, lalm;
double alev;
enum {
range_Lolo = 1,
range_Low,
range_Normal,
range_High,
range_Hihi
} alarmRange;
static const epicsEnum16 range_stat[] = {
SOFT_ALARM, LOLO_ALARM, LOW_ALARM,
NO_ALARM, HIGH_ALARM, HIHI_ALARM
};
double val, hyst, lalm, alev, aftc, afvl;
epicsEnum16 asev;
if (prec->udf) {
recGblSetSevr(prec, UDF_ALARM, INVALID_ALARM);
prec->afvl = 0;
return;
}
@@ -259,45 +308,89 @@ static void checkAlarms(calcRecord *prec)
hyst = prec->hyst;
lalm = prec->lalm;
/* alarm condition hihi */
asev = prec->hhsv;
alev = prec->hihi;
if (asev && (val >= alev || ((lalm == alev) && (val >= alev - hyst)))) {
if (recGblSetSevr(prec, HIHI_ALARM, asev))
prec->lalm = alev;
return;
/* check VAL against alarm limits */
if ((asev = prec->hhsv) &&
(val >= (alev = prec->hihi) ||
((lalm == alev) && (val >= alev - hyst))))
alarmRange = range_Hihi;
else
if ((asev = prec->llsv) &&
(val <= (alev = prec->lolo) ||
((lalm == alev) && (val <= alev + hyst))))
alarmRange = range_Lolo;
else
if ((asev = prec->hsv) &&
(val >= (alev = prec->high) ||
((lalm == alev) && (val >= alev - hyst))))
alarmRange = range_High;
else
if ((asev = prec->lsv) &&
(val <= (alev = prec->low) ||
((lalm == alev) && (val <= alev + hyst))))
alarmRange = range_Low;
else {
alev = val;
asev = NO_ALARM;
alarmRange = range_Normal;
}
/* alarm condition lolo */
asev = prec->llsv;
alev = prec->lolo;
if (asev && (val <= alev || ((lalm == alev) && (val <= alev + hyst)))) {
if (recGblSetSevr(prec, LOLO_ALARM, asev))
aftc = prec->aftc;
afvl = 0;
if (aftc > 0) {
/* Apply level filtering */
afvl = prec->afvl;
if (afvl == 0) {
afvl = (double)alarmRange;
} else {
double t = epicsTimeDiffInSeconds(&prec->time, timeLast);
double alpha = aftc / (t + aftc);
/* The sign of afvl indicates whether the result should be
* rounded up or down. This gives the filter hysteresis.
* If afvl > 0 the floor() function rounds to a lower alarm
* level, otherwise to a higher.
*/
afvl = alpha * afvl +
((afvl > 0) ? (1 - alpha) : (alpha - 1)) * alarmRange;
if (afvl - floor(afvl) > THRESHOLD)
afvl = -afvl; /* reverse rounding */
alarmRange = abs((int)floor(afvl));
switch (alarmRange) {
case range_Hihi:
asev = prec->hhsv;
alev = prec->hihi;
break;
case range_High:
asev = prec->hsv;
alev = prec->high;
break;
case range_Normal:
asev = NO_ALARM;
break;
case range_Low:
asev = prec->lsv;
alev = prec->low;
break;
case range_Lolo:
asev = prec->llsv;
alev = prec->lolo;
break;
}
}
}
prec->afvl = afvl;
if (asev) {
/* Report alarm condition, store LALM for future HYST calculations */
if (recGblSetSevr(prec, range_stat[alarmRange], asev))
prec->lalm = alev;
return;
} else {
/* No alarm condition, reset LALM */
prec->lalm = val;
}
/* alarm condition high */
asev = prec->hsv;
alev = prec->high;
if (asev && (val >= alev || ((lalm == alev) && (val >= alev - hyst)))) {
if (recGblSetSevr(prec, HIGH_ALARM, asev))
prec->lalm = alev;
return;
}
/* alarm condition low */
asev = prec->lsv;
alev = prec->low;
if (asev && (val <= alev || ((lalm == alev) && (val <= alev + hyst)))) {
if (recGblSetSevr(prec, LOW_ALARM, asev))
prec->lalm = alev;
return;
}
/* we get here only if val is out of alarm by at least hyst */
prec->lalm = val;
return;
}
static void monitor(calcRecord *prec)
@@ -311,34 +404,34 @@ static void monitor(calcRecord *prec)
delta = prec->mlst - prec->val;
if (delta < 0.0) delta = -delta;
if (delta > prec->mdel) {
/* post events for value change */
monitor_mask |= DBE_VALUE;
/* update last value monitored */
prec->mlst = prec->val;
/* post events for value change */
monitor_mask |= DBE_VALUE;
/* update last value monitored */
prec->mlst = prec->val;
}
/* check for archive change */
delta = prec->alst - prec->val;
if (delta < 0.0) delta = -delta;
if (delta > prec->adel) {
/* post events on value field for archive change */
monitor_mask |= DBE_LOG;
/* update last archive value monitored */
prec->alst = prec->val;
/* post events on value field for archive change */
monitor_mask |= DBE_LOG;
/* update last archive value monitored */
prec->alst = prec->val;
}
/* send out monitors connected to the value field */
if (monitor_mask){
db_post_events(prec, &prec->val, monitor_mask);
db_post_events(prec, &prec->val, monitor_mask);
}
/* check all input fields for changes*/
pnew = &prec->a;
pprev = &prec->la;
for (i = 0; i < CALCPERFORM_NARGS; i++, pnew++, pprev++) {
if (*pnew != *pprev ||
monitor_mask & DBE_ALARM) {
db_post_events(prec, pnew, monitor_mask | DBE_VALUE | DBE_LOG);
*pprev = *pnew;
}
if (*pnew != *pprev ||
monitor_mask & DBE_ALARM) {
db_post_events(prec, pnew, monitor_mask | DBE_VALUE | DBE_LOG);
*pprev = *pnew;
}
}
return;
}
@@ -353,10 +446,10 @@ static int fetch_values(calcRecord *prec)
plink = &prec->inpa;
pvalue = &prec->a;
for(i = 0; i < CALCPERFORM_NARGS; i++, plink++, pvalue++) {
int newStatus;
int newStatus;
newStatus = dbGetLink(plink, DBR_DOUBLE, pvalue, 0, 0);
if (status == 0) status = newStatus;
newStatus = dbGetLink(plink, DBR_DOUBLE, pvalue, 0, 0);
if (status == 0) status = newStatus;
}
return status;
}

View File

@@ -153,6 +153,16 @@ recordtype(calc) {
interest(1)
menu(menuAlarmSevr)
}
field(AFTC, DBF_DOUBLE) {
prompt("Alarm Filter Time Constant")
promptgroup(GUI_ALARMS)
interest(1)
}
field(AFVL, DBF_DOUBLE) {
prompt("Alarm Filter Value")
special(SPC_NOMOD)
interest(3)
}
field(HYST,DBF_DOUBLE) {
prompt("Alarm Deadband")
promptgroup(GUI_ALARMS)

View File

@@ -59,7 +59,7 @@ static long get_precision(DBADDR *, long *);
#define get_enum_strs NULL
#define put_enum_str NULL
static long get_graphic_double(DBADDR *, struct dbr_grDouble *);
static long get_ctrl_double(DBADDR *, struct dbr_ctrlDouble *);
static long get_control_double(DBADDR *, struct dbr_ctrlDouble *);
static long get_alarm_double(DBADDR *, struct dbr_alDouble *);
rset calcoutRSET = {
@@ -79,11 +79,16 @@ rset calcoutRSET = {
get_enum_strs,
put_enum_str,
get_graphic_double,
get_ctrl_double,
get_control_double,
get_alarm_double
};
epicsExportAddress(rset, calcoutRSET);
int calcoutODLYprecision = 2;
epicsExportAddress(int, calcoutODLYprecision);
double calcoutODLYlimit = 100000;
epicsExportAddress(double, calcoutODLYlimit);
typedef struct calcoutDSET {
long number;
DEVSUPFUN dev_report;
@@ -371,11 +376,34 @@ static long special(DBADDR *paddr, int after)
}
}
#define indexof(field) calcoutRecord##field
static long get_linkNumber(int fieldIndex) {
if (fieldIndex >= indexof(A) && fieldIndex <= indexof(L))
return fieldIndex - indexof(A);
if (fieldIndex >= indexof(LA) && fieldIndex <= indexof(LL))
return fieldIndex - indexof(LA);
return -1;
}
static long get_units(DBADDR *paddr, char *units)
{
calcoutRecord *prec = (calcoutRecord *)paddr->precord;
int fieldIndex = dbGetFieldIndex(paddr);
int linkNumber;
strncpy(units, prec->egu, DB_UNITS_SIZE);
if(fieldIndex == indexof(ODLY)) {
strcpy(units, "s");
return 0;
}
if(paddr->pfldDes->field_type == DBF_DOUBLE) {
linkNumber = get_linkNumber(dbGetFieldIndex(paddr));
if (linkNumber >= 0)
dbGetUnits(&prec->inpa + linkNumber, units, DB_UNITS_SIZE);
else
strncpy(units,prec->egu,DB_UNITS_SIZE);
}
return 0;
}
@@ -383,86 +411,109 @@ static long get_precision(DBADDR *paddr, long *pprecision)
{
calcoutRecord *prec = (calcoutRecord *)paddr->precord;
int fieldIndex = dbGetFieldIndex(paddr);
int linkNumber;
if(fieldIndex == indexof(ODLY)) {
*pprecision = calcoutODLYprecision;
return 0;
}
*pprecision = prec->prec;
if (fieldIndex != calcoutRecordVAL)
if (fieldIndex == indexof(VAL)) {
return 0;
}
linkNumber = get_linkNumber(fieldIndex);
if (linkNumber >= 0) {
short precision;
if (dbGetPrecision(&prec->inpa + linkNumber, &precision) == 0)
*pprecision = precision;
else
*pprecision = 15;
} else
recGblGetPrec(paddr, pprecision);
return 0;
}
static long get_graphic_double(DBADDR *paddr, struct dbr_grDouble *pgd)
{
calcoutRecord *prec = (calcoutRecord *)paddr->precord;
if (paddr->pfield == (void *)&prec->val ||
paddr->pfield == (void *)&prec->hihi ||
paddr->pfield == (void *)&prec->high ||
paddr->pfield == (void *)&prec->low ||
paddr->pfield == (void *)&prec->lolo) {
pgd->upper_disp_limit = prec->hopr;
pgd->lower_disp_limit = prec->lopr;
return 0;
int fieldIndex = dbGetFieldIndex(paddr);
int linkNumber;
switch (fieldIndex) {
case indexof(VAL):
case indexof(HIHI):
case indexof(HIGH):
case indexof(LOW):
case indexof(LOLO):
case indexof(LALM):
case indexof(ALST):
case indexof(MLST):
pgd->lower_disp_limit = prec->lopr;
pgd->upper_disp_limit = prec->hopr;
break;
case indexof(ODLY):
recGblGetGraphicDouble(paddr,pgd);
pgd->lower_disp_limit = 0.0;
break;
default:
linkNumber = get_linkNumber(fieldIndex);
if (linkNumber >= 0) {
dbGetGraphicLimits(&prec->inpa + linkNumber,
&pgd->lower_disp_limit,
&pgd->upper_disp_limit);
} else
recGblGetGraphicDouble(paddr,pgd);
}
if (paddr->pfield >= (void *)&prec->a &&
paddr->pfield <= (void *)&prec->l) {
pgd->upper_disp_limit = prec->hopr;
pgd->lower_disp_limit = prec->lopr;
return 0;
}
if (paddr->pfield >= (void *)&prec->la &&
paddr->pfield <= (void *)&prec->ll) {
pgd->upper_disp_limit = prec->hopr;
pgd->lower_disp_limit = prec->lopr;
return 0;
}
recGblGetGraphicDouble(paddr, pgd);
return 0;
}
static long get_ctrl_double(DBADDR *paddr, struct dbr_ctrlDouble *pcd)
static long get_control_double(DBADDR *paddr, struct dbr_ctrlDouble *pcd)
{
calcoutRecord *prec = (calcoutRecord *)paddr->precord;
if (paddr->pfield == (void *)&prec->val ||
paddr->pfield == (void *)&prec->hihi ||
paddr->pfield == (void *)&prec->high ||
paddr->pfield == (void *)&prec->low ||
paddr->pfield == (void *)&prec->lolo) {
pcd->upper_ctrl_limit = prec->hopr;
pcd->lower_ctrl_limit = prec->lopr;
return 0;
switch (dbGetFieldIndex(paddr)) {
case indexof(VAL):
case indexof(HIHI):
case indexof(HIGH):
case indexof(LOW):
case indexof(LOLO):
case indexof(LALM):
case indexof(ALST):
case indexof(MLST):
pcd->lower_ctrl_limit = prec->lopr;
pcd->upper_ctrl_limit = prec->hopr;
break;
case indexof(ODLY):
pcd->lower_ctrl_limit = 0.0;
pcd->upper_ctrl_limit = calcoutODLYlimit;
break;
default:
recGblGetControlDouble(paddr,pcd);
}
if (paddr->pfield >= (void *)&prec->a &&
paddr->pfield <= (void *)&prec->l) {
pcd->upper_ctrl_limit = prec->hopr;
pcd->lower_ctrl_limit = prec->lopr;
return 0;
}
if (paddr->pfield >= (void *)&prec->la &&
paddr->pfield <= (void *)&prec->ll) {
pcd->upper_ctrl_limit = prec->hopr;
pcd->lower_ctrl_limit = prec->lopr;
return 0;
}
recGblGetControlDouble(paddr, pcd);
return 0;
}
static long get_alarm_double(DBADDR *paddr, struct dbr_alDouble *pad)
{
calcoutRecord *prec = (calcoutRecord *)paddr->precord;
int fieldIndex = dbGetFieldIndex(paddr);
int linkNumber;
if (paddr->pfield == (void *)&prec->val) {
if (fieldIndex == indexof(VAL)) {
pad->upper_alarm_limit = prec->hhsv ? prec->hihi : epicsNAN;
pad->upper_warning_limit = prec->hsv ? prec->high : epicsNAN;
pad->lower_warning_limit = prec->lsv ? prec->low : epicsNAN;
pad->lower_alarm_limit = prec->llsv ? prec->lolo : epicsNAN;
} else {
recGblGetAlarmDouble(paddr, pad);
linkNumber = get_linkNumber(fieldIndex);
if (linkNumber >= 0) {
dbGetAlarmLimits(&prec->inpa + linkNumber,
&pad->lower_alarm_limit,
&pad->lower_warning_limit,
&pad->upper_warning_limit,
&pad->upper_alarm_limit);
} else
recGblGetAlarmDouble(paddr, pad);
}
return 0;
}

View File

@@ -513,3 +513,6 @@ recordtype(calcout) {
extra("char orpc[INFIX_TO_POSTFIX_SIZE(80)]")
}
}
variable(calcoutODLYprecision, int)
variable(calcoutODLYlimit, double)

View File

@@ -400,11 +400,16 @@ static long put_array_info(DBADDR *paddr, long nNew)
return(0);
}
#define indexof(field) compressRecord##field
static long get_units(DBADDR *paddr,char *units)
{
compressRecord *prec=(compressRecord *)paddr->precord;
strncpy(units,prec->egu,DB_UNITS_SIZE);
if(paddr->pfldDes->field_type == DBF_DOUBLE
|| dbGetFieldIndex(paddr) == indexof(VAL)) {
strncpy(units,prec->egu,DB_UNITS_SIZE);
}
return(0);
}
@@ -413,7 +418,7 @@ static long get_precision(DBADDR *paddr, long *precision)
compressRecord *prec=(compressRecord *)paddr->precord;
*precision = prec->prec;
if(paddr->pfield == (void *)prec->bptr) return(0);
if(dbGetFieldIndex(paddr) == indexof(BPTR)) return(0);
recGblGetPrec(paddr,precision);
return(0);
}
@@ -422,12 +427,16 @@ static long get_graphic_double(DBADDR *paddr,struct dbr_grDouble *pgd)
{
compressRecord *prec=(compressRecord *)paddr->precord;
if(paddr->pfield==(void *)prec->bptr
|| paddr->pfield==(void *)&prec->ihil
|| paddr->pfield==(void *)&prec->ilil){
pgd->upper_disp_limit = prec->hopr;
pgd->lower_disp_limit = prec->lopr;
} else recGblGetGraphicDouble(paddr,pgd);
switch (dbGetFieldIndex(paddr)) {
case indexof(BPTR):
case indexof(IHIL):
case indexof(ILIL):
pgd->upper_disp_limit = prec->hopr;
pgd->lower_disp_limit = prec->lopr;
break;
default:
recGblGetGraphicDouble(paddr,pgd);
}
return(0);
}
@@ -435,11 +444,15 @@ static long get_control_double(DBADDR *paddr, struct dbr_ctrlDouble *pcd)
{
compressRecord *prec=(compressRecord *)paddr->precord;
if(paddr->pfield==(void *)prec->bptr
|| paddr->pfield==(void *)&prec->ihil
|| paddr->pfield==(void *)&prec->ilil){
pcd->upper_ctrl_limit = prec->hopr;
pcd->lower_ctrl_limit = prec->lopr;
} else recGblGetControlDouble(paddr,pcd);
switch (dbGetFieldIndex(paddr)) {
case indexof(BPTR):
case indexof(IHIL):
case indexof(ILIL):
pcd->upper_ctrl_limit = prec->hopr;
pcd->lower_ctrl_limit = prec->lopr;
break;
default:
recGblGetControlDouble(paddr,pcd);
}
return(0);
}

View File

@@ -126,73 +126,72 @@ static long process(dfanoutRecord *prec)
return(status);
}
#define indexof(field) dfanoutRecord##field
static long get_units(DBADDR *paddr,char *units)
{
dfanoutRecord *prec=(dfanoutRecord *)paddr->precord;
strncpy(units,prec->egu,DB_UNITS_SIZE);
if(paddr->pfldDes->field_type == DBF_DOUBLE) {
strncpy(units,prec->egu,DB_UNITS_SIZE);
}
return(0);
}
static long get_precision(DBADDR *paddr,long *precision)
{
dfanoutRecord *prec=(dfanoutRecord *)paddr->precord;
int fieldIndex = dbGetFieldIndex(paddr);
if(fieldIndex == dfanoutRecordVAL
|| fieldIndex == dfanoutRecordHIHI
|| fieldIndex == dfanoutRecordHIGH
|| fieldIndex == dfanoutRecordLOW
|| fieldIndex == dfanoutRecordLOLO
|| fieldIndex == dfanoutRecordHOPR
|| fieldIndex == dfanoutRecordLOPR) {
*precision = prec->prec;
} else {
recGblGetPrec(paddr,precision);
}
*precision = prec->prec;
if (dbGetFieldIndex(paddr) == indexof(VAL)) return(0);
recGblGetPrec(paddr,precision);
return(0);
}
static long get_graphic_double(DBADDR *paddr,struct dbr_grDouble *pgd)
static long get_graphic_double(DBADDR *paddr,struct dbr_grDouble *pgd)
{
dfanoutRecord *prec=(dfanoutRecord *)paddr->precord;
int fieldIndex = dbGetFieldIndex(paddr);
if(fieldIndex == dfanoutRecordVAL
|| fieldIndex == dfanoutRecordHIHI
|| fieldIndex == dfanoutRecordHIGH
|| fieldIndex == dfanoutRecordLOW
|| fieldIndex == dfanoutRecordLOLO
|| fieldIndex == dfanoutRecordHOPR
|| fieldIndex == dfanoutRecordLOPR) {
pgd->upper_disp_limit = prec->hopr;
pgd->lower_disp_limit = prec->lopr;
} else recGblGetGraphicDouble(paddr,pgd);
switch (dbGetFieldIndex(paddr)) {
case indexof(VAL):
case indexof(HIHI):
case indexof(HIGH):
case indexof(LOW):
case indexof(LOLO):
case indexof(LALM):
case indexof(ALST):
case indexof(MLST):
pgd->upper_disp_limit = prec->hopr;
pgd->lower_disp_limit = prec->lopr;
break;
default:
recGblGetGraphicDouble(paddr,pgd);
}
return(0);
}
static long get_control_double(DBADDR *paddr,struct dbr_ctrlDouble *pcd)
{
dfanoutRecord *prec=(dfanoutRecord *)paddr->precord;
int fieldIndex = dbGetFieldIndex(paddr);
if(fieldIndex == dfanoutRecordVAL
|| fieldIndex == dfanoutRecordHIHI
|| fieldIndex == dfanoutRecordHIGH
|| fieldIndex == dfanoutRecordLOW
|| fieldIndex == dfanoutRecordLOLO) {
pcd->upper_ctrl_limit = prec->hopr;
pcd->lower_ctrl_limit = prec->lopr;
} else recGblGetControlDouble(paddr,pcd);
switch (dbGetFieldIndex(paddr)) {
case indexof(VAL):
case indexof(LALM):
case indexof(ALST):
case indexof(MLST):
pcd->upper_ctrl_limit = prec->hopr;
pcd->lower_ctrl_limit = prec->lopr;
break;
default:
recGblGetControlDouble(paddr,pcd);
}
return(0);
}
static long get_alarm_double(DBADDR *paddr,struct dbr_alDouble *pad)
{
dfanoutRecord *prec=(dfanoutRecord *)paddr->precord;
int fieldIndex = dbGetFieldIndex(paddr);
if(fieldIndex == dfanoutRecordVAL) {
if(dbGetFieldIndex(paddr) == indexof(VAL)) {
pad->upper_alarm_limit = prec->hhsv ? prec->hihi : epicsNAN;
pad->upper_warning_limit = prec->hsv ? prec->high : epicsNAN;
pad->lower_warning_limit = prec->lsv ? prec->low : epicsNAN;

View File

@@ -52,7 +52,7 @@ static long special(DBADDR *, int);
static long cvt_dbaddr(DBADDR *);
static long get_array_info(DBADDR *, long *, long *);
#define put_array_info NULL
#define get_units NULL
static long get_units(DBADDR *, char *);
static long get_precision(DBADDR *paddr,long *precision);
#define get_enum_str NULL
#define get_enum_strs NULL
@@ -83,6 +83,9 @@ rset histogramRSET={
};
epicsExportAddress(rset,histogramRSET);
int histogramSDELprecision = 2;
epicsExportAddress(int, histogramSDELprecision);
struct histogramdset { /* histogram input dset */
long number;
DEVSUPFUN dev_report;
@@ -386,42 +389,71 @@ static long readValue(histogramRecord *prec)
return(status);
}
#define indexof(field) histogramRecord##field
static long get_units(DBADDR *paddr, char *units)
{
if (dbGetFieldIndex(paddr) == indexof(SDEL)) {
strcpy(units,"s");
}
/* We should have EGU for other DOUBLE values or probably get it from input link SVL */
return(0);
}
static long get_precision(DBADDR *paddr,long *precision)
{
histogramRecord *prec=(histogramRecord *)paddr->precord;
int fieldIndex = dbGetFieldIndex(paddr);
*precision = prec->prec;
if(fieldIndex == histogramRecordULIM
|| fieldIndex == histogramRecordLLIM
|| fieldIndex == histogramRecordSDEL
|| fieldIndex == histogramRecordSGNL
|| fieldIndex == histogramRecordSVAL
|| fieldIndex == histogramRecordWDTH) {
*precision = prec->prec;
switch (dbGetFieldIndex(paddr)) {
case indexof(ULIM):
case indexof(LLIM):
case indexof(SGNL):
case indexof(SVAL):
case indexof(WDTH):
*precision = prec->prec;
break;
case indexof(SDEL):
*precision = histogramSDELprecision;
break;
default:
recGblGetPrec(paddr,precision);
}
recGblGetPrec(paddr,precision);
return(0);
}
static long get_graphic_double(DBADDR *paddr,struct dbr_grDouble *pgd)
{
histogramRecord *prec=(histogramRecord *)paddr->precord;
int fieldIndex = dbGetFieldIndex(paddr);
if(fieldIndex == histogramRecordBPTR){
pgd->upper_disp_limit = prec->hopr;
pgd->lower_disp_limit = prec->lopr;
} else recGblGetGraphicDouble(paddr,pgd);
switch (dbGetFieldIndex(paddr)) {
case indexof(BPTR):
pgd->upper_disp_limit = prec->hopr;
pgd->lower_disp_limit = prec->lopr;
break;
case indexof(WDTH):
pgd->upper_disp_limit = prec->ulim-prec->llim;
pgd->lower_disp_limit = 0.0;
break;
default:
recGblGetGraphicDouble(paddr,pgd);
}
return(0);
}
static long get_control_double(DBADDR *paddr,struct dbr_ctrlDouble *pcd)
{
histogramRecord *prec=(histogramRecord *)paddr->precord;
int fieldIndex = dbGetFieldIndex(paddr);
if(fieldIndex == histogramRecordBPTR){
pcd->upper_ctrl_limit = prec->hopr;
pcd->lower_ctrl_limit = prec->lopr;
} else recGblGetControlDouble(paddr,pcd);
switch (dbGetFieldIndex(paddr)) {
case indexof(BPTR):
pcd->upper_ctrl_limit = prec->hopr;
pcd->lower_ctrl_limit = prec->lopr;
break;
case indexof(WDTH):
pcd->upper_ctrl_limit = prec->ulim-prec->llim;
pcd->lower_ctrl_limit = 0.0;
break;
default:
recGblGetControlDouble(paddr,pcd);
}
return(0);
}

View File

@@ -135,3 +135,5 @@ recordtype(histogram) {
interest(1)
}
}
variable(histogramSDELprecision, int)

View File

@@ -37,6 +37,8 @@
#undef GEN_SIZE_OFFSET
#include "epicsExport.h"
/* Hysterisis for alarm filtering: 1-1/e */
#define THRESHOLD 0.6321
/* Create RSET - Record Support Entry Table*/
#define report NULL
#define initialize NULL
@@ -87,7 +89,7 @@ struct longindset { /* longin input dset */
DEVSUPFUN get_ioint_info;
DEVSUPFUN read_longin; /*returns: (-1,0)=>(failure,success)*/
};
static void checkAlarms(longinRecord *prec);
static void checkAlarms(longinRecord *prec, epicsTimeStamp *timeLast);
static void monitor(longinRecord *prec);
static long readValue(longinRecord *prec);
@@ -132,12 +134,14 @@ static long process(longinRecord *prec)
struct longindset *pdset = (struct longindset *)(prec->dset);
long status;
unsigned char pact=prec->pact;
epicsTimeStamp timeLast;
if( (pdset==NULL) || (pdset->read_longin==NULL) ) {
prec->pact=TRUE;
recGblRecordError(S_dev_missingSup,(void *)prec,"read_longin");
return(S_dev_missingSup);
}
timeLast = prec->time;
status=readValue(prec); /* read the new value */
/* check if device support set pact */
@@ -148,7 +152,7 @@ static long process(longinRecord *prec)
if (status==0) prec->udf = FALSE;
/* check for alarms */
checkAlarms(prec);
checkAlarms(prec, &timeLast);
/* check event list */
monitor(prec);
/* process the forward scan link record */
@@ -158,11 +162,15 @@ static long process(longinRecord *prec)
return(status);
}
#define indexof(field) longinRecord##field
static long get_units(DBADDR *paddr,char *units)
{
longinRecord *prec=(longinRecord *)paddr->precord;
strncpy(units,prec->egu,DB_UNITS_SIZE);
if(paddr->pfldDes->field_type == DBF_LONG) {
strncpy(units,prec->egu,DB_UNITS_SIZE);
}
return(0);
}
@@ -171,14 +179,22 @@ static long get_graphic_double(DBADDR *paddr, struct dbr_grDouble *pgd)
{
longinRecord *prec=(longinRecord *)paddr->precord;
if(paddr->pfield==(void *)&prec->val
|| paddr->pfield==(void *)&prec->hihi
|| paddr->pfield==(void *)&prec->high
|| paddr->pfield==(void *)&prec->low
|| paddr->pfield==(void *)&prec->lolo){
pgd->upper_disp_limit = prec->hopr;
pgd->lower_disp_limit = prec->lopr;
} else recGblGetGraphicDouble(paddr,pgd);
switch (dbGetFieldIndex(paddr)) {
case indexof(VAL):
case indexof(HIHI):
case indexof(HIGH):
case indexof(LOW):
case indexof(LOLO):
case indexof(LALM):
case indexof(ALST):
case indexof(MLST):
case indexof(SVAL):
pgd->upper_disp_limit = prec->hopr;
pgd->lower_disp_limit = prec->lopr;
break;
default:
recGblGetGraphicDouble(paddr,pgd);
}
return(0);
}
@@ -186,14 +202,22 @@ static long get_control_double(DBADDR *paddr, struct dbr_ctrlDouble *pcd)
{
longinRecord *prec=(longinRecord *)paddr->precord;
if(paddr->pfield==(void *)&prec->val
|| paddr->pfield==(void *)&prec->hihi
|| paddr->pfield==(void *)&prec->high
|| paddr->pfield==(void *)&prec->low
|| paddr->pfield==(void *)&prec->lolo){
pcd->upper_ctrl_limit = prec->hopr;
pcd->lower_ctrl_limit = prec->lopr;
} else recGblGetControlDouble(paddr,pcd);
switch (dbGetFieldIndex(paddr)) {
case indexof(VAL):
case indexof(HIHI):
case indexof(HIGH):
case indexof(LOW):
case indexof(LOLO):
case indexof(LALM):
case indexof(ALST):
case indexof(MLST):
case indexof(SVAL):
pcd->upper_ctrl_limit = prec->hopr;
pcd->lower_ctrl_limit = prec->lopr;
break;
default:
recGblGetControlDouble(paddr,pcd);
}
return(0);
}
@@ -201,7 +225,7 @@ static long get_alarm_double(DBADDR *paddr, struct dbr_alDouble *pad)
{
longinRecord *prec=(longinRecord *)paddr->precord;
if(paddr->pfield==(void *)&prec->val){
if(dbGetFieldIndex(paddr) == indexof(VAL)){
pad->upper_alarm_limit = prec->hihi;
pad->upper_warning_limit = prec->high;
pad->lower_warning_limit = prec->low;
@@ -210,14 +234,28 @@ static long get_alarm_double(DBADDR *paddr, struct dbr_alDouble *pad)
return(0);
}
static void checkAlarms(longinRecord *prec)
static void checkAlarms(longinRecord *prec, epicsTimeStamp *timeLast)
{
enum {
range_Lolo = 1,
range_Low,
range_Normal,
range_High,
range_Hihi
} alarmRange;
static const epicsEnum16 range_stat[] = {
SOFT_ALARM, LOLO_ALARM, LOW_ALARM,
NO_ALARM, HIGH_ALARM, HIHI_ALARM
};
double aftc, afvl;
epicsInt32 val, hyst, lalm;
epicsInt32 alev;
epicsEnum16 asev;
if (prec->udf) {
recGblSetSevr(prec, UDF_ALARM, INVALID_ALARM);
prec->afvl = 0;
return;
}
@@ -225,45 +263,88 @@ static void checkAlarms(longinRecord *prec)
hyst = prec->hyst;
lalm = prec->lalm;
/* alarm condition hihi */
asev = prec->hhsv;
alev = prec->hihi;
if (asev && (val >= alev || ((lalm == alev) && (val >= alev - hyst)))) {
if (recGblSetSevr(prec, HIHI_ALARM, asev))
prec->lalm = alev;
return;
/* check VAL against alarm limits */
if ((asev = prec->hhsv) &&
(val >= (alev = prec->hihi) ||
((lalm == alev) && (val >= alev - hyst))))
alarmRange = range_Hihi;
else
if ((asev = prec->llsv) &&
(val <= (alev = prec->lolo) ||
((lalm == alev) && (val <= alev + hyst))))
alarmRange = range_Lolo;
else
if ((asev = prec->hsv) &&
(val >= (alev = prec->high) ||
((lalm == alev) && (val >= alev - hyst))))
alarmRange = range_High;
else
if ((asev = prec->lsv) &&
(val <= (alev = prec->low) ||
((lalm == alev) && (val <= alev + hyst))))
alarmRange = range_Low;
else {
alev = val;
asev = NO_ALARM;
alarmRange = range_Normal;
}
/* alarm condition lolo */
asev = prec->llsv;
alev = prec->lolo;
if (asev && (val <= alev || ((lalm == alev) && (val <= alev + hyst)))) {
if (recGblSetSevr(prec, LOLO_ALARM, asev))
prec->lalm = alev;
return;
}
aftc = prec->aftc;
afvl = 0;
/* alarm condition high */
asev = prec->hsv;
alev = prec->high;
if (asev && (val >= alev || ((lalm == alev) && (val >= alev - hyst)))) {
if (recGblSetSevr(prec, HIGH_ALARM, asev))
prec->lalm = alev;
return;
}
if (aftc > 0) {
/* Apply level filtering */
afvl = prec->afvl;
if (afvl == 0) {
afvl = (double)alarmRange;
} else {
double t = epicsTimeDiffInSeconds(&prec->time, timeLast);
double alpha = aftc / (t + aftc);
/* alarm condition low */
asev = prec->lsv;
alev = prec->low;
if (asev && (val <= alev || ((lalm == alev) && (val <= alev + hyst)))) {
if (recGblSetSevr(prec, LOW_ALARM, asev))
prec->lalm = alev;
return;
}
/* The sign of afvl indicates whether the result should be
* rounded up or down. This gives the filter hysteresis.
* If afvl > 0 the floor() function rounds to a lower alarm
* level, otherwise to a higher.
*/
afvl = alpha * afvl +
((afvl > 0) ? (1 - alpha) : (alpha - 1)) * alarmRange;
if (afvl - floor(afvl) > THRESHOLD)
afvl = -afvl; /* reverse rounding */
/* we get here only if val is out of alarm by at least hyst */
prec->lalm = val;
return;
alarmRange = abs((int)floor(afvl));
switch (alarmRange) {
case range_Hihi:
asev = prec->hhsv;
alev = prec->hihi;
break;
case range_High:
asev = prec->hsv;
alev = prec->high;
break;
case range_Normal:
asev = NO_ALARM;
break;
case range_Low:
asev = prec->lsv;
alev = prec->low;
break;
case range_Lolo:
asev = prec->llsv;
alev = prec->lolo;
break;
}
}
}
prec->afvl = afvl;
if (asev) {
/* Report alarm condition, store LALM for future HYST calculations */
if (recGblSetSevr(prec, range_stat[alarmRange], asev))
prec->lalm = alev;
} else {
/* No alarm condition, reset LALM */
prec->lalm = val;
}
}
/* DELTA calculates the absolute difference between its arguments

View File

@@ -93,6 +93,16 @@ recordtype(longin) {
promptgroup(GUI_ALARMS)
interest(1)
}
field(AFTC, DBF_DOUBLE) {
prompt("Alarm Filter Time Constant")
promptgroup(GUI_ALARMS)
interest(1)
}
field(AFVL, DBF_DOUBLE) {
prompt("Alarm Filter Value")
special(SPC_NOMOD)
interest(3)
}
field(ADEL,DBF_LONG) {
prompt("Archive Deadband")
promptgroup(GUI_DISPLAY)

View File

@@ -190,58 +190,73 @@ static long process(longoutRecord *prec)
return(status);
}
#define indexof(field) longoutRecord##field
static long get_units(DBADDR *paddr,char *units)
{
longoutRecord *prec=(longoutRecord *)paddr->precord;
strncpy(units,prec->egu,DB_UNITS_SIZE);
if(paddr->pfldDes->field_type == DBF_LONG) {
strncpy(units,prec->egu,DB_UNITS_SIZE);
}
return(0);
}
static long get_graphic_double(DBADDR *paddr,struct dbr_grDouble *pgd)
{
longoutRecord *prec=(longoutRecord *)paddr->precord;
int fieldIndex = dbGetFieldIndex(paddr);
if(fieldIndex == longoutRecordVAL
|| fieldIndex == longoutRecordHIHI
|| fieldIndex == longoutRecordHIGH
|| fieldIndex == longoutRecordLOW
|| fieldIndex == longoutRecordLOLO) {
pgd->upper_disp_limit = prec->hopr;
pgd->lower_disp_limit = prec->lopr;
} else recGblGetGraphicDouble(paddr,pgd);
switch (dbGetFieldIndex(paddr)) {
case indexof(VAL):
case indexof(HIHI):
case indexof(HIGH):
case indexof(LOW):
case indexof(LOLO):
case indexof(LALM):
case indexof(ALST):
case indexof(MLST):
pgd->upper_disp_limit = prec->hopr;
pgd->lower_disp_limit = prec->lopr;
break;
default:
recGblGetGraphicDouble(paddr,pgd);
}
return(0);
}
static long get_control_double(DBADDR *paddr,struct dbr_ctrlDouble *pcd)
{
longoutRecord *prec=(longoutRecord *)paddr->precord;
int fieldIndex = dbGetFieldIndex(paddr);
if(fieldIndex == longoutRecordVAL
|| fieldIndex == longoutRecordHIHI
|| fieldIndex == longoutRecordHIGH
|| fieldIndex == longoutRecordLOW
|| fieldIndex == longoutRecordLOLO) {
/* do not change pre drvh/drvl behavior */
if(prec->drvh > prec->drvl) {
pcd->upper_ctrl_limit = prec->drvh;
pcd->lower_ctrl_limit = prec->drvl;
} else {
pcd->upper_ctrl_limit = prec->hopr;
pcd->lower_ctrl_limit = prec->lopr;
}
} else recGblGetControlDouble(paddr,pcd);
switch (dbGetFieldIndex(paddr)) {
case indexof(VAL):
case indexof(HIHI):
case indexof(HIGH):
case indexof(LOW):
case indexof(LOLO):
case indexof(LALM):
case indexof(ALST):
case indexof(MLST):
/* do not change pre drvh/drvl behavior */
if(prec->drvh > prec->drvl) {
pcd->upper_ctrl_limit = prec->drvh;
pcd->lower_ctrl_limit = prec->drvl;
} else {
pcd->upper_ctrl_limit = prec->hopr;
pcd->lower_ctrl_limit = prec->lopr;
}
break;
default:
recGblGetControlDouble(paddr,pcd);
}
return(0);
}
static long get_alarm_double(DBADDR *paddr,struct dbr_alDouble *pad)
{
longoutRecord *prec=(longoutRecord *)paddr->precord;
int fieldIndex = dbGetFieldIndex(paddr);
if(fieldIndex == longoutRecordVAL) {
if(dbGetFieldIndex(paddr) == indexof(VAL)) {
pad->upper_alarm_limit = prec->hihi;
pad->upper_warning_limit = prec->high;
pad->lower_warning_limit = prec->low;

View File

@@ -1,6 +1,6 @@
/*************************************************************************\
* Copyright (c) 2009 Helmholtz-Zentrum Berlin fuer Materialien und Energie.
* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne
* Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
@@ -27,6 +27,7 @@
#include "dbEvent.h"
#include "dbFldTypes.h"
#include "devSup.h"
#include "epicsMath.h"
#include "errMdef.h"
#include "menuSimm.h"
#include "recSup.h"
@@ -36,6 +37,10 @@
#include "mbbiRecord.h"
#undef GEN_SIZE_OFFSET
#include "epicsExport.h"
/* Hysterisis for alarm filtering: 1-1/e */
#define THRESHOLD 0.6321
/* Create RSET - Record Support Entry Table*/
#define report NULL
#define initialize NULL
@@ -54,56 +59,56 @@ static long put_enum_str(DBADDR *, char *);
#define get_graphic_double NULL
#define get_control_double NULL
#define get_alarm_double NULL
rset mbbiRSET={
RSETNUMBER,
report,
initialize,
init_record,
process,
special,
get_value,
cvt_dbaddr,
get_array_info,
put_array_info,
get_units,
get_precision,
get_enum_str,
get_enum_strs,
put_enum_str,
get_graphic_double,
get_control_double,
get_alarm_double
rset mbbiRSET = {
RSETNUMBER,
report,
initialize,
init_record,
process,
special,
get_value,
cvt_dbaddr,
get_array_info,
put_array_info,
get_units,
get_precision,
get_enum_str,
get_enum_strs,
put_enum_str,
get_graphic_double,
get_control_double,
get_alarm_double
};
epicsExportAddress(rset,mbbiRSET);
struct mbbidset { /* multi bit binary input dset */
long number;
DEVSUPFUN dev_report;
DEVSUPFUN init;
DEVSUPFUN init_record; /*returns: (-1,0)=>(failure,success)*/
DEVSUPFUN get_ioint_info;
DEVSUPFUN read_mbbi;/*(0,2)=>(success, success no convert)*/
long number;
DEVSUPFUN dev_report;
DEVSUPFUN init;
DEVSUPFUN init_record; /* returns: (-1,0) => (failure, success)*/
DEVSUPFUN get_ioint_info;
DEVSUPFUN read_mbbi;/* (0, 2) => (success, success no convert)*/
};
static void checkAlarms(mbbiRecord *);
static void checkAlarms(mbbiRecord *, epicsTimeStamp *);
static void monitor(mbbiRecord *);
static long readValue(mbbiRecord *);
static void init_common(mbbiRecord *prec)
{
epicsUInt32 *pstate_values;
char *pstate_string;
short i;
epicsUInt32 *pstate_values = &prec->zrvl;
char *pstate_string = prec->zrst;
int i;
/* determine if any states are defined */
pstate_values = &(prec->zrvl); pstate_string = prec->zrst;
prec->sdef = FALSE;
for (i=0; i<16; i++, pstate_string += sizeof(prec->zrst)) {
if((*(pstate_values+i) != 0) || (*pstate_string !='\0')) {
prec->sdef = TRUE;
return;
}
}
return;
/* Check if any states are defined */
for (i = 0; i < 16; i++, pstate_string += sizeof(prec->zrst)) {
if ((pstate_values[i] != 0) || (*pstate_string != '\0')) {
prec->sdef = TRUE;
return;
}
}
prec->sdef = FALSE;
}
static long init_record(mbbiRecord *prec, int pass)
@@ -111,258 +116,312 @@ static long init_record(mbbiRecord *prec, int pass)
struct mbbidset *pdset;
long status;
if (pass==0) return(0);
if (pass == 0)
return 0;
if (prec->siml.type == CONSTANT) {
recGblInitConstantLink(&prec->siml,DBF_USHORT,&prec->simm);
recGblInitConstantLink(&prec->siml, DBF_USHORT, &prec->simm);
}
if (prec->siol.type == CONSTANT) {
recGblInitConstantLink(&prec->siol,DBF_USHORT,&prec->sval);
recGblInitConstantLink(&prec->siol, DBF_USHORT, &prec->sval);
}
if(!(pdset = (struct mbbidset *)(prec->dset))) {
recGblRecordError(S_dev_noDSET,(void *)prec,"mbbi: init_record");
return(S_dev_noDSET);
pdset = (struct mbbidset *) prec->dset;
if (!pdset) {
recGblRecordError(S_dev_noDSET, prec, "mbbi: init_record");
return S_dev_noDSET;
}
/* must have read_mbbi function defined */
if( (pdset->number < 5) || (pdset->read_mbbi == NULL) ) {
recGblRecordError(S_dev_missingSup,(void *)prec,"mbbi: init_record");
return(S_dev_missingSup);
if ((pdset->number < 5) || (pdset->read_mbbi == NULL)) {
recGblRecordError(S_dev_missingSup, prec, "mbbi: init_record");
return S_dev_missingSup;
}
/* initialize mask*/
prec->mask = (1 << prec->nobt) - 1;
if( pdset->init_record ) {
if((status=(*pdset->init_record)(prec))) return(status);
/* initialize mask if the user didn't */
if (prec->mask == 0)
prec->mask = (1 << prec->nobt) - 1;
if (pdset->init_record) {
status = pdset->init_record(prec);
}
else
status = 0;
init_common(prec);
prec->mlst = prec->val;
prec->lalm = prec->val;
prec->oraw = prec->rval;
return(0);
return status;
}
static long process(mbbiRecord *prec)
{
struct mbbidset *pdset = (struct mbbidset *)(prec->dset);
long status;
unsigned char pact=prec->pact;
struct mbbidset *pdset = (struct mbbidset *) prec->dset;
long status;
int pact = prec->pact;
epicsTimeStamp timeLast;
if( (pdset==NULL) || (pdset->read_mbbi==NULL) ) {
prec->pact=TRUE;
recGblRecordError(S_dev_missingSup,(void *)prec,"read_mbbi");
return(S_dev_missingSup);
}
if ((pdset == NULL) || (pdset->read_mbbi == NULL)) {
prec->pact = TRUE;
recGblRecordError(S_dev_missingSup, prec, "read_mbbi");
return S_dev_missingSup;
}
status=readValue(prec); /* read the new value */
/* check if device support set pact */
if ( !pact && prec->pact ) return(0);
prec->pact = TRUE;
timeLast = prec->time;
recGblGetTimeStamp(prec);
if(status==0) { /* convert the value */
epicsUInt32 *pstate_values;
short i;
epicsUInt32 rval = prec->rval;
status = readValue(prec); /* read the new value */
/* check if device support set pact */
if (!pact && prec->pact)
return 0;
prec->pact = TRUE;
prec->udf = FALSE;
if(prec->shft>0) rval >>= prec->shft;
if (prec->sdef){
pstate_values = &(prec->zrvl);
prec->val = 65535; /* initalize to unknown state*/
for (i = 0; i < 16; i++){
if (*pstate_values == rval){
prec->val = i;
break;
}
pstate_values++;
}
}else{
/* the raw value is the desired value */
prec->val = (unsigned short)rval;
}
}
else if(status == 2) status = 0;
recGblGetTimeStamp(prec);
if (status == 0) { /* convert the value */
epicsUInt32 *pstate_values;
short i;
epicsUInt32 rval = prec->rval;
/* check for alarms */
checkAlarms(prec);
prec->udf = FALSE;
if (prec->shft > 0)
rval >>= prec->shft;
if (prec->sdef) {
pstate_values = &(prec->zrvl);
prec->val = 65535; /* initalize to unknown state*/
for (i = 0; i < 16; i++) {
if (*pstate_values == rval) {
prec->val = i;
break;
}
pstate_values++;
}
}
else {
/* the raw value is the desired value */
prec->val = rval;
}
}
else {
if (status == 2) {
status = 0;
}
}
/* check event list */
monitor(prec);
/* check for alarms */
checkAlarms(prec, &timeLast);
/* process the forward scan link record */
recGblFwdLink(prec);
/* check event list */
monitor(prec);
prec->pact=FALSE;
return(status);
/* process the forward scan link record */
recGblFwdLink(prec);
prec->pact=FALSE;
return status;
}
static long special(DBADDR *paddr,int after)
static long special(DBADDR *paddr, int after)
{
mbbiRecord *prec = (mbbiRecord *)(paddr->precord);
int special_type = paddr->special;
int fieldIndex = dbGetFieldIndex(paddr);
mbbiRecord *prec = (mbbiRecord *) paddr->precord;
int special_type = paddr->special;
int fieldIndex = dbGetFieldIndex(paddr);
if(!after) return(0);
switch(special_type) {
case(SPC_MOD):
init_common(prec);
if (fieldIndex >= mbbiRecordZRST && fieldIndex <= mbbiRecordFFST)
db_post_events(prec,&prec->val,DBE_PROPERTY);
return(0);
if (!after) return 0;
switch (special_type) {
case SPC_MOD:
init_common(prec);
if (fieldIndex >= mbbiRecordZRST && fieldIndex <= mbbiRecordFFST) {
int event = DBE_PROPERTY;
if (prec->val == fieldIndex - mbbiRecordZRST)
event |= DBE_VALUE | DBE_LOG;
db_post_events(prec, &prec->val, event);
}
return 0;
default:
recGblDbaddrError(S_db_badChoice,paddr,"mbbi: special");
return(S_db_badChoice);
recGblDbaddrError(S_db_badChoice, paddr, "mbbi: special");
return S_db_badChoice;
}
}
static long get_enum_str(DBADDR *paddr,char* pstring)
static long get_enum_str(DBADDR *paddr, char *pstring)
{
mbbiRecord *prec=(mbbiRecord *)paddr->precord;
char *psource;
int index;
unsigned short *pfield = (unsigned short *)paddr->pfield;
unsigned short val=*pfield;
mbbiRecord *prec = (mbbiRecord *) paddr->precord;
int index;
unsigned short *pfield = paddr->pfield;
epicsEnum16 val = *pfield;
index = dbGetFieldIndex(paddr);
if(index!=mbbiRecordVAL) {
strcpy(pstring,"Illegal_Value");
} else if(val<= 15) {
psource = (prec->zrst);
psource += (val * sizeof(prec->zrst));
strncpy(pstring,psource,sizeof(prec->zrst));
} else {
strcpy(pstring,"Illegal Value");
if (index != mbbiRecordVAL) {
strcpy(pstring, "Illegal_Value");
}
return(0);
else if (val <= 15) {
char *pstate = prec->zrst + val * sizeof(prec->zrst);
strncpy(pstring, pstate, sizeof(prec->zrst));
}
else {
strcpy(pstring, "Illegal Value");
}
return 0;
}
static long get_enum_strs(DBADDR *paddr, struct dbr_enumStrs *pes)
{
mbbiRecord *prec=(mbbiRecord *)paddr->precord;
char *psource;
int i;
short no_str;
mbbiRecord *prec = (mbbiRecord *) paddr->precord;
char *pstate = prec->zrst;
int i;
short states = 0;
no_str = 0;
memset(pes->strs,'\0',sizeof(pes->strs));
for(i=0,psource=(prec->zrst); i<16; i++, psource += sizeof(prec->zrst) ) {
strncpy(pes->strs[i],psource,sizeof(prec->zrst));
if(*psource!=0) no_str=i+1;
memset(pes->strs, '\0', sizeof(pes->strs));
for (i = 0; i < 16; i++, pstate += sizeof(prec->zrst) ) {
strncpy(pes->strs[i], pstate, sizeof(prec->zrst));
if (*pstate!=0) states = i+1;
}
pes->no_str=no_str;
return(0);
pes->no_str = states;
return 0;
}
static long put_enum_str(DBADDR *paddr, char *pstring)
{
mbbiRecord *prec=(mbbiRecord *)paddr->precord;
char *pstate_name;
short i;
mbbiRecord *prec = (mbbiRecord *) paddr->precord;
char *pstate;
short i;
if (prec->sdef){
pstate_name = prec->zrst;
for (i = 0; i < 16; i++){
if(strncmp(pstate_name,pstring,sizeof(prec->zrst))==0){
prec->val = i;
prec->udf = FALSE;
return(0);
}
pstate_name += sizeof(prec->zrst);
}
if (prec->sdef) {
pstate = prec->zrst;
for (i = 0; i < 16; i++) {
if (strncmp(pstate, pstring, sizeof(prec->zrst)) == 0) {
prec->val = i;
prec->udf = FALSE;
return 0;
}
pstate += sizeof(prec->zrst);
}
return(S_db_badChoice);
}
return S_db_badChoice;
}
static void checkAlarms(mbbiRecord *prec)
static void checkAlarms(mbbiRecord *prec, epicsTimeStamp *timeLast)
{
unsigned short *severities;
unsigned short val=prec->val;
double aftc, afvl;
unsigned short alarm;
epicsEnum16 asev;
epicsEnum16 val = prec->val;
/* check for udf alarm */
if(prec->udf == TRUE ){
recGblSetSevr(prec,UDF_ALARM,INVALID_ALARM);
/* check for udf alarm */
if (prec->udf) {
recGblSetSevr(prec, UDF_ALARM, INVALID_ALARM);
prec->afvl = 0;
return;
}
/* check for state alarm */
if (val > 15) {
/* Unknown state */
alarm = prec->unsv;
}
else {
/* State has a severity field */
epicsEnum16 *severities = &prec->zrsv;
alarm = severities[prec->val];
}
aftc = prec->aftc;
afvl = 0;
if (aftc > 0) {
afvl = prec->afvl;
if (afvl == 0) {
afvl = (double) alarm;
}
else {
double t = epicsTimeDiffInSeconds(&prec->time, timeLast);
double alpha = aftc / (t + aftc);
/* check for state alarm */
/* unknown state */
if (val > 15){
recGblSetSevr(prec,STATE_ALARM,prec->unsv);
} else {
/* in a state which is an error */
severities = (unsigned short *)&(prec->zrsv);
recGblSetSevr(prec,STATE_ALARM,severities[prec->val]);
}
afvl = alpha * afvl +
((afvl > 0) ? (1.0 - alpha) : (alpha - 1.0)) * alarm;
if (afvl - floor(afvl) > THRESHOLD)
afvl = -afvl;
/* check for cos alarm */
if(val == prec->lalm) return;
recGblSetSevr(prec,COS_ALARM,prec->cosv);
prec->lalm = val;
return;
alarm = abs((int)floor(afvl));
}
}
asev = alarm;
recGblSetSevr(prec, STATE_ALARM, asev);
/* check for cos alarm */
if (val == prec->lalm)
return;
recGblSetSevr(prec, COS_ALARM, prec->cosv);
prec->lalm = val;
}
static void monitor(mbbiRecord *prec)
{
unsigned short monitor_mask;
unsigned short monitor_mask;
monitor_mask = recGblResetAlarms(prec);
/* check for value change */
if (prec->mlst != prec->val){
/* post events for value change and archive change */
monitor_mask |= (DBE_VALUE | DBE_LOG);
/* update last value monitored */
prec->mlst = prec->val;
}
/* send out monitors connected to the value field */
if (monitor_mask){
db_post_events(prec,&prec->val,monitor_mask);
}
if(prec->oraw!=prec->rval) {
db_post_events(prec,&prec->rval,monitor_mask|DBE_VALUE);
prec->oraw = prec->rval;
}
return;
monitor_mask = recGblResetAlarms(prec);
/* check for value change */
if (prec->mlst != prec->val) {
/* post events for value change and archive change */
monitor_mask |= (DBE_VALUE | DBE_LOG);
/* update last value monitored */
prec->mlst = prec->val;
}
/* send out monitors connected to the value field */
if (monitor_mask) {
db_post_events(prec, &prec->val, monitor_mask);
}
if (prec->oraw != prec->rval) {
db_post_events(prec, &prec->rval, monitor_mask | DBE_VALUE);
prec->oraw = prec->rval;
}
}
static long readValue(mbbiRecord *prec)
{
long status;
struct mbbidset *pdset = (struct mbbidset *) (prec->dset);
struct mbbidset *pdset = (struct mbbidset *) prec->dset;
long status;
if (prec->pact == TRUE){
status=(*pdset->read_mbbi)(prec);
return(status);
}
if (prec->pact) {
status = pdset->read_mbbi(prec);
return status;
}
status=dbGetLink(&(prec->siml),DBR_USHORT,&(prec->simm),0,0);
if (status)
return(status);
status = dbGetLink(&prec->siml, DBR_USHORT, &prec->simm, 0, 0);
if (status)
return status;
if (prec->simm == menuSimmNO){
status=(*pdset->read_mbbi)(prec);
return(status);
}
if (prec->simm == menuSimmYES){
status=dbGetLink(&(prec->siol),DBR_ULONG,&(prec->sval),0,0);
if (status==0){
prec->val=(unsigned short)prec->sval;
prec->udf=FALSE;
}
status=2; /* dont convert */
}
else if (prec->simm == menuSimmRAW){
status=dbGetLink(&(prec->siol),DBR_ULONG,&(prec->sval),0,0);
if (status==0){
prec->rval=prec->sval;
prec->udf=FALSE;
}
status=0; /* convert since we've written RVAL */
} else {
status=-1;
recGblSetSevr(prec,SOFT_ALARM,INVALID_ALARM);
return(status);
}
recGblSetSevr(prec,SIMM_ALARM,prec->sims);
if (prec->simm == menuSimmNO) {
status = pdset->read_mbbi(prec);
return status;
}
if (prec->simm == menuSimmYES) {
status=dbGetLink(&prec->siol, DBR_ULONG, &prec->sval, 0, 0);
if (status == 0) {
prec->val = prec->sval;
prec->udf = FALSE;
}
status = 2; /* dont convert */
}
else if (prec->simm == menuSimmRAW) {
status = dbGetLink(&prec->siol, DBR_ULONG, &prec->sval, 0, 0);
if (status == 0) {
prec->rval = prec->sval;
prec->udf = FALSE;
}
status = 0; /* convert since we've written RVAL */
}
else {
status = -1;
recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM);
return status;
}
recGblSetSevr(prec, SIMM_ALARM, prec->sims);
return(status);
return status;
}

View File

@@ -394,6 +394,16 @@ recordtype(mbbi) {
interest(1)
menu(menuAlarmSevr)
}
field(AFTC, DBF_DOUBLE) {
prompt("Alarm Filter Time Constant")
promptgroup(GUI_ALARMS)
interest(1)
}
field(AFVL, DBF_DOUBLE) {
prompt("Alarm Filter Value")
special(SPC_NOMOD)
interest(3)
}
field(UNSV,DBF_MENU) {
prompt("Unknown State Severity")
promptgroup(GUI_MBB)

View File

@@ -1,6 +1,6 @@
/*************************************************************************\
* Copyright (c) 2009 Helmholtz-Zentrum Berlin fuer Materialien und Energie.
* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne
* Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
@@ -60,35 +60,35 @@ static long put_enum_str(DBADDR *, char *);
#define get_control_double NULL
#define get_alarm_double NULL
rset mbboRSET={
RSETNUMBER,
report,
initialize,
init_record,
process,
special,
get_value,
cvt_dbaddr,
get_array_info,
put_array_info,
get_units,
get_precision,
get_enum_str,
get_enum_strs,
put_enum_str,
get_graphic_double,
get_control_double,
get_alarm_double
rset mbboRSET = {
RSETNUMBER,
report,
initialize,
init_record,
process,
special,
get_value,
cvt_dbaddr,
get_array_info,
put_array_info,
get_units,
get_precision,
get_enum_str,
get_enum_strs,
put_enum_str,
get_graphic_double,
get_control_double,
get_alarm_double
};
epicsExportAddress(rset,mbboRSET);
struct mbbodset { /* multi bit binary output dset */
long number;
DEVSUPFUN dev_report;
DEVSUPFUN init;
DEVSUPFUN init_record; /*returns: (0,2)=>(success,success no convert)*/
DEVSUPFUN get_ioint_info;
DEVSUPFUN write_mbbo; /*returns: (0,2)=>(success,success no convert)*/
long number;
DEVSUPFUN dev_report;
DEVSUPFUN init;
DEVSUPFUN init_record; /*returns: (0, 2) => (success, success no convert)*/
DEVSUPFUN get_ioint_info;
DEVSUPFUN write_mbbo; /*returns: (0, 2) => (success, success no convert)*/
};
@@ -100,360 +100,370 @@ static long writeValue(mbboRecord *);
static void init_common(mbboRecord *prec)
{
epicsUInt32 *pstate_values;
char *pstate_string;
short i;
epicsUInt32 *pstate_values = &prec->zrvl;
char *pstate_string = prec->zrst;
int i;
/* determine if any states are defined */
pstate_values = &(prec->zrvl); pstate_string = prec->zrst;
prec->sdef = FALSE;
for (i=0; i<16; i++, pstate_string += sizeof(prec->zrst)) {
if((*(pstate_values+i)!= 0) || (*pstate_string !='\0')) {
prec->sdef = TRUE;
return;
}
/* Check if any states are defined */
for (i = 0; i < 16; i++, pstate_string += sizeof(prec->zrst)) {
if ((pstate_values[i] != 0) || (*pstate_string != '\0')) {
prec->sdef = TRUE;
return;
}
return;
}
prec->sdef = FALSE;
}
static long init_record(mbboRecord *prec, int pass)
{
struct mbbodset *pdset;
long status;
int i;
if (pass==0) {
if (pass == 0) {
init_common(prec);
return(0);
return 0;
}
/* mbbo.siml must be a CONSTANT or a PV_LINK or a DB_LINK */
if (prec->siml.type == CONSTANT) {
recGblInitConstantLink(&prec->siml,DBF_USHORT,&prec->simm);
recGblInitConstantLink(&prec->siml, DBF_USHORT, &prec->simm);
}
if(!(pdset = (struct mbbodset *)(prec->dset))) {
recGblRecordError(S_dev_noDSET,(void *)prec,"mbbo: init_record");
return(S_dev_noDSET);
pdset = (struct mbbodset *) prec->dset;
if (!pdset) {
recGblRecordError(S_dev_noDSET, prec, "mbbo: init_record");
return S_dev_noDSET;
}
/* must have write_mbbo function defined */
if( (pdset->number < 5) || (pdset->write_mbbo == NULL) ) {
recGblRecordError(S_dev_missingSup,(void *)prec,"mbbo: init_record");
return(S_dev_missingSup);
if ((pdset->number < 5) || (pdset->write_mbbo == NULL)) {
recGblRecordError(S_dev_missingSup, prec, "mbbo: init_record");
return S_dev_missingSup;
}
if (prec->dol.type == CONSTANT){
if(recGblInitConstantLink(&prec->dol,DBF_USHORT,&prec->val))
prec->udf = FALSE;
if (prec->dol.type == CONSTANT) {
if (recGblInitConstantLink(&prec->dol, DBF_USHORT, &prec->val))
prec->udf = FALSE;
}
/* initialize mask*/
prec->mask = 0;
for (i=0; i<prec->nobt; i++) {
prec->mask <<= 1; /* shift left 1 bit*/
prec->mask |= 1; /* set low order bit*/
}
if( pdset->init_record ) {
epicsUInt32 rval;
/* initialize mask if the user didn't */
if (prec->mask == 0)
prec->mask = (1 << prec->nobt) - 1;
status=(*pdset->init_record)(prec);
/* init_record might set status */
init_common(prec);
if(status==0){
rval = prec->rval;
if(prec->shft>0) rval >>= prec->shft;
if (prec->sdef){
epicsUInt32 *pstate_values;
short i;
if (pdset->init_record) {
status = pdset->init_record(prec);
init_common(prec);
if (status == 0) {
/* convert initial read-back */
epicsUInt32 rval = prec->rval;
pstate_values = &(prec->zrvl);
prec->val = 65535; /* initalize to unknown state*/
for (i = 0; i < 16; i++){
if (*pstate_values == rval){
prec->val = i;
break;
}
pstate_values++;
}
}else{
/* the raw is the desired val */
prec->val = (unsigned short)rval;
}
prec->udf = FALSE;
} else if (status==2) status=0;
if (prec->shft > 0)
rval >>= prec->shft;
if (prec->sdef) {
epicsUInt32 *pstate_values = &prec->zrvl;
int i;
prec->val = 65535; /* initalize to unknown state */
for (i = 0; i < 16; i++) {
if (*pstate_values == rval) {
prec->val = i;
break;
}
pstate_values++;
}
}
else {
/* No defined states, punt */
prec->val = rval;
}
prec->udf = FALSE;
}
else if (status == 2)
status = 0;
}
else {
init_common(prec);
status = 0;
}
init_common(prec);
/* convert val to rval */
convert(prec);
prec->mlst = prec->val;
prec->lalm = prec->val;
prec->oraw = prec->rval;
prec->orbv = prec->rbv;
return(0);
return status;
}
static long process(mbboRecord *prec)
{
struct mbbodset *pdset = (struct mbbodset *)(prec->dset);
long status=0;
unsigned char pact=prec->pact;
struct mbbodset *pdset = (struct mbbodset *) prec->dset;
long status = 0;
int pact = prec->pact;
if( (pdset==NULL) || (pdset->write_mbbo==NULL) ) {
prec->pact=TRUE;
recGblRecordError(S_dev_missingSup,(void *)prec,"write_mbbo");
return(S_dev_missingSup);
if ((pdset == NULL) || (pdset->write_mbbo == NULL)) {
prec->pact = TRUE;
recGblRecordError(S_dev_missingSup, prec, "write_mbbo");
return S_dev_missingSup;
}
if (!prec->pact) {
if (prec->dol.type != CONSTANT && prec->omsl == menuOmslclosed_loop) {
long status;
unsigned short val;
if (!pact) {
if (prec->dol.type != CONSTANT && prec->omsl == menuOmslclosed_loop) {
long status;
unsigned short val;
status = dbGetLink(&prec->dol,DBR_USHORT, &val,0,0);
if(status==0) {
prec->val= val;
prec->udf= FALSE;
} else {
recGblSetSevr(prec,LINK_ALARM,INVALID_ALARM);
goto CONTINUE;
}
}
if(prec->udf==TRUE) {
recGblSetSevr(prec,UDF_ALARM,INVALID_ALARM);
goto CONTINUE;
}
/* convert val to rval */
convert(prec);
status = dbGetLink(&prec->dol, DBR_USHORT, &val, 0, 0);
if (status == 0) {
prec->val = val;
prec->udf = FALSE;
} else {
recGblSetSevr(prec, LINK_ALARM, INVALID_ALARM);
goto CONTINUE;
}
}
if (prec->udf==TRUE) {
recGblSetSevr(prec, UDF_ALARM, INVALID_ALARM);
goto CONTINUE;
}
/* convert val to rval */
convert(prec);
}
CONTINUE:
/* check for alarms */
checkAlarms(prec);
if (prec->nsev < INVALID_ALARM )
status=writeValue(prec); /* write the new value */
if (prec->nsev < INVALID_ALARM)
status = writeValue(prec); /* write the new value */
else {
switch (prec->ivoa) {
case (menuIvoaContinue_normally) :
status=writeValue(prec); /* write the new value */
break;
case (menuIvoaDon_t_drive_outputs) :
break;
case (menuIvoaSet_output_to_IVOV) :
if (prec->pact == FALSE){
prec->val=prec->ivov;
convert(prec);
}
status=writeValue(prec); /* write the new value */
break;
default :
status=-1;
recGblRecordError(S_db_badField,(void *)prec,
"mbbo:process Illegal IVOA field");
switch (prec->ivoa) {
case menuIvoaSet_output_to_IVOV:
if (!prec->pact) {
prec->val = prec->ivov;
convert(prec);
}
/* no break, fall through... */
case menuIvoaContinue_normally:
status = writeValue(prec); /* write the new value */
break;
case menuIvoaDon_t_drive_outputs:
break;
default :
status = -1;
recGblRecordError(S_db_badField, prec,
"mbbo::process Illegal IVOA field");
}
}
/* check if device support set pact */
if ( !pact && prec->pact ) return(0);
if (!pact && prec->pact)
return 0;
prec->pact = TRUE;
recGblGetTimeStamp(prec);
/* check event list */
monitor(prec);
/* process the forward scan link record */
recGblFwdLink(prec);
prec->pact=FALSE;
return(status);
prec->pact = FALSE;
return status;
}
static long special(DBADDR *paddr, int after)
{
mbboRecord *prec = (mbboRecord *)(paddr->precord);
int special_type = paddr->special;
int fieldIndex = dbGetFieldIndex(paddr);
mbboRecord *prec = (mbboRecord *) paddr->precord;
int special_type = paddr->special;
int fieldIndex = dbGetFieldIndex(paddr);
if(!after) return(0);
switch(special_type) {
case(SPC_MOD):
if (!after)
return 0;
switch (special_type) {
case SPC_MOD:
init_common(prec);
if (fieldIndex >= mbboRecordZRST && fieldIndex <= mbboRecordFFST)
db_post_events(prec,&prec->val,DBE_PROPERTY);
return(0);
if (fieldIndex >= mbboRecordZRST && fieldIndex <= mbboRecordFFST) {
int event = DBE_PROPERTY;
if (prec->val == fieldIndex - mbboRecordZRST)
event |= DBE_VALUE | DBE_LOG;
db_post_events(prec, &prec->val, event);
}
return 0;
default:
recGblDbaddrError(S_db_badChoice,paddr,"mbbo: special");
return(S_db_badChoice);
recGblDbaddrError(S_db_badChoice, paddr, "mbbo: special");
return S_db_badChoice;
}
}
static long cvt_dbaddr(DBADDR *paddr)
{
mbboRecord *prec=(mbboRecord *)paddr->precord;
int index;
mbboRecord *prec = (mbboRecord *) paddr->precord;
index = dbGetFieldIndex(paddr);
if(index!=mbboRecordVAL) {
recGblDbaddrError(S_db_badField,paddr,"mbbo: cvt_dbaddr");
return(0);
if (dbGetFieldIndex(paddr) != mbboRecordVAL) {
recGblDbaddrError(S_db_badField, paddr, "mbbo: cvt_dbaddr");
return 0;
}
if(!prec->sdef) {
if (!prec->sdef) {
paddr->field_type = DBF_USHORT;
paddr->dbr_field_type = DBF_USHORT;
}
return(0);
return 0;
}
static long get_enum_str(DBADDR *paddr, char *pstring)
{
mbboRecord *prec=(mbboRecord *)paddr->precord;
char *psource;
int index;
unsigned short *pfield = (unsigned short *)paddr->pfield;
unsigned short val=*pfield;
mbboRecord *prec = (mbboRecord *) paddr->precord;
unsigned short *pfield = paddr->pfield;
int val = *pfield;
index = dbGetFieldIndex(paddr);
if(index!=mbboRecordVAL) {
strcpy(pstring,"Illegal_Value");
} else if(val<= 15) {
psource = (prec->zrst);
psource += (val * sizeof(prec->zrst));
strncpy(pstring,psource,sizeof(prec->zrst));
} else {
strcpy(pstring,"Illegal Value");
if (dbGetFieldIndex(paddr) != mbboRecordVAL) {
strcpy(pstring, "Bad Field");
}
return(0);
else if (val <= 15) {
const char *pstate = prec->zrst + val * sizeof(prec->zrst);
strncpy(pstring, pstate, sizeof(prec->zrst));
}
else {
strcpy(pstring, "Illegal Value");
}
return 0;
}
static long get_enum_strs(DBADDR *paddr, struct dbr_enumStrs *pes)
{
mbboRecord *prec=(mbboRecord *)paddr->precord;
char *psource;
int i;
short no_str;
mbboRecord *prec = (mbboRecord *) paddr->precord;
const char *pstate;
int i, states = 0;
no_str=0;
memset(pes->strs,'\0',sizeof(pes->strs));
for(i=0,psource=(prec->zrst); i<16; i++, psource += sizeof(prec->zrst) ) {
strncpy(pes->strs[i],psource,sizeof(prec->zrst));
if(*psource!=0)no_str=i+1;
memset(pes->strs, '\0', sizeof(pes->strs));
pstate = prec->zrst;
for (i = 0; i < 16; i++) {
strncpy(pes->strs[i], pstate, sizeof(prec->zrst));
if (*pstate) states = i + 1;
pstate += sizeof(prec->zrst);
}
pes->no_str = no_str;
pes->no_str = states;
return(0);
return 0;
}
static long put_enum_str(DBADDR *paddr,char *pstring)
{
mbboRecord *prec=(mbboRecord *)paddr->precord;
char *pstate_name;
short i;
mbboRecord *prec = (mbboRecord *) paddr->precord;
const char *pstate;
short i;
if (prec->sdef){
pstate_name = prec->zrst;
for (i = 0; i < 16; i++){
if(strncmp(pstate_name,pstring,sizeof(prec->zrst))==0){
prec->val = i;
return(0);
}
pstate_name += sizeof(prec->zrst);
}
if (prec->sdef) {
pstate = prec->zrst;
for (i = 0; i < 16; i++) {
if (strncmp(pstate, pstring, sizeof(prec->zrst)) == 0) {
prec->val = i;
return 0;
}
pstate += sizeof(prec->zrst);
}
return(S_db_badChoice);
}
return S_db_badChoice;
}
static void checkAlarms(mbboRecord *prec)
{
unsigned short *severities;
unsigned short val=prec->val;
epicsEnum16 val = prec->val;
/* check for state alarm */
if (val > 15) {
/* Unknown state */
recGblSetSevr(prec, STATE_ALARM, prec->unsv);
}
else {
/* State has a severity field */
epicsEnum16 *severities = &prec->zrsv;
recGblSetSevr(prec, STATE_ALARM, severities[prec->val]);
}
/* check for state alarm */
/* unknown state */
if (val > 15){
recGblSetSevr(prec,STATE_ALARM,prec->unsv);
} else {
/* in a state which is an error */
severities = (unsigned short *)&(prec->zrsv);
recGblSetSevr(prec,STATE_ALARM,severities[prec->val]);
}
/* check for cos alarm */
if(val == prec->lalm) return;
if(recGblSetSevr(prec,COS_ALARM,prec->cosv)) return;
prec->lalm = val;
return;
/* check for cos alarm */
if (val == prec->lalm) return;
if (recGblSetSevr(prec,COS_ALARM,prec->cosv)) return;
prec->lalm = val;
return;
}
static void monitor(mbboRecord *prec)
{
unsigned short monitor_mask;
unsigned short monitor_mask;
monitor_mask = recGblResetAlarms(prec);
/* check for value change */
if (prec->mlst != prec->val){
/* post events for value change and archive change */
monitor_mask |= (DBE_VALUE | DBE_LOG);
/* update last value monitored */
prec->mlst = prec->val;
}
/* send out monitors connected to the value field */
if (monitor_mask){
db_post_events(prec,&prec->val,monitor_mask);
}
if(prec->oraw!=prec->rval) {
db_post_events(prec,&prec->rval,monitor_mask|DBE_VALUE);
prec->oraw = prec->rval;
}
if(prec->orbv!=prec->rbv) {
db_post_events(prec,&prec->rbv,monitor_mask|DBE_VALUE);
prec->orbv = prec->rbv;
}
return;
monitor_mask = recGblResetAlarms(prec);
/* check for value change */
if (prec->mlst != prec->val) {
/* post events for value change and archive change */
monitor_mask |= (DBE_VALUE | DBE_LOG);
/* update last value monitored */
prec->mlst = prec->val;
}
/* send out monitors connected to the value field */
if (monitor_mask) {
db_post_events(prec, &prec->val, monitor_mask);
}
if (prec->oraw != prec->rval) {
db_post_events(prec, &prec->rval, monitor_mask | DBE_VALUE);
prec->oraw = prec->rval;
}
if (prec->orbv != prec->rbv) {
db_post_events(prec, &prec->rbv, monitor_mask | DBE_VALUE);
prec->orbv = prec->rbv;
}
return;
}
static void convert(mbboRecord *prec)
{
epicsUInt32 *pvalues = &(prec->zrvl);
epicsUInt32 *pvalues = &prec->zrvl;
/* convert val to rval */
if(prec->sdef) {
/* convert val to rval */
if (prec->sdef) {
if (prec->val > 15) {
recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM);
return;
}
prec->rval = pvalues[prec->val];
}
else
prec->rval = prec->val;
if(prec->val>15) {
recGblSetSevr(prec,SOFT_ALARM,INVALID_ALARM);
return;
}
prec->rval = pvalues[prec->val];
} else prec->rval = (epicsUInt32)(prec->val);
if(prec->shft>0) prec->rval <<= prec->shft;
if (prec->shft > 0)
prec->rval <<= prec->shft;
return;
return;
}
static long writeValue(mbboRecord *prec)
{
long status;
struct mbbodset *pdset = (struct mbbodset *) (prec->dset);
long status;
struct mbbodset *pdset = (struct mbbodset *) prec->dset;
if (prec->pact == TRUE){
status=(*pdset->write_mbbo)(prec);
return(status);
}
if (prec->pact) {
status = pdset->write_mbbo(prec);
return status;
}
status=dbGetLink(&(prec->siml),DBR_USHORT, &(prec->simm),0,0);
if (status)
return(status);
status = dbGetLink(&prec->siml, DBR_USHORT, &prec->simm, 0, 0);
if (status)
return status;
if (prec->simm == menuYesNoNO){
status=(*pdset->write_mbbo)(prec);
return(status);
}
if (prec->simm == menuYesNoYES){
status=dbPutLink(&prec->siol,DBR_USHORT, &prec->val,1);
} else {
status=-1;
recGblSetSevr(prec,SOFT_ALARM,INVALID_ALARM);
return(status);
}
recGblSetSevr(prec,SIMM_ALARM,prec->sims);
if (prec->simm == menuYesNoNO) {
status = pdset->write_mbbo(prec);
return status;
}
if (prec->simm == menuYesNoYES) {
status = dbPutLink(&prec->siol, DBR_USHORT, &prec->val, 1);
}
else {
status=-1;
recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM);
return status;
}
recGblSetSevr(prec, SIMM_ALARM, prec->sims);
return(status);
return status;
}

View File

@@ -132,11 +132,15 @@ static long process(selRecord *prec)
}
#define indexof(field) selRecord##field
static long get_units(DBADDR *paddr, char *units)
{
selRecord *prec=(selRecord *)paddr->precord;
strncpy(units,prec->egu,DB_UNITS_SIZE);
if(paddr->pfldDes->field_type == DBF_DOUBLE) {
strncpy(units,prec->egu,DB_UNITS_SIZE);
}
return(0);
}
@@ -166,56 +170,68 @@ static long get_precision(DBADDR *paddr, long *precision)
static long get_graphic_double(DBADDR *paddr, struct dbr_grDouble *pgd)
{
selRecord *prec=(selRecord *)paddr->precord;
if(paddr->pfield==(void *)&prec->val
|| paddr->pfield==(void *)&prec->hihi
|| paddr->pfield==(void *)&prec->high
|| paddr->pfield==(void *)&prec->low
|| paddr->pfield==(void *)&prec->lolo){
pgd->upper_disp_limit = prec->hopr;
pgd->lower_disp_limit = prec->lopr;
return(0);
int index = dbGetFieldIndex(paddr);
switch (index) {
case indexof(VAL):
case indexof(HIHI):
case indexof(HIGH):
case indexof(LOW):
case indexof(LOLO):
case indexof(LALM):
case indexof(ALST):
case indexof(MLST):
#ifdef __GNUC__
case indexof(A) ... indexof(L):
case indexof(LA) ... indexof(LL):
break;
default:
#else
break;
default:
if((index >= indexof(A) && index <= indexof(L))
|| (index >= indexof(LA) && index <= indexof(LL)))
break;
#endif
recGblGetGraphicDouble(paddr,pgd);
return(0);
}
if(paddr->pfield>=(void *)&prec->a && paddr->pfield<=(void *)&prec->l){
pgd->upper_disp_limit = prec->hopr;
pgd->lower_disp_limit = prec->lopr;
return(0);
}
if(paddr->pfield>=(void *)&prec->la && paddr->pfield<=(void *)&prec->ll){
pgd->upper_disp_limit = prec->hopr;
pgd->lower_disp_limit = prec->lopr;
return(0);
}
recGblGetGraphicDouble(paddr,pgd);
pgd->upper_disp_limit = prec->hopr;
pgd->lower_disp_limit = prec->lopr;
return(0);
}
static long get_control_double(struct dbAddr *paddr, struct dbr_ctrlDouble *pcd)
{
selRecord *prec=(selRecord *)paddr->precord;
if(paddr->pfield==(void *)&prec->val
|| paddr->pfield==(void *)&prec->hihi
|| paddr->pfield==(void *)&prec->high
|| paddr->pfield==(void *)&prec->low
|| paddr->pfield==(void *)&prec->lolo){
pcd->upper_ctrl_limit = prec->hopr;
pcd->lower_ctrl_limit = prec->lopr;
return(0);
int index = dbGetFieldIndex(paddr);
switch (index) {
case indexof(VAL):
case indexof(HIHI):
case indexof(HIGH):
case indexof(LOW):
case indexof(LOLO):
case indexof(LALM):
case indexof(ALST):
case indexof(MLST):
#ifdef __GNUC__
case indexof(A) ... indexof(L):
case indexof(LA) ... indexof(LL):
break;
default:
#else
break;
default:
if((index >= indexof(A) && index <= indexof(L))
|| (index >= indexof(LA) && index <= indexof(LL)))
break;
#endif
recGblGetControlDouble(paddr,pcd);
return(0);
}
if(paddr->pfield>=(void *)&prec->a && paddr->pfield<=(void *)&prec->l){
pcd->upper_ctrl_limit = prec->hopr;
pcd->lower_ctrl_limit = prec->lopr;
return(0);
}
if(paddr->pfield>=(void *)&prec->la && paddr->pfield<=(void *)&prec->ll){
pcd->upper_ctrl_limit = prec->hopr;
pcd->lower_ctrl_limit = prec->lopr;
return(0);
}
recGblGetControlDouble(paddr,pcd);
pcd->upper_ctrl_limit = prec->hopr;
pcd->lower_ctrl_limit = prec->lopr;
return(0);
}
@@ -223,7 +239,7 @@ static long get_alarm_double(DBADDR *paddr, struct dbr_alDouble *pad)
{
selRecord *prec=(selRecord *)paddr->precord;
if(paddr->pfield==(void *)&prec->val ){
if(dbGetFieldIndex(paddr) == indexof(VAL)) {
pad->upper_alarm_limit = prec->hhsv ? prec->hihi : epicsNAN;
pad->upper_warning_limit = prec->hsv ? prec->high : epicsNAN;
pad->lower_warning_limit = prec->lsv ? prec->low : epicsNAN;

View File

@@ -6,7 +6,7 @@
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* $Revision-Id$
*
@@ -39,37 +39,56 @@
int seqRecDebug = 0;
/* Create RSET - Record Support Entry Table*/
static long init_record(seqRecord *prec, int pass);
static long process(seqRecord *prec);
static int processNextLink(seqRecord *prec);
static long asyncFinish(seqRecord *prec);
static void processCallback(CALLBACK *arg);
static long get_precision(dbAddr *paddr, long *pprecision);
/* Create RSET - Record Support Entry Table*/
#define report NULL
#define initialize NULL
static long init_record(seqRecord *prec, int pass);
static long process(seqRecord *prec);
#define special NULL
#define get_value NULL
#define cvt_dbaddr NULL
#define get_array_info NULL
#define put_array_info NULL
static long get_units(DBADDR *, char *);
static long get_precision(dbAddr *paddr, long *);
#define get_enum_str NULL
#define get_enum_strs NULL
#define put_enum_str NULL
static long get_graphic_double(DBADDR *, struct dbr_grDouble *);
static long get_control_double(DBADDR *, struct dbr_ctrlDouble *);
static long get_alarm_double(DBADDR *, struct dbr_alDouble *);
rset seqRSET={
RSETNUMBER,
NULL, /* report */
NULL, /* initialize */
report, /* report */
initialize, /* initialize */
init_record, /* init_record */
process, /* process */
NULL, /* special */
NULL, /* get_value */
NULL, /* cvt_dbaddr */
NULL, /* get_array_info */
NULL, /* put_array_info */
NULL, /* get_units */
special, /* special */
get_value, /* get_value */
cvt_dbaddr, /* cvt_dbaddr */
get_array_info, /* get_array_info */
put_array_info, /* put_array_info */
get_units, /* get_units */
get_precision, /* get_precision */
NULL, /* get_enum_str */
NULL, /* get_enum_strs */
NULL, /* put_enum_str */
NULL, /* get_graphic_double */
NULL, /* get_control_double */
NULL /* get_alarm_double */
get_enum_str, /* get_enum_str */
get_enum_strs, /* get_enum_strs */
put_enum_str, /* put_enum_str */
get_graphic_double, /* get_graphic_double */
get_control_double, /* get_control_double */
get_alarm_double /* get_alarm_double */
};
epicsExportAddress(rset,seqRSET);
int seqDLYprecision = 2;
epicsExportAddress(int, seqDLYprecision);
double seqDLYlimit = 100000;
epicsExportAddress(double, seqDLYlimit);
/* Total number of link-groups in a sequence record */
#define NUM_LINKS 10
#define SELN_BIT_MASK ~(0xffff << NUM_LINKS)
@@ -406,15 +425,93 @@ static void processCallback(CALLBACK *arg)
* Return the precision value from PREC
*
*****************************************************************************/
#define indexof(field) seqRecord##field
#define get_dol(prec, fieldOffset) \
&((linkDesc*)&prec->dly1)[fieldOffset>>2].dol
static long get_units(DBADDR *paddr, char *units)
{
seqRecord *prec = (seqRecord *) paddr->precord;
int fieldOffset = dbGetFieldIndex(paddr) - indexof(DLY1);
if (fieldOffset >= 0) switch (fieldOffset & 2) {
case 0: /* DLYn */
strcpy(units, "s");
break;
case 2: /* DOn */
dbGetUnits(get_dol(prec, fieldOffset),
units, DB_UNITS_SIZE);
}
return(0);
}
static long get_precision(dbAddr *paddr, long *pprecision)
{
seqRecord *prec = (seqRecord *) paddr->precord;
int fieldOffset = dbGetFieldIndex(paddr) - indexof(DLY1);
short precision;
if (fieldOffset >= 0) switch (fieldOffset & 2) {
case 0: /* DLYn */
*pprecision = seqDLYprecision;
return 0;
case 2: /* DOn */
if (dbGetPrecision(get_dol(prec, fieldOffset),
&precision) == 0) {
*pprecision = precision;
return 0;
}
}
*pprecision = prec->prec;
if(paddr->pfield < (void *)&prec->val)
return 0; /* Field is NOT in dbCommon */
recGblGetPrec(paddr, pprecision); /* Field is in dbCommon */
recGblGetPrec(paddr, pprecision);
return 0;
}
static long get_graphic_double(DBADDR *paddr, struct dbr_grDouble *pgd)
{
seqRecord *prec = (seqRecord *) paddr->precord;
int fieldOffset = dbGetFieldIndex(paddr) - indexof(DLY1);
if (fieldOffset >= 0) switch (fieldOffset & 2) {
case 0: /* DLYn */
pgd->lower_disp_limit = 0.0;
pgd->lower_disp_limit = 10.0;
return 0;
case 2: /* DOn */
dbGetGraphicLimits(get_dol(prec, fieldOffset),
&pgd->lower_disp_limit,
&pgd->upper_disp_limit);
return 0;
}
recGblGetGraphicDouble(paddr,pgd);
return 0;
}
static long get_control_double(DBADDR *paddr,struct dbr_ctrlDouble *pcd)
{
int fieldOffset = dbGetFieldIndex(paddr) - indexof(DLY1);
if (fieldOffset >= 0 && (fieldOffset & 2) == 0) { /* DLYn */
pcd->lower_ctrl_limit = 0.0;
pcd->upper_ctrl_limit = seqDLYlimit;
} else
recGblGetControlDouble(paddr,pcd);
return(0);
}
static long get_alarm_double(DBADDR *paddr, struct dbr_alDouble *pad)
{
seqRecord *prec = (seqRecord *) paddr->precord;
int fieldOffset = dbGetFieldIndex(paddr) - indexof(DLY1);
if (fieldOffset >= 0 && (fieldOffset & 2) == 2) /* DOn */
dbGetAlarmLimits(get_dol(prec, fieldOffset),
&pad->lower_alarm_limit,
&pad->lower_warning_limit,
&pad->upper_warning_limit,
&pad->upper_alarm_limit);
else
recGblGetAlarmDouble(paddr, pad);
return 0;
}

View File

@@ -231,3 +231,6 @@ recordtype(seq) {
interest(1)
}
}
variable(seqDLYprecision, int)
variable(seqDLYlimit, double)

View File

@@ -200,25 +200,30 @@ static long put_array_info(DBADDR *paddr, long nNew)
return 0;
}
#define indexof(field) subArrayRecord##field
static long get_units(DBADDR *paddr, char *units)
{
subArrayRecord *prec = (subArrayRecord *) paddr->precord;
strncpy(units, prec->egu, DB_UNITS_SIZE);
switch (dbGetFieldIndex(paddr)) {
case indexof(VAL):
if (prec->ftvl == DBF_STRING || prec->ftvl == DBF_ENUM)
break;
case indexof(HOPR):
case indexof(LOPR):
strncpy(units,prec->egu,DB_UNITS_SIZE);
}
return 0;
}
static long get_precision(DBADDR *paddr, long *precision)
{
subArrayRecord *prec = (subArrayRecord *) paddr->precord;
int fieldIndex = dbGetFieldIndex(paddr);
*precision = prec->prec;
if (fieldIndex != subArrayRecordVAL)
if (dbGetFieldIndex(paddr) != indexof(VAL))
recGblGetPrec(paddr, precision);
return 0;
}
@@ -227,25 +232,29 @@ static long get_graphic_double(DBADDR *paddr, struct dbr_grDouble *pgd)
subArrayRecord *prec = (subArrayRecord *) paddr->precord;
switch (dbGetFieldIndex(paddr)) {
case subArrayRecordVAL:
pgd->upper_disp_limit = prec->hopr;
pgd->lower_disp_limit = prec->lopr;
break;
case subArrayRecordINDX:
pgd->upper_disp_limit = prec->malm - 1;
pgd->lower_disp_limit = 0;
break;
case subArrayRecordNELM:
pgd->upper_disp_limit = prec->malm;
pgd->lower_disp_limit = 1;
break;
default:
recGblGetGraphicDouble(paddr, pgd);
case indexof(VAL):
pgd->upper_disp_limit = prec->hopr;
pgd->lower_disp_limit = prec->lopr;
break;
case indexof(INDX):
pgd->upper_disp_limit = prec->malm - 1;
pgd->lower_disp_limit = 0;
break;
case indexof(NELM):
pgd->upper_disp_limit = prec->malm;
pgd->lower_disp_limit = 0;
break;
case indexof(NORD):
pgd->upper_disp_limit = prec->malm;
pgd->lower_disp_limit = 0;
break;
case indexof(BUSY):
pgd->upper_disp_limit = 1;
pgd->lower_disp_limit = 0;
break;
default:
recGblGetGraphicDouble(paddr, pgd);
}
return 0;
}
@@ -254,25 +263,29 @@ static long get_control_double(DBADDR *paddr, struct dbr_ctrlDouble *pcd)
subArrayRecord *prec = (subArrayRecord *) paddr->precord;
switch (dbGetFieldIndex(paddr)) {
case subArrayRecordVAL:
pcd->upper_ctrl_limit = prec->hopr;
pcd->lower_ctrl_limit = prec->lopr;
break;
case subArrayRecordINDX:
pcd->upper_ctrl_limit = prec->malm - 1;
pcd->lower_ctrl_limit = 0;
break;
case subArrayRecordNELM:
pcd->upper_ctrl_limit = prec->malm;
pcd->lower_ctrl_limit = 1;
break;
default:
recGblGetControlDouble(paddr, pcd);
case indexof(VAL):
pcd->upper_ctrl_limit = prec->hopr;
pcd->lower_ctrl_limit = prec->lopr;
break;
case indexof(INDX):
pcd->upper_ctrl_limit = prec->malm - 1;
pcd->lower_ctrl_limit = 0;
break;
case indexof(NELM):
pcd->upper_ctrl_limit = prec->malm;
pcd->lower_ctrl_limit = 1;
break;
case indexof(NORD):
pcd->upper_ctrl_limit = prec->malm;
pcd->lower_ctrl_limit = 0;
break;
case indexof(BUSY):
pcd->upper_ctrl_limit = 1;
pcd->lower_ctrl_limit = 0;
break;
default:
recGblGetControlDouble(paddr, pcd);
}
return 0;
}

View File

@@ -191,54 +191,79 @@ static long special(DBADDR *paddr, int after)
return S_db_BadSub;
}
#define indexof(field) subRecord##field
static long get_linkNumber(int fieldIndex) {
if (fieldIndex >= indexof(A) && fieldIndex <= indexof(L))
return fieldIndex - indexof(A);
if (fieldIndex >= indexof(LA) && fieldIndex <= indexof(LL))
return fieldIndex - indexof(LA);
return -1;
}
static long get_units(DBADDR *paddr, char *units)
{
subRecord *prec = (subRecord *)paddr->precord;
int linkNumber;
strncpy(units, prec->egu, DB_UNITS_SIZE);
if(paddr->pfldDes->field_type == DBF_DOUBLE) {
linkNumber = get_linkNumber(dbGetFieldIndex(paddr));
if (linkNumber >= 0)
dbGetUnits(&prec->inpa + linkNumber, units, DB_UNITS_SIZE);
else
strncpy(units,prec->egu,DB_UNITS_SIZE);
}
return 0;
}
static long get_precision(DBADDR *paddr, long *precision)
static long get_precision(DBADDR *paddr, long *pprecision)
{
subRecord *prec = (subRecord *)paddr->precord;
int fieldIndex = dbGetFieldIndex(paddr);
int linkNumber;
*precision = prec->prec;
if (fieldIndex != subRecordVAL)
recGblGetPrec(paddr, precision);
*pprecision = prec->prec;
if (fieldIndex == indexof(VAL)) {
return 0;
}
linkNumber = get_linkNumber(fieldIndex);
if (linkNumber >= 0) {
short precision;
if (dbGetPrecision(&prec->inpa + linkNumber, &precision) == 0)
*pprecision = precision;
else
*pprecision = 15;
} else
recGblGetPrec(paddr, pprecision);
return 0;
}
static long get_graphic_double(DBADDR *paddr, struct dbr_grDouble *pgd)
{
subRecord *prec = (subRecord *)paddr->precord;
int fieldIndex = dbGetFieldIndex(paddr);
int linkNumber;
switch (fieldIndex) {
case subRecordVAL:
case subRecordHIHI: case subRecordHIGH:
case subRecordLOW: case subRecordLOLO:
case subRecordA: case subRecordB:
case subRecordC: case subRecordD:
case subRecordE: case subRecordF:
case subRecordG: case subRecordH:
case subRecordI: case subRecordJ:
case subRecordK: case subRecordL:
case subRecordLA: case subRecordLB:
case subRecordLC: case subRecordLD:
case subRecordLE: case subRecordLF:
case subRecordLG: case subRecordLH:
case subRecordLI: case subRecordLJ:
case subRecordLK: case subRecordLL:
pgd->upper_disp_limit = prec->hopr;
pgd->lower_disp_limit = prec->lopr;
break;
default:
recGblGetGraphicDouble(paddr, pgd);
case indexof(VAL):
case indexof(HIHI):
case indexof(HIGH):
case indexof(LOW):
case indexof(LOLO):
case indexof(LALM):
case indexof(ALST):
case indexof(MLST):
pgd->lower_disp_limit = prec->lopr;
pgd->upper_disp_limit = prec->hopr;
break;
default:
linkNumber = get_linkNumber(fieldIndex);
if (linkNumber >= 0) {
dbGetGraphicLimits(&prec->inpa + linkNumber,
&pgd->lower_disp_limit,
&pgd->upper_disp_limit);
} else
recGblGetGraphicDouble(paddr,pgd);
}
return 0;
}
@@ -246,24 +271,21 @@ static long get_graphic_double(DBADDR *paddr, struct dbr_grDouble *pgd)
static long get_control_double(DBADDR *paddr, struct dbr_ctrlDouble *pcd)
{
subRecord *prec = (subRecord *)paddr->precord;
int fieldIndex = dbGetFieldIndex(paddr);
switch (fieldIndex) {
case subRecordVAL:
case subRecordHIHI: case subRecordHIGH:
case subRecordLOW: case subRecordLOLO:
case subRecordA: case subRecordB:
case subRecordC: case subRecordD:
case subRecordE: case subRecordF:
case subRecordG: case subRecordH:
case subRecordI: case subRecordJ:
case subRecordK: case subRecordL:
pcd->upper_ctrl_limit = prec->hopr;
pcd->lower_ctrl_limit = prec->lopr;
break;
default:
recGblGetControlDouble(paddr, pcd);
switch (dbGetFieldIndex(paddr)) {
case indexof(VAL):
case indexof(HIHI):
case indexof(HIGH):
case indexof(LOW):
case indexof(LOLO):
case indexof(LALM):
case indexof(ALST):
case indexof(MLST):
pcd->lower_ctrl_limit = prec->lopr;
pcd->upper_ctrl_limit = prec->hopr;
break;
default:
recGblGetControlDouble(paddr,pcd);
}
return 0;
}
@@ -272,6 +294,7 @@ static long get_alarm_double(DBADDR *paddr, struct dbr_alDouble *pad)
{
subRecord *prec = (subRecord *)paddr->precord;
int fieldIndex = dbGetFieldIndex(paddr);
int linkNumber;
if (fieldIndex == subRecordVAL) {
pad->upper_alarm_limit = prec->hhsv ? prec->hihi : epicsNAN;
@@ -279,7 +302,15 @@ static long get_alarm_double(DBADDR *paddr, struct dbr_alDouble *pad)
pad->lower_warning_limit = prec->lsv ? prec->low : epicsNAN;
pad->lower_alarm_limit = prec->llsv ? prec->lolo : epicsNAN;
} else {
recGblGetAlarmDouble(paddr, pad);
linkNumber = get_linkNumber(fieldIndex);
if (linkNumber >= 0) {
dbGetAlarmLimits(&prec->inpa + linkNumber,
&pad->lower_alarm_limit,
&pad->lower_warning_limit,
&pad->upper_warning_limit,
&pad->upper_alarm_limit);
} else
recGblGetAlarmDouble(paddr, pad);
}
return 0;
}

View File

@@ -177,7 +177,7 @@ static long get_array_info(DBADDR *paddr, long *no_elements, long *offset)
{
waveformRecord *prec = (waveformRecord *) paddr->precord;
*no_elements = prec->nord;
*no_elements = prec->nord;
*offset = 0;
return 0;
@@ -191,28 +191,34 @@ static long put_array_info(DBADDR *paddr, long nNew)
if (prec->nord > prec->nelm)
prec->nord = prec->nelm;
db_post_events(prec, &prec->nord, DBE_VALUE | DBE_LOG);
return 0;
}
#define indexof(field) waveformRecord##field
static long get_units(DBADDR *paddr, char *units)
{
waveformRecord *prec = (waveformRecord *) paddr->precord;
strncpy(units,prec->egu,DB_UNITS_SIZE);
switch (dbGetFieldIndex(paddr)) {
case indexof(VAL):
if (prec->ftvl == DBF_STRING || prec->ftvl == DBF_ENUM)
break;
case indexof(HOPR):
case indexof(LOPR):
strncpy(units,prec->egu,DB_UNITS_SIZE);
}
return 0;
}
static long get_precision(DBADDR *paddr, long *precision)
{
waveformRecord *prec = (waveformRecord *) paddr->precord;
int fieldIndex = dbGetFieldIndex(paddr);
*precision = prec->prec;
if (fieldIndex != waveformRecordVAL)
if (dbGetFieldIndex(paddr) != indexof(VAL))
recGblGetPrec(paddr, precision);
return 0;
}
@@ -220,11 +226,22 @@ static long get_graphic_double(DBADDR *paddr, struct dbr_grDouble *pgd)
{
waveformRecord *prec = (waveformRecord *) paddr->precord;
if (dbGetFieldIndex(paddr) == waveformRecordVAL) {
pgd->upper_disp_limit = prec->hopr;
pgd->lower_disp_limit = prec->lopr;
} else
recGblGetGraphicDouble(paddr, pgd);
switch (dbGetFieldIndex(paddr)) {
case indexof(VAL):
pgd->upper_disp_limit = prec->hopr;
pgd->lower_disp_limit = prec->lopr;
break;
case indexof(BUSY):
pgd->upper_disp_limit = 1;
pgd->lower_disp_limit = 0;
break;
case indexof(NORD):
pgd->upper_disp_limit = prec->nelm;
pgd->lower_disp_limit = 0;
break;
default:
recGblGetGraphicDouble(paddr, pgd);
}
return 0;
}
@@ -232,11 +249,22 @@ static long get_control_double(DBADDR *paddr, struct dbr_ctrlDouble *pcd)
{
waveformRecord *prec = (waveformRecord *) paddr->precord;
if (dbGetFieldIndex(paddr) == waveformRecordVAL) {
pcd->upper_ctrl_limit = prec->hopr;
pcd->lower_ctrl_limit = prec->lopr;
} else
recGblGetControlDouble(paddr, pcd);
switch (dbGetFieldIndex(paddr)) {
case indexof(VAL):
pcd->upper_ctrl_limit = prec->hopr;
pcd->lower_ctrl_limit = prec->lopr;
break;
case indexof(BUSY):
pcd->upper_ctrl_limit = 1;
pcd->lower_ctrl_limit = 0;
break;
case indexof(NORD):
pcd->upper_ctrl_limit = prec->nelm;
pcd->lower_ctrl_limit = 0;
break;
default:
recGblGetControlDouble(paddr, pcd);
}
return 0;
}
@@ -300,6 +328,7 @@ static long readValue(waveformRecord *prec)
/* nord set only for db links: needed for old db_access */
if (prec->siol.type != CONSTANT) {
prec->nord = nRequest;
db_post_events(prec, &prec->nord, DBE_VALUE | DBE_LOG);
if (status == 0)
prec->udf=FALSE;
}