Added support for scan and wait records
This commit is contained in:
@@ -14,7 +14,7 @@ SRCS = \
|
||||
../recEr.c ../recPal.c ../recSub.c ../recErevent.c \
|
||||
../recPermissive.c ../recSwitch.c ../recEvent.c ../recPid.c \
|
||||
../recTimer.c ../recFanout.c ../recPulseCounter.c ../recWaveform.c \
|
||||
../recSubArray.c
|
||||
../recSubArray.c ../recWait.c ../caMonitor.c ../recScan.c
|
||||
|
||||
OBJS = \
|
||||
recAi.o recGsub.o recPulseDelay.o recAo.o recHistogram.o \
|
||||
@@ -24,7 +24,7 @@ OBJS = \
|
||||
recStringin.o recEgevent.o recMbboDirect.o recStringout.o \
|
||||
recEr.o recPal.o recSub.o recErevent.o recPermissive.o recSwitch.o \
|
||||
recEvent.o recPid.o recTimer.o recFanout.o recPulseCounter.o \
|
||||
recWaveform.o recSubArray.o
|
||||
recWaveform.o recSubArray.o recWait.o caMonitor.o recScan.o
|
||||
|
||||
PROD = recSup
|
||||
|
||||
|
||||
152
src/rec/caMonitor.c
Normal file
152
src/rec/caMonitor.c
Normal file
@@ -0,0 +1,152 @@
|
||||
#include <vxWorks.h>
|
||||
#include <taskLib.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <rngLib.h>
|
||||
#include <ellLib.h>
|
||||
#include <vxLib.h>
|
||||
#include <dbDefs.h>
|
||||
#include <taskwd.h>
|
||||
#include <fast_lock.h>
|
||||
#include <cadef.h>
|
||||
#include <caerr.h>
|
||||
#include <caeventmask.h>
|
||||
#include <calink.h>
|
||||
#include <task_params.h>
|
||||
#include <freeList.h>
|
||||
#include <caMonitor.h>
|
||||
|
||||
#define QUEUE_SIZE 256
|
||||
LOCAL int taskid=0;
|
||||
LOCAL ELLLIST capvtList;
|
||||
LOCAL RING_ID ringQ;;
|
||||
LOCAL FAST_LOCK lock;
|
||||
LOCAL void *freeListPvt;
|
||||
|
||||
typedef enum {cmdNone,cmdAdd,cmdRemove} COMMAND;
|
||||
|
||||
typedef struct {
|
||||
ELLNODE node;
|
||||
CAMONITOR *pcamonitor;
|
||||
chid chid;
|
||||
evid evid;
|
||||
COMMAND cmd;
|
||||
struct dbr_sts_double rtndata; /*Not currently used */
|
||||
} CAPVT;
|
||||
|
||||
void caMonitorTask(void);
|
||||
|
||||
LOCAL void eventCallback(struct event_handler_args eha)
|
||||
{
|
||||
struct dbr_sts_double *pdata = eha.dbr;
|
||||
CAPVT *pcapvt;
|
||||
CAMONITOR *pcamonitor;
|
||||
|
||||
pcapvt = (CAPVT *)eha.usr;
|
||||
pcamonitor = pcapvt->pcamonitor;
|
||||
(pcamonitor->callback)(pcamonitor);
|
||||
}
|
||||
|
||||
LOCAL void caMonitorStart(void)
|
||||
{
|
||||
FASTLOCKINIT(&lock);
|
||||
freeListInitPvt(&freeListPvt,sizeof(CAPVT),1);
|
||||
if((ringQ = rngCreate(sizeof(void *) * QUEUE_SIZE)) == NULL) {
|
||||
errMessage(0,"caMonitorStart failed");
|
||||
exit(1);
|
||||
}
|
||||
ellInit(&capvtList);
|
||||
taskid = taskSpawn("caMonitorTask",CA_CLIENT_PRI-1,VX_FP_TASK,
|
||||
CA_CLIENT_STACK,(FUNCPTR)caMonitorTask,0,0,0,0,0,0,0,0,0,0);
|
||||
if(taskid==ERROR) {
|
||||
errMessage(0,"caMonitorStart: taskSpawn Failure\n");
|
||||
}
|
||||
}
|
||||
|
||||
long caMonitorAdd(CAMONITOR *pcamonitor)
|
||||
{
|
||||
CAPVT *pcapvt;
|
||||
|
||||
if(!taskid) caMonitorStart();
|
||||
FASTLOCK(&lock);
|
||||
pcapvt = freeListCalloc(freeListPvt);
|
||||
pcamonitor->caMonitorPvt = pcapvt;
|
||||
pcapvt->pcamonitor = pcamonitor;
|
||||
pcapvt->cmd = cmdAdd;
|
||||
if(rngBufPut(ringQ,(void *)&pcapvt,sizeof(pcapvt))
|
||||
!=sizeof(pcamonitor)) errMessage(0,"caMonitorAdd: rngBufPut error");
|
||||
ellAdd(&capvtList,(void *)pcapvt);
|
||||
FASTUNLOCK(&lock);
|
||||
}
|
||||
|
||||
long caMonitorDelete(CAMONITOR *pcamonitor)
|
||||
{
|
||||
CAPVT *pcapvt = pcamonitor->caMonitorPvt;
|
||||
|
||||
FASTLOCK(&lock);
|
||||
pcapvt->cmd = cmdRemove;
|
||||
if(rngBufPut(ringQ,(void *)&pcapvt,sizeof(pcapvt))
|
||||
!=sizeof(pcamonitor)) errMessage(0,"caMonitorDelete: rngBufPut error");
|
||||
FASTUNLOCK(&lock);
|
||||
}
|
||||
|
||||
/*LOCAL */
|
||||
void caMonitorTask(void)
|
||||
{
|
||||
CAPVT *pcapvt;
|
||||
CAMONITOR *pcamonitor;
|
||||
int status;
|
||||
|
||||
taskwdInsert(taskIdSelf(),NULL,NULL);
|
||||
SEVCHK(ca_task_initialize(),"ca_task_initialize");
|
||||
while(TRUE) {
|
||||
while (rngNBytes(ringQ)>=sizeof(pcapvt)){
|
||||
if(rngBufGet(ringQ,(void *)&pcapvt,sizeof(pcapvt))
|
||||
!=sizeof(pcapvt)) {
|
||||
errMessage(0,"caMonitorTask: rngBufGet error");
|
||||
continue;
|
||||
}
|
||||
FASTLOCK(&lock);
|
||||
pcamonitor = pcapvt->pcamonitor;
|
||||
if(pcapvt->cmd==cmdAdd) {
|
||||
SEVCHK(ca_build_and_connect(pcamonitor->channame,TYPENOTCONN,0,
|
||||
&pcapvt->chid,0,NULL,pcapvt),
|
||||
"ca_build_and_connect");
|
||||
SEVCHK(ca_add_event(DBR_STS_DOUBLE,pcapvt->chid,
|
||||
eventCallback,pcapvt,&pcapvt->evid),
|
||||
"ca_add_event");
|
||||
} else {/*must be cmdRemove*/
|
||||
SEVCHK(ca_clear_channel(pcapvt->chid),"ca_clear_channel");
|
||||
pcapvt->cmd=cmdNone;
|
||||
ellDelete(&capvtList,(void *)pcapvt);
|
||||
freeListFree(freeListPvt,pcapvt);
|
||||
}
|
||||
pcapvt->cmd=cmdNone;
|
||||
FASTUNLOCK(&lock);
|
||||
}
|
||||
status = ca_pend_event(.1);
|
||||
if(status!=ECA_NORMAL && status!=ECA_TIMEOUT)
|
||||
SEVCHK(status,"ca_pend_event");
|
||||
}
|
||||
}
|
||||
|
||||
static void myCallback(struct caMonitor *pcamonitor)
|
||||
{
|
||||
printf("myCallback: %s\n",pcamonitor->channame);
|
||||
}
|
||||
|
||||
int testCaMonitor(char *name)
|
||||
{
|
||||
CAMONITOR *pcamonitor;
|
||||
long status;
|
||||
|
||||
pcamonitor = calloc(1,sizeof(CAMONITOR));
|
||||
pcamonitor->channame = calloc(1,strlen(name)+1);
|
||||
pcamonitor->callback = myCallback;
|
||||
strcpy(pcamonitor->channame,name);
|
||||
status = caMonitorAdd(pcamonitor);
|
||||
if(status) errMessage(status,"testCaMonitor error");
|
||||
return(0);
|
||||
}
|
||||
9
src/rec/caMonitor.h
Normal file
9
src/rec/caMonitor.h
Normal file
@@ -0,0 +1,9 @@
|
||||
typedef struct caMonitor{
|
||||
char *channame;
|
||||
void (*callback)(struct caMonitor *pcamonitor);
|
||||
void *userPvt;
|
||||
void *caMonitorPvt;
|
||||
} CAMONITOR;
|
||||
|
||||
long caMonitorAdd(CAMONITOR *pcamonitor);
|
||||
long caMonitorDelete(CAMONITOR *pcamonitor);
|
||||
1994
src/rec/recScan.c
Normal file
1994
src/rec/recScan.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -179,6 +179,7 @@ static long process(psub)
|
||||
struct subRecord *psub;
|
||||
{
|
||||
long status=0;
|
||||
unsigned char pact=psub->pact;
|
||||
|
||||
if(!psub->pact){
|
||||
psub->pact = TRUE;
|
||||
@@ -186,6 +187,9 @@ static long process(psub)
|
||||
psub->pact = FALSE;
|
||||
}
|
||||
if(status==0) status = do_sub(psub);
|
||||
/* check if device support set pact */
|
||||
if ( !pact && psub->pact ) return(0);
|
||||
/*previously we had different rules. Lets support old subs*/
|
||||
psub->pact = TRUE;
|
||||
if(status==1) return(0);
|
||||
recGblGetTimeStamp(psub);
|
||||
|
||||
698
src/rec/recWait.c
Normal file
698
src/rec/recWait.c
Normal file
@@ -0,0 +1,698 @@
|
||||
/* recWait.c */
|
||||
/*
|
||||
* Original Author: Ned Arnold
|
||||
* Date: 05-31-94
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 05-31-94 nda initial try
|
||||
* .02 07-11-94 mrk/nda added "process on input change" feature
|
||||
* .03 08-16-94 mrk/nda continuing "process on input change" feature
|
||||
* .04 08-16-94 nda record does not get notified when a SCAN related field changes,
|
||||
* so for now we have to always add monitors. Search for MON_ALWAYS
|
||||
* Modifications for this are flagged with MON_ALWAYS
|
||||
* .05 08-18-94 nda Starting with R3.11.6, dbGetField locks the record before fetching
|
||||
* the data. This can cause deadlocks within a database. Change all
|
||||
* dbGetField() to dbGet()
|
||||
* .06 08-19-94 nda added Output data option of VAL or DOL
|
||||
* .07 09-14-94 nda corrected bug that caused SCAN_DISABLE to lock up the record forever
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <types.h>
|
||||
#include <stdioLib.h>
|
||||
#include <lstLib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <tickLib.h>
|
||||
#include <semLib.h>
|
||||
#include <taskLib.h>
|
||||
|
||||
#include <alarm.h>
|
||||
#include <cvtTable.h>
|
||||
#include <dbDefs.h>
|
||||
#include <dbAccess.h>
|
||||
#include <dbScan.h>
|
||||
#include <dbDefs.h>
|
||||
#include <dbFldTypes.h>
|
||||
#include <devSup.h>
|
||||
#include <errMdef.h>
|
||||
#include <recSup.h>
|
||||
#include <special.h>
|
||||
#include <callback.h>
|
||||
#include <taskwd.h>
|
||||
|
||||
#include <choiceWait.h>
|
||||
#include <waitRecord.h>
|
||||
#include <caMonitor.h>
|
||||
|
||||
|
||||
/* Create RSET - Record Support Entry Table*/
|
||||
#define report NULL
|
||||
#define initialize NULL
|
||||
static long init_record();
|
||||
static long process();
|
||||
static long special();
|
||||
static long get_value();
|
||||
#define cvt_dbaddr NULL
|
||||
#define get_array_info NULL
|
||||
#define put_array_info NULL
|
||||
#define get_units NULL
|
||||
static long get_precision();
|
||||
#define get_enum_str NULL
|
||||
#define get_enum_strs NULL
|
||||
#define put_enum_str NULL
|
||||
static long get_graphic_double();
|
||||
#define get_control_double NULL
|
||||
static long get_alarm_double();
|
||||
|
||||
struct rset waitRSET={
|
||||
RSETNUMBER,
|
||||
report,
|
||||
initialize,
|
||||
init_record,
|
||||
process,
|
||||
special,
|
||||
get_value,
|
||||
cvt_dbaddr,
|
||||
get_array_info,
|
||||
put_array_info,
|
||||
get_units,
|
||||
get_precision,
|
||||
get_enum_str,
|
||||
get_enum_strs,
|
||||
put_enum_str,
|
||||
get_graphic_double,
|
||||
get_control_double,
|
||||
get_alarm_double
|
||||
};
|
||||
|
||||
|
||||
/* Create DSET for "soft channel" to allow for IO Event (this is to implement
|
||||
the feature of processing the record when an input changes) */
|
||||
|
||||
static long get_ioint_info();
|
||||
struct {
|
||||
long number;
|
||||
DEVSUPFUN dev_report;
|
||||
DEVSUPFUN init_dev;
|
||||
DEVSUPFUN dev_init_record;
|
||||
DEVSUPFUN get_ioint_info;
|
||||
DEVSUPFUN read_event;
|
||||
}devWaitIoEvent={
|
||||
5,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
get_ioint_info,
|
||||
NULL};
|
||||
|
||||
|
||||
/* DEFINES */
|
||||
#define ARG_MAX 12
|
||||
#define PVN_SIZE 40 /* must match the string length defined in waitRecord.ascii */
|
||||
|
||||
/***************************
|
||||
Declare constants
|
||||
***************************/
|
||||
int waitRecDebug=0;
|
||||
static unsigned long tickStart;
|
||||
static void execOutput();
|
||||
static int fetch_values();
|
||||
static void monitor();
|
||||
static long initSiml();
|
||||
static void inputChanged();
|
||||
|
||||
|
||||
/* callback structure and miscellaneous data */
|
||||
struct cbStruct {
|
||||
CALLBACK callback; /* code assumes CALLBACK is 1st in structure */
|
||||
struct waitRecord *pwait; /* pointer to wait record which needs work done */
|
||||
IOSCANPVT ioscanpvt; /* used for IO_EVENT scanning */
|
||||
CAMONITOR inpMonitor[12]; /* required structures for each input variable */
|
||||
int procPending; /* flag to indicate record processing is pending */
|
||||
};
|
||||
|
||||
|
||||
static long get_ioint_info(cmd,pwait,ppvt)
|
||||
int cmd;
|
||||
struct waitRecord *pwait;
|
||||
IOSCANPVT *ppvt;
|
||||
{
|
||||
*ppvt = (((struct cbStruct *)pwait->cbst)->ioscanpvt);
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
static long init_record(pwait,pass)
|
||||
struct waitRecord *pwait;
|
||||
int pass;
|
||||
{
|
||||
struct cbStruct *pcbst;
|
||||
long status = 0;
|
||||
int i;
|
||||
|
||||
char *ppvn[PVN_SIZE];
|
||||
struct dbAddr **ppdbAddr; /* ptr to a ptr to dbAddr */
|
||||
long *paddrValid;
|
||||
|
||||
char rpbuf[184];
|
||||
short error_number;
|
||||
|
||||
if (pass==0) {
|
||||
pwait->inaa = calloc(1,sizeof(struct dbAddr));
|
||||
pwait->inba = calloc(1,sizeof(struct dbAddr));
|
||||
pwait->inca = calloc(1,sizeof(struct dbAddr));
|
||||
pwait->inda = calloc(1,sizeof(struct dbAddr));
|
||||
pwait->inea = calloc(1,sizeof(struct dbAddr));
|
||||
pwait->infa = calloc(1,sizeof(struct dbAddr));
|
||||
pwait->inga = calloc(1,sizeof(struct dbAddr));
|
||||
pwait->inha = calloc(1,sizeof(struct dbAddr));
|
||||
pwait->inia = calloc(1,sizeof(struct dbAddr));
|
||||
pwait->inja = calloc(1,sizeof(struct dbAddr));
|
||||
pwait->inka = calloc(1,sizeof(struct dbAddr));
|
||||
pwait->inla = calloc(1,sizeof(struct dbAddr));
|
||||
pwait->outa = calloc(1,sizeof(struct dbAddr));
|
||||
|
||||
pwait->cbst = calloc(1,sizeof(struct cbStruct));
|
||||
|
||||
/* init as much as we can */
|
||||
*ppvn = &pwait->inan[0];
|
||||
for(i=0;i<ARG_MAX; i++, *ppvn += PVN_SIZE) {
|
||||
((struct cbStruct *)pwait->cbst)->inpMonitor[i].channame = (char *)*ppvn;
|
||||
((struct cbStruct *)pwait->cbst)->inpMonitor[i].callback = inputChanged;
|
||||
((struct cbStruct *)pwait->cbst)->inpMonitor[i].userPvt = pwait;
|
||||
}
|
||||
|
||||
/* do scanIoInit here because init_dev doesn't know which record */
|
||||
scanIoInit(&(((struct cbStruct *)pwait->cbst)->ioscanpvt));
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* Do initial lookup of PV Names to dbAddr's */
|
||||
|
||||
*ppvn = &pwait->inan[0];
|
||||
ppdbAddr = (struct dbAddr **)&pwait->inaa;
|
||||
paddrValid = &pwait->inav;
|
||||
|
||||
for(i=0;i<ARG_MAX; i++, *ppvn += PVN_SIZE, ppdbAddr++, paddrValid++) {
|
||||
*paddrValid = dbNameToAddr(*ppvn, *ppdbAddr);
|
||||
}
|
||||
|
||||
pwait->outv = dbNameToAddr(pwait->outn, (struct dbAddr *)pwait->outa);
|
||||
pwait->dolv = dbNameToAddr(pwait->doln, (struct dbAddr *)pwait->dola);
|
||||
|
||||
pwait->clcv=postfix(pwait->calc,rpbuf,&error_number);
|
||||
if(pwait->clcv){
|
||||
recGblRecordError(S_db_badField,(void *)pwait,
|
||||
"wait: init_record: Illegal CALC field");
|
||||
}
|
||||
else {
|
||||
memcpy(pwait->rpcl,rpbuf,sizeof(pwait->rpcl));
|
||||
}
|
||||
db_post_events(pwait,&pwait->clcv,DBE_VALUE);
|
||||
|
||||
callbackSetCallback(execOutput, &((struct cbStruct *)pwait->cbst)->callback);
|
||||
callbackSetPriority(pwait->prio, &((struct cbStruct *)pwait->cbst)->callback);
|
||||
pcbst = (struct cbStruct *)pwait->cbst;
|
||||
pcbst->pwait = pwait;
|
||||
|
||||
/* Set up monitors on input channels if scan type is IO Event */
|
||||
|
||||
/* MON_ALWAYS if(pwait->scan == SCAN_IO_EVENT) { */
|
||||
if(1) {
|
||||
paddrValid = &pwait->inav;
|
||||
|
||||
for(i=0;i<ARG_MAX; i++, paddrValid++) {
|
||||
if(!(*paddrValid)) {
|
||||
if(waitRecDebug) printf("adding monitor\n");
|
||||
status = caMonitorAdd(&(((struct cbStruct *)pwait->cbst)->inpMonitor[i]));
|
||||
if(status) errMessage(status,"caMonitorAdd error");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (status=initSiml(pwait)) return(status);
|
||||
|
||||
/* now reset procPending so the next monitor processes the record */
|
||||
((struct cbStruct *)pwait->cbst)->procPending = 0;
|
||||
|
||||
pwait->init = TRUE;
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long process(pwait)
|
||||
struct waitRecord *pwait;
|
||||
{
|
||||
short async = FALSE;
|
||||
long status;
|
||||
long nRequest = 1;
|
||||
long options = 0;
|
||||
|
||||
pwait->pact = TRUE;
|
||||
pwait->oval = pwait->val;
|
||||
|
||||
/* Check for simulation mode */
|
||||
status=recGblGetLinkValue(&(pwait->siml),
|
||||
(void *)pwait,DBR_ENUM,&(pwait->simm),&options,&nRequest);
|
||||
|
||||
/* reset procPending before getting values so we don't miss any monitors */
|
||||
((struct cbStruct *)pwait->cbst)->procPending = 0;
|
||||
|
||||
if(pwait->simm == NO) {
|
||||
if(fetch_values(pwait)==0) {
|
||||
if(calcPerform(&pwait->a,&pwait->val,pwait->rpcl)) {
|
||||
recGblSetSevr(pwait,CALC_ALARM,INVALID_ALARM);
|
||||
} else pwait->udf = FALSE;
|
||||
}
|
||||
}
|
||||
else { /* SIMULATION MODE */
|
||||
status = recGblGetLinkValue(&(pwait->siol),
|
||||
(void *)pwait,DBR_DOUBLE,&(pwait->sval),&options,&nRequest);
|
||||
if (status==0){
|
||||
pwait->val=pwait->sval;
|
||||
pwait->udf=FALSE;
|
||||
}
|
||||
recGblSetSevr(pwait,SIMM_ALARM,pwait->sims);
|
||||
}
|
||||
|
||||
/* decide whether to write Output PV */
|
||||
switch(pwait->oopt) {
|
||||
case REC_WAIT_OUT_OPT_EVERY:
|
||||
callbackRequest(pwait->cbst);
|
||||
async = TRUE;
|
||||
break;
|
||||
case REC_WAIT_OUT_OPT_CHANGE:
|
||||
if(fabs(pwait->oval - pwait->val) > pwait->mdel) {
|
||||
callbackRequest(pwait->cbst);
|
||||
async = TRUE;
|
||||
}
|
||||
break;
|
||||
case REC_WAIT_OUT_OPT_CHG_TO_ZERO:
|
||||
if((pwait->oval != 0) && (pwait->val == 0)) {
|
||||
callbackRequest(pwait->cbst);
|
||||
async = TRUE;
|
||||
}
|
||||
break;
|
||||
case REC_WAIT_OUT_OPT_CHG_TO_NZERO:
|
||||
if((pwait->oval == 0) && (pwait->val != 0)) {
|
||||
callbackRequest(pwait->cbst);
|
||||
async = TRUE;
|
||||
}
|
||||
break;
|
||||
case REC_WAIT_OUT_OPT_WHEN_ZERO:
|
||||
if(!pwait->val) {
|
||||
callbackRequest(pwait->cbst);
|
||||
async = TRUE;
|
||||
}
|
||||
break;
|
||||
case REC_WAIT_OUT_OPT_WHEN_NZERO:
|
||||
if(pwait->val) {
|
||||
callbackRequest(pwait->cbst);
|
||||
async = TRUE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
recGblGetTimeStamp(pwait);
|
||||
/* check event list */
|
||||
monitor(pwait);
|
||||
|
||||
if (!async) {
|
||||
pwait->pact = FALSE;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long special(paddr,after)
|
||||
struct dbAddr *paddr;
|
||||
int after;
|
||||
{
|
||||
struct waitRecord *pwait = (struct waitRecord *)(paddr->precord);
|
||||
int special_type = paddr->special;
|
||||
char *ppvn[PVN_SIZE];
|
||||
struct dbAddr **ppdbAddr; /* ptr to a ptr to dbAddr */
|
||||
long *paddrValid;
|
||||
int i;
|
||||
long status;
|
||||
long odbv =0;
|
||||
short error_number;
|
||||
char rpbuf[184];
|
||||
|
||||
if(waitRecDebug) printf("entering special \n");
|
||||
if(!after) { /* this is called before ca changes the field */
|
||||
switch(special_type) {
|
||||
case(SPC_SCAN): /* about to change SCAN mechanism ... */
|
||||
if(pwait->scan == SCAN_IO_EVENT) {
|
||||
/* Leaving IO_EVENT, delete monitors */
|
||||
paddrValid = &pwait->inav;
|
||||
for(i=0;i<ARG_MAX; i++, paddrValid++) {
|
||||
if(!(*paddrValid)) {
|
||||
if(waitRecDebug) printf("deleting monitor\n");
|
||||
status = caMonitorDelete(&(((struct cbStruct *)pwait->cbst)->inpMonitor[i]));
|
||||
if(status) errMessage(status,"caMonitorDelete error");
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case(SPC_MOD): /* check if changing any PV names while monitored */
|
||||
/* MON_ALWAYS if(pwait->scan == SCAN_IO_EVENT) { */
|
||||
if(1) {
|
||||
*ppvn = &pwait->inan[0];
|
||||
paddrValid = &pwait->inav;
|
||||
for(i=0;i<ARG_MAX; i++, *ppvn += PVN_SIZE, paddrValid++) {
|
||||
if((paddr->pfield==*ppvn) && !(*paddrValid)) {
|
||||
if(waitRecDebug) printf("deleting monitor\n");
|
||||
status = caMonitorDelete(&(((struct cbStruct *)pwait->cbst)->inpMonitor[i]));
|
||||
if(status) errMessage(status,"caMonitorDelete error");
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* this is executed after ca changed the field */
|
||||
switch(special_type) {
|
||||
case(SPC_SCAN): /* Changed SCAN mechanism, set monitors on input links */
|
||||
if(pwait->scan == SCAN_IO_EVENT) {
|
||||
paddrValid = &pwait->inav;
|
||||
for(i=0;i<ARG_MAX; i++, paddrValid++) {
|
||||
if(!(*paddrValid)) {
|
||||
if(waitRecDebug) printf("adding monitor\n");
|
||||
status = caMonitorAdd(&(((struct cbStruct *)pwait->cbst)->inpMonitor[i]));
|
||||
if(status) errMessage(status,"caMonitorAdd error");
|
||||
}
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
case(SPC_MOD): /* check if changing any PV names */
|
||||
*ppvn = &pwait->inan[0];
|
||||
ppdbAddr = (struct dbAddr **)&pwait->inaa;
|
||||
paddrValid = &pwait->inav;
|
||||
|
||||
for(i=0;i<ARG_MAX; i++, *ppvn += PVN_SIZE, ppdbAddr++, paddrValid++) {
|
||||
if(paddr->pfield==*ppvn) {
|
||||
odbv = *paddrValid;
|
||||
*paddrValid = dbNameToAddr(*ppvn, *ppdbAddr);
|
||||
if (odbv != *paddrValid) {
|
||||
db_post_events(pwait,paddrValid,DBE_VALUE);
|
||||
}
|
||||
/* MON_ALWAYS if((pwait->scan == SCAN_IO_EVENT) && !(*paddrValid)) { */
|
||||
if((1) && !(*paddrValid)) {
|
||||
if(waitRecDebug) printf("adding monitor\n");
|
||||
status = caMonitorAdd(&(((struct cbStruct *)pwait->cbst)->inpMonitor[i]));
|
||||
if(status) errMessage(status,"caMonitorAdd error");
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
if(paddr->pfield==pwait->outn) { /* this is the output link */
|
||||
odbv = pwait->outv;
|
||||
pwait->outv = dbNameToAddr(pwait->outn,(struct dbAddr *)pwait->outa);
|
||||
if (odbv != pwait->outv) {
|
||||
db_post_events(pwait,&pwait->outv,DBE_VALUE);
|
||||
}
|
||||
}
|
||||
else if(paddr->pfield==pwait->doln) { /* this is the DOL link */
|
||||
odbv = pwait->dolv;
|
||||
pwait->dolv = dbNameToAddr(pwait->doln,(struct dbAddr *)pwait->dola);
|
||||
if (odbv != pwait->dolv) {
|
||||
db_post_events(pwait,&pwait->dolv,DBE_VALUE);
|
||||
}
|
||||
}
|
||||
else if(paddr->pfield==(void *)&pwait->prio) {
|
||||
callbackSetPriority(pwait->prio, &((struct cbStruct *)pwait->cbst)->callback);
|
||||
}
|
||||
|
||||
return(0);
|
||||
|
||||
case(SPC_CALC):
|
||||
pwait->clcv=postfix(pwait->calc,rpbuf,&error_number);
|
||||
if(pwait->clcv){
|
||||
recGblRecordError(S_db_badField,(void *)pwait,
|
||||
"wait: init_record: Illegal CALC field");
|
||||
db_post_events(pwait,&pwait->clcv,DBE_VALUE);
|
||||
return(S_db_badField);
|
||||
}
|
||||
db_post_events(pwait,&pwait->clcv,DBE_VALUE);
|
||||
memcpy(pwait->rpcl,rpbuf,sizeof(pwait->rpcl));
|
||||
db_post_events(pwait,pwait->calc,DBE_VALUE);
|
||||
db_post_events(pwait,pwait->clcv,DBE_VALUE);
|
||||
return(0);
|
||||
default:
|
||||
recGblDbaddrError(S_db_badChoice,paddr,"wait: special");
|
||||
return(S_db_badChoice);
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
static long get_value(pwait,pvdes)
|
||||
struct waitRecord *pwait;
|
||||
struct valueDes *pvdes;
|
||||
{
|
||||
pvdes->field_type = DBF_DOUBLE;
|
||||
pvdes->no_elements=1;
|
||||
(double *)(pvdes->pvalue) = &pwait->val;
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long get_precision(paddr,precision)
|
||||
struct dbAddr *paddr;
|
||||
long *precision;
|
||||
{
|
||||
struct waitRecord *pwait=(struct waitRecord *)paddr->precord;
|
||||
|
||||
*precision = pwait->prec;
|
||||
if(paddr->pfield == (void *)&pwait->val) return(0);
|
||||
recGblGetPrec(paddr,precision);
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long get_graphic_double(paddr,pgd)
|
||||
struct dbAddr *paddr;
|
||||
struct dbr_grDouble *pgd;
|
||||
{
|
||||
struct waitRecord *pwait=(struct waitRecord *)paddr->precord;
|
||||
|
||||
if (paddr->pfield==(void *)&pwait->val) {
|
||||
pgd->upper_disp_limit = pwait->hopr;
|
||||
pgd->lower_disp_limit = pwait->lopr;
|
||||
} else recGblGetGraphicDouble(paddr,pgd);
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long get_alarm_double(paddr,pad)
|
||||
struct dbAddr *paddr;
|
||||
struct dbr_alDouble *pad;
|
||||
{
|
||||
recGblGetAlarmDouble(paddr,pad);
|
||||
return(0);
|
||||
}
|
||||
|
||||
static void monitor(pwait)
|
||||
struct waitRecord *pwait;
|
||||
{
|
||||
unsigned short monitor_mask;
|
||||
double delta;
|
||||
double *pnew;
|
||||
double *pprev;
|
||||
int i;
|
||||
|
||||
monitor_mask = recGblResetAlarms(pwait);
|
||||
/* check for value change */
|
||||
delta = pwait->mlst - pwait->val;
|
||||
if(delta<0.0) delta = -delta;
|
||||
if (delta > pwait->mdel) {
|
||||
/* post events for value change */
|
||||
monitor_mask |= DBE_VALUE;
|
||||
/* update last value monitored */
|
||||
pwait->mlst = pwait->val;
|
||||
}
|
||||
/* check for archive change */
|
||||
delta = pwait->alst - pwait->val;
|
||||
if(delta<0.0) delta = -delta;
|
||||
if (delta > pwait->adel) {
|
||||
/* post events on value field for archive change */
|
||||
monitor_mask |= DBE_LOG;
|
||||
/* update last archive value monitored */
|
||||
pwait->alst = pwait->val;
|
||||
}
|
||||
|
||||
/* send out monitors connected to the value field */
|
||||
if (monitor_mask){
|
||||
db_post_events(pwait,&pwait->val,monitor_mask);
|
||||
}
|
||||
/* check all input fields for changes */
|
||||
for(i=0, pnew=&pwait->a, pprev=&pwait->la; i<ARG_MAX; i++, pnew++, pprev++) {
|
||||
if(*pnew != *pprev) {
|
||||
db_post_events(pwait,pnew,monitor_mask|DBE_VALUE);
|
||||
*pprev = *pnew;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static long initSiml(pwait)
|
||||
struct waitRecord *pwait;
|
||||
{
|
||||
long status;
|
||||
/* wait.siml must be a CONSTANT or a PV_LINK or a DB_LINK */
|
||||
switch (pwait->siml.type) {
|
||||
case (CONSTANT) :
|
||||
pwait->simm = pwait->siml.value.value;
|
||||
break;
|
||||
case (PV_LINK) :
|
||||
status = dbCaAddInlink(&(pwait->siml), (void *) pwait, "SIMM");
|
||||
if(status) return(status);
|
||||
break;
|
||||
case (DB_LINK) :
|
||||
break;
|
||||
default :
|
||||
recGblRecordError(S_db_badField,(void *)pwait,
|
||||
"wait: init_record Illegal SIML field");
|
||||
return(S_db_badField);
|
||||
}
|
||||
|
||||
/* wait.siol must be a CONSTANT or a PV_LINK or a DB_LINK */
|
||||
switch (pwait->siol.type) {
|
||||
case (CONSTANT) :
|
||||
pwait->sval = pwait->siol.value.value;
|
||||
break;
|
||||
case (PV_LINK) :
|
||||
status = dbCaAddInlink(&(pwait->siol), (void *) pwait, "SVAL");
|
||||
if(status) return(status);
|
||||
break;
|
||||
case (DB_LINK) :
|
||||
break;
|
||||
default :
|
||||
recGblRecordError(S_db_badField,(void *)pwait,
|
||||
"wait: init_record Illegal SIOL field");
|
||||
return(S_db_badField);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int fetch_values(pwait)
|
||||
struct waitRecord *pwait;
|
||||
{
|
||||
struct dbAddr **ppdba; /* a ptr to a ptr to dbAddr */
|
||||
double *pvalue;
|
||||
long *pvalid;
|
||||
long status=0,options=0,nRequest=1;
|
||||
int i;
|
||||
|
||||
for(i=0, ppdba= (struct dbAddr **)&pwait->inaa, pvalue=&pwait->a, pvalid = &pwait->inav;
|
||||
i<ARG_MAX; i++, ppdba++, pvalue++, pvalid++) {
|
||||
|
||||
/* only fetch a value if the dbAddr is valid, otherwise, leave it alone */
|
||||
if(!(*pvalid)) {
|
||||
status = dbGet(*ppdba, DBR_DOUBLE,
|
||||
pvalue, &options, &nRequest, NULL);
|
||||
}
|
||||
|
||||
if (!RTN_SUCCESS(status)) return(status);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* This is the code that is executed by the callback task to do the record
|
||||
* outputs. It is done with a separate task so one need not worry about
|
||||
* lock sets.
|
||||
*
|
||||
******************************************************************************/
|
||||
void execOutput(pcbst)
|
||||
struct cbStruct *pcbst;
|
||||
{
|
||||
static long status;
|
||||
static long nRequest = 1;
|
||||
static long options = 0;
|
||||
static double oldDold;
|
||||
|
||||
/* if output link is valid , decide between VAL and DOL */
|
||||
if(!pcbst->pwait->outv) {
|
||||
if(pcbst->pwait->dopt) {
|
||||
if(!pcbst->pwait->dolv) {
|
||||
oldDold = pcbst->pwait->dold;
|
||||
status = dbGet(pcbst->pwait->dola,DBR_DOUBLE,
|
||||
&(pcbst->pwait->dold), &options, &nRequest, NULL);
|
||||
if(pcbst->pwait->dold != oldDold)
|
||||
db_post_events(pcbst->pwait,&pcbst->pwait->dold,DBE_VALUE);
|
||||
}
|
||||
status = dbPutField(pcbst->pwait->outa,DBR_DOUBLE,
|
||||
&(pcbst->pwait->dold), 1);
|
||||
} else {
|
||||
status = dbPutField(pcbst->pwait->outa,DBR_DOUBLE,
|
||||
&(pcbst->pwait->val), 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* post event if output event != 0 */
|
||||
if(pcbst->pwait->oevt > 0) {
|
||||
post_event((int)pcbst->pwait->oevt);
|
||||
}
|
||||
|
||||
recGblFwdLink(pcbst->pwait);
|
||||
pcbst->pwait->pact = FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void inputChanged(struct caMonitor *pcamonitor)
|
||||
{
|
||||
|
||||
struct waitRecord *pwait = (struct waitRecord *)pcamonitor->userPvt;
|
||||
struct cbStruct *pcbst = (struct cbStruct *)pwait->cbst;
|
||||
|
||||
/* the next line is here because the monitors are always active ... MON_ALWAYS */
|
||||
if(pwait->scan != SCAN_IO_EVENT) return;
|
||||
|
||||
|
||||
/* if record hasn't been processed or is DISABLED, don't set procPending yet */
|
||||
if((pwait->stat == DISABLE_ALARM) || pwait->udf) {
|
||||
if(waitRecDebug) printf("processing due to monitor\n");
|
||||
scanIoRequest(pcbst->ioscanpvt);
|
||||
} else if(pcbst->procPending) {
|
||||
if(waitRecDebug) printf("discarding monitor\n");
|
||||
return;
|
||||
} else {
|
||||
pcbst->procPending = 1;
|
||||
if(waitRecDebug) printf("processing due to monitor\n");
|
||||
scanIoRequest(pcbst->ioscanpvt);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user