diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..19c9068 --- /dev/null +++ b/Makefile @@ -0,0 +1,31 @@ +# Makefile at top of application tree +TOP = . +include $(TOP)/configure/CONFIG + +# Directories to build, any order +DIRS += configure +DIRS += $(wildcard *Sup) +DIRS += $(wildcard *App) +DIRS += $(wildcard *Top) +DIRS += $(wildcard iocBoot) + +# The build order is controlled by these dependency rules: + +# All dirs except configure depend on configure +$(foreach dir, $(filter-out configure, $(DIRS)), \ + $(eval $(dir)_DEPEND_DIRS += configure)) + +# Any *App dirs depend on all *Sup dirs +$(foreach dir, $(filter %App, $(DIRS)), \ + $(eval $(dir)_DEPEND_DIRS += $(filter %Sup, $(DIRS)))) + +# Any *Top dirs depend on all *Sup and *App dirs +$(foreach dir, $(filter %Top, $(DIRS)), \ + $(eval $(dir)_DEPEND_DIRS += $(filter %Sup %App, $(DIRS)))) + +# iocBoot depends on all *App dirs +iocBoot_DEPEND_DIRS += $(filter %App,$(DIRS)) + +# Add any additional dependency rules here: + +include $(TOP)/configure/RULES_TOP diff --git a/configure/CONFIG b/configure/CONFIG new file mode 100644 index 0000000..c1a4703 --- /dev/null +++ b/configure/CONFIG @@ -0,0 +1,29 @@ +# CONFIG - Load build configuration data +# +# Do not make changes to this file! + +# Allow user to override where the build rules come from +RULES = $(EPICS_BASE) + +# RELEASE files point to other application tops +include $(TOP)/configure/RELEASE +-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).Common +ifdef T_A +-include $(TOP)/configure/RELEASE.Common.$(T_A) +-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).$(T_A) +endif + +CONFIG = $(RULES)/configure +include $(CONFIG)/CONFIG + +# Override the Base definition: +INSTALL_LOCATION = $(TOP) + +# CONFIG_SITE files contain other build configuration settings +include $(TOP)/configure/CONFIG_SITE +-include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).Common +ifdef T_A + -include $(TOP)/configure/CONFIG_SITE.Common.$(T_A) + -include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A) +endif + diff --git a/configure/CONFIG_SITE b/configure/CONFIG_SITE new file mode 100644 index 0000000..212485e --- /dev/null +++ b/configure/CONFIG_SITE @@ -0,0 +1,43 @@ +# CONFIG_SITE + +# Make any application-specific changes to the EPICS build +# configuration variables in this file. +# +# Host/target specific settings can be specified in files named +# CONFIG_SITE.$(EPICS_HOST_ARCH).Common +# CONFIG_SITE.Common.$(T_A) +# CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A) + +# CHECK_RELEASE controls the consistency checking of the support +# applications pointed to by the RELEASE* files. +# Normally CHECK_RELEASE should be set to YES. +# Set CHECK_RELEASE to NO to disable checking completely. +# Set CHECK_RELEASE to WARN to perform consistency checking but +# continue building even if conflicts are found. +CHECK_RELEASE = YES + +# Set this when you only want to compile this application +# for a subset of the cross-compiled target architectures +# that Base is built for. +#CROSS_COMPILER_TARGET_ARCHS = vxWorks-ppc32 + +# To install files into a location other than $(TOP) define +# INSTALL_LOCATION here. +#INSTALL_LOCATION= + +# Set this when the IOC and build host use different paths +# to the install location. This may be needed to boot from +# a Microsoft FTP server say, or on some NFS configurations. +#IOCS_APPL_TOP = + +# For application debugging purposes, override the HOST_OPT and/ +# or CROSS_OPT settings from base/configure/CONFIG_SITE +#HOST_OPT = NO +#CROSS_OPT = NO + +# These allow developers to override the CONFIG_SITE variable +# settings without having to modify the configure/CONFIG_SITE +# file itself. +-include $(TOP)/../CONFIG_SITE.local +-include $(TOP)/configure/CONFIG_SITE.local + diff --git a/configure/Makefile b/configure/Makefile new file mode 100644 index 0000000..9254309 --- /dev/null +++ b/configure/Makefile @@ -0,0 +1,8 @@ +TOP=.. + +include $(TOP)/configure/CONFIG + +TARGETS = $(CONFIG_TARGETS) +CONFIGS += $(subst ../,,$(wildcard $(CONFIG_INSTALLS))) + +include $(TOP)/configure/RULES diff --git a/configure/RELEASE b/configure/RELEASE new file mode 100644 index 0000000..a1f52b1 --- /dev/null +++ b/configure/RELEASE @@ -0,0 +1,43 @@ +# RELEASE - Location of external support modules +# +# IF YOU MAKE ANY CHANGES to this file you must subsequently +# do a "gnumake rebuild" in this application's top level +# directory. +# +# The build process does not check dependencies against files +# that are outside this application, thus you should do a +# "gnumake rebuild" in the top level directory after EPICS_BASE +# or any other external module pointed to below is rebuilt. +# +# Host- or target-specific settings can be given in files named +# RELEASE.$(EPICS_HOST_ARCH).Common +# RELEASE.Common.$(T_A) +# RELEASE.$(EPICS_HOST_ARCH).$(T_A) +# +# This file is parsed by both GNUmake and an EPICS Perl script, +# so it can ONLY contain definititions of paths to other support +# modules, variable definitions that are used in module paths, +# and include statements that pull in other RELEASE files. +# Variables may be used before their values have been set. +# Build variables that are NOT used in paths should be set in +# the CONFIG_SITE file. + +# Variables and paths to dependent modules: +#MODULES = /path/to/modules +#MYMODULE = $(MODULES)/my-module + +# If using the sequencer, point SNCSEQ at its top directory: +#SNCSEQ = $(MODULES)/seq-ver + +# EPICS_BASE should appear last so earlier modules can override stuff: +EPICS_BASE = /home/ralph/work/EPICS/V3/base-3.15.6 + +# Set RULES here if you want to use build rules from somewhere +# other than EPICS_BASE: +#RULES = $(MODULES)/build-rules + +# These allow developers to override the RELEASE variable settings +# without having to modify the configure/RELEASE file itself. +-include $(TOP)/../RELEASE.local +-include $(TOP)/configure/RELEASE.local + diff --git a/configure/RULES b/configure/RULES new file mode 100644 index 0000000..6d56e14 --- /dev/null +++ b/configure/RULES @@ -0,0 +1,6 @@ +# RULES + +include $(CONFIG)/RULES + +# Library should be rebuilt because LIBOBJS may have changed. +$(LIBNAME): ../Makefile diff --git a/configure/RULES.ioc b/configure/RULES.ioc new file mode 100644 index 0000000..901987c --- /dev/null +++ b/configure/RULES.ioc @@ -0,0 +1,2 @@ +#RULES.ioc +include $(CONFIG)/RULES.ioc diff --git a/configure/RULES_DIRS b/configure/RULES_DIRS new file mode 100644 index 0000000..3ba269d --- /dev/null +++ b/configure/RULES_DIRS @@ -0,0 +1,2 @@ +#RULES_DIRS +include $(CONFIG)/RULES_DIRS diff --git a/configure/RULES_TOP b/configure/RULES_TOP new file mode 100644 index 0000000..d09d668 --- /dev/null +++ b/configure/RULES_TOP @@ -0,0 +1,3 @@ +#RULES_TOP +include $(CONFIG)/RULES_TOP + diff --git a/exampleApp/Db/Makefile b/exampleApp/Db/Makefile new file mode 100644 index 0000000..667845e --- /dev/null +++ b/exampleApp/Db/Makefile @@ -0,0 +1,18 @@ +TOP=../.. +include $(TOP)/configure/CONFIG +#---------------------------------------- +# ADD MACRO DEFINITIONS BELOW HERE + +# Install databases, templates & substitutions like this +DB += dbExample1.db +DB += dbExample2.db +DB += dbSubExample.db +DB += user.substitutions + +# If .db template is not named *.template add +# _TEMPLATE = + +include $(TOP)/configure/RULES +#---------------------------------------- +# ADD EXTRA GNUMAKE RULES BELOW HERE + diff --git a/exampleApp/Db/dbExample1.db b/exampleApp/Db/dbExample1.db new file mode 100644 index 0000000..4f16ada --- /dev/null +++ b/exampleApp/Db/dbExample1.db @@ -0,0 +1,62 @@ +record(ai, "$(user):aiExample") +{ + field(DESC, "Analog input") + field(INP, "$(user):calcExample.VAL NPP NMS") + field(EGUF, "10") + field(EGU, "Counts") + field(HOPR, "10") + field(LOPR, "0") + field(HIHI, "8") + field(HIGH, "6") + field(LOW, "4") + field(LOLO, "2") + field(HHSV, "MAJOR") + field(HSV, "MINOR") + field(LSV, "MINOR") + field(LLSV, "MAJOR") +} +record(calc, "$(user):calcExample") +{ + field(DESC, "Counter") + field(SCAN,"1 second") + field(FLNK, "$(user):aiExample") + field(CALC, "(A/dbd +DBD += xxxSupport.dbd + +# Build an IOC support library +LIBRARY_IOC += exampleSupport + +# Compile and add the code to the support library +exampleSupport_SRCS += xxxRecord.c +exampleSupport_SRCS += devXxxSoft.c + +# Link locally-provided code into the support library, +# rather than directly into the IOC application. +# This is required for Windows DLL builds. +exampleSupport_SRCS += dbSubExample.c +exampleSupport_SRCS += exampleHello.c +exampleSupport_SRCS += initTrace.c + +exampleSupport_LIBS += $(EPICS_BASE_IOC_LIBS) + + +# Build the IOC application +PROD_IOC = example + +# example.dbd will be created and installed +DBD += example.dbd + +# example.dbd will include these files: +example_DBD += base.dbd +example_DBD += xxxSupport.dbd +example_DBD += dbSubExample.dbd +example_DBD += exampleHello.dbd +example_DBD += initTrace.dbd + +# example_registerRecordDeviceDriver.cpp derives from example.dbd +example_SRCS += example_registerRecordDeviceDriver.cpp + +# Build the main IOC entry point where needed +example_SRCS_DEFAULT += exampleMain.cpp +example_SRCS_vxWorks += -nil- + +# Link in the code from our support library +example_LIBS += exampleSupport + +# To build SNL programs, SNCSEQ must be defined +# in the /configure/RELEASE file +ifneq ($(SNCSEQ),) + # Build sncExample into exampleSupport + sncExample_SNCFLAGS += +r + example_DBD += sncExample.dbd + # A .stt sequence program is *not* pre-processed: + exampleSupport_SRCS += sncExample.stt + exampleSupport_LIBS += seq pv + example_LIBS += seq pv + + # Build sncProgram as a standalone program + PROD_HOST += sncProgram + sncProgram_SNCFLAGS += +m + # A .st sequence program *is* pre-processed: + sncProgram_SRCS += sncProgram.st + sncProgram_LIBS += seq pv + sncProgram_LIBS += $(EPICS_BASE_HOST_LIBS) +endif + +# Finally link IOC to the EPICS Base libraries +example_LIBS += $(EPICS_BASE_IOC_LIBS) + +include $(TOP)/configure/RULES +#---------------------------------------- +# ADD EXTRA GNUMAKE RULES BELOW HERE + diff --git a/exampleApp/src/dbSubExample.c b/exampleApp/src/dbSubExample.c new file mode 100644 index 0000000..1cc748b --- /dev/null +++ b/exampleApp/src/dbSubExample.c @@ -0,0 +1,49 @@ +#include + +#include +#include +#include +#include +#include + +int mySubDebug; + +static long mySubInit(subRecord *precord) +{ + if (mySubDebug) + printf("Record %s called mySubInit(%p)\n", + precord->name, (void*) precord); + return 0; +} + +static long mySubProcess(subRecord *precord) +{ + if (mySubDebug) + printf("Record %s called mySubProcess(%p)\n", + precord->name, (void*) precord); + return 0; +} + +static long myAsubInit(aSubRecord *precord) +{ + if (mySubDebug) + printf("Record %s called myAsubInit(%p)\n", + precord->name, (void*) precord); + return 0; +} + +static long myAsubProcess(aSubRecord *precord) +{ + if (mySubDebug) + printf("Record %s called myAsubProcess(%p)\n", + precord->name, (void*) precord); + return 0; +} + +/* Register these symbols for use by IOC code: */ + +epicsExportAddress(int, mySubDebug); +epicsRegisterFunction(mySubInit); +epicsRegisterFunction(mySubProcess); +epicsRegisterFunction(myAsubInit); +epicsRegisterFunction(myAsubProcess); diff --git a/exampleApp/src/dbSubExample.dbd b/exampleApp/src/dbSubExample.dbd new file mode 100644 index 0000000..5f6e40a --- /dev/null +++ b/exampleApp/src/dbSubExample.dbd @@ -0,0 +1,5 @@ +variable(mySubDebug) +function(mySubInit) +function(mySubProcess) +function(myAsubInit) +function(myAsubProcess) diff --git a/exampleApp/src/devXxxSoft.c b/exampleApp/src/devXxxSoft.c new file mode 100644 index 0000000..0507fdf --- /dev/null +++ b/exampleApp/src/devXxxSoft.c @@ -0,0 +1,58 @@ +/* devXxxSoft.c */ +/* Example device support module */ + +#include +#include +#include +#include + +#include "alarm.h" +#include "cvtTable.h" +#include "dbDefs.h" +#include "dbAccess.h" +#include "recGbl.h" +#include "recSup.h" +#include "devSup.h" +#include "link.h" +#include "xxxRecord.h" +#include "epicsExport.h" + +/*Create the dset for devXxxSoft */ +static long init_record(); +static long read_xxx(); +struct { + long number; + DEVSUPFUN report; + DEVSUPFUN init; + DEVSUPFUN init_record; + DEVSUPFUN get_ioint_info; + DEVSUPFUN read_xxx; +}devXxxSoft={ + 5, + NULL, + NULL, + init_record, + NULL, + read_xxx, +}; +epicsExportAddress(dset,devXxxSoft); + + +static long init_record(pxxx) + struct xxxRecord *pxxx; +{ + if(recGblInitConstantLink(&pxxx->inp,DBF_DOUBLE,&pxxx->val)) + pxxx->udf = FALSE; + return(0); +} + +static long read_xxx(pxxx) + struct xxxRecord *pxxx; +{ + long status; + + status = dbGetLink(&(pxxx->inp),DBF_DOUBLE, &(pxxx->val),0,0); + /*If return was succesful then set undefined false*/ + if(!status) pxxx->udf = FALSE; + return(0); +} diff --git a/exampleApp/src/exampleHello.c b/exampleApp/src/exampleHello.c new file mode 100644 index 0000000..a51327e --- /dev/null +++ b/exampleApp/src/exampleHello.c @@ -0,0 +1,31 @@ +/* Example showing how to register a new command with iocsh */ + +#include + +#include +#include + +/* This is the command, which the vxWorks shell will call directly */ +void hello(const char *name) { + if (name) { + printf("Hello %s, from example\n", name); + } else { + puts("Hello from example"); + } +} + +/* Information needed by iocsh */ +static const iocshArg helloArg0 = {"name", iocshArgString}; +static const iocshArg *helloArgs[] = {&helloArg0}; +static const iocshFuncDef helloFuncDef = {"hello", 1, helloArgs}; + +/* Wrapper called by iocsh, selects the argument types that hello needs */ +static void helloCallFunc(const iocshArgBuf *args) { + hello(args[0].sval); +} + +/* Registration routine, runs at startup */ +static void helloRegister(void) { + iocshRegister(&helloFuncDef, helloCallFunc); +} +epicsExportRegistrar(helloRegister); diff --git a/exampleApp/src/exampleHello.dbd b/exampleApp/src/exampleHello.dbd new file mode 100644 index 0000000..64eb038 --- /dev/null +++ b/exampleApp/src/exampleHello.dbd @@ -0,0 +1 @@ +registrar(helloRegister) diff --git a/exampleApp/src/exampleMain.cpp b/exampleApp/src/exampleMain.cpp new file mode 100644 index 0000000..5dd4c0a --- /dev/null +++ b/exampleApp/src/exampleMain.cpp @@ -0,0 +1,23 @@ +/* exampleMain.cpp */ +/* Author: Marty Kraimer Date: 17MAR2000 */ + +#include +#include +#include +#include +#include + +#include "epicsExit.h" +#include "epicsThread.h" +#include "iocsh.h" + +int main(int argc,char *argv[]) +{ + if(argc>=2) { + iocsh(argv[1]); + epicsThreadSleep(.2); + } + iocsh(NULL); + epicsExit(0); + return(0); +} diff --git a/exampleApp/src/initTrace.c b/exampleApp/src/initTrace.c new file mode 100644 index 0000000..50bc8e8 --- /dev/null +++ b/exampleApp/src/initTrace.c @@ -0,0 +1,39 @@ +/* initTrace.c */ + +/* + * An initHook routine to trace the iocInit() process. + * Prints out the name of each state as it is reached. + */ + +#include + +#include "initHooks.h" +#include "epicsExport.h" +#include "iocsh.h" + + +static void trace(initHookState state) { + printf("iocInit: Reached %s\n", initHookName(state)); +} + +int traceIocInit(void) { + static int done = 0; + if (done) + return -1; + done = 1; + + initHookRegister(trace); + puts("iocInit will be traced"); + return 0; +} + + +static const iocshFuncDef traceInitFuncDef = {"traceIocInit", 0, NULL}; +static void traceInitFunc(const iocshArgBuf *args) { + traceIocInit(); +} + +static void initTraceRegister(void) { + iocshRegister(&traceInitFuncDef, traceInitFunc); +} +epicsExportRegistrar(initTraceRegister); diff --git a/exampleApp/src/initTrace.dbd b/exampleApp/src/initTrace.dbd new file mode 100644 index 0000000..8083c0a --- /dev/null +++ b/exampleApp/src/initTrace.dbd @@ -0,0 +1 @@ +registrar(initTraceRegister) diff --git a/exampleApp/src/sncExample.dbd b/exampleApp/src/sncExample.dbd new file mode 100644 index 0000000..df61066 --- /dev/null +++ b/exampleApp/src/sncExample.dbd @@ -0,0 +1 @@ +registrar(sncExampleRegistrar) diff --git a/exampleApp/src/sncExample.stt b/exampleApp/src/sncExample.stt new file mode 100644 index 0000000..235f3f4 --- /dev/null +++ b/exampleApp/src/sncExample.stt @@ -0,0 +1,22 @@ +program sncExample +double v; +assign v to "{user}:aiExample"; +monitor v; + +ss ss1 { + state init { + when (delay(10)) { + printf("sncExample: Startup delay over\n"); + } state low + } + state low { + when (v > 5.0) { + printf("sncExample: Changing to high\n"); + } state high + } + state high { + when (v <= 5.0) { + printf("sncExample: Changing to low\n"); + } state low + } +} diff --git a/exampleApp/src/sncProgram.st b/exampleApp/src/sncProgram.st new file mode 100644 index 0000000..1ba2989 --- /dev/null +++ b/exampleApp/src/sncProgram.st @@ -0,0 +1 @@ +#include "../sncExample.stt" diff --git a/exampleApp/src/xxxRecord.c b/exampleApp/src/xxxRecord.c new file mode 100644 index 0000000..5cf0d15 --- /dev/null +++ b/exampleApp/src/xxxRecord.c @@ -0,0 +1,273 @@ +/* xxxRecord.c */ +/* Example record support module */ + +#include +#include +#include +#include + +#include "epicsMath.h" +#include "alarm.h" +#include "dbAccess.h" +#include "recGbl.h" +#include "dbEvent.h" +#include "dbDefs.h" +#include "dbAccess.h" +#include "devSup.h" +#include "errMdef.h" +#include "recSup.h" +#include "special.h" +#define GEN_SIZE_OFFSET +#include "xxxRecord.h" +#undef GEN_SIZE_OFFSET +#include "epicsExport.h" + +/* Create RSET - Record Support Entry Table */ +#define report NULL +#define initialize NULL +static long init_record(); +static long process(); +#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(); +static long get_precision(); +#define get_enum_str NULL +#define get_enum_strs NULL +#define put_enum_str NULL +static long get_graphic_double(); +static long get_control_double(); +static long get_alarm_double(); + +rset xxxRSET={ + 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,xxxRSET); + +typedef struct xxxset { /* xxx input dset */ + long number; + DEVSUPFUN dev_report; + DEVSUPFUN init; + DEVSUPFUN init_record; /*returns: (-1,0)=>(failure,success)*/ + DEVSUPFUN get_ioint_info; + DEVSUPFUN read_xxx; +}xxxdset; + +static void checkAlarms(xxxRecord *prec); +static void monitor(xxxRecord *prec); + +static long init_record(void *precord,int pass) +{ + xxxRecord *prec = (xxxRecord *)precord; + xxxdset *pdset; + long status; + + if (pass==0) return(0); + + if(!(pdset = (xxxdset *)(prec->dset))) { + recGblRecordError(S_dev_noDSET,(void *)prec,"xxx: init_record"); + return(S_dev_noDSET); + } + /* must have read_xxx function defined */ + if( (pdset->number < 5) || (pdset->read_xxx == NULL) ) { + recGblRecordError(S_dev_missingSup,(void *)prec,"xxx: init_record"); + return(S_dev_missingSup); + } + + if( pdset->init_record ) { + if((status=(*pdset->init_record)(prec))) return(status); + } + return(0); +} + +static long process(void *precord) +{ + xxxRecord *prec = (xxxRecord *)precord; + xxxdset *pdset = (xxxdset *)(prec->dset); + long status; + unsigned char pact=prec->pact; + + if( (pdset==NULL) || (pdset->read_xxx==NULL) ) { + prec->pact=TRUE; + recGblRecordError(S_dev_missingSup,(void *)prec,"read_xxx"); + return(S_dev_missingSup); + } + + /* pact must not be set until after calling device support */ + status=(*pdset->read_xxx)(prec); + /* check if device support set pact */ + if ( !pact && prec->pact ) return(0); + prec->pact = TRUE; + + recGblGetTimeStamp(prec); + /* check for alarms */ + checkAlarms(prec); + /* check event list */ + monitor(prec); + /* process the forward scan link record */ + recGblFwdLink(prec); + + prec->pact=FALSE; + return(status); +} + +static long get_units(DBADDR *paddr, char *units) +{ + xxxRecord *prec=(xxxRecord *)paddr->precord; + + strncpy(units,prec->egu,DB_UNITS_SIZE); + return(0); +} + +static long get_precision(DBADDR *paddr, long *precision) +{ + xxxRecord *prec=(xxxRecord *)paddr->precord; + + *precision = prec->prec; + if(paddr->pfield == (void *)&prec->val) return(0); + recGblGetPrec(paddr,precision); + return(0); +} + +static long get_graphic_double(DBADDR *paddr,struct dbr_grDouble *pgd) +{ + xxxRecord *prec=(xxxRecord *)paddr->precord; + int fieldIndex = dbGetFieldIndex(paddr); + + if(fieldIndex == xxxRecordVAL + || fieldIndex == xxxRecordHIHI + || fieldIndex == xxxRecordHIGH + || fieldIndex == xxxRecordLOW + || fieldIndex == xxxRecordLOLO + || fieldIndex == xxxRecordHOPR + || fieldIndex == xxxRecordLOPR) { + pgd->upper_disp_limit = prec->hopr; + pgd->lower_disp_limit = prec->lopr; + } else recGblGetGraphicDouble(paddr,pgd); + return(0); +} + +static long get_control_double(DBADDR *paddr,struct dbr_ctrlDouble *pcd) +{ + xxxRecord *prec=(xxxRecord *)paddr->precord; + int fieldIndex = dbGetFieldIndex(paddr); + + if(fieldIndex == xxxRecordVAL + || fieldIndex == xxxRecordHIHI + || fieldIndex == xxxRecordHIGH + || fieldIndex == xxxRecordLOW + || fieldIndex == xxxRecordLOLO) { + pcd->upper_ctrl_limit = prec->hopr; + pcd->lower_ctrl_limit = prec->lopr; + } else recGblGetControlDouble(paddr,pcd); + return(0); +} + +static long get_alarm_double(DBADDR *paddr,struct dbr_alDouble *pad) +{ + xxxRecord *prec=(xxxRecord *)paddr->precord; + int fieldIndex = dbGetFieldIndex(paddr); + + if(fieldIndex == xxxRecordVAL) { + 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(xxxRecord *prec) +{ + double val, hyst, lalm; + float hihi, high, low, lolo; + unsigned short hhsv, llsv, hsv, lsv; + + if(prec->udf == TRUE ){ + recGblSetSevr(prec,UDF_ALARM,prec->udfs); + return; + } + hihi = prec->hihi; lolo = prec->lolo; high = prec->high; low = prec->low; + hhsv = prec->hhsv; llsv = prec->llsv; hsv = prec->hsv; lsv = prec->lsv; + val = prec->val; hyst = prec->hyst; lalm = prec->lalm; + + /* alarm condition hihi */ + if (hhsv && (val >= hihi || ((lalm==hihi) && (val >= hihi-hyst)))){ + if (recGblSetSevr(prec,HIHI_ALARM,prec->hhsv)) prec->lalm = hihi; + return; + } + + /* alarm condition lolo */ + if (llsv && (val <= lolo || ((lalm==lolo) && (val <= lolo+hyst)))){ + if (recGblSetSevr(prec,LOLO_ALARM,prec->llsv)) prec->lalm = lolo; + return; + } + + /* alarm condition high */ + if (hsv && (val >= high || ((lalm==high) && (val >= high-hyst)))){ + if (recGblSetSevr(prec,HIGH_ALARM,prec->hsv)) prec->lalm = high; + return; + } + + /* alarm condition low */ + if (lsv && (val <= low || ((lalm==low) && (val <= low+hyst)))){ + if (recGblSetSevr(prec,LOW_ALARM,prec->lsv)) prec->lalm = low; + return; + } + + /* we get here only if val is out of alarm by at least hyst */ + prec->lalm = val; + return; +} + +static void monitor(xxxRecord *prec) +{ + unsigned short monitor_mask; + double delta; + + monitor_mask = recGblResetAlarms(prec); + /* check for value change */ + 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; + } + + /* 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; + } + + /* send out monitors connected to the value field */ + if (monitor_mask){ + db_post_events(prec,&prec->val,monitor_mask); + } + return; +} diff --git a/exampleApp/src/xxxRecord.dbd b/exampleApp/src/xxxRecord.dbd new file mode 100644 index 0000000..12c1d62 --- /dev/null +++ b/exampleApp/src/xxxRecord.dbd @@ -0,0 +1,118 @@ +recordtype(xxx) { + include "dbCommon.dbd" + field(VAL,DBF_DOUBLE) { + prompt("Current EGU Value") + promptgroup("40 - Input") + asl(ASL0) + pp(TRUE) + } + field(INP,DBF_INLINK) { + prompt("Input Specification") + promptgroup("40 - Input") + special(SPC_NOMOD) + interest(1) + } + field(PREC,DBF_SHORT) { + prompt("Display Precision") + promptgroup("80 - Display") + interest(1) + } + field(EGU,DBF_STRING) { + prompt("Engineering Units") + promptgroup("80 - Display") + interest(1) + size(16) + } + field(HOPR,DBF_FLOAT) { + prompt("High Operating Range") + promptgroup("80 - Display") + interest(1) + } + field(LOPR,DBF_FLOAT) { + prompt("Low Operating Range") + promptgroup("80 - Display") + interest(1) + } + field(HIHI,DBF_FLOAT) { + prompt("Hihi Alarm Limit") + promptgroup("70 - Alarm") + pp(TRUE) + interest(1) + } + field(LOLO,DBF_FLOAT) { + prompt("Lolo Alarm Limit") + promptgroup("70 - Alarm") + pp(TRUE) + interest(1) + } + field(HIGH,DBF_FLOAT) { + prompt("High Alarm Limit") + promptgroup("70 - Alarm") + pp(TRUE) + interest(1) + } + field(LOW,DBF_FLOAT) { + prompt("Low Alarm Limit") + promptgroup("70 - Alarm") + pp(TRUE) + interest(1) + } + field(HHSV,DBF_MENU) { + prompt("Hihi Severity") + promptgroup("70 - Alarm") + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(LLSV,DBF_MENU) { + prompt("Lolo Severity") + promptgroup("70 - Alarm") + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(HSV,DBF_MENU) { + prompt("High Severity") + promptgroup("70 - Alarm") + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(LSV,DBF_MENU) { + prompt("Low Severity") + promptgroup("70 - Alarm") + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(HYST,DBF_DOUBLE) { + prompt("Alarm Deadband") + promptgroup("70 - Alarm") + interest(1) + } + field(ADEL,DBF_DOUBLE) { + prompt("Archive Deadband") + promptgroup("80 - Display") + interest(1) + } + field(MDEL,DBF_DOUBLE) { + prompt("Monitor Deadband") + promptgroup("80 - Display") + interest(1) + } + field(LALM,DBF_DOUBLE) { + prompt("Last Value Alarmed") + special(SPC_NOMOD) + interest(3) + } + field(ALST,DBF_DOUBLE) { + prompt("Last Value Archived") + special(SPC_NOMOD) + interest(3) + } + field(MLST,DBF_DOUBLE) { + prompt("Last Val Monitored") + special(SPC_NOMOD) + interest(3) + } +} diff --git a/exampleApp/src/xxxSupport.dbd b/exampleApp/src/xxxSupport.dbd new file mode 100644 index 0000000..8094bdd --- /dev/null +++ b/exampleApp/src/xxxSupport.dbd @@ -0,0 +1,2 @@ +include "xxxRecord.dbd" +device(xxx,CONSTANT,devXxxSoft,"SoftChannel")