diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html index 9f0c79849..8d47d9b2a 100644 --- a/documentation/RELEASE_NOTES.html +++ b/documentation/RELEASE_NOTES.html @@ -15,6 +15,40 @@ EPICS Base 3.15.0.x releases are not intended for use in production systems.

Changes between 3.14.x and 3.15.0.x

+

Alarm filtering added to input record types

+ +

The record types ai, calc, longin and mbbi have a new alarm filter added to +them. This provides a low-pass filter that can be used to delay the reporting of +alarms caused by the input level passing the HIGH, HIHI, LOW or LOLO values. The +filter is controlled with a new AFTC field that sets the filter's time constant. +The default value for this field is zero, which keeps the record's original +alarm behaviour.

+ +

The record must be scanned often enough for the filtering action to work +effectively and the alarm severity can only change when the record is processed, +but that processing does not have to be regular; the filter uses the time since +the record last processed in its calculation. Setting AFTC to a positive number +of seconds will delay the record going into or out of a minor alarm severity or +from minor to major severity until the input signal has been in that range for +that number of seconds.

+ +

Post events on Waveform record's NORD field

+ +

When the record type or soft device support modify the NORD field of a +waveform record they now also post a DBE_VALUE and DBE_LOG event, signalling the +array length change to any clients monitoring the NORD field. Input device +support routines should be modified to do this as well.

+ +

Attributes of Non-VAL Fields

+ +

Non-VAL fields now report meaningful information for precision, units, +graphic limits, control limits, and alarm limits instead of simply using +PREC, EGU, HOPR, LOPR, DRVL, DRVH, HIHI, HIGH, LOW, and LOLO. All delay +fields have a default precision of 2 digits, units "s" and control limits +of 0 to 100,000 seconds (these precision and limit values can be changed +for each record type as a whole at runtime by updating a registered global +variable). Input fields like A-L of the calc record read their metadata +from the corresponding INPn link if possible.

epicsStdioRedirect.h merged into epicsStdio.h

The definitions from the header file epicsStdioRedirect.h have been moved diff --git a/src/std/dev/devWfSoft.c b/src/std/dev/devWfSoft.c index 92bb3c566..ea9280051 100644 --- a/src/std/dev/devWfSoft.c +++ b/src/std/dev/devWfSoft.c @@ -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; diff --git a/src/std/rec/aSubRecord.c b/src/std/rec/aSubRecord.c index 24447cee3..1c033b3ba 100644 --- a/src/std/rec/aSubRecord.c +++ b/src/std/rec/aSubRecord.c @@ -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) { diff --git a/src/std/rec/aaiRecord.c b/src/std/rec/aaiRecord.c index 5c88791c4..428916de9 100644 --- a/src/std/rec/aaiRecord.c +++ b/src/std/rec/aaiRecord.c @@ -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; } diff --git a/src/std/rec/aaoRecord.c b/src/std/rec/aaoRecord.c index 695f8e1b1..46c837310 100644 --- a/src/std/rec/aaoRecord.c +++ b/src/std/rec/aaoRecord.c @@ -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; } diff --git a/src/std/rec/aiRecord.c b/src/std/rec/aiRecord.c index 343d62126..94f665af7 100644 --- a/src/std/rec/aiRecord.c +++ b/src/std/rec/aiRecord.c @@ -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) diff --git a/src/std/rec/aiRecord.dbd b/src/std/rec/aiRecord.dbd index a7518ab73..52fd4b05b 100644 --- a/src/std/rec/aiRecord.dbd +++ b/src/std/rec/aiRecord.dbd @@ -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) diff --git a/src/std/rec/aoRecord.c b/src/std/rec/aoRecord.c index 5f8436ab2..5b77b607e 100644 --- a/src/std/rec/aoRecord.c +++ b/src/std/rec/aoRecord.c @@ -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; diff --git a/src/std/rec/boRecord.c b/src/std/rec/boRecord.c index 5248bd661..ed6364734 100644 --- a/src/std/rec/boRecord.c +++ b/src/std/rec/boRecord.c @@ -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)); diff --git a/src/std/rec/boRecord.dbd b/src/std/rec/boRecord.dbd index adc6704ad..4bc44c2fd 100644 --- a/src/std/rec/boRecord.dbd +++ b/src/std/rec/boRecord.dbd @@ -149,3 +149,6 @@ recordtype(bo) { interest(2) } } + +variable(boHIGHprecision, int) +variable(boHIGHlimit, double) diff --git a/src/std/rec/calcRecord.c b/src/std/rec/calcRecord.c index 722ce0698..acbc85668 100644 --- a/src/std/rec/calcRecord.c +++ b/src/std/rec/calcRecord.c @@ -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; } diff --git a/src/std/rec/calcRecord.dbd b/src/std/rec/calcRecord.dbd index 0248f34cd..b4d4cc99b 100644 --- a/src/std/rec/calcRecord.dbd +++ b/src/std/rec/calcRecord.dbd @@ -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) diff --git a/src/std/rec/calcoutRecord.c b/src/std/rec/calcoutRecord.c index 9e18c0996..3fe97732e 100644 --- a/src/std/rec/calcoutRecord.c +++ b/src/std/rec/calcoutRecord.c @@ -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; } diff --git a/src/std/rec/calcoutRecord.dbd b/src/std/rec/calcoutRecord.dbd index bc916c961..f58ac242f 100644 --- a/src/std/rec/calcoutRecord.dbd +++ b/src/std/rec/calcoutRecord.dbd @@ -513,3 +513,6 @@ recordtype(calcout) { extra("char orpc[INFIX_TO_POSTFIX_SIZE(80)]") } } + +variable(calcoutODLYprecision, int) +variable(calcoutODLYlimit, double) diff --git a/src/std/rec/compressRecord.c b/src/std/rec/compressRecord.c index 2879852d8..46966dba4 100644 --- a/src/std/rec/compressRecord.c +++ b/src/std/rec/compressRecord.c @@ -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); } diff --git a/src/std/rec/dfanoutRecord.c b/src/std/rec/dfanoutRecord.c index 672c1cccd..4628ab7a6 100644 --- a/src/std/rec/dfanoutRecord.c +++ b/src/std/rec/dfanoutRecord.c @@ -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; diff --git a/src/std/rec/histogramRecord.c b/src/std/rec/histogramRecord.c index e78be26c5..cb086d523 100644 --- a/src/std/rec/histogramRecord.c +++ b/src/std/rec/histogramRecord.c @@ -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); } diff --git a/src/std/rec/histogramRecord.dbd b/src/std/rec/histogramRecord.dbd index 6def0f41a..dc0d2df31 100644 --- a/src/std/rec/histogramRecord.dbd +++ b/src/std/rec/histogramRecord.dbd @@ -135,3 +135,5 @@ recordtype(histogram) { interest(1) } } + +variable(histogramSDELprecision, int) diff --git a/src/std/rec/longinRecord.c b/src/std/rec/longinRecord.c index 011b6c882..a625b56e4 100644 --- a/src/std/rec/longinRecord.c +++ b/src/std/rec/longinRecord.c @@ -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 diff --git a/src/std/rec/longinRecord.dbd b/src/std/rec/longinRecord.dbd index 4bd734018..ef9506e3d 100644 --- a/src/std/rec/longinRecord.dbd +++ b/src/std/rec/longinRecord.dbd @@ -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) diff --git a/src/std/rec/longoutRecord.c b/src/std/rec/longoutRecord.c index d7d53d44f..ba1fa34b9 100644 --- a/src/std/rec/longoutRecord.c +++ b/src/std/rec/longoutRecord.c @@ -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; diff --git a/src/std/rec/mbbiRecord.c b/src/std/rec/mbbiRecord.c index 6a1ef943d..3bdffe12e 100644 --- a/src/std/rec/mbbiRecord.c +++ b/src/std/rec/mbbiRecord.c @@ -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; } diff --git a/src/std/rec/mbbiRecord.dbd b/src/std/rec/mbbiRecord.dbd index b0c33ad9e..bbb9fd17a 100644 --- a/src/std/rec/mbbiRecord.dbd +++ b/src/std/rec/mbbiRecord.dbd @@ -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) diff --git a/src/std/rec/mbboRecord.c b/src/std/rec/mbboRecord.c index 5df97ff07..c2fc5e84c 100644 --- a/src/std/rec/mbboRecord.c +++ b/src/std/rec/mbboRecord.c @@ -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; inobt; 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; } diff --git a/src/std/rec/selRecord.c b/src/std/rec/selRecord.c index 6bc43c227..514b42d82 100644 --- a/src/std/rec/selRecord.c +++ b/src/std/rec/selRecord.c @@ -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; diff --git a/src/std/rec/seqRecord.c b/src/std/rec/seqRecord.c index 5b43d34e8..77959725c 100644 --- a/src/std/rec/seqRecord.c +++ b/src/std/rec/seqRecord.c @@ -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; +} + diff --git a/src/std/rec/seqRecord.dbd b/src/std/rec/seqRecord.dbd index 518310220..ae183d2db 100644 --- a/src/std/rec/seqRecord.dbd +++ b/src/std/rec/seqRecord.dbd @@ -231,3 +231,6 @@ recordtype(seq) { interest(1) } } + +variable(seqDLYprecision, int) +variable(seqDLYlimit, double) diff --git a/src/std/rec/subArrayRecord.c b/src/std/rec/subArrayRecord.c index dc18a6ad3..f40f5ac0c 100644 --- a/src/std/rec/subArrayRecord.c +++ b/src/std/rec/subArrayRecord.c @@ -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; } diff --git a/src/std/rec/subRecord.c b/src/std/rec/subRecord.c index c07de5692..3b7632ecc 100644 --- a/src/std/rec/subRecord.c +++ b/src/std/rec/subRecord.c @@ -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; } diff --git a/src/std/rec/waveformRecord.c b/src/std/rec/waveformRecord.c index 6cd7a05b4..006de248d 100644 --- a/src/std/rec/waveformRecord.c +++ b/src/std/rec/waveformRecord.c @@ -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; }