Files
epics-base/modules/database/src/std/rec/dfanoutRecord.c

342 lines
9.4 KiB
C
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*************************************************************************\
* Copyright (c) 2002 Southeastern Universities Research Association, as
* Operator of Thomas Jefferson National Accelerator Facility.
* SPDX-License-Identifier: EPICS
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* recDfanout.c - Record Support Routines for Dfanout records */
/*
* Original Author: Matt Bickley (Sometime in 1994)
*
* Modification Log:
* -----------------
* .01 1994 mhb Started with longout record to make the data fanout
* .02 May 10, 96 jt Bug Fix
* .03 11SEP2000 mrk LONG=>DOUBLE, add SELL,SELN,SELM
*/
#include <stddef.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include "dbDefs.h"
#include "epicsPrint.h"
#include "epicsMath.h"
#include "alarm.h"
#include "dbAccess.h"
#include "dbEvent.h"
#include "dbFldTypes.h"
#include "devSup.h"
#include "errMdef.h"
#include "recSup.h"
#include "recGbl.h"
#include "special.h"
#include "menuOmsl.h"
#include "menuIvoa.h"
#define GEN_SIZE_OFFSET
#include "dfanoutRecord.h"
#undef GEN_SIZE_OFFSET
#include "epicsExport.h"
/* Create RSET - Record Support Entry Table*/
#define report NULL
#define initialize NULL
static long init_record(struct dbCommon *, int);
static long process(struct dbCommon *);
#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(const DBADDR *, 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 dfanoutRSET={
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,dfanoutRSET);
static void checkAlarms(dfanoutRecord *);
static void monitor(dfanoutRecord *);
static void push_values(dfanoutRecord *);
#define OUT_ARG_MAX 16
static long init_record(struct dbCommon *pcommon, int pass)
{
struct dfanoutRecord *prec = (struct dfanoutRecord *)pcommon;
if (pass==0)
return 0;
recGblInitConstantLink(&prec->sell, DBF_USHORT, &prec->seln);
/* get the initial value dol is a constant*/
if (recGblInitConstantLink(&prec->dol, DBF_DOUBLE, &prec->val))
prec->udf = isnan(prec->val);
return 0;
}
static long process(struct dbCommon *pcommon)
{
struct dfanoutRecord *prec = (struct dfanoutRecord *)pcommon;
long status=0;
if (!prec->pact &&
!dbLinkIsConstant(&prec->dol) &&
prec->omsl == menuOmslclosed_loop) {
status = dbGetLink(&prec->dol, DBR_DOUBLE, &prec->val, 0, 0);
if (!dbLinkIsConstant(&prec->dol) && !status)
prec->udf = isnan(prec->val);
}
prec->pact = TRUE;
recGblGetTimeStamp(prec);
/* Push out the data to all the forward links */
dbGetLink(&(prec->sell),DBR_USHORT,&(prec->seln),0,0);
checkAlarms(prec);
if (prec->nsev < INVALID_ALARM)
push_values(prec);
else {
switch (prec->ivoa) {
case menuIvoaContinue_normally:
push_values(prec);
break;
case menuIvoaDon_t_drive_outputs:
break;
case menuIvoaSet_output_to_IVOV:
prec->val=prec->ivov;
push_values(prec);
break;
default :
status=-1;
recGblRecordError(S_db_badField,(void *)prec,
"dfanout:process Illegal IVOA field");
}
}
monitor(prec);
recGblFwdLink(prec);
prec->pact=FALSE;
return(status);
}
#define indexof(field) dfanoutRecord##field
static long get_units(DBADDR *paddr,char *units)
{
dfanoutRecord *prec=(dfanoutRecord *)paddr->precord;
if(paddr->pfldDes->field_type == DBF_DOUBLE) {
strncpy(units,prec->egu,DB_UNITS_SIZE);
}
return(0);
}
static long get_precision(const DBADDR *paddr,long *precision)
{
dfanoutRecord *prec=(dfanoutRecord *)paddr->precord;
*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)
{
dfanoutRecord *prec=(dfanoutRecord *)paddr->precord;
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;
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;
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;
pad->lower_alarm_limit = prec->llsv ? prec->lolo : epicsNAN;
} else recGblGetAlarmDouble(paddr,pad);
return(0);
}
static void checkAlarms(dfanoutRecord *prec)
{
double val, hyst, lalm;
double alev;
epicsEnum16 asev;
if (prec->udf) {
recGblSetSevr(prec, UDF_ALARM, prec->udfs);
return;
}
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;
}
/* 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;
}
/* 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(dfanoutRecord *prec)
{
unsigned monitor_mask = recGblResetAlarms(prec);
/* check for value change */
recGblCheckDeadband(&prec->mlst, prec->val, prec->mdel, &monitor_mask, DBE_VALUE);
/* check for archive change */
recGblCheckDeadband(&prec->alst, prec->val, prec->adel, &monitor_mask, DBE_ARCHIVE);
/* send out monitors connected to the value field */
if (monitor_mask){
db_post_events(prec,&prec->val,monitor_mask);
}
return;
}
static void push_values(dfanoutRecord *prec)
{
struct link *plink; /* structure of the link field */
int i;
long status;
epicsUInt16 state;
switch (prec->selm){
case (dfanoutSELM_All):
for(i=0, plink=&(prec->outa); i<OUT_ARG_MAX; i++, plink++) {
status=dbPutLink(plink,DBR_DOUBLE,&(prec->val),1);
if(status) recGblSetSevr(prec,LINK_ALARM,MAJOR_ALARM);
}
break;
case (dfanoutSELM_Specified):
if(prec->seln>OUT_ARG_MAX) {
recGblSetSevr(prec,SOFT_ALARM,INVALID_ALARM);
break;
}
if(prec->seln==0) break;
plink=&(prec->outa);
plink += (prec->seln -1);
status=dbPutLink(plink,DBR_DOUBLE,&(prec->val),1);
if(status) recGblSetSevr(prec,LINK_ALARM,MAJOR_ALARM);
break;
case (dfanoutSELM_Mask):
if(prec->seln==0) break;
for(i=0, plink=&(prec->outa), state=prec->seln;
i<OUT_ARG_MAX;
i++, plink++, state>>=1) {
if(state&1) {
status=dbPutLink(plink,DBR_DOUBLE,&(prec->val),1);
if(status) recGblSetSevr(prec,LINK_ALARM,MAJOR_ALARM);
}
}
break;
default:
recGblSetSevr(prec,SOFT_ALARM,INVALID_ALARM);
}
}