Add AFTC flag for bi record and fix mbbi AFTC bug (#817)

* Add AFTC feature to bi record with tests.

* Fix broken AFTC handling for mbbi record, also fix bug in COSV and LALM handling.

* Add release notes and update record docs.
This commit is contained in:
Edmund Blomley authored and GitHub committed 2026-04-01 11:53:39 -05:00
1 parent 631c8831b9
commit c9817fa591
9 files changed
+371 -17

No files matched your search

+43 -11
View File
@@ -23,6 +23,7 @@
#include "dbDefs.h"
#include "epicsPrint.h"
#include "epicsMath.h"
#include "alarm.h"
#include "callback.h"
#include "dbAccess.h"
@@ -40,6 +41,9 @@
#undef GEN_SIZE_OFFSET
#include "epicsExport.h"
/* Hysteresis for alarm filtering: 1-1/e */
#define THRESHOLD 0.6321
/* Create RSET - Record Support Entry Table*/
#define report NULL
#define initialize NULL
@@ -80,7 +84,7 @@ rset biRSET={
};
epicsExportAddress(rset,biRSET);
static void checkAlarms(biRecord *);
static void checkAlarms(biRecord *, epicsTimeStamp *);
static void monitor(biRecord *);
static long readValue(biRecord *);
@@ -119,6 +123,7 @@ static long process(struct dbCommon *pcommon)
bidset *pdset = (bidset *)(prec->dset);
long status;
unsigned char pact=prec->pact;
epicsTimeStamp timeLast;
if( (pdset==NULL) || (pdset->read_bi==NULL) ) {
prec->pact=TRUE;
@@ -126,6 +131,8 @@ static long process(struct dbCommon *pcommon)
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);
@@ -140,7 +147,7 @@ static long process(struct dbCommon *pcommon)
}
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,27 +224,52 @@ static long put_enum_str(const DBADDR *paddr, const char *pstring)
}
static void checkAlarms(biRecord *prec)
static void checkAlarms(biRecord *prec, epicsTimeStamp *timeLast)
{
epicsEnum16 asev;
unsigned short val = prec->val;
if(prec->udf == TRUE){
recGblSetSevr(prec,UDF_ALARM,prec->udfs);
return;
}
if(val>1)return;
/* check for state alarm */
if (val == 0){
recGblSetSevr(prec,STATE_ALARM,prec->zsv);
}else{
recGblSetSevr(prec,STATE_ALARM,prec->osv);
if (val == 0) {
asev = prec->zsv;
} else {
asev = prec->osv;
}
/* check for cos alarm */
unsigned short alarm = asev; /* Initialize alarm with current state severity */
double aftc = prec->aftc;
double 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);
afvl = alpha * afvl +
((afvl > 0) ? (1.0 - alpha) : (alpha - 1.0)) * alarm;
if (afvl - floor(afvl) > THRESHOLD)
afvl = -afvl;
alarm = abs((int)floor(afvl));
}
}
prec->afvl = afvl;
asev = alarm;
recGblSetSevr(prec,STATE_ALARM,asev);
/* check for cos alarm */
if(val == prec->lalm) return;
recGblSetSevr(prec,COS_ALARM,prec->cosv);
recGblSetSevr(prec,COS_ALARM,prec->cosv);
prec->lalm = val;
return;
}
+19 -2
View File
@@ -107,13 +107,20 @@ C<MAJOR>. The ZSV field holds the severity for the zero state; OSV, for
the one state. COSV causes an alarm whenever the state changes between
0 and 1 and the severity is configured as MINOR or MAJOR.
Since UNRELEASED, the alarm filter time constant (AFTC) is available for the bi record.
The AFTC field sets the time constant on a low-pass filter that delays the
reporting of limit alarms until the signal has been within the alarm range for
that number of seconds (the default AFTC value of zero retains the previous
behavior). Be sure that the bi record is processed at a reasonably fast rate
when using AFTC, so that the record can respond to changes in the input signal
within the time constant.
See L<Alarm Specification|https://docs.epics-controls.org/en/latest/process-database/EPICS_Process_Database_Concepts.html#alarm-specification>
for a complete explanation of record alarms and of the standard fields.
L<Alarm Fields|dbCommonRecord/Alarm Fields> lists other fields related
to alarms that are common to all record types.
=fields ZSV, OSV, COSV
=fields ZSV, OSV, COSV, AFTC
=head3 Run-time Parameters
These parameters are used by the run-time code for processing the binary
@@ -220,6 +227,16 @@ is not equal to VAL.
special(SPC_NOMOD)
interest(3)
}
field(AFTC, DBF_DOUBLE) {
prompt("Alarm Filter Time Constant")
promptgroup("70 - Alarm")
interest(1)
}
field(AFVL, DBF_DOUBLE) {
prompt("Alarm Filter Value")
special(SPC_NOMOD)
interest(3)
}
=head3 Simulation Mode Parameters
+3 -3
View File
@@ -336,15 +336,15 @@ static void checkAlarms(mbbiRecord *prec, epicsTimeStamp *timeLast)
alarm = abs((int)floor(afvl));
}
}
prec->afvl = afvl;
asev = alarm;
recGblSetSevr(prec, STATE_ALARM, asev);
/* Check for COS alarm */
if (val == prec->lalm ||
recGblSetSevr(prec, COS_ALARM, prec->cosv))
if (val == prec->lalm)
return;
recGblSetSevr(prec, COS_ALARM, prec->cosv);
prec->lalm = val;
}