Merge 3.16 branch into 7.0
This commit is contained in:
@ -76,11 +76,14 @@ COMMON_DIR = ../O.Common
|
||||
IOCS_APPL_TOP = $(shell $(FULLPATHNAME) $(INSTALL_LOCATION))
|
||||
|
||||
#-------------------------------------------------------
|
||||
# Make echo output - suppress echoing if make's '-s' flag is set
|
||||
# Silencing the build - suppress messages during 'make -s'
|
||||
NOP = :
|
||||
ECHO = @$(if $(findstring s,$(patsubst T_A=%,,$(MAKEFLAGS))),$(NOP),echo)
|
||||
QUIET_FLAG := $(if $(findstring s,$(MAKEFLAGS)),-q,)
|
||||
QUESTION_FLAG := $(if $(findstring q,$(MAKEFLAGS)),-i,)
|
||||
ECHO = @$(if $(findstring s,$(MFLAGS)),$(NOP),echo)
|
||||
QUIET_FLAG := $(if $(findstring s,$(MFLAGS)),-q,)
|
||||
|
||||
#-------------------------------------------------------
|
||||
# Convert 'make -q' flag into '-i' for genVersionHeader.pl
|
||||
QUESTION_FLAG := $(if $(findstring q,$(MFLAGS)),-i,)
|
||||
|
||||
#-------------------------------------------------------
|
||||
ifdef T_A
|
||||
@ -90,7 +93,7 @@ INSTALL_SHRLIB = $(INSTALL_LOCATION_LIB)/$(T_A)
|
||||
INSTALL_TCLLIB = $(INSTALL_LOCATION_LIB)/$(T_A)
|
||||
INSTALL_BIN = $(INSTALL_LOCATION_BIN)/$(T_A)
|
||||
|
||||
#Directories for libraries
|
||||
# Directories for libraries
|
||||
SHRLIB_SEARCH_DIRS = $(INSTALL_LIB)
|
||||
|
||||
#-------------------------------------------------------
|
||||
|
@ -43,6 +43,7 @@ LOADABLE_LIBRARY += $(LOADABLE_LIBRARY_HOST)
|
||||
OBJS += $(OBJS_HOST)
|
||||
PROD += $(PROD_HOST)
|
||||
SCRIPTS += $(SCRIPTS_HOST)
|
||||
TARGETS += $(TARGETS_HOST)
|
||||
TESTLIBRARY += $(TESTLIBRARY_HOST)
|
||||
TESTSCRIPTS += $(TESTSCRIPTS_HOST)
|
||||
TESTPROD += $(TESTPROD_HOST)
|
||||
@ -54,6 +55,7 @@ LOADABLE_LIBRARY += $(LOADABLE_LIBRARY_IOC)
|
||||
OBJS += $(OBJS_IOC)
|
||||
PROD += $(PROD_IOC)
|
||||
SCRIPTS += $(SCRIPTS_IOC)
|
||||
TARGETS += $(TARGETS_IOC)
|
||||
TESTLIBRARY += $(TESTLIBRARY_IOC)
|
||||
TESTSCRIPTS += $(TESTSCRIPTS_IOC)
|
||||
TESTPROD += $(TESTPROD_IOC)
|
||||
@ -360,14 +362,17 @@ ifneq ($(TAPFILES),)
|
||||
ifdef RUNTESTS_ENABLED
|
||||
prove --failures --ext .tap --exec "$(CAT)" --color $(TAPFILES)
|
||||
endif
|
||||
|
||||
CURRENT_TAPFILES := $(wildcard $(TAPFILES))
|
||||
CURRENT_JUNITFILES := $(wildcard $(JUNITFILES))
|
||||
endif
|
||||
|
||||
clean-tests:
|
||||
ifneq ($(TAPFILES),)
|
||||
$(RM) $(TAPFILES)
|
||||
ifneq ($(CURRENT_TAPFILES),)
|
||||
$(RM) $(CURRENT_TAPFILES)
|
||||
endif
|
||||
ifneq ($(JUNITFILES),)
|
||||
$(RM) $(JUNITFILES)
|
||||
ifneq ($(CURRENT_JUNITFILES),)
|
||||
$(RM) $(CURRENT_JUNITFILES)
|
||||
endif
|
||||
|
||||
tapfiles: $(TESTSCRIPTS) $(TAPFILES)
|
||||
|
@ -76,7 +76,7 @@ CPPFLAGS += $($(BUILD_CLASS)_CPPFLAGS) $(POSIX_CPPFLAGS) $(OPT_CPPFLAGS)\
|
||||
$(USR_CPPFLAGS) $(CMD_CPPFLAGS) $(ARCH_DEP_CPPFLAGS) $(OP_SYS_CPPFLAGS)\
|
||||
$(OP_SYS_INCLUDE_CPPFLAGS) $(CODE_CPPFLAGS)
|
||||
|
||||
ECHO = @$(if $(findstring s,$(patsubst T_A=%,,$(MAKEFLAGS))),$(NOP),echo)
|
||||
ECHO = @$(if $(findstring s,$(MFLAGS)),$(NOP),echo)
|
||||
|
||||
#--------------------------------------------------
|
||||
# Although RTEMS uses gcc, it wants to use gcc its own way
|
||||
|
@ -146,8 +146,10 @@ SHRLIB_CFLAGS =
|
||||
SHRLIB_LDFLAGS =
|
||||
|
||||
#--------------------------------------------------
|
||||
# Earlier versions of gcc don't understand -MF
|
||||
HDEPENDS_COMPFLAGS = -MM > $@
|
||||
# Don't use gcc 2.x for dependency generation
|
||||
|
||||
HDEPENDS_METHOD_2 = MKMF
|
||||
HDEPENDS_METHOD = $(firstword $(HDEPENDS_METHOD_$(VX_GNU_MAJOR_VERSION)) COMP)
|
||||
|
||||
#--------------------------------------------------
|
||||
# osithead use default stack, YES or NO override
|
||||
|
@ -112,6 +112,25 @@ be happy to try and answer them!</p>
|
||||
|
||||
<!-- Insert inherited items immediately below here ... -->
|
||||
|
||||
<h3>Status reporting for the callback and scanOnce task queues</h3>
|
||||
|
||||
<p>Two new iocsh commands and some associated underlying APIs have been added to
|
||||
show the state of the queues that feed the three callback tasks and the scanOnce
|
||||
task, including a high-water mark which can optionally be reset. The new iocsh
|
||||
commands are <tt>callbackQueueShow</tt> and <tt>scanOnceQueueShow</tt>; both
|
||||
take an optional integer argument which must be non-zero to reset the
|
||||
high-water mark.</p>
|
||||
|
||||
<h3>Support for event codes greater than or equal to NUM_TIME_EVENTS</h3>
|
||||
|
||||
<p>Event numbers greater than or equal to NUM_TIME_EVENTS are now allowed if
|
||||
supported by the registered event time provider, which must provide its own
|
||||
advancing timestamp validation for such events.</p>
|
||||
|
||||
<p>Time events numbered 0 through (NUM_TIME_EVENTS-1) are still validated by
|
||||
code in epicsGeneralTime.c that checks for advancing timestamps and enforces
|
||||
that restriction.</p>
|
||||
|
||||
<h3>Type-safe Device and Driver Support Tables</h3>
|
||||
|
||||
<p>Type-safe versions of the device and driver support structures <tt>dset</tt>
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include <alarm.h>
|
||||
#include <cadef.h>
|
||||
#include <epicsGetopt.h>
|
||||
#include "epicsVersion.h"
|
||||
|
||||
#include "tool_lib.h"
|
||||
|
||||
@ -55,6 +56,7 @@ static void usage (void)
|
||||
{
|
||||
fprintf (stderr, "\nUsage: caget [options] <PV name> ...\n\n"
|
||||
" -h: Help: Print this message\n"
|
||||
" -V: Version: Show EPICS and CA versions\n"
|
||||
"Channel Access options:\n"
|
||||
" -w <sec>: Wait time, specifies CA timeout, default is %f second(s)\n"
|
||||
" -c: Asynchronous get (use ca_get_callback and wait for completion)\n"
|
||||
@ -389,11 +391,14 @@ int main (int argc, char *argv[])
|
||||
|
||||
LINE_BUFFER(stdout); /* Configure stdout buffering */
|
||||
|
||||
while ((opt = getopt(argc, argv, ":taicnhsSe:f:g:l:#:d:0:w:p:F:")) != -1) {
|
||||
while ((opt = getopt(argc, argv, ":taicnhsSVe:f:g:l:#:d:0:w:p:F:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'h': /* Print usage */
|
||||
usage();
|
||||
return 0;
|
||||
case 'V':
|
||||
printf( "\nEPICS Version %s, CA Protocol version %s\n", EPICS_VERSION_STRING, ca_version() );
|
||||
return 0;
|
||||
case 't': /* Terse output mode */
|
||||
complainIfNotPlainAndSet(&format, terse);
|
||||
break;
|
||||
|
@ -23,6 +23,7 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <epicsStdlib.h>
|
||||
#include "epicsVersion.h"
|
||||
|
||||
#include <cadef.h>
|
||||
#include <epicsGetopt.h>
|
||||
@ -36,12 +37,14 @@ void usage (void)
|
||||
{
|
||||
fprintf (stderr, "\nUsage: cainfo [options] <PV name> ...\n\n"
|
||||
" -h: Help: Print this message\n"
|
||||
" -V: Version: Show EPICS and CA versions\n"
|
||||
"Channel Access options:\n"
|
||||
" -w <sec>: Wait time, specifies CA timeout, default is %f second(s)\n"
|
||||
" -s <level>: Call ca_client_status with the specified interest level\n"
|
||||
" -p <prio>: CA priority (0-%u, default 0=lowest)\n"
|
||||
"\nExample: cainfo my_channel another_channel\n\n"
|
||||
, DEFAULT_TIMEOUT, CA_PRIORITY_MAX);
|
||||
fprintf (stderr, "\nEPICS Version %s, CA Protocol version %s\n", EPICS_VERSION_STRING, ca_version() );
|
||||
}
|
||||
|
||||
|
||||
@ -137,11 +140,14 @@ int main (int argc, char *argv[])
|
||||
|
||||
LINE_BUFFER(stdout); /* Configure stdout buffering */
|
||||
|
||||
while ((opt = getopt(argc, argv, ":nhw:s:p:")) != -1) {
|
||||
while ((opt = getopt(argc, argv, ":nhVw:s:p:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'h': /* Print usage */
|
||||
usage();
|
||||
return 0;
|
||||
case 'V':
|
||||
printf( "\nEPICS Version %s, CA Protocol version %s\n", EPICS_VERSION_STRING, ca_version() );
|
||||
return 0;
|
||||
case 'w': /* Set CA timeout value */
|
||||
if(epicsScanDouble(optarg, &caTimeout) != 1)
|
||||
{
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <stdio.h>
|
||||
#include <epicsStdlib.h>
|
||||
#include <string.h>
|
||||
#include "epicsVersion.h"
|
||||
|
||||
#include <cadef.h>
|
||||
#include <epicsGetopt.h>
|
||||
@ -44,7 +45,8 @@ void usage (void)
|
||||
{
|
||||
fprintf (stderr, "\nUsage: camonitor [options] <PV name> ...\n"
|
||||
"\n"
|
||||
" -h: Help; Print this message\n"
|
||||
" -h: Help: Print this message\n"
|
||||
" -V: Version: Show EPICS and CA versions\n"
|
||||
"Channel Access options:\n"
|
||||
" -w <sec>: Wait time, specifies CA timeout, default is %f second(s)\n"
|
||||
" -m <msk>: Specify CA event mask to use. <msk> is any combination of\n"
|
||||
@ -209,11 +211,14 @@ int main (int argc, char *argv[])
|
||||
|
||||
LINE_BUFFER(stdout); /* Configure stdout buffering */
|
||||
|
||||
while ((opt = getopt(argc, argv, ":nhm:sSe:f:g:l:#:0:w:t:p:F:")) != -1) {
|
||||
while ((opt = getopt(argc, argv, ":nhVm:sSe:f:g:l:#:0:w:t:p:F:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'h': /* Print usage */
|
||||
usage();
|
||||
return 0;
|
||||
case 'V':
|
||||
printf( "\nEPICS Version %s, CA Protocol version %s\n", EPICS_VERSION_STRING, ca_version() );
|
||||
return 0;
|
||||
case 'n': /* Print ENUM as index numbers */
|
||||
enumAsNr=1;
|
||||
break;
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include <epicsGetopt.h>
|
||||
#include <epicsEvent.h>
|
||||
#include <epicsString.h>
|
||||
#include "epicsVersion.h"
|
||||
|
||||
#include "tool_lib.h"
|
||||
|
||||
@ -59,6 +60,7 @@ void usage (void)
|
||||
fprintf (stderr, "\nUsage: caput [options] <PV name> <PV value> ...\n"
|
||||
" caput -a [options] <PV name> <no of values> <PV value> ...\n\n"
|
||||
" -h: Help: Print this message\n"
|
||||
" -V: Version: Show EPICS and CA versions\n"
|
||||
"Channel Access options:\n"
|
||||
" -w <sec>: Wait time, specifies CA timeout, default is %f second(s)\n"
|
||||
" -c: Asynchronous put (use ca_put_callback and wait for completion)\n"
|
||||
@ -281,11 +283,14 @@ int main (int argc, char *argv[])
|
||||
LINE_BUFFER(stdout); /* Configure stdout buffering */
|
||||
putenv("POSIXLY_CORRECT="); /* Behave correct on GNU getopt systems */
|
||||
|
||||
while ((opt = getopt(argc, argv, ":cnlhatsS#:w:p:F:")) != -1) {
|
||||
while ((opt = getopt(argc, argv, ":cnlhatsVS#:w:p:F:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'h': /* Print usage */
|
||||
usage();
|
||||
return 0;
|
||||
case 'V':
|
||||
printf( "\nEPICS Version %s, CA Protocol version %s\n", EPICS_VERSION_STRING, ca_version() );
|
||||
return 0;
|
||||
case 'n': /* Force interpret ENUM as index number */
|
||||
enumAsNr = 1;
|
||||
enumAsString = 0;
|
||||
|
@ -61,7 +61,7 @@ DBDINC += menuScan
|
||||
DBDINC += dbCommon
|
||||
|
||||
dbMenusPod = $(notdir $(wildcard ../db/menu*.dbd.pod))
|
||||
HTMLS += $(patsubst %.dbd.pod,%.html,$(menusPod))
|
||||
HTMLS += $(patsubst %.dbd.pod,%.html,$(dbMenusPod))
|
||||
|
||||
dbCore_SRCS += dbLock.c
|
||||
dbCore_SRCS += dbAccess.c
|
||||
|
@ -54,6 +54,7 @@ typedef struct cbQueueSet {
|
||||
epicsEventId semWakeUp;
|
||||
epicsRingPointerId queue;
|
||||
int queueOverflow;
|
||||
int queueOverflows;
|
||||
int shutdown;
|
||||
int threadsConfigured;
|
||||
int threadsRunning;
|
||||
@ -103,6 +104,51 @@ int callbackSetQueueSize(int size)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int callbackQueueStatus(const int reset, callbackQueueStats *result)
|
||||
{
|
||||
int ret;
|
||||
if (!callbackIsInit) return -1;
|
||||
if (result) {
|
||||
int prio;
|
||||
result->size = callbackQueueSize;
|
||||
for(prio = 0; prio < NUM_CALLBACK_PRIORITIES; prio++) {
|
||||
epicsRingPointerId qId = callbackQueue[prio].queue;
|
||||
result->numUsed[prio] = epicsRingPointerGetUsed(qId);
|
||||
result->maxUsed[prio] = epicsRingPointerGetHighWaterMark(qId);
|
||||
result->numOverflow[prio] = epicsAtomicGetIntT(&callbackQueue[prio].queueOverflows);
|
||||
}
|
||||
ret = 0;
|
||||
} else {
|
||||
ret = -2;
|
||||
}
|
||||
if (reset) {
|
||||
int prio;
|
||||
for(prio = 0; prio < NUM_CALLBACK_PRIORITIES; prio++) {
|
||||
epicsRingPointerResetHighWaterMark(callbackQueue[prio].queue);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void callbackQueueShow(const int reset)
|
||||
{
|
||||
callbackQueueStats stats;
|
||||
if (callbackQueueStatus(reset, &stats) == -1) {
|
||||
fprintf(stderr, "Callback system not initialized, yet. Please run "
|
||||
"iocInit before using this command.\n");
|
||||
} else {
|
||||
int prio;
|
||||
printf("PRIORITY HIGH-WATER MARK ITEMS IN Q Q SIZE %% USED Q OVERFLOWS\n");
|
||||
for (prio = 0; prio < NUM_CALLBACK_PRIORITIES; prio++) {
|
||||
double qusage = 100.0 * stats.numUsed[prio] / stats.size;
|
||||
printf("%8s %15d %10d %6d %6.1f %11d\n",
|
||||
threadNamePrefix[prio], stats.maxUsed[prio],
|
||||
stats.numUsed[prio], stats.size, qusage,
|
||||
stats.numOverflow[prio]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int callbackParallelThreads(int count, const char *prio)
|
||||
{
|
||||
if (callbackIsInit) {
|
||||
@ -290,6 +336,7 @@ int callbackRequest(CALLBACK *pcallback)
|
||||
if (!pushOK) {
|
||||
epicsInterruptContextMessage(fullMessage[priority]);
|
||||
mySet->queueOverflow = TRUE;
|
||||
epicsAtomicIncrIntT(&mySet->queueOverflows);
|
||||
return S_db_bufFull;
|
||||
}
|
||||
epicsEventSignal(mySet->semWakeUp);
|
||||
|
@ -48,6 +48,13 @@ typedef epicsCallback CALLBACK;
|
||||
|
||||
typedef void (*CALLBACKFUNC)(struct callbackPvt*);
|
||||
|
||||
typedef struct callbackQueueStats {
|
||||
int size;
|
||||
int numUsed[NUM_CALLBACK_PRIORITIES];
|
||||
int maxUsed[NUM_CALLBACK_PRIORITIES];
|
||||
int numOverflow[NUM_CALLBACK_PRIORITIES];
|
||||
} callbackQueueStats;
|
||||
|
||||
#define callbackSetCallback(PFUN, PCALLBACK) \
|
||||
( (PCALLBACK)->callback = (PFUN) )
|
||||
#define callbackSetPriority(PRIORITY, PCALLBACK) \
|
||||
@ -73,6 +80,8 @@ epicsShareFunc void callbackCancelDelayed(CALLBACK *pcallback);
|
||||
epicsShareFunc void callbackRequestProcessCallbackDelayed(
|
||||
CALLBACK *pCallback, int Priority, void *pRec, double seconds);
|
||||
epicsShareFunc int callbackSetQueueSize(int size);
|
||||
epicsShareFunc int callbackQueueStatus(const int reset, callbackQueueStats *result);
|
||||
epicsShareFunc void callbackQueueShow(const int reset);
|
||||
epicsShareFunc int callbackParallelThreads(int count, const char *prio);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -703,7 +703,12 @@ static long doLocked(struct link *plink, dbLinkUserCallback rtn, void *priv)
|
||||
caLink *pca;
|
||||
long status;
|
||||
|
||||
pcaGetCheck
|
||||
assert(plink);
|
||||
if (plink->type != CA_LINK) return -1;
|
||||
pca = (caLink *)plink->value.pv_link.pvt;
|
||||
assert(pca);
|
||||
epicsMutexMustLock(pca->lock);
|
||||
assert(pca->plink);
|
||||
status = rtn(plink, priv);
|
||||
epicsMutexUnlock(pca->lock);
|
||||
return status;
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "cantProceed.h"
|
||||
#include "epicsAssert.h"
|
||||
#include "epicsString.h"
|
||||
#include "epicsStdio.h"
|
||||
#include "errlog.h"
|
||||
#include "freeList.h"
|
||||
#include "gpHash.h"
|
||||
|
@ -296,6 +296,17 @@ static void scanOnceSetQueueSizeCallFunc(const iocshArgBuf *args)
|
||||
scanOnceSetQueueSize(args[0].ival);
|
||||
}
|
||||
|
||||
/* scanOnceQueueShow */
|
||||
static const iocshArg scanOnceQueueShowArg0 = { "reset",iocshArgInt};
|
||||
static const iocshArg * const scanOnceQueueShowArgs[1] =
|
||||
{&scanOnceQueueShowArg0};
|
||||
static const iocshFuncDef scanOnceQueueShowFuncDef =
|
||||
{"scanOnceQueueShow",1,scanOnceQueueShowArgs};
|
||||
static void scanOnceQueueShowCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
scanOnceQueueShow(args[0].ival);
|
||||
}
|
||||
|
||||
/* scanppl */
|
||||
static const iocshArg scanpplArg0 = { "rate",iocshArgDouble};
|
||||
static const iocshArg * const scanpplArgs[1] = {&scanpplArg0};
|
||||
@ -335,6 +346,17 @@ static void callbackSetQueueSizeCallFunc(const iocshArgBuf *args)
|
||||
callbackSetQueueSize(args[0].ival);
|
||||
}
|
||||
|
||||
/* callbackQueueShow */
|
||||
static const iocshArg callbackQueueShowArg0 = { "reset", iocshArgInt};
|
||||
static const iocshArg * const callbackQueueShowArgs[1] =
|
||||
{&callbackQueueShowArg0};
|
||||
static const iocshFuncDef callbackQueueShowFuncDef =
|
||||
{"callbackQueueShow",1,callbackQueueShowArgs};
|
||||
static void callbackQueueShowCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
callbackQueueShow(args[0].ival);
|
||||
}
|
||||
|
||||
/* callbackParallelThreads */
|
||||
static const iocshArg callbackParallelThreadsArg0 = { "no of threads", iocshArgInt};
|
||||
static const iocshArg callbackParallelThreadsArg1 = { "priority", iocshArgString};
|
||||
@ -441,12 +463,14 @@ void dbIocRegister(void)
|
||||
iocshRegister(&dbLockShowLockedFuncDef,dbLockShowLockedCallFunc);
|
||||
|
||||
iocshRegister(&scanOnceSetQueueSizeFuncDef,scanOnceSetQueueSizeCallFunc);
|
||||
iocshRegister(&scanOnceQueueShowFuncDef,scanOnceQueueShowCallFunc);
|
||||
iocshRegister(&scanpplFuncDef,scanpplCallFunc);
|
||||
iocshRegister(&scanpelFuncDef,scanpelCallFunc);
|
||||
iocshRegister(&postEventFuncDef,postEventCallFunc);
|
||||
iocshRegister(&scanpiolFuncDef,scanpiolCallFunc);
|
||||
|
||||
iocshRegister(&callbackSetQueueSizeFuncDef,callbackSetQueueSizeCallFunc);
|
||||
iocshRegister(&callbackQueueShowFuncDef,callbackQueueShowCallFunc);
|
||||
iocshRegister(&callbackParallelThreadsFuncDef,callbackParallelThreadsCallFunc);
|
||||
|
||||
/* Needed before callback system is initialized */
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "cantProceed.h"
|
||||
#include "dbDefs.h"
|
||||
#include "ellLib.h"
|
||||
#include "epicsAtomic.h"
|
||||
#include "epicsEvent.h"
|
||||
#include "epicsMutex.h"
|
||||
#include "epicsPrint.h"
|
||||
@ -63,6 +64,7 @@ static volatile enum ctl scanCtl;
|
||||
static int onceQueueSize = 1000;
|
||||
static epicsEventId onceSem;
|
||||
static epicsRingBytesId onceQ;
|
||||
static int onceQOverruns = 0;
|
||||
static epicsThreadId onceTaskId;
|
||||
static void *exitOnce;
|
||||
|
||||
@ -676,6 +678,7 @@ int scanOnceCallback(struct dbCommon *precord, once_complete cb, void *usr)
|
||||
if (!pushOK) {
|
||||
if (newOverflow) errlogPrintf("scanOnce: Ring buffer overflow\n");
|
||||
newOverflow = FALSE;
|
||||
epicsAtomicIncrIntT(&onceQOverruns);
|
||||
} else {
|
||||
newOverflow = TRUE;
|
||||
}
|
||||
@ -722,6 +725,40 @@ int scanOnceSetQueueSize(int size)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int scanOnceQueueStatus(const int reset, scanOnceQueueStats *result)
|
||||
{
|
||||
int ret;
|
||||
if (!onceQ) return -1;
|
||||
if (result) {
|
||||
result->size = epicsRingBytesSize(onceQ) / sizeof(onceEntry);
|
||||
result->numUsed = epicsRingBytesUsedBytes(onceQ) / sizeof(onceEntry);
|
||||
result->maxUsed = epicsRingBytesHighWaterMark(onceQ) / sizeof(onceEntry);
|
||||
result->numOverflow = epicsAtomicGetIntT(&onceQOverruns);
|
||||
ret = 0;
|
||||
} else {
|
||||
ret = -2;
|
||||
}
|
||||
if (reset) {
|
||||
epicsRingBytesResetHighWaterMark(onceQ);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void scanOnceQueueShow(const int reset)
|
||||
{
|
||||
scanOnceQueueStats stats;
|
||||
if (scanOnceQueueStatus(reset, &stats) == -1) {
|
||||
fprintf(stderr, "scanOnce system not initialized, yet. Please run "
|
||||
"iocInit before using this command.\n");
|
||||
} else {
|
||||
double qusage = 100.0 * stats.numUsed / stats.size;
|
||||
printf("PRIORITY HIGH-WATER MARK ITEMS IN Q Q SIZE %% USED Q OVERFLOWS\n");
|
||||
printf("%8s %15d %10d %6d %6.1f %11d\n", "scanOnce", stats.maxUsed,
|
||||
stats.numUsed, stats.size, qusage,
|
||||
epicsAtomicGetIntT(&onceQOverruns));
|
||||
}
|
||||
}
|
||||
|
||||
static void initOnce(void)
|
||||
{
|
||||
if ((onceQ = epicsRingBytesLockedCreate(sizeof(onceEntry)*onceQueueSize)) == NULL) {
|
||||
|
@ -42,6 +42,13 @@ struct dbCommon;
|
||||
typedef void (*io_scan_complete)(void *usr, IOSCANPVT, int prio);
|
||||
typedef void (*once_complete)(void *usr, struct dbCommon*);
|
||||
|
||||
typedef struct scanOnceQueueStats {
|
||||
int size;
|
||||
int numUsed;
|
||||
int maxUsed;
|
||||
int numOverflow;
|
||||
} scanOnceQueueStats;
|
||||
|
||||
epicsShareFunc long scanInit(void);
|
||||
epicsShareFunc void scanRun(void);
|
||||
epicsShareFunc void scanPause(void);
|
||||
@ -57,6 +64,8 @@ epicsShareFunc double scanPeriod(int scan);
|
||||
epicsShareFunc int scanOnce(struct dbCommon *);
|
||||
epicsShareFunc int scanOnceCallback(struct dbCommon *, once_complete cb, void *usr);
|
||||
epicsShareFunc int scanOnceSetQueueSize(int size);
|
||||
epicsShareFunc int scanOnceQueueStatus(const int reset, scanOnceQueueStats *result);
|
||||
epicsShareFunc void scanOnceQueueShow(const int reset);
|
||||
|
||||
/*print periodic lists*/
|
||||
epicsShareFunc int scanppl(double rate);
|
||||
|
@ -1,11 +1,48 @@
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne
|
||||
# Copyright (c) 2018 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.
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
|
||||
=head1 Menu menuScan
|
||||
|
||||
This menu is used for the C<SCAN> field of all record types.
|
||||
|
||||
The set of periodic scan rates may be modified for an individual IOC by
|
||||
copying the F<menuScan.dbd> file from Base into the IOC's source
|
||||
directory and changing it to contain the desired scan rates.
|
||||
|
||||
The scan periods are extracted from the choice strings at runtime, which
|
||||
must be expressed as a number with any of the following units appended:
|
||||
|
||||
=over 4
|
||||
|
||||
second
|
||||
seconds
|
||||
minute
|
||||
minutes
|
||||
hour
|
||||
hours
|
||||
Hertz
|
||||
Hz
|
||||
|
||||
=back
|
||||
|
||||
At IOC start-up a separate scan thread will be created for each period,
|
||||
with thread priority increasing further down the list, so faster periods
|
||||
should appear after slower ones.
|
||||
|
||||
Scan rates that cannot be achieved will generate a warning message from
|
||||
the C<iocInit> command.
|
||||
|
||||
|
||||
=menu menuScan
|
||||
|
||||
=cut
|
||||
|
||||
menu(menuScan) {
|
||||
choice(menuScanPassive,"Passive")
|
||||
choice(menuScanEvent,"Event")
|
@ -1,134 +0,0 @@
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
# National Laboratory.
|
||||
# Copyright (c) 2002 The Regents of the University of California, as
|
||||
# Operator of Los Alamos National Laboratory.
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
recordtype(bi) {
|
||||
include "dbCommon.dbd"
|
||||
field(INP,DBF_INLINK) {
|
||||
prompt("Input Specification")
|
||||
promptgroup("40 - Input")
|
||||
interest(1)
|
||||
}
|
||||
field(VAL,DBF_ENUM) {
|
||||
prompt("Current Value")
|
||||
promptgroup("40 - Input")
|
||||
asl(ASL0)
|
||||
pp(TRUE)
|
||||
}
|
||||
field(ZSV,DBF_MENU) {
|
||||
prompt("Zero Error Severity")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
menu(menuAlarmSevr)
|
||||
}
|
||||
field(OSV,DBF_MENU) {
|
||||
prompt("One Error Severity")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
menu(menuAlarmSevr)
|
||||
}
|
||||
field(COSV,DBF_MENU) {
|
||||
prompt("Change of State Svr")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
menu(menuAlarmSevr)
|
||||
}
|
||||
field(ZNAM,DBF_STRING) {
|
||||
prompt("Zero Name")
|
||||
promptgroup("80 - Display")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
size(26)
|
||||
prop(YES)
|
||||
}
|
||||
field(ONAM,DBF_STRING) {
|
||||
prompt("One Name")
|
||||
promptgroup("80 - Display")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
size(26)
|
||||
prop(YES)
|
||||
}
|
||||
field(RVAL,DBF_ULONG) {
|
||||
prompt("Raw Value")
|
||||
pp(TRUE)
|
||||
}
|
||||
field(ORAW,DBF_ULONG) {
|
||||
prompt("prev Raw Value")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(MASK,DBF_ULONG) {
|
||||
prompt("Hardware Mask")
|
||||
special(SPC_NOMOD)
|
||||
interest(1)
|
||||
}
|
||||
field(LALM,DBF_USHORT) {
|
||||
prompt("Last Value Alarmed")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(MLST,DBF_USHORT) {
|
||||
prompt("Last Value Monitored")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(SIOL,DBF_INLINK) {
|
||||
prompt("Simulation Input Link")
|
||||
promptgroup("90 - Simulate")
|
||||
interest(1)
|
||||
}
|
||||
field(SVAL,DBF_ULONG) {
|
||||
prompt("Simulation Value")
|
||||
}
|
||||
field(SIML,DBF_INLINK) {
|
||||
prompt("Simulation Mode Link")
|
||||
promptgroup("90 - Simulate")
|
||||
interest(1)
|
||||
}
|
||||
field(SIMM,DBF_MENU) {
|
||||
prompt("Simulation Mode")
|
||||
special(SPC_MOD)
|
||||
interest(1)
|
||||
menu(menuSimm)
|
||||
}
|
||||
field(SIMS,DBF_MENU) {
|
||||
prompt("Simulation Mode Severity")
|
||||
promptgroup("90 - Simulate")
|
||||
interest(2)
|
||||
menu(menuAlarmSevr)
|
||||
}
|
||||
field(OLDSIMM,DBF_MENU) {
|
||||
prompt("Prev. Simulation Mode")
|
||||
special(SPC_NOMOD)
|
||||
interest(4)
|
||||
menu(menuSimm)
|
||||
}
|
||||
field(SSCN,DBF_MENU) {
|
||||
prompt("Sim. Mode Scan")
|
||||
promptgroup("90 - Simulate")
|
||||
interest(1)
|
||||
menu(menuScan)
|
||||
initial("65535")
|
||||
}
|
||||
field(SDLY,DBF_DOUBLE) {
|
||||
prompt("Sim. Mode Async Delay")
|
||||
promptgroup("90 - Simulate")
|
||||
interest(2)
|
||||
initial("-1.0")
|
||||
}
|
||||
%#include "callback.h"
|
||||
field(SIMPVT,DBF_NOACCESS) {
|
||||
prompt("Sim. Mode Private")
|
||||
special(SPC_NOMOD)
|
||||
interest(4)
|
||||
extra("CALLBACK *simpvt")
|
||||
}
|
||||
}
|
491
modules/database/src/std/rec/biRecord.dbd.pod
Normal file
491
modules/database/src/std/rec/biRecord.dbd.pod
Normal file
@ -0,0 +1,491 @@
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
# National Laboratory.
|
||||
# Copyright (c) 2002 The Regents of the University of California, as
|
||||
# Operator of Los Alamos National Laboratory.
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
|
||||
=title Binary Input Record (bi)
|
||||
|
||||
This record type is normally used to obtain a binary value of 0 or 1. Most
|
||||
device support modules obtain values from hardware and place the value in
|
||||
RVAL. For these devices, record processing sets VAL = (0,1) if RVAL is (0,
|
||||
not 0). Device support modules may optionally read a value directly from
|
||||
VAL.
|
||||
|
||||
Soft device modules are provided to obtain input via database or channel
|
||||
access links via dbPutField or dbPutLink requests. Two soft device support
|
||||
modules are provided: C<Soft Channel> and C<Raw Soft Channel>. The first
|
||||
allows VAL to be an arbitrary unsigned short integer. The second reads the
|
||||
value into RVAL just like normal hardware modules.
|
||||
|
||||
=head2 Parameter Fields
|
||||
|
||||
The binary input's fields fall into the following categories:
|
||||
|
||||
=over
|
||||
|
||||
=item *
|
||||
scan Parameters
|
||||
|
||||
=item *
|
||||
read and convert parameters
|
||||
|
||||
=item *
|
||||
operator display parameters
|
||||
|
||||
=item *
|
||||
alarm parameters
|
||||
|
||||
=item *
|
||||
run-time parameters
|
||||
|
||||
=back
|
||||
|
||||
=recordtype bi
|
||||
|
||||
=cut
|
||||
|
||||
recordtype(bi) {
|
||||
|
||||
=head3 Scan Parameters
|
||||
|
||||
The binary input record has the standard fields for specifying under what
|
||||
circumstances the record will be processed. These fields are listed in
|
||||
L<Scan Fields>. In addition, L<Scanning Specification> explains how these
|
||||
fields are used. Note that I/O event scanning is only supported for those
|
||||
card types that interrupt.
|
||||
|
||||
=fields SCAN
|
||||
|
||||
=head3 Read and Convert Parameters
|
||||
|
||||
The read and convert fields determine where the binary input gets its
|
||||
input from and how to convert the raw signal to engineering units. The INP
|
||||
field contains the address from where device support retrieves the value.
|
||||
If the binary input record gets its value from hardware, the address of the
|
||||
card must be entered in the INP field, and the name of the device support
|
||||
module must be entered in the DTYP field. See L<Address Specification> for
|
||||
information on the format of the hardware address. Be aware that the format
|
||||
differs between types of cards. You can see a list of device support
|
||||
modules currently supported at the user's local site by using C<dbst>
|
||||
utility (R3.13).
|
||||
|
||||
For records that specify C<Soft Channel> or C<Raw Soft Channel> device
|
||||
support routines, the INP field can be a channel or a database link, or a
|
||||
constant. If a constant, VAL can be changed directly by dbPuts. See
|
||||
L<Address Specification> for information on the format of database and
|
||||
channel access addresses. Also, see L<Device Support for Soft Records> in
|
||||
this chapter for information on soft device support.
|
||||
|
||||
If the record gets its values from hardware or uses the C<Raw Soft Channel>
|
||||
device support, the device support routines place the value in the RVAL
|
||||
field which is then converted using the process described in the next
|
||||
section.
|
||||
|
||||
=fields INP, DTYP, ZNAM, ONAM, RVAL, VAL
|
||||
|
||||
=head3 Conversion Fields
|
||||
|
||||
The VAL field is set equal to (0,1) if the RVAL field is (0, not 0), unless
|
||||
the device support module reads a value directly into VAL or the
|
||||
C<Soft Channel> device support is used. The value can also be fetched as one of
|
||||
the strings specified in the ZNAM or ONAM fields. The ZNAM field has a
|
||||
string that corresponds to the 0 state, so when the value is fetched as
|
||||
this string, C<put_enum_str> will return a 0. The ONAM field hold the
|
||||
string that corresponds to the 1 state, so when the value is fetched as
|
||||
this string, C<put_enum_str> returns a 1.
|
||||
|
||||
=fields ZNAM, ONAM
|
||||
|
||||
=head3 Operator Display Parameters
|
||||
|
||||
These parameters are used to present meaningful data to the operator. The
|
||||
C<get_enum_str> record support routine can retrieve the state string
|
||||
corresponding to the VAL's state. If the value is 1, C<get_enum_str> will
|
||||
return the string in the ONAM field; and if 0, C<get_enum_str> will return
|
||||
the ZNAM string.
|
||||
|
||||
See L<Fields Common to All Record Types> for more on the record name (NAME)
|
||||
and description (DESC) fields.
|
||||
|
||||
=fields ZNAM, ONAM, NAME, DESC
|
||||
|
||||
=head3 Alarm Parameters
|
||||
|
||||
These parameters are used to determine if the binary input is in alarm
|
||||
condition and to determine the severity of that condition. The possible
|
||||
alarm conditions for binary inputs are the SCAN, READ state alarms, and the
|
||||
change of state alarm. The SCAN and READ alarms are called by the device
|
||||
supprt routines.
|
||||
|
||||
The user can choose the severity of each state in the ZSV and OSV fields.
|
||||
The possible values for these fields are C<NO_ALARM>, C<MINOR>, and
|
||||
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.
|
||||
|
||||
See L<Alarm Specification> for a complete explanation of the discrete alarm
|
||||
states. L<Alarm Fields> lists other fields related to alarms that are
|
||||
common to all record types.
|
||||
|
||||
=fields ZSV, OSV, COSV
|
||||
|
||||
=head3 Run-time Parameters and Simulation Mode Parameters
|
||||
|
||||
These parameters are used by the run-time code for processing the binary
|
||||
input. They are not configured using a database configuration tool.
|
||||
|
||||
ORAW is used to determine if monitors should be triggered for RVAL at the same
|
||||
time they are triggered for VAL.
|
||||
|
||||
MASK is given a value by ithe device support routines. This value is used to
|
||||
manipulate the record's value, but is only the concern of the hardware device
|
||||
support routines.
|
||||
|
||||
The LALM fields holds the value of the last occurence of the change of
|
||||
state alarm. It is used to implement the change of state alarm, and thus
|
||||
only has meaning if COSV is MAJOR or MINOR.
|
||||
|
||||
The MSLT field is used by the C<process> record support routine to
|
||||
determine if archive and value change monitors are invoked. They are if MSLT
|
||||
is not equal to VAL.
|
||||
|
||||
=fields ORAW, MASK, LALM, MLST
|
||||
|
||||
The following fields are used to operate the binary input in simulation
|
||||
mode. See L<Fields Common to Many Record Types> for more information on
|
||||
these fields.
|
||||
|
||||
=fields SIOL, SVAL, SIML, SIMM, SIMS
|
||||
|
||||
|
||||
=cut
|
||||
|
||||
include "dbCommon.dbd"
|
||||
field(INP,DBF_INLINK) {
|
||||
prompt("Input Specification")
|
||||
promptgroup("40 - Input")
|
||||
interest(1)
|
||||
}
|
||||
field(VAL,DBF_ENUM) {
|
||||
prompt("Current Value")
|
||||
promptgroup("40 - Input")
|
||||
asl(ASL0)
|
||||
pp(TRUE)
|
||||
}
|
||||
field(ZSV,DBF_MENU) {
|
||||
prompt("Zero Error Severity")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
menu(menuAlarmSevr)
|
||||
}
|
||||
field(OSV,DBF_MENU) {
|
||||
prompt("One Error Severity")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
menu(menuAlarmSevr)
|
||||
}
|
||||
field(COSV,DBF_MENU) {
|
||||
prompt("Change of State Svr")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
menu(menuAlarmSevr)
|
||||
}
|
||||
field(ZNAM,DBF_STRING) {
|
||||
prompt("Zero Name")
|
||||
promptgroup("80 - Display")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
size(26)
|
||||
prop(YES)
|
||||
}
|
||||
field(ONAM,DBF_STRING) {
|
||||
prompt("One Name")
|
||||
promptgroup("80 - Display")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
size(26)
|
||||
prop(YES)
|
||||
}
|
||||
field(RVAL,DBF_ULONG) {
|
||||
prompt("Raw Value")
|
||||
pp(TRUE)
|
||||
}
|
||||
field(ORAW,DBF_ULONG) {
|
||||
prompt("prev Raw Value")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(MASK,DBF_ULONG) {
|
||||
prompt("Hardware Mask")
|
||||
special(SPC_NOMOD)
|
||||
interest(1)
|
||||
}
|
||||
field(LALM,DBF_USHORT) {
|
||||
prompt("Last Value Alarmed")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(MLST,DBF_USHORT) {
|
||||
prompt("Last Value Monitored")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(SIOL,DBF_INLINK) {
|
||||
prompt("Simulation Input Link")
|
||||
promptgroup("90 - Simulate")
|
||||
interest(1)
|
||||
}
|
||||
field(SVAL,DBF_ULONG) {
|
||||
prompt("Simulation Value")
|
||||
}
|
||||
field(SIML,DBF_INLINK) {
|
||||
prompt("Simulation Mode Link")
|
||||
promptgroup("90 - Simulate")
|
||||
interest(1)
|
||||
}
|
||||
field(SIMM,DBF_MENU) {
|
||||
prompt("Simulation Mode")
|
||||
special(SPC_MOD)
|
||||
interest(1)
|
||||
menu(menuSimm)
|
||||
}
|
||||
field(SIMS,DBF_MENU) {
|
||||
prompt("Simulation Mode Severity")
|
||||
promptgroup("90 - Simulate")
|
||||
interest(2)
|
||||
menu(menuAlarmSevr)
|
||||
}
|
||||
field(OLDSIMM,DBF_MENU) {
|
||||
prompt("Prev. Simulation Mode")
|
||||
special(SPC_NOMOD)
|
||||
interest(4)
|
||||
menu(menuSimm)
|
||||
}
|
||||
field(SSCN,DBF_MENU) {
|
||||
prompt("Sim. Mode Scan")
|
||||
promptgroup("90 - Simulate")
|
||||
interest(1)
|
||||
menu(menuScan)
|
||||
initial("65535")
|
||||
}
|
||||
field(SDLY,DBF_DOUBLE) {
|
||||
prompt("Sim. Mode Async Delay")
|
||||
promptgroup("90 - Simulate")
|
||||
interest(2)
|
||||
initial("-1.0")
|
||||
}
|
||||
%#include "callback.h"
|
||||
field(SIMPVT,DBF_NOACCESS) {
|
||||
prompt("Sim. Mode Private")
|
||||
special(SPC_NOMOD)
|
||||
interest(4)
|
||||
extra("CALLBACK *simpvt")
|
||||
}
|
||||
|
||||
=head2 Record Support
|
||||
|
||||
=head3 Record Support Routines
|
||||
|
||||
=head2 C<init_record>
|
||||
|
||||
This routine initializes SIMM with the value of SIML if SIML type is a
|
||||
CONSTANT link or creates a channel access link if SIML type is PV_LINK.
|
||||
SVAL is likewise initialized if SIOL is a CONSTANT or PV_LINK.
|
||||
|
||||
This routine next checks to see that device support is available and a
|
||||
device support routine is defined. If neither exist, an error is issued and
|
||||
processing is terminated.
|
||||
|
||||
If device support includes C<init_record>, it is called.
|
||||
|
||||
=head2 C<process>
|
||||
|
||||
See next section.
|
||||
|
||||
=head2 C<get_value>
|
||||
|
||||
Fills in the values of struct valueDes so that they refer to VAL.
|
||||
|
||||
=head2 C<get_enum_str>
|
||||
|
||||
Retrieves ASCII string corresponding to VAL.
|
||||
|
||||
=head2 C<get_enum_strs>
|
||||
|
||||
Retrieves ASCII strings for ZNAM and ONAM.
|
||||
|
||||
=head2 C<put_enum_str>
|
||||
|
||||
Check if string matches ZNAM or ONAM, and if it does, sets VAL.
|
||||
|
||||
=head2 Record Processing
|
||||
|
||||
Routine process implements the following algorithm:
|
||||
|
||||
=over 1
|
||||
|
||||
=item 1.
|
||||
Check to see that the appropriate device support module exists. If it
|
||||
doesn't, an error message is issued and processing is terminated with
|
||||
the PACT field still set to TRUE. This ensures that processes will no
|
||||
longer be called for this record. Thus error storms will not occur.
|
||||
|
||||
=item 2.
|
||||
C<readValue> is called. See L<Input Records> for details.
|
||||
|
||||
=item 3.
|
||||
If PACT has been changed to TRUE, the device support read routine has
|
||||
started but has not completed reading a new input value. In this case, the
|
||||
processing routine merely returns, leaving PACT TRUE.
|
||||
|
||||
=item 4.
|
||||
Convert.
|
||||
|
||||
=back
|
||||
|
||||
=over 1
|
||||
|
||||
=item *
|
||||
status = read_bi
|
||||
|
||||
=item *
|
||||
PACT = TRUE
|
||||
|
||||
=item *
|
||||
TIME = tslocaltime
|
||||
|
||||
=item *
|
||||
if status is 0, then set VAL=(0,1) if RVAL is (0, not 0) and UDF = False.
|
||||
|
||||
=item *
|
||||
if status is 2, set status = 0
|
||||
|
||||
=back
|
||||
|
||||
=over 1
|
||||
|
||||
=item 5.
|
||||
Check alarms: This routine checks to see if the new VAL causes the alarm
|
||||
status and severity to change. If so, NSEV, NSTA and LALM are set. Note
|
||||
that if VAL is greater than 1, no checking is performed.
|
||||
|
||||
=item 6.
|
||||
Check if monitors should be invoked:
|
||||
|
||||
=back
|
||||
|
||||
=over 1
|
||||
|
||||
=item *
|
||||
Alarm monitors are invoked if the alarm status or severity has changed.
|
||||
|
||||
=item *
|
||||
Archive and value change monitors are invoked if MSLT is not equal to VAL.
|
||||
|
||||
=item *
|
||||
Monitors for RVAL are checked whenever other monitors are invoked.
|
||||
|
||||
=item *
|
||||
NSEV and NSTA are reset to 0.
|
||||
|
||||
=back
|
||||
|
||||
=over 1
|
||||
|
||||
=item 7.
|
||||
Scan forward link if necessary, set PACT FALSE, and return.
|
||||
|
||||
=back
|
||||
|
||||
=head2 Device Support
|
||||
|
||||
=head3 Fields of Interest to Device Support
|
||||
|
||||
Each binary input record must have an associated set of device support
|
||||
routines. The primary resposibility of the device support routines is to
|
||||
obtain a new raw input value whenever C<read_bi> is called. The device
|
||||
support routines are primarily interested in the following fields:
|
||||
|
||||
=fields PACT, DPVT, UDF, NSEV, NSTA, VAL, INP, RVAL, MASK
|
||||
|
||||
=head3 Device Support routines
|
||||
|
||||
Device support consists of the following routines:
|
||||
|
||||
=head2 C<report(FILE fp, paddr)>
|
||||
|
||||
Not currently used.
|
||||
|
||||
=head2 C<init()>
|
||||
|
||||
This routine is called once during IOC initialization.
|
||||
|
||||
=head2 C<init_record(precord)>
|
||||
|
||||
This routine is optional. If provided, it is called by the record support
|
||||
C<init_record> routine.
|
||||
|
||||
=head2 C<get_ioint_info(int cmd, struct dbCommon *precord, IOSCANPVT *ppvt)>
|
||||
|
||||
This routine is called by the C<ioEventScan> system each time the record is
|
||||
added or deleted from an I/O event scan list. C<cmd> has the value (0,1) if
|
||||
the record is being (added to, deleted from) and I/O event list. It must be
|
||||
provided for any device type that can use the ioEvent scanner.
|
||||
|
||||
=head2 C<read_bi(precord)>
|
||||
|
||||
This routine must provide a new input value. It returns the following
|
||||
values:
|
||||
|
||||
=over
|
||||
|
||||
=item 0:
|
||||
Success. A new raw value is placed in RVAL. The record support module
|
||||
forces VAL to be (0,1) if RVAL is (0, not 0).
|
||||
|
||||
=item 2:
|
||||
Success, but don't modify VAL.
|
||||
|
||||
=item Other:
|
||||
Error.
|
||||
|
||||
=back
|
||||
|
||||
=head3 Device Support for Soft Records
|
||||
|
||||
Two soft device support modules, Soft Channel and Raw Soft Channel, are
|
||||
provided for input records not related to actual hardware devices. The INP
|
||||
link type must be either CONSTANT, DB_LINK, or CA_LINK.
|
||||
|
||||
=head3 Soft Channel
|
||||
|
||||
C<read_bi> always returns a value of 2, which means that no conversion is
|
||||
performed.
|
||||
|
||||
If the INP link type is CONSTANT, then the constant value is stored in VAL
|
||||
by C<init_record>, and the UDF is set to FALSE. VAL can be changed via
|
||||
C<dbPut> requests. If the INP link type is PV_LINK, the C<dbCaAddInlink> is
|
||||
called by C<init_record>.
|
||||
|
||||
C<read_bi> calls C<recGbleGetLinkValue> to read the current value of VAL.
|
||||
See L<Soft Input> for details.
|
||||
|
||||
If the return status of C<recGblGetLinkValue> is zero, then C<read_bi> sets
|
||||
UDF to FALSE. The status of C<recGblGetLinkValue> is returned.
|
||||
|
||||
=head3 Raw Soft Channel
|
||||
|
||||
This module is like the previous except that values are read into RVAL.
|
||||
|
||||
C<read_bi> returns a value of 0. Thus the record processing routine will
|
||||
force VAL to be 0 or 1.
|
||||
|
||||
=cut
|
||||
}
|
@ -1,182 +0,0 @@
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
# National Laboratory.
|
||||
# Copyright (c) 2002 The Regents of the University of California, as
|
||||
# Operator of Los Alamos National Laboratory.
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
recordtype(bo) {
|
||||
include "dbCommon.dbd"
|
||||
field(VAL,DBF_ENUM) {
|
||||
prompt("Current Value")
|
||||
promptgroup("50 - Output")
|
||||
asl(ASL0)
|
||||
pp(TRUE)
|
||||
}
|
||||
field(OMSL,DBF_MENU) {
|
||||
prompt("Output Mode Select")
|
||||
promptgroup("50 - Output")
|
||||
interest(1)
|
||||
menu(menuOmsl)
|
||||
}
|
||||
field(DOL,DBF_INLINK) {
|
||||
prompt("Desired Output Loc")
|
||||
promptgroup("40 - Input")
|
||||
interest(1)
|
||||
}
|
||||
field(OUT,DBF_OUTLINK) {
|
||||
prompt("Output Specification")
|
||||
promptgroup("50 - Output")
|
||||
interest(1)
|
||||
}
|
||||
field(HIGH,DBF_DOUBLE) {
|
||||
prompt("Seconds to Hold High")
|
||||
promptgroup("30 - Action")
|
||||
interest(1)
|
||||
}
|
||||
field(ZNAM,DBF_STRING) {
|
||||
prompt("Zero Name")
|
||||
promptgroup("80 - Display")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
size(26)
|
||||
prop(YES)
|
||||
}
|
||||
field(ONAM,DBF_STRING) {
|
||||
prompt("One Name")
|
||||
promptgroup("80 - Display")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
size(26)
|
||||
prop(YES)
|
||||
}
|
||||
field(RVAL,DBF_ULONG) {
|
||||
prompt("Raw Value")
|
||||
pp(TRUE)
|
||||
}
|
||||
field(ORAW,DBF_ULONG) {
|
||||
prompt("prev Raw Value")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(MASK,DBF_ULONG) {
|
||||
prompt("Hardware Mask")
|
||||
special(SPC_NOMOD)
|
||||
interest(1)
|
||||
}
|
||||
field(RPVT,DBF_NOACCESS) {
|
||||
prompt("Record Private")
|
||||
special(SPC_NOMOD)
|
||||
interest(4)
|
||||
extra("void * rpvt")
|
||||
}
|
||||
field(WDPT,DBF_NOACCESS) {
|
||||
prompt("Watch Dog Timer ID")
|
||||
special(SPC_NOMOD)
|
||||
interest(4)
|
||||
extra("void * wdpt")
|
||||
}
|
||||
field(ZSV,DBF_MENU) {
|
||||
prompt("Zero Error Severity")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
menu(menuAlarmSevr)
|
||||
}
|
||||
field(OSV,DBF_MENU) {
|
||||
prompt("One Error Severity")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
menu(menuAlarmSevr)
|
||||
}
|
||||
field(COSV,DBF_MENU) {
|
||||
prompt("Change of State Sevr")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
menu(menuAlarmSevr)
|
||||
}
|
||||
field(RBV,DBF_ULONG) {
|
||||
prompt("Readback Value")
|
||||
special(SPC_NOMOD)
|
||||
}
|
||||
field(ORBV,DBF_ULONG) {
|
||||
prompt("Prev Readback Value")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(MLST,DBF_USHORT) {
|
||||
prompt("Last Value Monitored")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(LALM,DBF_USHORT) {
|
||||
prompt("Last Value Alarmed")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(SIOL,DBF_OUTLINK) {
|
||||
prompt("Simulation Output Link")
|
||||
promptgroup("90 - Simulate")
|
||||
interest(1)
|
||||
}
|
||||
field(SIML,DBF_INLINK) {
|
||||
prompt("Simulation Mode Link")
|
||||
promptgroup("90 - Simulate")
|
||||
interest(1)
|
||||
}
|
||||
field(SIMM,DBF_MENU) {
|
||||
prompt("Simulation Mode")
|
||||
special(SPC_MOD)
|
||||
interest(1)
|
||||
menu(menuYesNo)
|
||||
}
|
||||
field(SIMS,DBF_MENU) {
|
||||
prompt("Simulation Mode Severity")
|
||||
promptgroup("90 - Simulate")
|
||||
interest(2)
|
||||
menu(menuAlarmSevr)
|
||||
}
|
||||
field(OLDSIMM,DBF_MENU) {
|
||||
prompt("Prev. Simulation Mode")
|
||||
special(SPC_NOMOD)
|
||||
interest(4)
|
||||
menu(menuSimm)
|
||||
}
|
||||
field(SSCN,DBF_MENU) {
|
||||
prompt("Sim. Mode Scan")
|
||||
promptgroup("90 - Simulate")
|
||||
interest(1)
|
||||
menu(menuScan)
|
||||
initial("65535")
|
||||
}
|
||||
field(SDLY,DBF_DOUBLE) {
|
||||
prompt("Sim. Mode Async Delay")
|
||||
promptgroup("90 - Simulate")
|
||||
interest(2)
|
||||
initial("-1.0")
|
||||
}
|
||||
%#include "callback.h"
|
||||
field(SIMPVT,DBF_NOACCESS) {
|
||||
prompt("Sim. Mode Private")
|
||||
special(SPC_NOMOD)
|
||||
interest(4)
|
||||
extra("CALLBACK *simpvt")
|
||||
}
|
||||
field(IVOA,DBF_MENU) {
|
||||
prompt("INVALID outpt action")
|
||||
promptgroup("50 - Output")
|
||||
interest(2)
|
||||
menu(menuIvoa)
|
||||
}
|
||||
field(IVOV,DBF_USHORT) {
|
||||
prompt("INVALID output value")
|
||||
promptgroup("50 - Output")
|
||||
interest(2)
|
||||
}
|
||||
}
|
||||
|
||||
variable(boHIGHprecision, int)
|
||||
variable(boHIGHlimit, double)
|
611
modules/database/src/std/rec/boRecord.dbd.pod
Normal file
611
modules/database/src/std/rec/boRecord.dbd.pod
Normal file
@ -0,0 +1,611 @@
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
# National Laboratory.
|
||||
# Copyright (c) 2002 The Regents of the University of California, as
|
||||
# Operator of Los Alamos National Laboratory.
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
|
||||
=title Binary Output Record (bo)
|
||||
|
||||
The normal use for this record type is to store a simple bit (0 or 1) value
|
||||
to be sent to a Digital Output module. It can also be used to write binary
|
||||
values into other records via database or channel access links. This record
|
||||
can implement both latched and momentary binary outputs depending on how
|
||||
the HIGH field is configured.
|
||||
|
||||
=head2 Parameter Fields
|
||||
|
||||
The binary output's fields fall into the following categories:
|
||||
|
||||
=over 1
|
||||
|
||||
=item *
|
||||
scan parameters
|
||||
|
||||
=item *
|
||||
convert and write parameters
|
||||
|
||||
=item *
|
||||
operator display parameters
|
||||
|
||||
=item *
|
||||
alarm parameters
|
||||
|
||||
=item *
|
||||
run-time parameters
|
||||
|
||||
=back
|
||||
|
||||
=recordtype bo
|
||||
|
||||
=cut
|
||||
|
||||
recordtype(bo) {
|
||||
|
||||
=head3 Scan Parameters
|
||||
|
||||
The binary output record has the standard fields for specifying under what
|
||||
circumstances the record will be processed. The fields are listed in
|
||||
L<Scan Fields>. In addition, L<Scanning Specification> explains how these
|
||||
fields are used. Note that I/O event scanning is only supported for those card
|
||||
types that interrupt.
|
||||
|
||||
=fields SCAN
|
||||
|
||||
=head3 Desired Output Parameters
|
||||
|
||||
The binary output record must specify where its desired output originates.
|
||||
The desired output needs to be in engineering units.
|
||||
|
||||
The first field that determines where the desired output originates is the
|
||||
output mode select (OMSL) field, which can have two possible values:
|
||||
C<losed_loop> or C<supervisory>. If C<supervisory> is specified, the value
|
||||
in the VAL field can be set externally via dbPuts at run-time. If
|
||||
C<closed_loop> is specified, the VAL field's value is obtained from the
|
||||
address specified in the desired output location (DOL) field which can be a
|
||||
database link, a channel access link, or a constant. To achieve continuous
|
||||
control, a database link to a control algorithm record should be entered in
|
||||
the DOL field.
|
||||
|
||||
L<Address Specification> presents more information on database addresses
|
||||
and links. L<Scanning Specification> explaines the effect of database
|
||||
linkage on scanning.
|
||||
|
||||
=fields DOL, OMSL
|
||||
|
||||
=head3 Convert and Write Parameters
|
||||
|
||||
These parameters are used to determine where the binary output writes to
|
||||
and how to convert the engineering units to a raw signal. After VAL is set
|
||||
and forced to be either 1 or 0, as the result of either a dbPut or a new
|
||||
value being retrieved from the link in the DOL field, then what happens
|
||||
next depends on which device support routine is used and how the HIGH field
|
||||
is configured.
|
||||
|
||||
If the C<Soft Channel> device support routine is specified, then the device
|
||||
support routine writes the VAL field's value to the address specified in
|
||||
the OUT field. Otherwise, RVAL is the value written by the device support
|
||||
routines after being converted.
|
||||
|
||||
If VAL is equal to 0, then the record processing routine sets RVAL equal to
|
||||
zero. When VAL is not equal to 0, then RVAL is set equal to the value
|
||||
contained in the MASK field. (MASK is set by the device support routines
|
||||
and is of no concern to the user.) Also, when VAL is not 0 and after RVAL is
|
||||
set equal to MASK, the record processing routine checks to see if the HIGH
|
||||
field is greater than 0. If it is, then the routine will process the record
|
||||
again with VAL set to 0 after the number of seconds specified by HIGH.
|
||||
Thus, HIGH implements a momentary output which changes the state of the
|
||||
device back to 0 after I<N> number of seconds.
|
||||
|
||||
=fields DTYP, OUT, VAL, RVAL, HIGH, ZNAM, ONAM
|
||||
|
||||
=head3 Conversion Parameters
|
||||
|
||||
The ZNAM field has the string that corresponds to the 0 state, and the ONAM
|
||||
field holds the string that corresponds to the 1 state. These fields, other
|
||||
than being used to tell the operator what each state represents, are used
|
||||
to perform conversions if the value fetched by DOL is a string. If it is,
|
||||
VAL is set to the state which corresponds to that string. For instance, if the
|
||||
value fetched is the string "Off" and the ZNAM string is "Off," then VAL is
|
||||
set to 0.
|
||||
|
||||
After VAL is set, if VAL is equal to 0, then the record processing routine
|
||||
sets RVAL equal to zero. When VAL is not equal to 0, then RVAL is set equal
|
||||
to the value contained in the MASK field. (Mask is set by the device
|
||||
support routines and is of no concern to the user.) Also when VAL is equal
|
||||
to 1 and after RVAL is set equal to MASK, the record processing routine checks
|
||||
to see if the HIGH field is greater than 0. If it is, then the routine
|
||||
processes the record again with VAL=0 after the number of seconds specified
|
||||
by HIGH. Thus, HIGH implements a latched output which changes the state of
|
||||
the device or link to 1, then changes it back to 0 after I<N> number of seconds.
|
||||
|
||||
=fields ZNAM, ONAM, HIGH
|
||||
|
||||
=head3 Output Specification
|
||||
|
||||
The OUT field specifies where the binary output record writes its output.
|
||||
It must specify the address of an I/O card if the record sends its output
|
||||
to hardware, and the DTYP field must contain the corresponding device
|
||||
support module. Be aware that the address format differs according to the
|
||||
I/O bus used. See L<Address Specification> for information on the format of
|
||||
hardware addresses. You can see a list of device support modules currently
|
||||
supported at the user's local site by using the C<dbst> utility in R3.13.
|
||||
|
||||
Otherwise, if the record is configured to use the soft device support
|
||||
modules, then it can be either a database link, a channel access link, or a
|
||||
constant. Be aware that nothing will be written when OUT is a constant. See
|
||||
L<Address Specification> for information on the format of the database and
|
||||
channel access addresses. Also, see L<Device Support For Soft Records> in
|
||||
this chapter for more on output to other records.
|
||||
|
||||
=head3 Operator Display Parameters
|
||||
|
||||
These parameters are used to present meaningful data to the operator, The
|
||||
C<get_enum_str> record support routine can retrieve the state string
|
||||
corresponding to the VAL's state. So, if the value is 1, C<get_enum_str>
|
||||
will return the string in the ONAM field: and if 0, C<get_enum_str> will
|
||||
return the ZNAM string.
|
||||
|
||||
See L<Fields Common to All Record Types> for more on the record name (NAME)
|
||||
and description (DESC) fields.
|
||||
|
||||
=fields ZNAM, ONAM, NAME, DESC
|
||||
|
||||
=head3 Alarm Parameters
|
||||
|
||||
These parameters are used to determine the binary output's alarm condition
|
||||
and to determine the severity of that condition. The possible alarm
|
||||
conditions for binary outputs are the SCAN, READ, INVALID and state alarms.
|
||||
The user can configure the state alarm conditions using these fields.
|
||||
|
||||
The possible values for these fields are C<NO_ALARM>, C<MINOR>, and
|
||||
C<MAJOR>. The ZSV holds the severity for the zero state; OSV for the one
|
||||
state. COSV is used to cause an alarm whenever the state changes between
|
||||
states (0-1, 1-0) and its severity is configured as MINOR or MAJOR.
|
||||
|
||||
See L<Invalid Alarm Output Action> for more information on the IVOA and
|
||||
IVOV fields. L<Alarm Fields> lists other fields related to alarms that are
|
||||
common to all record types.
|
||||
|
||||
=fields ZSV, OSV, COSV, IVOA, IVOV
|
||||
|
||||
=head3 Run-Time and Simulation Mode Parameters
|
||||
|
||||
These parameters are used by the run-time code for processiong the binary
|
||||
output. They are not configurable using a configuration tool. They
|
||||
represent the current state of the binary output.
|
||||
|
||||
ORAW is used to determine if monitors should be triggered for RVAL at the
|
||||
same time they are triggered for VAL.
|
||||
|
||||
MASK is given a value by the device support routines and should not concern
|
||||
the user.
|
||||
|
||||
The RBV field is also set by device support. It is the actual read back
|
||||
value obtained from the hardware itself or from the associated device
|
||||
driver.
|
||||
|
||||
The ORBV field is used to decide if monitors should be triggered
|
||||
for RBV at the same time monitors are triggered for changes in VAL.
|
||||
|
||||
The LALM field holds the value of the last occurrence of the change of
|
||||
state alarm. It is used to implement the change of state alarm, and thus
|
||||
only has meaning if COSV is MINOR or MAJOR.
|
||||
|
||||
The MLST is used by the C<process> record support routine to determine if
|
||||
archive and value change monitors are invoked. They are if MLST is not
|
||||
equal to VAL.
|
||||
|
||||
The WPDT field is a private field for honoring seconds to hold HIGH.
|
||||
|
||||
=fields ORAW, MASK, RBV, ORBV, LALM, MLST, RPVT, WDPT
|
||||
|
||||
The following fields are used to operate the binary output in the
|
||||
simulation mode. See L<Fields Common to Many Record Types> for more
|
||||
information on these fields.
|
||||
|
||||
=fields SIOL, SIML, SIMM, SIMS
|
||||
|
||||
=cut
|
||||
|
||||
include "dbCommon.dbd"
|
||||
field(VAL,DBF_ENUM) {
|
||||
prompt("Current Value")
|
||||
promptgroup("50 - Output")
|
||||
asl(ASL0)
|
||||
pp(TRUE)
|
||||
}
|
||||
field(OMSL,DBF_MENU) {
|
||||
prompt("Output Mode Select")
|
||||
promptgroup("50 - Output")
|
||||
interest(1)
|
||||
menu(menuOmsl)
|
||||
}
|
||||
field(DOL,DBF_INLINK) {
|
||||
prompt("Desired Output Loc")
|
||||
promptgroup("40 - Input")
|
||||
interest(1)
|
||||
}
|
||||
field(OUT,DBF_OUTLINK) {
|
||||
prompt("Output Specification")
|
||||
promptgroup("50 - Output")
|
||||
interest(1)
|
||||
}
|
||||
field(HIGH,DBF_DOUBLE) {
|
||||
prompt("Seconds to Hold High")
|
||||
promptgroup("30 - Action")
|
||||
interest(1)
|
||||
}
|
||||
field(ZNAM,DBF_STRING) {
|
||||
prompt("Zero Name")
|
||||
promptgroup("80 - Display")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
size(26)
|
||||
prop(YES)
|
||||
}
|
||||
field(ONAM,DBF_STRING) {
|
||||
prompt("One Name")
|
||||
promptgroup("80 - Display")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
size(26)
|
||||
prop(YES)
|
||||
}
|
||||
field(RVAL,DBF_ULONG) {
|
||||
prompt("Raw Value")
|
||||
pp(TRUE)
|
||||
}
|
||||
field(ORAW,DBF_ULONG) {
|
||||
prompt("prev Raw Value")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(MASK,DBF_ULONG) {
|
||||
prompt("Hardware Mask")
|
||||
special(SPC_NOMOD)
|
||||
interest(1)
|
||||
}
|
||||
field(RPVT,DBF_NOACCESS) {
|
||||
prompt("Record Private")
|
||||
special(SPC_NOMOD)
|
||||
interest(4)
|
||||
extra("void * rpvt")
|
||||
}
|
||||
field(WDPT,DBF_NOACCESS) {
|
||||
prompt("Watch Dog Timer ID")
|
||||
special(SPC_NOMOD)
|
||||
interest(4)
|
||||
extra("void * wdpt")
|
||||
}
|
||||
field(ZSV,DBF_MENU) {
|
||||
prompt("Zero Error Severity")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
menu(menuAlarmSevr)
|
||||
}
|
||||
field(OSV,DBF_MENU) {
|
||||
prompt("One Error Severity")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
menu(menuAlarmSevr)
|
||||
}
|
||||
field(COSV,DBF_MENU) {
|
||||
prompt("Change of State Sevr")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
menu(menuAlarmSevr)
|
||||
}
|
||||
field(RBV,DBF_ULONG) {
|
||||
prompt("Readback Value")
|
||||
special(SPC_NOMOD)
|
||||
}
|
||||
field(ORBV,DBF_ULONG) {
|
||||
prompt("Prev Readback Value")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(MLST,DBF_USHORT) {
|
||||
prompt("Last Value Monitored")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(LALM,DBF_USHORT) {
|
||||
prompt("Last Value Alarmed")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(SIOL,DBF_OUTLINK) {
|
||||
prompt("Simulation Output Link")
|
||||
promptgroup("90 - Simulate")
|
||||
interest(1)
|
||||
}
|
||||
field(SIML,DBF_INLINK) {
|
||||
prompt("Simulation Mode Link")
|
||||
promptgroup("90 - Simulate")
|
||||
interest(1)
|
||||
}
|
||||
field(SIMM,DBF_MENU) {
|
||||
prompt("Simulation Mode")
|
||||
special(SPC_MOD)
|
||||
interest(1)
|
||||
menu(menuYesNo)
|
||||
}
|
||||
field(SIMS,DBF_MENU) {
|
||||
prompt("Simulation Mode Severity")
|
||||
promptgroup("90 - Simulate")
|
||||
interest(2)
|
||||
menu(menuAlarmSevr)
|
||||
}
|
||||
field(OLDSIMM,DBF_MENU) {
|
||||
prompt("Prev. Simulation Mode")
|
||||
special(SPC_NOMOD)
|
||||
interest(4)
|
||||
menu(menuSimm)
|
||||
}
|
||||
field(SSCN,DBF_MENU) {
|
||||
prompt("Sim. Mode Scan")
|
||||
promptgroup("90 - Simulate")
|
||||
interest(1)
|
||||
menu(menuScan)
|
||||
initial("65535")
|
||||
}
|
||||
field(SDLY,DBF_DOUBLE) {
|
||||
prompt("Sim. Mode Async Delay")
|
||||
promptgroup("90 - Simulate")
|
||||
interest(2)
|
||||
initial("-1.0")
|
||||
}
|
||||
%#include "callback.h"
|
||||
field(SIMPVT,DBF_NOACCESS) {
|
||||
prompt("Sim. Mode Private")
|
||||
special(SPC_NOMOD)
|
||||
interest(4)
|
||||
extra("CALLBACK *simpvt")
|
||||
}
|
||||
field(IVOA,DBF_MENU) {
|
||||
prompt("INVALID outpt action")
|
||||
promptgroup("50 - Output")
|
||||
interest(2)
|
||||
menu(menuIvoa)
|
||||
}
|
||||
field(IVOV,DBF_USHORT) {
|
||||
prompt("INVALID output value")
|
||||
promptgroup("50 - Output")
|
||||
interest(2)
|
||||
}
|
||||
|
||||
|
||||
=head2 Record Support
|
||||
|
||||
=head3 Record Support Routines
|
||||
|
||||
=head2 C<init_record>
|
||||
|
||||
This routine initializes SIMM if SIML is a constant or creates a channel
|
||||
access link if SIML is PV_LINK. If SIOL is a PV_LINK a channel access link
|
||||
is created.
|
||||
|
||||
This routine next checks to see that device support is available. The
|
||||
routine next checks to see if the device support write routine is defined.
|
||||
|
||||
If either device support or the device support write routine does not
|
||||
exist, and error message is issued and processing is terminated.
|
||||
|
||||
If DOL is a constant, then VAL is initialized to 1 if its value is nonzero
|
||||
or initialzed to 0 if DOL is zero, and UDF is set to FALSE.
|
||||
|
||||
If device support includes C<init_record>, it is called. VAL is set using
|
||||
RVAL, and UDF is set to FALSE.
|
||||
|
||||
=head2 C<process>
|
||||
|
||||
See next section.
|
||||
|
||||
=head2 C<get_value>
|
||||
|
||||
Fills in the values of struct valueDes so that they refer to VAL.
|
||||
|
||||
=head2 C<get_enum_str>
|
||||
|
||||
Retrieves ASCII string corresponding to VAL.
|
||||
|
||||
=head2 C<get_enum_strs>
|
||||
|
||||
Retrieves ASCII strings for ZNAM and ONAM.
|
||||
|
||||
=head2 C<put_enum_str>
|
||||
|
||||
Checks if string matches ZNAM or ONAM, and if it does, sets VAL.
|
||||
|
||||
=head2 Record Processing
|
||||
|
||||
Routine process implements the following algorithm:
|
||||
|
||||
=over 1
|
||||
|
||||
=item 1.
|
||||
Check to see that the appropriate device support module exists. If it
|
||||
doesn't, an error message is issued and processing is terminated with
|
||||
the PACT field still set to TRUE. This ensures that processes will no
|
||||
longer be called for this record. Thus error storms will not occur.
|
||||
|
||||
=item 2.
|
||||
If PACT is FALSE
|
||||
|
||||
=back
|
||||
|
||||
=over
|
||||
|
||||
=item *
|
||||
If DOL is DB_LINK and OMSL is CLOSED_LOOP
|
||||
|
||||
=over
|
||||
|
||||
=item *
|
||||
get values from DOL
|
||||
|
||||
=item *
|
||||
check for link alarm
|
||||
|
||||
=item *
|
||||
force VAL to be 0 or 1
|
||||
|
||||
=item *
|
||||
if MASK is defined
|
||||
|
||||
=over
|
||||
|
||||
=item *
|
||||
if VAL is 0 set RVAL = 0
|
||||
|
||||
=back
|
||||
|
||||
=item *
|
||||
else set RVAL = MASK
|
||||
|
||||
=back
|
||||
|
||||
=back
|
||||
|
||||
=over
|
||||
|
||||
=item 3.
|
||||
Check alarms: This routine checks to see if the new VAL causes the alarm
|
||||
status and severity to change. If so, NSEV, NSTA, and LALM are set.
|
||||
|
||||
=item 4.
|
||||
Check severity and write the new value. See L<Invalid Alarm Output Action>
|
||||
for more information on how INVALID alarms affect output.
|
||||
|
||||
=item 5.
|
||||
If PACT has been changed to TRUE, the device support write output routine
|
||||
has started but has not completed writing the new value. in this case, the
|
||||
processing routine merely returns, leaving PACT TRUE.
|
||||
|
||||
=item 6.
|
||||
Check WAIT. If VAL is 1 and WAIT is greater than 0, process again with a
|
||||
VAL=0 after WAIT seconds.
|
||||
|
||||
=item 7.
|
||||
Check to see if monitors should be invoked.
|
||||
|
||||
=back
|
||||
|
||||
=over 1
|
||||
|
||||
=item *
|
||||
Alarm monitors are invoked if the alarm status or severity has changed.
|
||||
|
||||
=item *
|
||||
Archive and value change monitors are invoked if MLST is not equal to VAL.
|
||||
|
||||
=item *
|
||||
Monitors for RVAL and for RBV are checked whenever other monitors are
|
||||
invoked.
|
||||
|
||||
=item *
|
||||
NSEV and NSTA are reset to 0.
|
||||
|
||||
=back
|
||||
|
||||
=over
|
||||
|
||||
=item 8
|
||||
Scan forward link if necessary, set PACT FALSE, and return
|
||||
|
||||
=back
|
||||
|
||||
=head2 Device support
|
||||
|
||||
=head3 Fields Of Interest To Device Support
|
||||
|
||||
Each binary output record must have an associated set of device support
|
||||
routines. The primary responsibility of the device support routines is to
|
||||
write a new value whenever C<write_bo> is called. The device support routines
|
||||
are primarily interested in the following fields:
|
||||
|
||||
=fields PACT, DPVT, NSEV, NSTA, VAL, OUT, RVAL, MASK, RBV
|
||||
|
||||
=head3 Decive Support Routines
|
||||
|
||||
Device support consists of the following routines:
|
||||
|
||||
=head2 C<report(FILE fp, paddr)>
|
||||
|
||||
Not currently used.
|
||||
|
||||
=head2 C<init()>
|
||||
|
||||
This routine is called once during IOC initialization.
|
||||
|
||||
=head2 C<init_record(precord)>
|
||||
|
||||
This routine is optional. If provided, it is called by record support
|
||||
C<init_record> routine. It should determine MASK if it is needed.
|
||||
|
||||
=over
|
||||
|
||||
=item *
|
||||
0: Success. RVAL modified (VAL will be set accordingly)
|
||||
|
||||
=item *
|
||||
2: Success. VAL modified
|
||||
|
||||
=item *
|
||||
other: Error
|
||||
|
||||
=back
|
||||
|
||||
=head2 C<get_ioint_info(int cmd, struct dbCommon *precord, IOSCANPVT *ppvt)>
|
||||
|
||||
This routine is called by the ioEventScan system each time the record is
|
||||
added or deleted from an I/O event scan list. C<cmd> has the value (0,1) if
|
||||
the record is being (added to, deleted from) an I/O event list. It must be
|
||||
provided for any device type that can use the ioEvent scanner.
|
||||
|
||||
=head2 C<write_bo(precord)>
|
||||
|
||||
This routine must output a new value. It returns the following values:
|
||||
|
||||
=over
|
||||
|
||||
=item *
|
||||
0: Success
|
||||
|
||||
=item *
|
||||
other: Error.
|
||||
|
||||
=back
|
||||
|
||||
=head2 Device Support For Soft Records
|
||||
|
||||
Two soft device support modules C<Soft Channel> and C<Raw Soft Channel> are
|
||||
provided for output records not related to actual hardware devices. The OUT
|
||||
link type must be either CONSTANT, DB_LINK, or CA_LINK.
|
||||
|
||||
=head3 Soft Channel
|
||||
|
||||
This module writes the current value of VAL.
|
||||
|
||||
If the OUT link type is PV_LINK, then C<dbCaAddInlink> is called by
|
||||
C<init_record>. C<init_record> always returns a value of 2, which means
|
||||
that no conversion will ever be attempted. C<write_bo> calls
|
||||
C<recGblPutLinkValue> to write the current value of VAL. See L<Soft Output>
|
||||
for details.
|
||||
|
||||
=head3 Raw Soft Channel
|
||||
|
||||
This module is like the previous except that it writes the current value of
|
||||
RVAL
|
||||
|
||||
=cut
|
||||
}
|
||||
|
||||
variable(boHIGHprecision, int)
|
||||
variable(boHIGHlimit, double)
|
@ -1,324 +0,0 @@
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2007 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.
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
recordtype(calc) {
|
||||
include "dbCommon.dbd"
|
||||
field(VAL,DBF_DOUBLE) {
|
||||
prompt("Result")
|
||||
promptgroup("50 - Output")
|
||||
asl(ASL0)
|
||||
}
|
||||
field(CALC,DBF_STRING) {
|
||||
prompt("Calculation")
|
||||
promptgroup("30 - Action")
|
||||
special(SPC_CALC)
|
||||
pp(TRUE)
|
||||
size(80)
|
||||
initial("0")
|
||||
}
|
||||
field(INPA,DBF_INLINK) {
|
||||
prompt("Input A")
|
||||
promptgroup("41 - Input A-F")
|
||||
interest(1)
|
||||
}
|
||||
field(INPB,DBF_INLINK) {
|
||||
prompt("Input B")
|
||||
promptgroup("41 - Input A-F")
|
||||
interest(1)
|
||||
}
|
||||
field(INPC,DBF_INLINK) {
|
||||
prompt("Input C")
|
||||
promptgroup("41 - Input A-F")
|
||||
interest(1)
|
||||
}
|
||||
field(INPD,DBF_INLINK) {
|
||||
prompt("Input D")
|
||||
promptgroup("41 - Input A-F")
|
||||
interest(1)
|
||||
}
|
||||
field(INPE,DBF_INLINK) {
|
||||
prompt("Input E")
|
||||
promptgroup("41 - Input A-F")
|
||||
interest(1)
|
||||
}
|
||||
field(INPF,DBF_INLINK) {
|
||||
prompt("Input F")
|
||||
promptgroup("41 - Input A-F")
|
||||
interest(1)
|
||||
}
|
||||
field(INPG,DBF_INLINK) {
|
||||
prompt("Input G")
|
||||
promptgroup("42 - Input G-L")
|
||||
interest(1)
|
||||
}
|
||||
field(INPH,DBF_INLINK) {
|
||||
prompt("Input H")
|
||||
promptgroup("42 - Input G-L")
|
||||
interest(1)
|
||||
}
|
||||
field(INPI,DBF_INLINK) {
|
||||
prompt("Input I")
|
||||
promptgroup("42 - Input G-L")
|
||||
interest(1)
|
||||
}
|
||||
field(INPJ,DBF_INLINK) {
|
||||
prompt("Input J")
|
||||
promptgroup("42 - Input G-L")
|
||||
interest(1)
|
||||
}
|
||||
field(INPK,DBF_INLINK) {
|
||||
prompt("Input K")
|
||||
promptgroup("42 - Input G-L")
|
||||
interest(1)
|
||||
}
|
||||
field(INPL,DBF_INLINK) {
|
||||
prompt("Input L")
|
||||
promptgroup("42 - Input G-L")
|
||||
interest(1)
|
||||
}
|
||||
field(EGU,DBF_STRING) {
|
||||
prompt("Engineering Units")
|
||||
promptgroup("80 - Display")
|
||||
interest(1)
|
||||
size(16)
|
||||
prop(YES)
|
||||
}
|
||||
field(PREC,DBF_SHORT) {
|
||||
prompt("Display Precision")
|
||||
promptgroup("80 - Display")
|
||||
interest(1)
|
||||
prop(YES)
|
||||
}
|
||||
field(HOPR,DBF_DOUBLE) {
|
||||
prompt("High Operating Rng")
|
||||
promptgroup("80 - Display")
|
||||
interest(1)
|
||||
prop(YES)
|
||||
}
|
||||
field(LOPR,DBF_DOUBLE) {
|
||||
prompt("Low Operating Range")
|
||||
promptgroup("80 - Display")
|
||||
interest(1)
|
||||
prop(YES)
|
||||
}
|
||||
field(HIHI,DBF_DOUBLE) {
|
||||
prompt("Hihi Alarm Limit")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
prop(YES)
|
||||
}
|
||||
field(LOLO,DBF_DOUBLE) {
|
||||
prompt("Lolo Alarm Limit")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
prop(YES)
|
||||
}
|
||||
field(HIGH,DBF_DOUBLE) {
|
||||
prompt("High Alarm Limit")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
prop(YES)
|
||||
}
|
||||
field(LOW,DBF_DOUBLE) {
|
||||
prompt("Low Alarm Limit")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
prop(YES)
|
||||
}
|
||||
field(HHSV,DBF_MENU) {
|
||||
prompt("Hihi Severity")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
prop(YES)
|
||||
menu(menuAlarmSevr)
|
||||
}
|
||||
field(LLSV,DBF_MENU) {
|
||||
prompt("Lolo Severity")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
prop(YES)
|
||||
menu(menuAlarmSevr)
|
||||
}
|
||||
field(HSV,DBF_MENU) {
|
||||
prompt("High Severity")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
prop(YES)
|
||||
menu(menuAlarmSevr)
|
||||
}
|
||||
field(LSV,DBF_MENU) {
|
||||
prompt("Low Severity")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
prop(YES)
|
||||
menu(menuAlarmSevr)
|
||||
}
|
||||
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)
|
||||
}
|
||||
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(A,DBF_DOUBLE) {
|
||||
prompt("Value of Input A")
|
||||
pp(TRUE)
|
||||
}
|
||||
field(B,DBF_DOUBLE) {
|
||||
prompt("Value of Input B")
|
||||
pp(TRUE)
|
||||
}
|
||||
field(C,DBF_DOUBLE) {
|
||||
prompt("Value of Input C")
|
||||
pp(TRUE)
|
||||
}
|
||||
field(D,DBF_DOUBLE) {
|
||||
prompt("Value of Input D")
|
||||
pp(TRUE)
|
||||
}
|
||||
field(E,DBF_DOUBLE) {
|
||||
prompt("Value of Input E")
|
||||
pp(TRUE)
|
||||
}
|
||||
field(F,DBF_DOUBLE) {
|
||||
prompt("Value of Input F")
|
||||
pp(TRUE)
|
||||
}
|
||||
field(G,DBF_DOUBLE) {
|
||||
prompt("Value of Input G")
|
||||
pp(TRUE)
|
||||
}
|
||||
field(H,DBF_DOUBLE) {
|
||||
prompt("Value of Input H")
|
||||
pp(TRUE)
|
||||
}
|
||||
field(I,DBF_DOUBLE) {
|
||||
prompt("Value of Input I")
|
||||
pp(TRUE)
|
||||
}
|
||||
field(J,DBF_DOUBLE) {
|
||||
prompt("Value of Input J")
|
||||
pp(TRUE)
|
||||
}
|
||||
field(K,DBF_DOUBLE) {
|
||||
prompt("Value of Input K")
|
||||
pp(TRUE)
|
||||
}
|
||||
field(L,DBF_DOUBLE) {
|
||||
prompt("Value of Input L")
|
||||
pp(TRUE)
|
||||
}
|
||||
field(LA,DBF_DOUBLE) {
|
||||
prompt("Prev Value of A")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(LB,DBF_DOUBLE) {
|
||||
prompt("Prev Value of B")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(LC,DBF_DOUBLE) {
|
||||
prompt("Prev Value of C")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(LD,DBF_DOUBLE) {
|
||||
prompt("Prev Value of D")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(LE,DBF_DOUBLE) {
|
||||
prompt("Prev Value of E")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(LF,DBF_DOUBLE) {
|
||||
prompt("Prev Value of F")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(LG,DBF_DOUBLE) {
|
||||
prompt("Prev Value of G")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(LH,DBF_DOUBLE) {
|
||||
prompt("Prev Value of H")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(LI,DBF_DOUBLE) {
|
||||
prompt("Prev Value of I")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(LJ,DBF_DOUBLE) {
|
||||
prompt("Prev Value of J")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(LK,DBF_DOUBLE) {
|
||||
prompt("Prev Value of K")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(LL,DBF_DOUBLE) {
|
||||
prompt("Prev Value of L")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
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)
|
||||
}
|
||||
%#include "postfix.h"
|
||||
field(RPCL,DBF_NOACCESS) {
|
||||
prompt("Reverse Polish Calc")
|
||||
special(SPC_NOMOD)
|
||||
interest(4)
|
||||
extra("char rpcl[INFIX_TO_POSTFIX_SIZE(80)]")
|
||||
}
|
||||
}
|
948
modules/database/src/std/rec/calcRecord.dbd.pod
Normal file
948
modules/database/src/std/rec/calcRecord.dbd.pod
Normal file
@ -0,0 +1,948 @@
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2007 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.
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
|
||||
=title Calculation Record (calc)
|
||||
|
||||
The calculation or "Calc" record is used to perform algebraic, relational,
|
||||
and logical operations on values retrieved from other records. The result
|
||||
of its operations can then be accessed by another record so that it can
|
||||
then be used.
|
||||
|
||||
=head2 Parameter Fields
|
||||
|
||||
The fields in the record fall into the following categories:
|
||||
|
||||
=over 1
|
||||
|
||||
=item *
|
||||
scan parameters
|
||||
|
||||
=item *
|
||||
read parameters
|
||||
|
||||
=item *
|
||||
expression parameters
|
||||
|
||||
=item *
|
||||
operator display parameters
|
||||
|
||||
=item *
|
||||
alarm parameters
|
||||
|
||||
=item *
|
||||
monitor parameters
|
||||
|
||||
=item *
|
||||
run-time parameters
|
||||
|
||||
=back
|
||||
|
||||
=recordtype calc
|
||||
|
||||
=cut
|
||||
|
||||
recordtype(calc) {
|
||||
|
||||
=head3 Scan Parameters
|
||||
|
||||
The Calc record has the standard fields for specifying under what
|
||||
circumstances the record will be processed. These fields are listed in
|
||||
L<Scan Fields>. In addition, L<Scanning Specification> explains how these
|
||||
fields are used. Since the Calc record supports no direct interfaces to
|
||||
hardware, it cannot be scanned on I/O interrupt, so its SCAN field cannot
|
||||
be C<I/O Intr>.
|
||||
|
||||
=fields SCAN
|
||||
|
||||
|
||||
=head3 Read Parameters
|
||||
|
||||
The read parameters for the Calc record consist of 12 input links INPA,
|
||||
INPB, ... INPL. The fields can be database links, channel access links, or
|
||||
constants. If they are links, they must specify another record's field or a
|
||||
channel access link. If they are constants, they will be initialized with
|
||||
the value they are configured with and can be changed via C<dbPuts>. They
|
||||
cannot be hardware addresses.
|
||||
|
||||
See L<Address Specification> for information on how to specify database
|
||||
links.
|
||||
|
||||
=fields INPA, INPB, INPC, INPD, INPE, INPF, INPG, INPH, INPI, INPJ, INPK, INPL
|
||||
|
||||
=head3 Expression
|
||||
|
||||
At the core of the Calc record lies the CALC and RPCL fields. The CALC field
|
||||
contains the infix expresion which the record routine will use when it
|
||||
processes the record. The resulting value is placed in the VAL field and
|
||||
can be accessed from there. The CALC expression is actually converted to
|
||||
opcode and stored as Reverse Polish Notation in the RPCL field. It is this
|
||||
expression which is actually used to calculate VAL. The Reverse Polish
|
||||
expression is evaluated more efficiently during run-time than an infix
|
||||
expression. CALC can be changed at run-time, and a special record routine
|
||||
calls a function to convert it to Reverse Polish Notation.
|
||||
|
||||
The infix expressions that can be used are very similar to the C expression
|
||||
syntax, but with some additions and subtle differences in operator meaning
|
||||
and precedence. The string may contain a series of expressions separated by
|
||||
a semi-colon character ";" any one of which may actually provide the
|
||||
calculation result; however, all of the other expressions included must
|
||||
assign their result to a variable. All alphabetic elements described below
|
||||
are case independent, so upper and lower case letters may be used and mixed
|
||||
in the variable and function names as desired. Spaces may be used anywhere
|
||||
within an expression except between characters that make up a single
|
||||
expression element.
|
||||
|
||||
The range of expressions supported by the calculation record are separated
|
||||
into literals, constants, operands, algebraic operators, trigonometric operators,
|
||||
relational operators, logical operators, the assignment operator,
|
||||
parentheses and commas, and the question mark or '?:' operator.
|
||||
|
||||
=fields CALC, RPCL
|
||||
|
||||
=head3 Literals
|
||||
|
||||
=over 1
|
||||
|
||||
=item *
|
||||
Standard double precision floating point numbers
|
||||
|
||||
=item *
|
||||
Inf: Infinity
|
||||
|
||||
=item *
|
||||
Nan: Not a Number
|
||||
|
||||
=back
|
||||
|
||||
=head3 Constants
|
||||
|
||||
=over 1
|
||||
|
||||
=item *
|
||||
PI: returns the mathematical constant E<pi>
|
||||
|
||||
=item *
|
||||
D2R: evaluates to E<pi>/180 which, when used as a multiplier, converts an
|
||||
angle from degrees to radians
|
||||
|
||||
=item *
|
||||
R2D: evaluates to 180/E<pi> which as a multiplier converts an angle from
|
||||
radians to degrees
|
||||
|
||||
=back
|
||||
|
||||
=head3 Operands
|
||||
|
||||
The expression uses the values retrieved from the INPx links as operands,
|
||||
though constants can be used as operands too. These values retrieved from
|
||||
the input links are stored in the A-L fields. The values to be used in the
|
||||
expression are simply referenced by the field letter. For instance, the
|
||||
value obtained from INPA link is stored in the field A, and the value
|
||||
obtained from INPB is stored in field B. The field names can be included in
|
||||
the expression which will operate on their respective values, as in A+B.
|
||||
Also, the RNDM nullary function can be included as an operand in the
|
||||
expression in order to generate a random number between 0 and 1.
|
||||
|
||||
=fields A, B, C, D, E, F, G, H, I, J, K, L
|
||||
|
||||
The keyword VAL returns the current contents of the VAL field (which can be
|
||||
written to by a CA put, so it might I<not> be the result from the last time
|
||||
the expression was evaluated).
|
||||
|
||||
=head3 Algebraic Operators
|
||||
|
||||
=over 1
|
||||
|
||||
=item *
|
||||
ABS: Absolute value (unary)
|
||||
|
||||
=item *
|
||||
SQR: Square root (unary)
|
||||
|
||||
=item *
|
||||
MIN: Minimum (any number of args)
|
||||
|
||||
=item *
|
||||
MAX: Maximum (any number of args)
|
||||
|
||||
=item *
|
||||
FINITE: returns non-zero if none of the arguments are NaN or Inf (any
|
||||
number of args)
|
||||
|
||||
=item *
|
||||
ISNAN: returns non-zero if any of the arguments is NaN or Inf (any number
|
||||
of args)
|
||||
|
||||
=item *
|
||||
CEIL: Ceiling (unary)
|
||||
|
||||
=item *
|
||||
FLOOR: Floor (unary)
|
||||
|
||||
=item *
|
||||
LOG: Log base 10 (unary)
|
||||
|
||||
=item *
|
||||
LOGE: Natural log (unary)
|
||||
|
||||
=item *
|
||||
LN: Natural log (unary)
|
||||
|
||||
=item *
|
||||
EXP: Exponential function (unary)
|
||||
|
||||
=item *
|
||||
^ : Exponential (binary)
|
||||
|
||||
=item *
|
||||
** : Exponential (binary)
|
||||
|
||||
=item *
|
||||
+ : Addition (binary)
|
||||
|
||||
=item *
|
||||
- : Subtraction (binary)
|
||||
|
||||
=item *
|
||||
* : Multiplication (binary)
|
||||
|
||||
=item *
|
||||
/ : Division (binary)
|
||||
|
||||
=item *
|
||||
% : Modulo (binary)
|
||||
|
||||
=item *
|
||||
NOT: Negate (unary)
|
||||
|
||||
=back
|
||||
|
||||
=head3 Trigonometric Operators
|
||||
|
||||
=over 1
|
||||
|
||||
=item *
|
||||
SIN: Sine
|
||||
|
||||
=item *
|
||||
SINH: Hyperbolic sine
|
||||
|
||||
=item *
|
||||
ASIN: Arc sine
|
||||
|
||||
=item *
|
||||
COS: Cosine
|
||||
|
||||
=item *
|
||||
COSH: Hyperbolic cosine
|
||||
|
||||
=item *
|
||||
ACOS: Arc cosine
|
||||
|
||||
=item *
|
||||
TAN: Tangent
|
||||
|
||||
=item *
|
||||
TANH: Hyperbolic tangent
|
||||
|
||||
=item *
|
||||
ATAN: Arc tangent
|
||||
|
||||
=back
|
||||
|
||||
=head3 Relational Operators
|
||||
|
||||
=over 1
|
||||
|
||||
=item *
|
||||
>= : Greater than or equal to
|
||||
|
||||
=item *
|
||||
> : Greater than
|
||||
|
||||
=item *
|
||||
<= : Less than or equal to
|
||||
|
||||
=item *
|
||||
< : Less than
|
||||
|
||||
=item *
|
||||
# : Not equal to
|
||||
|
||||
=item *
|
||||
= : Equal to
|
||||
|
||||
=back
|
||||
|
||||
=head3 Logical Operators
|
||||
|
||||
=over 1
|
||||
|
||||
=item *
|
||||
&& : And
|
||||
|
||||
=item *
|
||||
|| : Or
|
||||
|
||||
=item *
|
||||
! : Not
|
||||
|
||||
=back
|
||||
|
||||
=head3 Bitwise Operators
|
||||
|
||||
=over 1
|
||||
|
||||
=item *
|
||||
| : Bitwise Or
|
||||
|
||||
=item *
|
||||
& : Bitwise And
|
||||
|
||||
=item *
|
||||
OR : Bitwise Or
|
||||
|
||||
=item *
|
||||
AND : Bitwise And
|
||||
|
||||
=item *
|
||||
XOR : Bitwise Exclusive Or
|
||||
|
||||
=item *
|
||||
~ : One's Complement
|
||||
|
||||
=item *
|
||||
<< : Left shift
|
||||
|
||||
=item *
|
||||
>> : Right shift
|
||||
|
||||
=back
|
||||
|
||||
=head3 Assignment Operator
|
||||
|
||||
=over 1
|
||||
|
||||
=item *
|
||||
:= : assigns a value (right hand side) to a variable (i.e. field)
|
||||
|
||||
=back
|
||||
|
||||
=head3 Parantheses, Comma, and Semicolon
|
||||
|
||||
The open and close parentheses are supported. Nested parentheses are
|
||||
supported.
|
||||
|
||||
The comma is supported when used to separate the arguments of a binary
|
||||
function.
|
||||
|
||||
The semicolon is used to separate expressions. Although only one
|
||||
traditional calculation expression is allowed, multiple assignment
|
||||
expressions are allowed.
|
||||
|
||||
=head3 Conditional Expression
|
||||
|
||||
The C language's question mark operator is supported. The format is:
|
||||
C<condition ? True result : False result>
|
||||
|
||||
=head3 Expression Examples
|
||||
|
||||
=head3 Algebraic
|
||||
|
||||
C<A + B + 10>
|
||||
|
||||
=over 1
|
||||
|
||||
=item *
|
||||
Result is A + B + 10
|
||||
|
||||
=back
|
||||
|
||||
=head3 Relational
|
||||
|
||||
C<(A + B) < (C + D)>
|
||||
|
||||
=over 1
|
||||
|
||||
=item *
|
||||
Result is 1 if (A + B) < (C + D)
|
||||
|
||||
=item *
|
||||
Result is 0 if (A + B) >= (C + D)
|
||||
|
||||
=back
|
||||
|
||||
=head3 Question Mark
|
||||
|
||||
C<(A + B) < (C + D) ? E : F + L + 10>
|
||||
|
||||
=over 1
|
||||
|
||||
=item *
|
||||
Result is E if (A + B) < (C + D)
|
||||
|
||||
=item *
|
||||
Result is F + L + 10 if (A + B) >= (C + D)
|
||||
|
||||
=back
|
||||
|
||||
Prior to Base 3.14.9 it was legal to omit the : and the second (else) part
|
||||
of the conditional, like this:
|
||||
|
||||
C<(A + B)<(C + D) ? E>
|
||||
|
||||
=over 1
|
||||
|
||||
=item
|
||||
Result is E if (A + B)<(C + D)
|
||||
|
||||
=item
|
||||
Result is unchanged if (A + B)>=(C + D)
|
||||
|
||||
From 3.14.9 onwards, this expresion must be written as
|
||||
C<(A + B) < (C + D) ? E : VAL>
|
||||
|
||||
=back
|
||||
|
||||
=head3 Logical
|
||||
|
||||
C<A&B>
|
||||
|
||||
=over 1
|
||||
|
||||
=item *
|
||||
Causes the following to occur:
|
||||
|
||||
=over 1
|
||||
|
||||
=item *
|
||||
Convert A to integer
|
||||
|
||||
=item *
|
||||
Convert B to integer
|
||||
|
||||
=item *
|
||||
Bitwise And A and B
|
||||
|
||||
=item *
|
||||
Convert result to floating point
|
||||
|
||||
=back
|
||||
|
||||
=back
|
||||
|
||||
=head3 Assignment
|
||||
|
||||
C<sin(a); a:=a+D2R>
|
||||
|
||||
=over 1
|
||||
|
||||
=item *
|
||||
Causes the Calc record to output the successive values of a sine curve in
|
||||
1 degree intervals.
|
||||
|
||||
=back
|
||||
|
||||
=head3 Operator Display Parameters
|
||||
|
||||
These parameters are used to present meaningful data to the operator. These
|
||||
fields are used to display VAL and other parameters of the calculation
|
||||
record either textually or graphically.
|
||||
|
||||
The EGU field contains a string of up to 16 characters which is supplied by
|
||||
the user and which describes the values being operated upon. The string is
|
||||
retrieved whenever the routine C<get_units> is called. The EGU string is
|
||||
solely for an operator's sake and does not have to be used.
|
||||
|
||||
The HOPR and LOPR fields only refer to the limits of the VAL, HIHI, HIGH,
|
||||
LOW and LOLO fields. PREC controls the precision of the VAL field.
|
||||
|
||||
See L<Fields Common to All Record Types> for more on the record name (NAME)
|
||||
and description (DESC) fields.
|
||||
|
||||
=fields EGU, PREC, HOPR, LOPR, NAME, DESC
|
||||
|
||||
=head3 Alarm Parameters
|
||||
|
||||
The possible alarm conditions for the Calc record are the SCAN, READ,
|
||||
Calculation, and limit alarms. The SCAN and READ alarms are called by the
|
||||
record support routines. The Calculation alarm is called by the record
|
||||
processing routine when the CALC expression is an invalid one, upon which
|
||||
an error message is generated.
|
||||
|
||||
The following alarm parameters which are configured by the user, define the
|
||||
limit alarms for the VAL field and the severity corresponding to those
|
||||
conditions.
|
||||
|
||||
The HYST field defines an alarm deadband for each limit. See L<Alarm Specification>
|
||||
for a complete explanation of alarms of these fields. L<Alarm Fields>
|
||||
lists other fields related to alarms that are common to all record types.
|
||||
|
||||
=fields HIHI, HIGH, LOW, LOLO, HHSV, HSV, LSV, LLSV, HYST
|
||||
|
||||
=head3 Monitor Parameters
|
||||
|
||||
These paramaeters are used to determine when to send monitors for the value
|
||||
fields. These monitors are sent when the value field exceeds the last
|
||||
monitored field by the appropriate deadband, the ADEL for archiver monitors
|
||||
and the MDEL field for all other types of monitors. If these fields have a
|
||||
value of zero, everytime the value changes, monitors are triggered; if they have a
|
||||
value of -1, everytime the record is scanned, monitors are triggered. See
|
||||
L<Monitor Specification> for a complete explanation of monitors.
|
||||
|
||||
=fields ADEL, MDEL
|
||||
|
||||
=head3 Run-time Parameters
|
||||
|
||||
These fields are not configurable using a configuration tool and none are
|
||||
modifiable at run-time. They are used to process the record.
|
||||
|
||||
The LALM field is used to implement the hysteresis factor for the alarm
|
||||
limits.
|
||||
|
||||
The LA-LL fields are used to decide when to trigger monitors for the
|
||||
corresponding fields. For instance, if LA does not equal the value A,
|
||||
monitors for A are triggered. The MLST and ALST fields are used in the same
|
||||
manner for the VAL field.
|
||||
|
||||
=fields LALM, ALST, MLST, LA, LB, LC, LD, LE, LF, LG, LH, LI, LJ, LK, LL
|
||||
|
||||
=cut
|
||||
|
||||
include "dbCommon.dbd"
|
||||
field(VAL,DBF_DOUBLE) {
|
||||
prompt("Result")
|
||||
promptgroup("50 - Output")
|
||||
asl(ASL0)
|
||||
}
|
||||
field(CALC,DBF_STRING) {
|
||||
prompt("Calculation")
|
||||
promptgroup("30 - Action")
|
||||
special(SPC_CALC)
|
||||
pp(TRUE)
|
||||
size(80)
|
||||
initial("0")
|
||||
}
|
||||
field(INPA,DBF_INLINK) {
|
||||
prompt("Input A")
|
||||
promptgroup("41 - Input A-F")
|
||||
interest(1)
|
||||
}
|
||||
field(INPB,DBF_INLINK) {
|
||||
prompt("Input B")
|
||||
promptgroup("41 - Input A-F")
|
||||
interest(1)
|
||||
}
|
||||
field(INPC,DBF_INLINK) {
|
||||
prompt("Input C")
|
||||
promptgroup("41 - Input A-F")
|
||||
interest(1)
|
||||
}
|
||||
field(INPD,DBF_INLINK) {
|
||||
prompt("Input D")
|
||||
promptgroup("41 - Input A-F")
|
||||
interest(1)
|
||||
}
|
||||
field(INPE,DBF_INLINK) {
|
||||
prompt("Input E")
|
||||
promptgroup("41 - Input A-F")
|
||||
interest(1)
|
||||
}
|
||||
field(INPF,DBF_INLINK) {
|
||||
prompt("Input F")
|
||||
promptgroup("41 - Input A-F")
|
||||
interest(1)
|
||||
}
|
||||
field(INPG,DBF_INLINK) {
|
||||
prompt("Input G")
|
||||
promptgroup("42 - Input G-L")
|
||||
interest(1)
|
||||
}
|
||||
field(INPH,DBF_INLINK) {
|
||||
prompt("Input H")
|
||||
promptgroup("42 - Input G-L")
|
||||
interest(1)
|
||||
}
|
||||
field(INPI,DBF_INLINK) {
|
||||
prompt("Input I")
|
||||
promptgroup("42 - Input G-L")
|
||||
interest(1)
|
||||
}
|
||||
field(INPJ,DBF_INLINK) {
|
||||
prompt("Input J")
|
||||
promptgroup("42 - Input G-L")
|
||||
interest(1)
|
||||
}
|
||||
field(INPK,DBF_INLINK) {
|
||||
prompt("Input K")
|
||||
promptgroup("42 - Input G-L")
|
||||
interest(1)
|
||||
}
|
||||
field(INPL,DBF_INLINK) {
|
||||
prompt("Input L")
|
||||
promptgroup("42 - Input G-L")
|
||||
interest(1)
|
||||
}
|
||||
field(EGU,DBF_STRING) {
|
||||
prompt("Engineering Units")
|
||||
promptgroup("80 - Display")
|
||||
interest(1)
|
||||
size(16)
|
||||
prop(YES)
|
||||
}
|
||||
field(PREC,DBF_SHORT) {
|
||||
prompt("Display Precision")
|
||||
promptgroup("80 - Display")
|
||||
interest(1)
|
||||
prop(YES)
|
||||
}
|
||||
field(HOPR,DBF_DOUBLE) {
|
||||
prompt("High Operating Rng")
|
||||
promptgroup("80 - Display")
|
||||
interest(1)
|
||||
prop(YES)
|
||||
}
|
||||
field(LOPR,DBF_DOUBLE) {
|
||||
prompt("Low Operating Range")
|
||||
promptgroup("80 - Display")
|
||||
interest(1)
|
||||
prop(YES)
|
||||
}
|
||||
field(HIHI,DBF_DOUBLE) {
|
||||
prompt("Hihi Alarm Limit")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
prop(YES)
|
||||
}
|
||||
field(LOLO,DBF_DOUBLE) {
|
||||
prompt("Lolo Alarm Limit")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
prop(YES)
|
||||
}
|
||||
field(HIGH,DBF_DOUBLE) {
|
||||
prompt("High Alarm Limit")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
prop(YES)
|
||||
}
|
||||
field(LOW,DBF_DOUBLE) {
|
||||
prompt("Low Alarm Limit")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
prop(YES)
|
||||
}
|
||||
field(HHSV,DBF_MENU) {
|
||||
prompt("Hihi Severity")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
prop(YES)
|
||||
menu(menuAlarmSevr)
|
||||
}
|
||||
field(LLSV,DBF_MENU) {
|
||||
prompt("Lolo Severity")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
prop(YES)
|
||||
menu(menuAlarmSevr)
|
||||
}
|
||||
field(HSV,DBF_MENU) {
|
||||
prompt("High Severity")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
prop(YES)
|
||||
menu(menuAlarmSevr)
|
||||
}
|
||||
field(LSV,DBF_MENU) {
|
||||
prompt("Low Severity")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
prop(YES)
|
||||
menu(menuAlarmSevr)
|
||||
}
|
||||
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)
|
||||
}
|
||||
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(A,DBF_DOUBLE) {
|
||||
prompt("Value of Input A")
|
||||
pp(TRUE)
|
||||
}
|
||||
field(B,DBF_DOUBLE) {
|
||||
prompt("Value of Input B")
|
||||
pp(TRUE)
|
||||
}
|
||||
field(C,DBF_DOUBLE) {
|
||||
prompt("Value of Input C")
|
||||
pp(TRUE)
|
||||
}
|
||||
field(D,DBF_DOUBLE) {
|
||||
prompt("Value of Input D")
|
||||
pp(TRUE)
|
||||
}
|
||||
field(E,DBF_DOUBLE) {
|
||||
prompt("Value of Input E")
|
||||
pp(TRUE)
|
||||
}
|
||||
field(F,DBF_DOUBLE) {
|
||||
prompt("Value of Input F")
|
||||
pp(TRUE)
|
||||
}
|
||||
field(G,DBF_DOUBLE) {
|
||||
prompt("Value of Input G")
|
||||
pp(TRUE)
|
||||
}
|
||||
field(H,DBF_DOUBLE) {
|
||||
prompt("Value of Input H")
|
||||
pp(TRUE)
|
||||
}
|
||||
field(I,DBF_DOUBLE) {
|
||||
prompt("Value of Input I")
|
||||
pp(TRUE)
|
||||
}
|
||||
field(J,DBF_DOUBLE) {
|
||||
prompt("Value of Input J")
|
||||
pp(TRUE)
|
||||
}
|
||||
field(K,DBF_DOUBLE) {
|
||||
prompt("Value of Input K")
|
||||
pp(TRUE)
|
||||
}
|
||||
field(L,DBF_DOUBLE) {
|
||||
prompt("Value of Input L")
|
||||
pp(TRUE)
|
||||
}
|
||||
field(LA,DBF_DOUBLE) {
|
||||
prompt("Prev Value of A")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(LB,DBF_DOUBLE) {
|
||||
prompt("Prev Value of B")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(LC,DBF_DOUBLE) {
|
||||
prompt("Prev Value of C")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(LD,DBF_DOUBLE) {
|
||||
prompt("Prev Value of D")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(LE,DBF_DOUBLE) {
|
||||
prompt("Prev Value of E")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(LF,DBF_DOUBLE) {
|
||||
prompt("Prev Value of F")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(LG,DBF_DOUBLE) {
|
||||
prompt("Prev Value of G")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(LH,DBF_DOUBLE) {
|
||||
prompt("Prev Value of H")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(LI,DBF_DOUBLE) {
|
||||
prompt("Prev Value of I")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(LJ,DBF_DOUBLE) {
|
||||
prompt("Prev Value of J")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(LK,DBF_DOUBLE) {
|
||||
prompt("Prev Value of K")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(LL,DBF_DOUBLE) {
|
||||
prompt("Prev Value of L")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
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)
|
||||
}
|
||||
%#include "postfix.h"
|
||||
field(RPCL,DBF_NOACCESS) {
|
||||
prompt("Reverse Polish Calc")
|
||||
special(SPC_NOMOD)
|
||||
interest(4)
|
||||
extra("char rpcl[INFIX_TO_POSTFIX_SIZE(80)]")
|
||||
}
|
||||
|
||||
=head2 Record Support
|
||||
|
||||
=head3 Record Support Routines
|
||||
|
||||
=head2 C<init_record>
|
||||
|
||||
For each constant input link, the corresponding value field is initialized
|
||||
with the constant value if the input link is CONSTANT or a channel access
|
||||
link is created if the input link is a PV_LINK.
|
||||
|
||||
A routine postfix is called to convert the infix expression in CALC to
|
||||
Reverse Polish Notation. The result is stored in RPCL.
|
||||
|
||||
=head2 C<process>
|
||||
|
||||
See next section.
|
||||
|
||||
=head2 C<special>
|
||||
|
||||
This is called if CALC is changed. C<special> calls postfix.
|
||||
|
||||
=head2 C<get_value>
|
||||
|
||||
Fills in the values of struct valueDes so that the refer to VAL.
|
||||
|
||||
=head2 C<get_units>
|
||||
|
||||
Retrieves EGU.
|
||||
|
||||
=head2 C<get_precision>
|
||||
|
||||
Retrieves PREC.
|
||||
|
||||
=head2 C<get_graphic_double>
|
||||
|
||||
Sets the upper display and lower display limits for a field. If the field
|
||||
is VAL, HIHI, HIGH, LOW, or LOLO, the limits are set to HOPR and LOPR, else
|
||||
if the field has upper and lower limits defined they will be used, else the
|
||||
upper and lower maximum values for the field will be used.
|
||||
|
||||
=head2 C<get_control_double>
|
||||
|
||||
Sets the upper control and the lower control limits for a field. If the
|
||||
field is VAL, HIHI, HIGH, LOW, or LOLO, the limits are set to HOPR and
|
||||
LOPR, else if the field has upper and lower limits defined they will be
|
||||
used, else the upper and lower maximum values for the field type will be
|
||||
used.
|
||||
|
||||
=head2 C<get_alarm_double>
|
||||
|
||||
Sets the following values:
|
||||
|
||||
=over 1
|
||||
|
||||
upper_alarm_limit = HIHI
|
||||
|
||||
upper_warning_limit = HIGH
|
||||
|
||||
lower_warning_limit = LOW
|
||||
|
||||
lower_alarm_limit = LOLO
|
||||
|
||||
=back
|
||||
|
||||
=head3 Record Processing
|
||||
|
||||
Routine process implements the following algorithm:
|
||||
|
||||
=over 1
|
||||
|
||||
=item 1.
|
||||
Fetch all arguments.
|
||||
|
||||
=item 2.
|
||||
Call routine C<calcPerform>, which calculates VAL from the postfix version of
|
||||
the expression given in CALC. If C<calcPerform> returns success UDF is set to
|
||||
FALSE.
|
||||
|
||||
=item 3.
|
||||
Check alarms. This routine checks to see if the new VAL causes the alarm
|
||||
status and severity to change. If so, NSEV, NSTA, and LALM are set. It also
|
||||
honors the alarm hysteresis factor (HYST). Thus the value must change by
|
||||
at least HYST before the alarm status and severity changes.
|
||||
|
||||
=item 4.
|
||||
Check to see if monitors should be invoked.
|
||||
|
||||
=back
|
||||
|
||||
=over 1
|
||||
|
||||
=item *
|
||||
Alarm monitors are invoked if the alarm status or severity has changed.
|
||||
|
||||
=item *
|
||||
Archive and values change monitors are invoked if ADEL and MDEL conditions
|
||||
are met.
|
||||
|
||||
=item *
|
||||
Monitors for A-L are checked whenever other monitors are invoked.
|
||||
|
||||
=item *
|
||||
NSEV and NSTA are reset to 0.
|
||||
|
||||
=back
|
||||
|
||||
=over
|
||||
|
||||
=item 5.
|
||||
Scan forward link if necessary, set PACT FALSE, and return.
|
||||
|
||||
=back
|
||||
|
||||
=cut
|
||||
|
||||
}
|
@ -1,530 +0,0 @@
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2007 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.
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
menu(calcoutOOPT) {
|
||||
choice(calcoutOOPT_Every_Time,"Every Time")
|
||||
choice(calcoutOOPT_On_Change,"On Change")
|
||||
choice(calcoutOOPT_When_Zero,"When Zero")
|
||||
choice(calcoutOOPT_When_Non_zero,"When Non-zero")
|
||||
choice(calcoutOOPT_Transition_To_Zero,"Transition To Zero")
|
||||
choice(calcoutOOPT_Transition_To_Non_zero,"Transition To Non-zero")
|
||||
}
|
||||
menu(calcoutDOPT) {
|
||||
choice(calcoutDOPT_Use_VAL,"Use CALC")
|
||||
choice(calcoutDOPT_Use_OVAL,"Use OCAL")
|
||||
}
|
||||
menu(calcoutINAV) {
|
||||
choice(calcoutINAV_EXT_NC,"Ext PV NC")
|
||||
choice(calcoutINAV_EXT,"Ext PV OK")
|
||||
choice(calcoutINAV_LOC,"Local PV")
|
||||
choice(calcoutINAV_CON,"Constant")
|
||||
}
|
||||
recordtype(calcout) {
|
||||
include "dbCommon.dbd"
|
||||
field(RPVT,DBF_NOACCESS) {
|
||||
prompt("Record Private")
|
||||
special(SPC_NOMOD)
|
||||
interest(4)
|
||||
extra("struct rpvtStruct *rpvt")
|
||||
}
|
||||
field(VAL,DBF_DOUBLE) {
|
||||
prompt("Result")
|
||||
promptgroup("50 - Output")
|
||||
asl(ASL0)
|
||||
}
|
||||
field(PVAL,DBF_DOUBLE) {
|
||||
prompt("Previous Value")
|
||||
}
|
||||
field(CALC,DBF_STRING) {
|
||||
prompt("Calculation")
|
||||
promptgroup("30 - Action")
|
||||
special(SPC_CALC)
|
||||
pp(TRUE)
|
||||
size(80)
|
||||
initial("0")
|
||||
}
|
||||
field(CLCV,DBF_LONG) {
|
||||
prompt("CALC Valid")
|
||||
interest(1)
|
||||
}
|
||||
field(INPA,DBF_INLINK) {
|
||||
prompt("Input A")
|
||||
special(SPC_MOD)
|
||||
promptgroup("41 - Input A-F")
|
||||
interest(1)
|
||||
}
|
||||
field(INPB,DBF_INLINK) {
|
||||
prompt("Input B")
|
||||
special(SPC_MOD)
|
||||
promptgroup("41 - Input A-F")
|
||||
interest(1)
|
||||
}
|
||||
field(INPC,DBF_INLINK) {
|
||||
prompt("Input C")
|
||||
special(SPC_MOD)
|
||||
promptgroup("41 - Input A-F")
|
||||
interest(1)
|
||||
}
|
||||
field(INPD,DBF_INLINK) {
|
||||
prompt("Input D")
|
||||
special(SPC_MOD)
|
||||
promptgroup("41 - Input A-F")
|
||||
interest(1)
|
||||
}
|
||||
field(INPE,DBF_INLINK) {
|
||||
prompt("Input E")
|
||||
special(SPC_MOD)
|
||||
promptgroup("41 - Input A-F")
|
||||
interest(1)
|
||||
}
|
||||
field(INPF,DBF_INLINK) {
|
||||
prompt("Input F")
|
||||
special(SPC_MOD)
|
||||
promptgroup("41 - Input A-F")
|
||||
interest(1)
|
||||
}
|
||||
field(INPG,DBF_INLINK) {
|
||||
prompt("Input G")
|
||||
special(SPC_MOD)
|
||||
promptgroup("42 - Input G-L")
|
||||
interest(1)
|
||||
}
|
||||
field(INPH,DBF_INLINK) {
|
||||
prompt("Input H")
|
||||
special(SPC_MOD)
|
||||
promptgroup("42 - Input G-L")
|
||||
interest(1)
|
||||
}
|
||||
field(INPI,DBF_INLINK) {
|
||||
prompt("Input I")
|
||||
special(SPC_MOD)
|
||||
promptgroup("42 - Input G-L")
|
||||
interest(1)
|
||||
}
|
||||
field(INPJ,DBF_INLINK) {
|
||||
prompt("Input J")
|
||||
special(SPC_MOD)
|
||||
promptgroup("42 - Input G-L")
|
||||
interest(1)
|
||||
}
|
||||
field(INPK,DBF_INLINK) {
|
||||
prompt("Input K")
|
||||
special(SPC_MOD)
|
||||
promptgroup("42 - Input G-L")
|
||||
interest(1)
|
||||
}
|
||||
field(INPL,DBF_INLINK) {
|
||||
prompt("Input L")
|
||||
special(SPC_MOD)
|
||||
promptgroup("42 - Input G-L")
|
||||
interest(1)
|
||||
}
|
||||
field(OUT,DBF_OUTLINK) {
|
||||
prompt("Output Specification")
|
||||
special(SPC_MOD)
|
||||
promptgroup("50 - Output")
|
||||
interest(1)
|
||||
}
|
||||
field(INAV,DBF_MENU) {
|
||||
prompt("INPA PV Status")
|
||||
special(SPC_NOMOD)
|
||||
interest(1)
|
||||
menu(calcoutINAV)
|
||||
initial("1")
|
||||
}
|
||||
field(INBV,DBF_MENU) {
|
||||
prompt("INPB PV Status")
|
||||
special(SPC_NOMOD)
|
||||
interest(1)
|
||||
menu(calcoutINAV)
|
||||
initial("1")
|
||||
}
|
||||
field(INCV,DBF_MENU) {
|
||||
prompt("INPC PV Status")
|
||||
special(SPC_NOMOD)
|
||||
interest(1)
|
||||
menu(calcoutINAV)
|
||||
initial("1")
|
||||
}
|
||||
field(INDV,DBF_MENU) {
|
||||
prompt("INPD PV Status")
|
||||
special(SPC_NOMOD)
|
||||
interest(1)
|
||||
menu(calcoutINAV)
|
||||
initial("1")
|
||||
}
|
||||
field(INEV,DBF_MENU) {
|
||||
prompt("INPE PV Status")
|
||||
special(SPC_NOMOD)
|
||||
interest(1)
|
||||
menu(calcoutINAV)
|
||||
initial("1")
|
||||
}
|
||||
field(INFV,DBF_MENU) {
|
||||
prompt("INPF PV Status")
|
||||
special(SPC_NOMOD)
|
||||
interest(1)
|
||||
menu(calcoutINAV)
|
||||
initial("1")
|
||||
}
|
||||
field(INGV,DBF_MENU) {
|
||||
prompt("INPG PV Status")
|
||||
special(SPC_NOMOD)
|
||||
interest(1)
|
||||
menu(calcoutINAV)
|
||||
initial("1")
|
||||
}
|
||||
field(INHV,DBF_MENU) {
|
||||
prompt("INPH PV Status")
|
||||
special(SPC_NOMOD)
|
||||
interest(1)
|
||||
menu(calcoutINAV)
|
||||
initial("1")
|
||||
}
|
||||
field(INIV,DBF_MENU) {
|
||||
prompt("INPI PV Status")
|
||||
special(SPC_NOMOD)
|
||||
interest(1)
|
||||
menu(calcoutINAV)
|
||||
initial("1")
|
||||
}
|
||||
field(INJV,DBF_MENU) {
|
||||
prompt("INPJ PV Status")
|
||||
special(SPC_NOMOD)
|
||||
interest(1)
|
||||
menu(calcoutINAV)
|
||||
initial("1")
|
||||
}
|
||||
field(INKV,DBF_MENU) {
|
||||
prompt("INPK PV Status")
|
||||
special(SPC_NOMOD)
|
||||
interest(1)
|
||||
menu(calcoutINAV)
|
||||
initial("1")
|
||||
}
|
||||
field(INLV,DBF_MENU) {
|
||||
prompt("INPL PV Status")
|
||||
special(SPC_NOMOD)
|
||||
interest(1)
|
||||
menu(calcoutINAV)
|
||||
initial("1")
|
||||
}
|
||||
field(OUTV,DBF_MENU) {
|
||||
prompt("OUT PV Status")
|
||||
special(SPC_NOMOD)
|
||||
interest(1)
|
||||
menu(calcoutINAV)
|
||||
}
|
||||
field(OOPT,DBF_MENU) {
|
||||
prompt("Output Execute Opt")
|
||||
promptgroup("50 - Output")
|
||||
interest(1)
|
||||
menu(calcoutOOPT)
|
||||
}
|
||||
field(ODLY,DBF_DOUBLE) {
|
||||
prompt("Output Execute Delay")
|
||||
promptgroup("50 - Output")
|
||||
asl(ASL0)
|
||||
interest(1)
|
||||
}
|
||||
field(DLYA,DBF_USHORT) {
|
||||
prompt("Output Delay Active")
|
||||
special(SPC_NOMOD)
|
||||
asl(ASL0)
|
||||
}
|
||||
field(DOPT,DBF_MENU) {
|
||||
prompt("Output Data Opt")
|
||||
promptgroup("30 - Action")
|
||||
interest(1)
|
||||
menu(calcoutDOPT)
|
||||
}
|
||||
field(OCAL,DBF_STRING) {
|
||||
prompt("Output Calculation")
|
||||
promptgroup("30 - Action")
|
||||
special(SPC_CALC)
|
||||
pp(TRUE)
|
||||
size(80)
|
||||
initial("0")
|
||||
}
|
||||
field(OCLV,DBF_LONG) {
|
||||
prompt("OCAL Valid")
|
||||
interest(1)
|
||||
}
|
||||
field(OEVT,DBF_STRING) {
|
||||
prompt("Event To Issue")
|
||||
promptgroup("30 - Action")
|
||||
special(SPC_MOD)
|
||||
asl(ASL0)
|
||||
size(40)
|
||||
}
|
||||
%#include "dbScan.h"
|
||||
field(EPVT, DBF_NOACCESS) {
|
||||
prompt("Event private")
|
||||
special(SPC_NOMOD)
|
||||
interest(4)
|
||||
extra("EVENTPVT epvt")
|
||||
}
|
||||
field(IVOA,DBF_MENU) {
|
||||
prompt("INVALID output action")
|
||||
promptgroup("50 - Output")
|
||||
interest(2)
|
||||
menu(menuIvoa)
|
||||
}
|
||||
field(IVOV,DBF_DOUBLE) {
|
||||
prompt("INVALID output value")
|
||||
promptgroup("50 - Output")
|
||||
interest(2)
|
||||
}
|
||||
field(EGU,DBF_STRING) {
|
||||
prompt("Engineering Units")
|
||||
promptgroup("80 - Display")
|
||||
interest(1)
|
||||
size(16)
|
||||
prop(YES)
|
||||
}
|
||||
field(PREC,DBF_SHORT) {
|
||||
prompt("Display Precision")
|
||||
promptgroup("80 - Display")
|
||||
interest(1)
|
||||
prop(YES)
|
||||
}
|
||||
field(HOPR,DBF_DOUBLE) {
|
||||
prompt("High Operating Rng")
|
||||
promptgroup("80 - Display")
|
||||
interest(1)
|
||||
prop(YES)
|
||||
}
|
||||
field(LOPR,DBF_DOUBLE) {
|
||||
prompt("Low Operating Range")
|
||||
promptgroup("80 - Display")
|
||||
interest(1)
|
||||
prop(YES)
|
||||
}
|
||||
field(HIHI,DBF_DOUBLE) {
|
||||
prompt("Hihi Alarm Limit")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
prop(YES)
|
||||
}
|
||||
field(LOLO,DBF_DOUBLE) {
|
||||
prompt("Lolo Alarm Limit")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
prop(YES)
|
||||
}
|
||||
field(HIGH,DBF_DOUBLE) {
|
||||
prompt("High Alarm Limit")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
prop(YES)
|
||||
}
|
||||
field(LOW,DBF_DOUBLE) {
|
||||
prompt("Low Alarm Limit")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
prop(YES)
|
||||
}
|
||||
field(HHSV,DBF_MENU) {
|
||||
prompt("Hihi Severity")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
prop(YES)
|
||||
menu(menuAlarmSevr)
|
||||
}
|
||||
field(LLSV,DBF_MENU) {
|
||||
prompt("Lolo Severity")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
prop(YES)
|
||||
menu(menuAlarmSevr)
|
||||
}
|
||||
field(HSV,DBF_MENU) {
|
||||
prompt("High Severity")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
prop(YES)
|
||||
menu(menuAlarmSevr)
|
||||
}
|
||||
field(LSV,DBF_MENU) {
|
||||
prompt("Low Severity")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
prop(YES)
|
||||
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(A,DBF_DOUBLE) {
|
||||
prompt("Value of Input A")
|
||||
pp(TRUE)
|
||||
}
|
||||
field(B,DBF_DOUBLE) {
|
||||
prompt("Value of Input B")
|
||||
pp(TRUE)
|
||||
}
|
||||
field(C,DBF_DOUBLE) {
|
||||
prompt("Value of Input C")
|
||||
pp(TRUE)
|
||||
}
|
||||
field(D,DBF_DOUBLE) {
|
||||
prompt("Value of Input D")
|
||||
pp(TRUE)
|
||||
}
|
||||
field(E,DBF_DOUBLE) {
|
||||
prompt("Value of Input E")
|
||||
pp(TRUE)
|
||||
}
|
||||
field(F,DBF_DOUBLE) {
|
||||
prompt("Value of Input F")
|
||||
pp(TRUE)
|
||||
}
|
||||
field(G,DBF_DOUBLE) {
|
||||
prompt("Value of Input G")
|
||||
pp(TRUE)
|
||||
}
|
||||
field(H,DBF_DOUBLE) {
|
||||
prompt("Value of Input H")
|
||||
pp(TRUE)
|
||||
}
|
||||
field(I,DBF_DOUBLE) {
|
||||
prompt("Value of Input I")
|
||||
pp(TRUE)
|
||||
}
|
||||
field(J,DBF_DOUBLE) {
|
||||
prompt("Value of Input J")
|
||||
pp(TRUE)
|
||||
}
|
||||
field(K,DBF_DOUBLE) {
|
||||
prompt("Value of Input K")
|
||||
pp(TRUE)
|
||||
}
|
||||
field(L,DBF_DOUBLE) {
|
||||
prompt("Value of Input L")
|
||||
pp(TRUE)
|
||||
}
|
||||
field(OVAL,DBF_DOUBLE) {
|
||||
prompt("Output Value")
|
||||
asl(ASL0)
|
||||
}
|
||||
field(LA,DBF_DOUBLE) {
|
||||
prompt("Prev Value of A")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(LB,DBF_DOUBLE) {
|
||||
prompt("Prev Value of B")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(LC,DBF_DOUBLE) {
|
||||
prompt("Prev Value of C")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(LD,DBF_DOUBLE) {
|
||||
prompt("Prev Value of D")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(LE,DBF_DOUBLE) {
|
||||
prompt("Prev Value of E")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(LF,DBF_DOUBLE) {
|
||||
prompt("Prev Value of F")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(LG,DBF_DOUBLE) {
|
||||
prompt("Prev Value of G")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(LH,DBF_DOUBLE) {
|
||||
prompt("Prev Value of H")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(LI,DBF_DOUBLE) {
|
||||
prompt("Prev Value of I")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(LJ,DBF_DOUBLE) {
|
||||
prompt("Prev Value of J")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(LK,DBF_DOUBLE) {
|
||||
prompt("Prev Value of K")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(LL,DBF_DOUBLE) {
|
||||
prompt("Prev Value of L")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(POVL,DBF_DOUBLE) {
|
||||
prompt("Prev Value of OVAL")
|
||||
asl(ASL0)
|
||||
}
|
||||
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)
|
||||
}
|
||||
%#include "postfix.h"
|
||||
field(RPCL,DBF_NOACCESS) {
|
||||
prompt("Reverse Polish Calc")
|
||||
special(SPC_NOMOD)
|
||||
interest(4)
|
||||
extra("char rpcl[INFIX_TO_POSTFIX_SIZE(80)]")
|
||||
}
|
||||
field(ORPC,DBF_NOACCESS) {
|
||||
prompt("Reverse Polish OCalc")
|
||||
special(SPC_NOMOD)
|
||||
interest(4)
|
||||
extra("char orpc[INFIX_TO_POSTFIX_SIZE(80)]")
|
||||
}
|
||||
}
|
||||
|
||||
variable(calcoutODLYprecision, int)
|
||||
variable(calcoutODLYlimit, double)
|
1271
modules/database/src/std/rec/calcoutRecord.dbd.pod
Normal file
1271
modules/database/src/std/rec/calcoutRecord.dbd.pod
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,204 +0,0 @@
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
# National Laboratory.
|
||||
# Copyright (c) 2002 The Regents of the University of California, as
|
||||
# Operator of Los Alamos National Laboratory.
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
menu(dfanoutSELM) {
|
||||
choice(dfanoutSELM_All,"All")
|
||||
choice(dfanoutSELM_Specified,"Specified")
|
||||
choice(dfanoutSELM_Mask,"Mask")
|
||||
}
|
||||
recordtype(dfanout) {
|
||||
include "dbCommon.dbd"
|
||||
field(VAL,DBF_DOUBLE) {
|
||||
prompt("Desired Output")
|
||||
promptgroup("40 - Input")
|
||||
asl(ASL0)
|
||||
pp(TRUE)
|
||||
}
|
||||
field(SELM,DBF_MENU) {
|
||||
prompt("Select Mechanism")
|
||||
promptgroup("30 - Action")
|
||||
interest(1)
|
||||
menu(dfanoutSELM)
|
||||
}
|
||||
field(SELN,DBF_USHORT) {
|
||||
prompt("Link Selection")
|
||||
interest(1)
|
||||
initial("1")
|
||||
}
|
||||
field(SELL,DBF_INLINK) {
|
||||
prompt("Link Selection Loc")
|
||||
promptgroup("30 - Action")
|
||||
interest(1)
|
||||
}
|
||||
field(OUTA,DBF_OUTLINK) {
|
||||
prompt("Output Spec A")
|
||||
promptgroup("50 - Output")
|
||||
interest(1)
|
||||
}
|
||||
field(OUTB,DBF_OUTLINK) {
|
||||
prompt("Output Spec B")
|
||||
promptgroup("50 - Output")
|
||||
interest(1)
|
||||
}
|
||||
field(OUTC,DBF_OUTLINK) {
|
||||
prompt("Output Spec C")
|
||||
promptgroup("50 - Output")
|
||||
interest(1)
|
||||
}
|
||||
field(OUTD,DBF_OUTLINK) {
|
||||
prompt("Output Spec D")
|
||||
promptgroup("50 - Output")
|
||||
interest(1)
|
||||
}
|
||||
field(OUTE,DBF_OUTLINK) {
|
||||
prompt("Output Spec E")
|
||||
promptgroup("50 - Output")
|
||||
interest(1)
|
||||
}
|
||||
field(OUTF,DBF_OUTLINK) {
|
||||
prompt("Output Spec F")
|
||||
promptgroup("50 - Output")
|
||||
interest(1)
|
||||
}
|
||||
field(OUTG,DBF_OUTLINK) {
|
||||
prompt("Output Spec G")
|
||||
promptgroup("50 - Output")
|
||||
interest(1)
|
||||
}
|
||||
field(OUTH,DBF_OUTLINK) {
|
||||
prompt("Output Spec H")
|
||||
promptgroup("50 - Output")
|
||||
interest(1)
|
||||
}
|
||||
field(DOL,DBF_INLINK) {
|
||||
prompt("Desired Output Loc")
|
||||
promptgroup("40 - Input")
|
||||
interest(1)
|
||||
}
|
||||
field(OMSL,DBF_MENU) {
|
||||
prompt("Output Mode Select")
|
||||
promptgroup("50 - Output")
|
||||
interest(1)
|
||||
menu(menuOmsl)
|
||||
}
|
||||
field(EGU,DBF_STRING) {
|
||||
prompt("Engineering Units")
|
||||
promptgroup("80 - Display")
|
||||
interest(1)
|
||||
size(16)
|
||||
prop(YES)
|
||||
}
|
||||
field(PREC,DBF_SHORT) {
|
||||
prompt("Display Precision")
|
||||
promptgroup("80 - Display")
|
||||
interest(1)
|
||||
prop(YES)
|
||||
}
|
||||
field(HOPR,DBF_DOUBLE) {
|
||||
prompt("High Operating Range")
|
||||
promptgroup("80 - Display")
|
||||
interest(1)
|
||||
prop(YES)
|
||||
}
|
||||
field(LOPR,DBF_DOUBLE) {
|
||||
prompt("Low Operating Range")
|
||||
promptgroup("80 - Display")
|
||||
interest(1)
|
||||
prop(YES)
|
||||
}
|
||||
field(HIHI,DBF_DOUBLE) {
|
||||
prompt("Hihi Alarm Limit")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
prop(YES)
|
||||
}
|
||||
field(LOLO,DBF_DOUBLE) {
|
||||
prompt("Lolo Alarm Limit")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
prop(YES)
|
||||
}
|
||||
field(HIGH,DBF_DOUBLE) {
|
||||
prompt("High Alarm Limit")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
prop(YES)
|
||||
}
|
||||
field(LOW,DBF_DOUBLE) {
|
||||
prompt("Low Alarm Limit")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
prop(YES)
|
||||
}
|
||||
field(HHSV,DBF_MENU) {
|
||||
prompt("Hihi Severity")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
prop(YES)
|
||||
menu(menuAlarmSevr)
|
||||
}
|
||||
field(LLSV,DBF_MENU) {
|
||||
prompt("Lolo Severity")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
prop(YES)
|
||||
menu(menuAlarmSevr)
|
||||
}
|
||||
field(HSV,DBF_MENU) {
|
||||
prompt("High Severity")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
prop(YES)
|
||||
menu(menuAlarmSevr)
|
||||
}
|
||||
field(LSV,DBF_MENU) {
|
||||
prompt("Low Severity")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
prop(YES)
|
||||
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)
|
||||
}
|
||||
}
|
454
modules/database/src/std/rec/dfanoutRecord.dbd.pod
Normal file
454
modules/database/src/std/rec/dfanoutRecord.dbd.pod
Normal file
@ -0,0 +1,454 @@
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
# National Laboratory.
|
||||
# Copyright (c) 2002 The Regents of the University of California, as
|
||||
# Operator of Los Alamos National Laboratory.
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
|
||||
=title Data Fanout Record (dfanout)
|
||||
|
||||
The Data Fanout or "dfanout" record is used to forward data to up to
|
||||
eight other records. It's similar to the fanout record except that the
|
||||
capability to forward data has been added to it. If has no associated
|
||||
device support.
|
||||
|
||||
=head2 Parameter Fields
|
||||
|
||||
The fields in this record can be classified into the following categories:
|
||||
|
||||
=over
|
||||
|
||||
=item *
|
||||
scan parameters
|
||||
|
||||
=item *
|
||||
desired output parameters
|
||||
|
||||
=item *
|
||||
write parameters
|
||||
|
||||
=item *
|
||||
operator display parameters
|
||||
|
||||
=item *
|
||||
alarm parameters
|
||||
|
||||
=item *
|
||||
monitor parameters
|
||||
|
||||
=item *
|
||||
run-time and simulation mode parameters
|
||||
|
||||
=back
|
||||
|
||||
=recordtype dfanout
|
||||
|
||||
=cut
|
||||
|
||||
menu(dfanoutSELM) {
|
||||
choice(dfanoutSELM_All,"All")
|
||||
choice(dfanoutSELM_Specified,"Specified")
|
||||
choice(dfanoutSELM_Mask,"Mask")
|
||||
}
|
||||
|
||||
recordtype(dfanout) {
|
||||
|
||||
=head3 Scan Parameters
|
||||
|
||||
The data fanout record has the standard fields for specifying under what
|
||||
circumstances it will be processed. These fields are listed in
|
||||
L<Scan Fields>. In addition, L<Scanning Specification> explains how these
|
||||
fields are used. Since the data fanout record supports no direct interfaces
|
||||
to hardware, it cannot be scanned on I/O interrupt, so its SCAN field
|
||||
cannot be C<I/O Intr>.
|
||||
|
||||
=head3 Desired Output Parameters
|
||||
|
||||
The data fanout record must specify where the desired output value
|
||||
originates, i.e., the data which is to be fowarded to the records in its
|
||||
output links. The output mode select (OMSL) field determines whether the
|
||||
output originates from another record or from run-time database access.
|
||||
When set to C<closed_loop>, the desired output is retrieved from the link
|
||||
specified in the desired output (DOL) field, which can specify either a
|
||||
database or a channel access link, and placed into the VAL field. When set
|
||||
to C<supervisory>, the desired output can be written to the VAL field via
|
||||
dbPuts at run-time.
|
||||
|
||||
The DOL field can also be a constant in which case the VAL field is
|
||||
initialized to the constant value.
|
||||
|
||||
Note that there are no conversion parameters, so the desired output value
|
||||
undergoes no conversions before it is sent out to the output links.
|
||||
|
||||
=fields DOL, OMSL, VAL
|
||||
|
||||
=head3 Write Parameters
|
||||
|
||||
The OUTA-OUTH fields specify where VAL is to be sent. Each field that is to
|
||||
forward data must specify an address to another record. See
|
||||
L<Address Specification> for information on specifying links.
|
||||
|
||||
The SELL, SELM, and SELN fields specify which output links are to be
|
||||
used.
|
||||
|
||||
=head4 Menu dfanoutSELM
|
||||
|
||||
SELM is a menu, with three choices:
|
||||
|
||||
=menu dfanoutSELM
|
||||
|
||||
If SELM=="All", then all output links are used, and the values of
|
||||
SELL and SELN are ignored.
|
||||
|
||||
If SELM=="Specified", then the value of SELN is used to specify a single
|
||||
link which will be used. If SELN==0, then no link will be used; if SELN==1,
|
||||
then OUTA will be used, and so on.
|
||||
|
||||
SELN can either have its value set directly, or have its values retrieved
|
||||
from another EPICS PV. If SELL is a valid PV link, then SELN will be set to
|
||||
the values of the linked PV.
|
||||
|
||||
If SELM=="Mask", then SELN will be treated as a bit mask. If bit one of
|
||||
SELN is set, then OUTA will be used, if bit two is set, OUTB will be used.
|
||||
Thus if SELN==5, OUTC and OUTA will be used.
|
||||
|
||||
=fields OUTA, OUTB, OUTC, OUTD, OUTE, OUTF, OUTG, OUTH
|
||||
|
||||
=head3 Operator Display Parameters
|
||||
|
||||
These parameters are used to present meaningful data to the operator. They
|
||||
display the value and other parameters of the data fanout record either
|
||||
textually or graphically.
|
||||
|
||||
The EGU field can contain a string of up to 16 characters describing the
|
||||
value on the VAL field.
|
||||
|
||||
The HOPR and LOPR fields determine the upper and lower display limits for
|
||||
graphic displays and the upper and lower control limits for control
|
||||
displays. They apply to the VAL, HIHI, HIGH, LOW, and LOLO fields. The
|
||||
record support routines C<get_graphic_double> or C<get_control_double>
|
||||
retrieve HOPR and LOPR.
|
||||
|
||||
See L<Fields Common to All Record Types> for more on the record name (NAME)
|
||||
and description (DESC) fields.
|
||||
|
||||
=fields EGU, HOPR, LOPR, NAME, DESC
|
||||
|
||||
=head3 Alarm Parameters
|
||||
|
||||
The possible alarm conditions for data fanouts are the SCAN, READ, INVALID,
|
||||
and limit alarms. The SCAN and READ alarms are called by the record
|
||||
routines. The limit alarms are configured by the user in the HIHI, LOLO,
|
||||
HIGH, and LOW fields using floating point values. The limit alarms apply
|
||||
only to the VAL field. The severity for each of these limits is specified
|
||||
in the corresponding field (HHSV, LLSV, HSV, LSV) and can be either
|
||||
NO_ALARM, MINOR, or MAJOR. In the hysteresis field (HYST) can be entered a
|
||||
number which serves as the deadband on the limit alarms.
|
||||
|
||||
See L<Alarm Specification> for a complete explanation of alarms and these
|
||||
fields. L<Alarm Fields> lists other fields related to alarms that are
|
||||
common to all record types.
|
||||
|
||||
=fields HIHI, HIGH, LOW, LOLO, HHSV, HSV, LSV, LLSV, HYST
|
||||
|
||||
=head3 Monitor Parameters
|
||||
|
||||
These parameters are used to determine when to send monitors placed on the
|
||||
VAL field. These monitors are sent when the value field exceeds the last
|
||||
monitored fields by the specified deadband, ADEL for archivers monitors and
|
||||
MDEL for all other types of monitors. If these fields have a value of zero,
|
||||
everytime the value changes, a monitor will be triggered; if they have a
|
||||
value of -1, everytime the record is scanned, monitors are triggered. See
|
||||
L<Monitor Specification> for a complete explanation of monitors.
|
||||
|
||||
=fields ADEL, MDEL
|
||||
|
||||
=head3 Run-Time Parameters and Simulation Mode Parameters
|
||||
|
||||
These parameters are used by the run-time code for processing the data
|
||||
fanout record. Ther are not configurable. They are used to implement the
|
||||
hysteresis factors for monitor callbacks.
|
||||
|
||||
=fields LALM, ALST, MLST
|
||||
|
||||
=cut
|
||||
|
||||
include "dbCommon.dbd"
|
||||
field(VAL,DBF_DOUBLE) {
|
||||
prompt("Desired Output")
|
||||
promptgroup("40 - Input")
|
||||
asl(ASL0)
|
||||
pp(TRUE)
|
||||
}
|
||||
field(SELM,DBF_MENU) {
|
||||
prompt("Select Mechanism")
|
||||
promptgroup("30 - Action")
|
||||
interest(1)
|
||||
menu(dfanoutSELM)
|
||||
}
|
||||
field(SELN,DBF_USHORT) {
|
||||
prompt("Link Selection")
|
||||
interest(1)
|
||||
initial("1")
|
||||
}
|
||||
field(SELL,DBF_INLINK) {
|
||||
prompt("Link Selection Loc")
|
||||
promptgroup("30 - Action")
|
||||
interest(1)
|
||||
}
|
||||
field(OUTA,DBF_OUTLINK) {
|
||||
prompt("Output Spec A")
|
||||
promptgroup("50 - Output")
|
||||
interest(1)
|
||||
}
|
||||
field(OUTB,DBF_OUTLINK) {
|
||||
prompt("Output Spec B")
|
||||
promptgroup("50 - Output")
|
||||
interest(1)
|
||||
}
|
||||
field(OUTC,DBF_OUTLINK) {
|
||||
prompt("Output Spec C")
|
||||
promptgroup("50 - Output")
|
||||
interest(1)
|
||||
}
|
||||
field(OUTD,DBF_OUTLINK) {
|
||||
prompt("Output Spec D")
|
||||
promptgroup("50 - Output")
|
||||
interest(1)
|
||||
}
|
||||
field(OUTE,DBF_OUTLINK) {
|
||||
prompt("Output Spec E")
|
||||
promptgroup("50 - Output")
|
||||
interest(1)
|
||||
}
|
||||
field(OUTF,DBF_OUTLINK) {
|
||||
prompt("Output Spec F")
|
||||
promptgroup("50 - Output")
|
||||
interest(1)
|
||||
}
|
||||
field(OUTG,DBF_OUTLINK) {
|
||||
prompt("Output Spec G")
|
||||
promptgroup("50 - Output")
|
||||
interest(1)
|
||||
}
|
||||
field(OUTH,DBF_OUTLINK) {
|
||||
prompt("Output Spec H")
|
||||
promptgroup("50 - Output")
|
||||
interest(1)
|
||||
}
|
||||
field(DOL,DBF_INLINK) {
|
||||
prompt("Desired Output Loc")
|
||||
promptgroup("40 - Input")
|
||||
interest(1)
|
||||
}
|
||||
field(OMSL,DBF_MENU) {
|
||||
prompt("Output Mode Select")
|
||||
promptgroup("50 - Output")
|
||||
interest(1)
|
||||
menu(menuOmsl)
|
||||
}
|
||||
field(EGU,DBF_STRING) {
|
||||
prompt("Engineering Units")
|
||||
promptgroup("80 - Display")
|
||||
interest(1)
|
||||
size(16)
|
||||
prop(YES)
|
||||
}
|
||||
field(PREC,DBF_SHORT) {
|
||||
prompt("Display Precision")
|
||||
promptgroup("80 - Display")
|
||||
interest(1)
|
||||
prop(YES)
|
||||
}
|
||||
field(HOPR,DBF_DOUBLE) {
|
||||
prompt("High Operating Range")
|
||||
promptgroup("80 - Display")
|
||||
interest(1)
|
||||
prop(YES)
|
||||
}
|
||||
field(LOPR,DBF_DOUBLE) {
|
||||
prompt("Low Operating Range")
|
||||
promptgroup("80 - Display")
|
||||
interest(1)
|
||||
prop(YES)
|
||||
}
|
||||
field(HIHI,DBF_DOUBLE) {
|
||||
prompt("Hihi Alarm Limit")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
prop(YES)
|
||||
}
|
||||
field(LOLO,DBF_DOUBLE) {
|
||||
prompt("Lolo Alarm Limit")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
prop(YES)
|
||||
}
|
||||
field(HIGH,DBF_DOUBLE) {
|
||||
prompt("High Alarm Limit")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
prop(YES)
|
||||
}
|
||||
field(LOW,DBF_DOUBLE) {
|
||||
prompt("Low Alarm Limit")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
prop(YES)
|
||||
}
|
||||
field(HHSV,DBF_MENU) {
|
||||
prompt("Hihi Severity")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
prop(YES)
|
||||
menu(menuAlarmSevr)
|
||||
}
|
||||
field(LLSV,DBF_MENU) {
|
||||
prompt("Lolo Severity")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
prop(YES)
|
||||
menu(menuAlarmSevr)
|
||||
}
|
||||
field(HSV,DBF_MENU) {
|
||||
prompt("High Severity")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
prop(YES)
|
||||
menu(menuAlarmSevr)
|
||||
}
|
||||
field(LSV,DBF_MENU) {
|
||||
prompt("Low Severity")
|
||||
promptgroup("70 - Alarm")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
prop(YES)
|
||||
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)
|
||||
}
|
||||
|
||||
=head2 Record Support
|
||||
|
||||
=head3 Record Support Routines
|
||||
|
||||
=head2 C<init_record()>
|
||||
|
||||
This routine initializes all output links that are defined. Then it initializes
|
||||
DOL if DOL is a constant or a PV_LINK. When initializing the output links
|
||||
and the DOL link, a non-zero value is returned if an error occurs.
|
||||
|
||||
=head2 C<process()>
|
||||
|
||||
See next section.
|
||||
|
||||
=head2 C<get_value()>
|
||||
|
||||
This routine fills in the members of C<struct valueDes> with the VAL fields
|
||||
value and characteristics.
|
||||
|
||||
=head2 C<get_units()>
|
||||
|
||||
The routine copies the string specified in the EGU field to the location
|
||||
specified by a pointer which is passed to the routine.
|
||||
|
||||
=head2 C<get_graphic_double()>
|
||||
|
||||
If the referenced field is VAL, HIHI, HIGH, LOW, or LOLO, this routine sets
|
||||
the C<upper_disp_limit> member of the C<dbr_grDouble> structure to the
|
||||
HOPR and the C<lower_disp_limit> member to the LOPR. If the referenced
|
||||
field is not one of the above fields, then C<recGblGetControlDouble()>
|
||||
routine is called.
|
||||
|
||||
=head2 C<get_control_double()>
|
||||
|
||||
Same as the C<get_graphic_double> routine except that it uses the
|
||||
C<dbr_ctrlDouble> structure.
|
||||
|
||||
=head2 C<get_alarm_double()>
|
||||
|
||||
This sets the members of the C<dbr_alDouble> structure to the specified
|
||||
alarm limits if the referenced field is VAL:
|
||||
|
||||
=over
|
||||
|
||||
upper_alarm_limit = HIHI
|
||||
|
||||
upper_warning_limit = HIGH
|
||||
|
||||
lower_warning_limit = LOW
|
||||
|
||||
lower_alarm_limit = LOLO
|
||||
|
||||
=back
|
||||
|
||||
If the referenced field is not VAL, the C<recGblGetAlarmDouble()> routine
|
||||
is called.
|
||||
|
||||
=head3 Record Processing
|
||||
|
||||
=over
|
||||
|
||||
=item 1.
|
||||
The C<process()> routine first retrieves a value for DOL and places it in
|
||||
VAL if OMSL is set to colsed loop mode. If an error occurs, then UDF is set
|
||||
to FALSE.
|
||||
|
||||
=item 2.
|
||||
PACT is set TRUE
|
||||
|
||||
=item 3.
|
||||
VAL is then sent to all the records specified in the OUTA-OUTH fields by
|
||||
calling C<recGblePutLinkValue()> for each link.
|
||||
|
||||
=item 4.
|
||||
Alarms are checked and monitors are called if conditions apply.
|
||||
|
||||
=item 5.
|
||||
The data fanout's own forward link is then processed.
|
||||
|
||||
=item 6.
|
||||
PACT is set FALSE, and the C<process()> routine returns. A -1 is returned
|
||||
if there was an error writing values to one of the output links.
|
||||
|
||||
=back
|
||||
|
||||
=cut
|
||||
}
|
@ -97,7 +97,7 @@ sub ParseDBD {
|
||||
my $rtyp = $dbd->recordtype($record_type);
|
||||
if (!defined $rtyp) {
|
||||
$rtyp = DBD::Recordtype->new($record_type);
|
||||
warn "Device using undefined record type '$record_type', place-holder created\n";
|
||||
warn "Device using unknown record type '$record_type', declaration created\n";
|
||||
$dbd->add($rtyp);
|
||||
}
|
||||
$rtyp->add_device(DBD::Device->new($link_type, $dset, $choice));
|
||||
@ -218,7 +218,12 @@ sub parse_breaktable {
|
||||
sub parse_recordtype {
|
||||
my ($dbd, $record_type) = @_;
|
||||
pushContext("recordtype($record_type)");
|
||||
my $rtyp = DBD::Recordtype->new($record_type);
|
||||
# Re-use a matching declaration record type if one exists
|
||||
my $rtyp = $dbd->recordtype($record_type);
|
||||
if (!defined($rtyp) || $rtyp->fields) {
|
||||
# Earlier record type is not a declaration, don't re-use it
|
||||
$rtyp = DBD::Recordtype->new($record_type);
|
||||
}
|
||||
while(1) {
|
||||
parseCommon($rtyp);
|
||||
if (m/\G field \s* \( \s* $RXstr \s* , \s* $RXstr \s* \) \s* \{/xgc) {
|
||||
|
@ -130,7 +130,18 @@ sub attribute {
|
||||
}
|
||||
|
||||
sub equals {
|
||||
dieContext("Record field objects are not comparable");
|
||||
my ($l, $r) = @_;
|
||||
return 1 if $l eq $r;
|
||||
return 0 if
|
||||
$l->{NAME} ne $r->{NAME} ||
|
||||
$l->{DBF_TYPE} ne $r->{DBF_TYPE};
|
||||
my ($la, $ra) = ($l->{ATTR_INDEX}, $r->{ATTR_INDEX});
|
||||
my @keys = sort keys %$la;
|
||||
return 0 if join(',', @keys) ne join(',', sort keys %$ra);
|
||||
foreach my $k (@keys) {
|
||||
return 0 if $la->{$k} ne $ra->{$k};
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub check_valid {
|
||||
|
@ -104,9 +104,19 @@ sub pod {
|
||||
|
||||
sub equals {
|
||||
my ($new, $known) = @_;
|
||||
return 0 if ! $known->fields;
|
||||
return 1 if ! $new->fields;
|
||||
dieContext("Duplicate definition of record type '$known->{NAME}'");
|
||||
return 1 if $new eq $known;
|
||||
return 0 if $new->{NAME} ne $known->{NAME};
|
||||
return 1 if ! $new->fields; # Later declarations always match
|
||||
# NB: Definition after declaration is handled in parse_recordtype()
|
||||
my @nf = @{$new->{FIELD_LIST}};
|
||||
my @kf = @{$known->{FIELD_LIST}};
|
||||
return 0 if scalar @nf != scalar @kf;
|
||||
while (@nf) {
|
||||
my $nf = shift @nf;
|
||||
my $kf = shift @kf;
|
||||
return 0 if ! $nf->equals($kf);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub toDeclaration {
|
||||
|
@ -127,6 +127,33 @@ if ($opt_D) { # Output dependencies only
|
||||
open my $out, '>', $opt_o or
|
||||
die "Can't create $opt_o: $!\n";
|
||||
|
||||
my $podHtml;
|
||||
my $idify;
|
||||
|
||||
if ($::XHTML) {
|
||||
$podHtml = Pod::Simple::XHTML->new();
|
||||
$podHtml->html_doctype(<< '__END_DOCTYPE');
|
||||
<?xml version='1.0' encoding='iso-8859-1'?>
|
||||
<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN'
|
||||
'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'>
|
||||
__END_DOCTYPE
|
||||
$podHtml->html_header_tags($podHtml->html_header_tags .
|
||||
"\n<link rel='stylesheet' href='style.css' type='text/css'>");
|
||||
|
||||
$idify = sub {
|
||||
my $title = shift;
|
||||
return $podHtml->idify($title, 1);
|
||||
}
|
||||
} else { # Fall back to HTML
|
||||
$podHtml = Pod::Simple::HTML->new();
|
||||
$podHtml->html_css('style.css');
|
||||
|
||||
$idify = sub {
|
||||
my $title = shift;
|
||||
return Pod::Simple::HTML::esc($podHtml->section_escape($title));
|
||||
}
|
||||
}
|
||||
|
||||
# Parse the Pod text from the root DBD object
|
||||
my $pod = join "\n", '=for html <div class="pod">', '',
|
||||
map {
|
||||
@ -156,22 +183,6 @@ my $pod = join "\n", '=for html <div class="pod">', '',
|
||||
} $dbd->pod,
|
||||
'=for html </div>', '';
|
||||
|
||||
my $podHtml;
|
||||
|
||||
if ($::XHTML) {
|
||||
$podHtml = Pod::Simple::XHTML->new();
|
||||
$podHtml->html_doctype(<< '__END_DOCTYPE');
|
||||
<?xml version='1.0' encoding='iso-8859-1'?>
|
||||
<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN'
|
||||
'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'>
|
||||
__END_DOCTYPE
|
||||
$podHtml->html_header_tags($podHtml->html_header_tags .
|
||||
"\n<link rel='stylesheet' href='style.css' type='text/css'>");
|
||||
} else { # Fall back to HTML
|
||||
$podHtml = Pod::Simple::HTML->new();
|
||||
$podHtml->html_css('style.css');
|
||||
}
|
||||
|
||||
$podHtml->force_title(encode_entities($title));
|
||||
$podHtml->perldoc_url_prefix('');
|
||||
$podHtml->perldoc_url_postfix('.html');
|
||||
@ -249,7 +260,7 @@ sub fieldTableRow {
|
||||
if ($type eq 'MENU') {
|
||||
my $mn = $fld->attribute('menu');
|
||||
my $menu = $dbd->menu($mn);
|
||||
my $url = $menu ? "#Menu_$mn" : "${mn}.html";
|
||||
my $url = $menu ? '#' . &$idify("Menu $mn") : "${mn}.html";
|
||||
$html .= " (<a href='$url'>$mn</a>)";
|
||||
}
|
||||
$html .= '</td><td class="cell">';
|
||||
@ -377,6 +388,8 @@ can be found in the aai and aSub record types.
|
||||
|
||||
If you look at the L<aoRecord.dbd.pod> file you'll see that the POD there starts
|
||||
by documenting a record-specific menu definition. The "menu" keyword generates a
|
||||
table that lists all the choices found in the named menu.
|
||||
table that lists all the choices found in the named menu. Any MENU fields in the
|
||||
field tables that refer to a locally-defined menu will generate a link to a
|
||||
document section which must be titled "Menu [menuName]".
|
||||
|
||||
=cut
|
||||
|
@ -114,6 +114,7 @@ TESTPROD_HOST += regressTest
|
||||
regressTest_SRCS += regressTest.c
|
||||
regressTest_SRCS += regressTest_registerRecordDeviceDriver.cpp
|
||||
TESTFILES += $(COMMON_DIR)/regressTest.dbd ../regressArray1.db ../regressHex.db ../regressLinkMS.db
|
||||
TESTFILES += ../badCaLink.db
|
||||
TESTS += regressTest
|
||||
|
||||
TARGETS += $(COMMON_DIR)/simmTest.dbd
|
||||
|
4
modules/database/test/std/rec/badCaLink.db
Normal file
4
modules/database/test/std/rec/badCaLink.db
Normal file
@ -0,0 +1,4 @@
|
||||
record(ai, "ai:disconn") {
|
||||
field(INP , "invalid CA")
|
||||
field(UDF , "0")
|
||||
}
|
@ -8,6 +8,7 @@
|
||||
#include <testMain.h>
|
||||
#include <dbAccess.h>
|
||||
#include <errlog.h>
|
||||
#include <alarm.h>
|
||||
|
||||
#include <calcoutRecord.h>
|
||||
#include <waveformRecord.h>
|
||||
@ -123,12 +124,26 @@ void testLinkMS(void)
|
||||
testdbCleanup();
|
||||
}
|
||||
|
||||
/* lp:1798855 disconnected CA link must alarm */
|
||||
static
|
||||
void testCADisconn(void)
|
||||
{
|
||||
testDiag("In testCADisconn()");
|
||||
|
||||
startRegressTestIoc("badCaLink.db");
|
||||
|
||||
testdbPutFieldOk("ai:disconn.PROC", DBF_LONG, 1);
|
||||
testdbGetFieldEqual("ai:disconn.SEVR", DBF_LONG, INVALID_ALARM);
|
||||
testdbGetFieldEqual("ai:disconn.STAT", DBF_LONG, LINK_ALARM);
|
||||
}
|
||||
|
||||
|
||||
MAIN(regressTest)
|
||||
{
|
||||
testPlan(31);
|
||||
testPlan(34);
|
||||
testArrayLength1();
|
||||
testHexConstantLinks();
|
||||
testLinkMS();
|
||||
testCADisconn();
|
||||
return testDone();
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
use lib '@TOP@/lib/perl';
|
||||
|
||||
use Test::More tests => 17;
|
||||
use Test::More tests => 23;
|
||||
|
||||
use DBD::Recordtype;
|
||||
use DBD::Recfield;
|
||||
@ -13,6 +13,11 @@ isa_ok $rtyp, 'DBD::Recordtype';
|
||||
is $rtyp->name, 'test', 'Record name';
|
||||
is $rtyp->fields, 0, 'No fields yet';
|
||||
|
||||
is $rtyp->equals($rtyp), 1, 'A declaration == itself';
|
||||
|
||||
my $rt2 = DBD::Recordtype->new('test');
|
||||
is $rtyp->equals($rt2), 1, 'A declaration == a different declaration';
|
||||
|
||||
my $fld1 = DBD::Recfield->new('NAME', 'DBF_STRING');
|
||||
$fld1->add_attribute("size", "41");
|
||||
$fld1->check_valid;
|
||||
@ -26,6 +31,18 @@ is $rtyp->fields, 1, 'First field added';
|
||||
$rtyp->add_field($fld2);
|
||||
is $rtyp->fields, 2, 'Second field added';
|
||||
|
||||
is $rtyp->equals($rtyp), 1, 'A definition == itself';
|
||||
is $rt2->equals($rtyp), 1, 'A declaration == a definition';
|
||||
|
||||
$rt2->add_field($fld1);
|
||||
my $fld3 = DBD::Recfield->new('DTYP', 'DBF_DEVICE');
|
||||
$fld3->check_valid;
|
||||
$rt2->add_field($fld3);
|
||||
is $rt2->equals($rtyp), 1, 'Identical definitions are equal';
|
||||
|
||||
$fld3->add_attribute("pp", "TRUE");
|
||||
is $rt2->equals($rtyp), 0, 'Different definitions are not equal';
|
||||
|
||||
my @fields = $rtyp->fields;
|
||||
is_deeply \@fields, [$fld1, $fld2], 'Field list';
|
||||
|
||||
|
@ -601,12 +601,12 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros)
|
||||
macPushScope(handle);
|
||||
macInstallMacros(handle, defines);
|
||||
|
||||
wasOkToBlock = epicsThreadIsOkToBlock();
|
||||
epicsThreadSetOkToBlock(1);
|
||||
|
||||
/*
|
||||
* Read commands till EOF or exit
|
||||
*/
|
||||
argc = 0;
|
||||
wasOkToBlock = epicsThreadIsOkToBlock();
|
||||
epicsThreadSetOkToBlock(1);
|
||||
for (;;) {
|
||||
/*
|
||||
* Read a line
|
||||
@ -681,15 +681,15 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros)
|
||||
redirect = NULL;
|
||||
for (;;) {
|
||||
if (argc >= argvCapacity) {
|
||||
char **av;
|
||||
argvCapacity += 50;
|
||||
av = (char **)realloc (argv, argvCapacity * sizeof *argv);
|
||||
if (av == NULL) {
|
||||
int newCapacity = argvCapacity + 20;
|
||||
char **newv = (char **)realloc (argv, newCapacity * sizeof *argv);
|
||||
if (newv == NULL) {
|
||||
fprintf (epicsGetStderr(), "Out of memory!\n");
|
||||
argc = -1;
|
||||
break;
|
||||
}
|
||||
argv = av;
|
||||
argv = newv;
|
||||
argvCapacity = newCapacity;
|
||||
}
|
||||
c = line[icin++];
|
||||
if (c == '\0')
|
||||
@ -838,16 +838,14 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros)
|
||||
break;
|
||||
}
|
||||
if (iarg >= argBufCapacity) {
|
||||
void *np;
|
||||
|
||||
argBufCapacity += 20;
|
||||
np = realloc (argBuf, argBufCapacity * sizeof *argBuf);
|
||||
if (np == NULL) {
|
||||
int newCapacity = argBufCapacity + 20;
|
||||
void *newBuf = realloc(argBuf, newCapacity * sizeof *argBuf);
|
||||
if (newBuf == NULL) {
|
||||
fprintf (epicsGetStderr(), "Out of memory!\n");
|
||||
argBufCapacity -= 20;
|
||||
break;
|
||||
}
|
||||
argBuf = (iocshArgBuf *)np;
|
||||
argBuf = (iocshArgBuf *) newBuf;
|
||||
argBufCapacity = newCapacity;
|
||||
}
|
||||
if (piocshFuncDef->arg[iarg]->type == iocshArgArgv) {
|
||||
argBuf[iarg].aval.ac = argc-iarg;
|
||||
@ -892,7 +890,7 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros)
|
||||
errlogFlush();
|
||||
if (readlineContext)
|
||||
epicsReadlineEnd(readlineContext);
|
||||
epicsThreadSetOkToBlock( wasOkToBlock);
|
||||
epicsThreadSetOkToBlock(wasOkToBlock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -236,6 +236,7 @@ static const iocshFuncDef errlogFuncDef = {"errlog",1,errlogArgs};
|
||||
static void errlogCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
errlog(args[0].sval);
|
||||
errlogFlush();
|
||||
}
|
||||
|
||||
/* iocLogPrefix */
|
||||
|
@ -225,14 +225,14 @@ static int generalTimeGetEventPriority(epicsTimeStamp *pDest, int eventNumber,
|
||||
gtProvider *ptp;
|
||||
int status = S_time_noProvider;
|
||||
epicsTimeStamp ts;
|
||||
STATIC_ASSERT ( epicsTimeEventBestTime == -1 );
|
||||
|
||||
generalTime_Init();
|
||||
|
||||
IFDEBUG(2)
|
||||
printf("generalTimeGetEventPriority(eventNum=%d)\n", eventNumber);
|
||||
|
||||
if ((eventNumber < 0 || eventNumber >= NUM_TIME_EVENTS) &&
|
||||
(eventNumber != epicsTimeEventBestTime))
|
||||
if (eventNumber < epicsTimeEventBestTime)
|
||||
return S_time_badEvent;
|
||||
|
||||
epicsMutexMustLock(gtPvt.eventListLock);
|
||||
@ -245,7 +245,9 @@ static int generalTimeGetEventPriority(epicsTimeStamp *pDest, int eventNumber,
|
||||
if (pPrio)
|
||||
*pPrio = ptp->priority;
|
||||
|
||||
if (eventNumber == epicsTimeEventBestTime) {
|
||||
if (eventNumber >= NUM_TIME_EVENTS) {
|
||||
*pDest = ts;
|
||||
} else if (eventNumber == epicsTimeEventBestTime) {
|
||||
if (epicsTimeGreaterThanEqual(&ts,
|
||||
>Pvt.lastProvidedBestTime)) {
|
||||
*pDest = ts;
|
||||
|
@ -17,7 +17,11 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#define NUM_TIME_EVENTS 256
|
||||
/* Time Events are numbered 0 through (NUM_TIME_EVENTS-1) */
|
||||
/* Time Events numbered 0 through (NUM_TIME_EVENTS-1) are validated by */
|
||||
/* code in epicsGeneralTime.c that tests for advancing timestamps and */
|
||||
/* enforces that restriction. Event numbers greater than or equal to */
|
||||
/* NUM_TIME_EVENTS are now allowed if supported by a custom time provider */
|
||||
/* which should provide its own advancing timestamp validation. */
|
||||
|
||||
epicsShareFunc void generalTime_Init(void);
|
||||
|
||||
|
@ -38,6 +38,7 @@ typedef struct ringPvt {
|
||||
volatile int nextPut;
|
||||
volatile int nextGet;
|
||||
int size;
|
||||
int highWaterMark;
|
||||
volatile char buffer[1]; /* actually larger */
|
||||
}ringPvt;
|
||||
|
||||
@ -47,6 +48,7 @@ epicsShareFunc epicsRingBytesId epicsShareAPI epicsRingBytesCreate(int size)
|
||||
if(!pring)
|
||||
return NULL;
|
||||
pring->size = size + SLOP;
|
||||
pring->highWaterMark = 0;
|
||||
pring->nextGet = 0;
|
||||
pring->nextPut = 0;
|
||||
pring->lock = 0;
|
||||
@ -118,7 +120,7 @@ epicsShareFunc int epicsShareAPI epicsRingBytesPut(
|
||||
{
|
||||
ringPvt *pring = (ringPvt *)id;
|
||||
int nextGet, nextPut, size;
|
||||
int freeCount, copyCount, topCount;
|
||||
int freeCount, copyCount, topCount, used;
|
||||
|
||||
if (pring->lock) epicsSpinLock(pring->lock);
|
||||
nextGet = pring->nextGet;
|
||||
@ -131,8 +133,9 @@ epicsShareFunc int epicsShareAPI epicsRingBytesPut(
|
||||
if (pring->lock) epicsSpinUnlock(pring->lock);
|
||||
return 0;
|
||||
}
|
||||
if (nbytes)
|
||||
if (nbytes) {
|
||||
memcpy ((void *)&pring->buffer[nextPut], value, nbytes);
|
||||
}
|
||||
nextPut += nbytes;
|
||||
}
|
||||
else {
|
||||
@ -143,8 +146,9 @@ epicsShareFunc int epicsShareAPI epicsRingBytesPut(
|
||||
}
|
||||
topCount = size - nextPut;
|
||||
copyCount = (nbytes > topCount) ? topCount : nbytes;
|
||||
if (copyCount)
|
||||
if (copyCount) {
|
||||
memcpy ((void *)&pring->buffer[nextPut], value, copyCount);
|
||||
}
|
||||
nextPut += copyCount;
|
||||
if (nextPut == size) {
|
||||
int nLeft = nbytes - copyCount;
|
||||
@ -155,6 +159,10 @@ epicsShareFunc int epicsShareAPI epicsRingBytesPut(
|
||||
}
|
||||
pring->nextPut = nextPut;
|
||||
|
||||
used = nextPut - nextGet;
|
||||
if (used < 0) used += pring->size;
|
||||
if (used > pring->highWaterMark) pring->highWaterMark = used;
|
||||
|
||||
if (pring->lock) epicsSpinUnlock(pring->lock);
|
||||
return nbytes;
|
||||
}
|
||||
@ -224,3 +232,20 @@ epicsShareFunc int epicsShareAPI epicsRingBytesIsFull(epicsRingBytesId id)
|
||||
{
|
||||
return (epicsRingBytesFreeBytes(id) <= 0);
|
||||
}
|
||||
|
||||
epicsShareFunc int epicsShareAPI epicsRingBytesHighWaterMark(epicsRingBytesIdConst id)
|
||||
{
|
||||
ringPvt *pring = (ringPvt *)id;
|
||||
return pring->highWaterMark;
|
||||
}
|
||||
|
||||
epicsShareFunc void epicsShareAPI epicsRingBytesResetHighWaterMark(epicsRingBytesId id)
|
||||
{
|
||||
ringPvt *pring = (ringPvt *)id;
|
||||
int used;
|
||||
if (pring->lock) epicsSpinLock(pring->lock);
|
||||
used = pring->nextGet - pring->nextPut;
|
||||
if (used < 0) used += pring->size;
|
||||
pring->highWaterMark = used;
|
||||
if (pring->lock) epicsSpinUnlock(pring->lock);
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ extern "C" {
|
||||
#include "shareLib.h"
|
||||
|
||||
typedef void *epicsRingBytesId;
|
||||
typedef void const *epicsRingBytesIdConst;
|
||||
|
||||
epicsShareFunc epicsRingBytesId epicsShareAPI epicsRingBytesCreate(int nbytes);
|
||||
/* Same, but secured by a spinlock */
|
||||
@ -39,6 +40,8 @@ epicsShareFunc int epicsShareAPI epicsRingBytesUsedBytes(epicsRingBytesId id);
|
||||
epicsShareFunc int epicsShareAPI epicsRingBytesSize(epicsRingBytesId id);
|
||||
epicsShareFunc int epicsShareAPI epicsRingBytesIsEmpty(epicsRingBytesId id);
|
||||
epicsShareFunc int epicsShareAPI epicsRingBytesIsFull(epicsRingBytesId id);
|
||||
epicsShareFunc int epicsShareAPI epicsRingBytesHighWaterMark(epicsRingBytesIdConst id);
|
||||
epicsShareFunc void epicsShareAPI epicsRingBytesResetHighWaterMark(epicsRingBytesId id);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -90,3 +90,15 @@ epicsShareFunc int epicsShareAPI epicsRingPointerIsFull(epicsRingPointerId id)
|
||||
voidPointer *pvoidPointer = reinterpret_cast<voidPointer*>(id);
|
||||
return((pvoidPointer->isFull()) ? 1 : 0);
|
||||
}
|
||||
|
||||
epicsShareFunc int epicsShareAPI epicsRingPointerGetHighWaterMark(epicsRingPointerIdConst id)
|
||||
{
|
||||
voidPointer const *pvoidPointer = reinterpret_cast<voidPointer const*>(id);
|
||||
return(pvoidPointer->getHighWaterMark());
|
||||
}
|
||||
|
||||
epicsShareFunc void epicsShareAPI epicsRingPointerResetHighWaterMark(epicsRingPointerId id)
|
||||
{
|
||||
voidPointer *pvoidPointer = reinterpret_cast<voidPointer*>(id);
|
||||
pvoidPointer->resetHighWaterMark();
|
||||
}
|
||||
|
@ -40,18 +40,22 @@ public: /* Functions */
|
||||
int getSize() const;
|
||||
bool isEmpty() const;
|
||||
bool isFull() const;
|
||||
int getHighWaterMark() const;
|
||||
void resetHighWaterMark();
|
||||
|
||||
private: /* Prevent compiler-generated member functions */
|
||||
/* default constructor, copy constructor, assignment operator */
|
||||
epicsRingPointer();
|
||||
epicsRingPointer(const epicsRingPointer &);
|
||||
epicsRingPointer& operator=(const epicsRingPointer &);
|
||||
int getUsedNoLock() const;
|
||||
|
||||
private: /* Data */
|
||||
epicsSpinId lock;
|
||||
volatile int nextPush;
|
||||
volatile int nextPop;
|
||||
int size;
|
||||
int highWaterMark;
|
||||
T * volatile * buffer;
|
||||
};
|
||||
|
||||
@ -59,6 +63,7 @@ extern "C" {
|
||||
#endif /*__cplusplus */
|
||||
|
||||
typedef void *epicsRingPointerId;
|
||||
typedef void const *epicsRingPointerIdConst;
|
||||
|
||||
epicsShareFunc epicsRingPointerId epicsShareAPI epicsRingPointerCreate(int size);
|
||||
/* Same, but secured by a spinlock */
|
||||
@ -74,6 +79,8 @@ epicsShareFunc int epicsShareAPI epicsRingPointerGetUsed(epicsRingPointerId id)
|
||||
epicsShareFunc int epicsShareAPI epicsRingPointerGetSize(epicsRingPointerId id);
|
||||
epicsShareFunc int epicsShareAPI epicsRingPointerIsEmpty(epicsRingPointerId id);
|
||||
epicsShareFunc int epicsShareAPI epicsRingPointerIsFull(epicsRingPointerId id);
|
||||
epicsShareFunc int epicsShareAPI epicsRingPointerGetHighWaterMark(epicsRingPointerIdConst id);
|
||||
epicsShareFunc void epicsShareAPI epicsRingPointerResetHighWaterMark(epicsRingPointerId id);
|
||||
|
||||
/* This routine was incorrectly named in previous releases */
|
||||
#define epicsRingPointerSize epicsRingPointerGetSize
|
||||
@ -95,7 +102,8 @@ epicsShareFunc int epicsShareAPI epicsRingPointerIsFull(epicsRingPointerId id);
|
||||
|
||||
template <class T>
|
||||
inline epicsRingPointer<T>::epicsRingPointer(int sz, bool locked) :
|
||||
lock(0), nextPush(0), nextPop(0), size(sz+1), buffer(new T* [sz+1])
|
||||
lock(0), nextPush(0), nextPop(0), size(sz+1), highWaterMark(0),
|
||||
buffer(new T* [sz+1])
|
||||
{
|
||||
if (locked)
|
||||
lock = epicsSpinCreate();
|
||||
@ -121,6 +129,8 @@ inline bool epicsRingPointer<T>::push(T *p)
|
||||
}
|
||||
buffer[next] = p;
|
||||
nextPush = newNext;
|
||||
int used = getUsedNoLock();
|
||||
if (used > highWaterMark) highWaterMark = used;
|
||||
if (lock) epicsSpinUnlock(lock);
|
||||
return(true);
|
||||
}
|
||||
@ -161,12 +171,19 @@ inline int epicsRingPointer<T>::getFree() const
|
||||
return n;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline int epicsRingPointer<T>::getUsedNoLock() const
|
||||
{
|
||||
int n = nextPush - nextPop;
|
||||
if (n < 0) n += size;
|
||||
return n;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline int epicsRingPointer<T>::getUsed() const
|
||||
{
|
||||
if (lock) epicsSpinLock(lock);
|
||||
int n = nextPush - nextPop;
|
||||
if (n < 0) n += size;
|
||||
int n = getUsedNoLock();
|
||||
if (lock) epicsSpinUnlock(lock);
|
||||
return n;
|
||||
}
|
||||
@ -196,6 +213,20 @@ inline bool epicsRingPointer<T>::isFull() const
|
||||
return((count == 0) || (count == size));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline int epicsRingPointer<T>::getHighWaterMark() const
|
||||
{
|
||||
return highWaterMark;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void epicsRingPointer<T>::resetHighWaterMark()
|
||||
{
|
||||
if (lock) epicsSpinLock(lock);
|
||||
highWaterMark = getUsedNoLock();
|
||||
if (lock) epicsSpinUnlock(lock);
|
||||
}
|
||||
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* INCepicsRingPointerh */
|
||||
|
@ -30,7 +30,8 @@ typedef struct info {
|
||||
epicsRingBytesId ring;
|
||||
}info;
|
||||
|
||||
static void check(epicsRingBytesId ring, int expectedFree)
|
||||
static void check(epicsRingBytesId ring, int expectedFree,
|
||||
int expectedHighWaterMark)
|
||||
{
|
||||
int expectedUsed = RINGSIZE - expectedFree;
|
||||
int expectedEmpty = (expectedUsed == 0);
|
||||
@ -39,11 +40,14 @@ static void check(epicsRingBytesId ring, int expectedFree)
|
||||
int nUsed = epicsRingBytesUsedBytes(ring);
|
||||
int isEmpty = epicsRingBytesIsEmpty(ring);
|
||||
int isFull = epicsRingBytesIsFull(ring);
|
||||
int highWaterMark = epicsRingBytesHighWaterMark(ring);
|
||||
|
||||
testOk(nFree == expectedFree, "Free: %d == %d", nFree, expectedFree);
|
||||
testOk(nUsed == expectedUsed, "Used: %d == %d", nUsed, expectedUsed);
|
||||
testOk(isEmpty == expectedEmpty, "Empty: %d == %d", isEmpty, expectedEmpty);
|
||||
testOk(isFull == expectedFull, "Full: %d == %d", isFull, expectedFull);
|
||||
testOk(highWaterMark == expectedHighWaterMark, "HighWaterMark: %d == %d",
|
||||
highWaterMark, expectedHighWaterMark);
|
||||
}
|
||||
|
||||
MAIN(ringBytesTest)
|
||||
@ -55,7 +59,7 @@ MAIN(ringBytesTest)
|
||||
char get[RINGSIZE+1];
|
||||
epicsRingBytesId ring;
|
||||
|
||||
testPlan(245);
|
||||
testPlan(292);
|
||||
|
||||
pinfo = calloc(1,sizeof(info));
|
||||
if (!pinfo) {
|
||||
@ -70,50 +74,54 @@ MAIN(ringBytesTest)
|
||||
if (!ring) {
|
||||
testAbort("epicsRingBytesCreate failed");
|
||||
}
|
||||
check(ring, RINGSIZE);
|
||||
check(ring, RINGSIZE, 0);
|
||||
|
||||
for (i = 0 ; i < sizeof(put) ; i++)
|
||||
put[i] = i;
|
||||
for(i = 0 ; i < RINGSIZE ; i++) {
|
||||
n = epicsRingBytesPut(ring, put, i);
|
||||
testOk(n==i, "ring put %d", i);
|
||||
check(ring, RINGSIZE-i);
|
||||
check(ring, RINGSIZE-i, i);
|
||||
n = epicsRingBytesGet(ring, get, i);
|
||||
testOk(n==i, "ring get %d", i);
|
||||
check(ring, RINGSIZE);
|
||||
check(ring, RINGSIZE, i);
|
||||
testOk(memcmp(put,get,i)==0, "get matches write");
|
||||
}
|
||||
|
||||
epicsRingBytesResetHighWaterMark(ring);
|
||||
|
||||
for(i = 0 ; i < RINGSIZE ; i++) {
|
||||
n = epicsRingBytesPut(ring, put+i, 1);
|
||||
testOk(n==1, "ring put 1, %d", i);
|
||||
check(ring, RINGSIZE-1-i);
|
||||
check(ring, RINGSIZE-1-i, i + 1);
|
||||
}
|
||||
n = epicsRingBytesPut(ring, put+RINGSIZE, 1);
|
||||
testOk(n==0, "put to full ring");
|
||||
check(ring, 0);
|
||||
check(ring, 0, RINGSIZE);
|
||||
for(i = 0 ; i < RINGSIZE ; i++) {
|
||||
n = epicsRingBytesGet(ring, get+i, 1);
|
||||
testOk(n==1, "ring get 1, %d", i);
|
||||
check(ring, 1+i);
|
||||
check(ring, 1+i, RINGSIZE);
|
||||
}
|
||||
testOk(memcmp(put,get,RINGSIZE)==0, "get matches write");
|
||||
n = epicsRingBytesGet(ring, get+RINGSIZE, 1);
|
||||
testOk(n==0, "get from empty ring");
|
||||
check(ring, RINGSIZE);
|
||||
check(ring, RINGSIZE, RINGSIZE);
|
||||
|
||||
epicsRingBytesResetHighWaterMark(ring);
|
||||
|
||||
n = epicsRingBytesPut(ring, put, RINGSIZE+1);
|
||||
testOk(n==0, "ring put beyond ring capacity (%d, expected 0)",n);
|
||||
check(ring, RINGSIZE);
|
||||
check(ring, RINGSIZE, 0);
|
||||
n = epicsRingBytesPut(ring, put, 1);
|
||||
testOk(n==1, "ring put %d", 1);
|
||||
check(ring, RINGSIZE-1);
|
||||
check(ring, RINGSIZE-1, 1);
|
||||
n = epicsRingBytesPut(ring, put, RINGSIZE);
|
||||
testOk(n==0, "ring put beyond ring capacity (%d, expected 0)",n);
|
||||
check(ring, RINGSIZE-1);
|
||||
check(ring, RINGSIZE-1, 1);
|
||||
n = epicsRingBytesGet(ring, get, 1);
|
||||
testOk(n==1, "ring get %d", 1);
|
||||
check(ring, RINGSIZE);
|
||||
check(ring, RINGSIZE, 1);
|
||||
|
||||
epicsRingBytesDelete(ring);
|
||||
epicsEventDestroy(consumerEvent);
|
||||
|
@ -64,6 +64,7 @@ static void testSingle(void)
|
||||
testOk1(epicsRingPointerGetFree(ring)==rsize);
|
||||
testOk1(epicsRingPointerGetSize(ring)==rsize);
|
||||
testOk1(epicsRingPointerGetUsed(ring)==0);
|
||||
testOk1(epicsRingPointerGetHighWaterMark(ring)==0);
|
||||
|
||||
testOk1(epicsRingPointerPop(ring)==NULL);
|
||||
|
||||
@ -75,6 +76,10 @@ static void testSingle(void)
|
||||
testOk1(epicsRingPointerGetFree(ring)==rsize-1);
|
||||
testOk1(epicsRingPointerGetSize(ring)==rsize);
|
||||
testOk1(epicsRingPointerGetUsed(ring)==1);
|
||||
testOk1(epicsRingPointerGetHighWaterMark(ring)==1);
|
||||
|
||||
epicsRingPointerResetHighWaterMark(ring);
|
||||
testOk1(epicsRingPointerGetHighWaterMark(ring)==1);
|
||||
|
||||
testDiag("Fill it up");
|
||||
for(i=2; i<2*rsize; i++) {
|
||||
@ -92,6 +97,7 @@ static void testSingle(void)
|
||||
testOk1(epicsRingPointerGetFree(ring)==0);
|
||||
testOk1(epicsRingPointerGetSize(ring)==rsize);
|
||||
testOk1(epicsRingPointerGetUsed(ring)==rsize);
|
||||
testOk1(epicsRingPointerGetHighWaterMark(ring)==rsize);
|
||||
|
||||
testDiag("Drain it out");
|
||||
for(i=1; i<2*rsize; i++) {
|
||||
@ -108,6 +114,7 @@ static void testSingle(void)
|
||||
testOk1(epicsRingPointerGetFree(ring)==rsize);
|
||||
testOk1(epicsRingPointerGetSize(ring)==rsize);
|
||||
testOk1(epicsRingPointerGetUsed(ring)==0);
|
||||
testOk1(epicsRingPointerGetHighWaterMark(ring)==rsize);
|
||||
|
||||
testDiag("Fill it up again");
|
||||
for(i=2; i<2*rsize; i++) {
|
||||
@ -236,7 +243,7 @@ MAIN(ringPointerTest)
|
||||
{
|
||||
int prio = epicsThreadGetPrioritySelf();
|
||||
|
||||
testPlan(37);
|
||||
testPlan(42);
|
||||
testSingle();
|
||||
if (prio)
|
||||
epicsThreadSetPriority(epicsThreadGetIdSelf(), epicsThreadPriorityScanLow);
|
||||
|
@ -1,4 +1,4 @@
|
||||
#!/usr/bin/perl
|
||||
#!/usr/bin/env perl
|
||||
=head1 NAME
|
||||
|
||||
tap-to-junit-xml - convert perl-style TAP test output to JUnit-style XML
|
||||
|
Reference in New Issue
Block a user