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

@@ -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;
}