diff --git a/src/rec/Makefile.Vx b/src/rec/Makefile.Vx index 96e89cbda..576b433ff 100644 --- a/src/rec/Makefile.Vx +++ b/src/rec/Makefile.Vx @@ -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 diff --git a/src/rec/caMonitor.c b/src/rec/caMonitor.c new file mode 100644 index 000000000..c3d63bca3 --- /dev/null +++ b/src/rec/caMonitor.c @@ -0,0 +1,152 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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); +} diff --git a/src/rec/caMonitor.h b/src/rec/caMonitor.h new file mode 100644 index 000000000..fff220740 --- /dev/null +++ b/src/rec/caMonitor.h @@ -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); diff --git a/src/rec/recScan.c b/src/rec/recScan.c new file mode 100644 index 000000000..f8dab3402 --- /dev/null +++ b/src/rec/recScan.c @@ -0,0 +1,1994 @@ +/* recScan.c */ +/* + * Original Author: Ned D. Arnold + * Date: 07-18-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 07-18-94 nda significantly expanded functionality from prototype + * .02 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() + * .03 08-23-94 nda added code for checking/adjusting linear scan + * params (it gets a little messy !) + * .04 08-25-94 nda Added check of scan positions vs Positioner Control + * Limits + * .05 08-29-94 nda Added "viewScanPos" that puts desired positions + * in D1 array any time a scan parameter is changed + * .06 10-03-94 nda added code for enumerated string .CMND. Changed + * .EXSC to a SHORT in record definition. Added VERSION + * for .VERS field (1.06) to keep track of version. + */ + +#define VERSION 1.06 + + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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(); +static long cvt_dbaddr(); +static long get_array_info(); +static long put_array_info(); +static long get_units(); +static long get_precision(); +static long get_enum_str(); +static long get_enum_strs(); +static long put_enum_str(); +static long get_graphic_double(); +static long get_control_double(); +static long get_alarm_double(); + +struct rset scanRSET={ + 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 +}; + +struct p_limits { + DBRctrlDouble + float value; +}; + + +struct recPvtStruct { + CALLBACK doPutsCallback;/* do output links callback structure */ + struct scanRecord *pscan; /* ptr to record which needs work done */ + short phase; /* what to do to the above record */ + short validRbPvs; /* at least 1 valid Readback PV name */ + short validDtPvs; /* at least 1 valid Detector Trig PV */ + short validDataBuf; /* which data array buffer is valid */ + float *pdet1Fill; /* points to data array to be filled */ + float *pdet1DataA; /* points to data array A */ + float *pdet1DataB; /* points to data array B */ + float *pdet2Fill; + float *pdet2DataA; + float *pdet2DataB; + float *pdet3Fill; + float *pdet3DataA; + float *pdet3DataB; + float *pdet4Fill; + float *pdet4DataA; + float *pdet4DataB; + struct p_limits *pP1Limits; + struct p_limits *pP2Limits; + struct p_limits *pP3Limits; + struct p_limits *pP4Limits; + unsigned long tickStart; /* used to time the scan */ + unsigned char scanErr; + unsigned char nptsCause; /* who caused the "# of points to change: + 0-operator; 1-4 Positioners*/ +}; + + +/* the following structure must match EXACTLY with the order and type of + fields defined in scanRecord.h for each positioner (even including + the "Created Pad"s */ + +struct linScanParms { + float p_sp; /* Start Position */ + unsigned short p_fs; /* Freeze Start Pos */ + char p76 [2]; /* Created Pad */ + float p_si; /* Step Increment */ + unsigned short p_fi; /* Freeze Step Inc */ + char p77 [2]; /* Created Pad */ + float p_cp; /* Center Position */ + unsigned short p_fc; /* Freeze Center Pos */ + char p78 [2]; /* Created Pad */ + float p_ep; /* End Position */ + unsigned short p_fe; /* Freeze End Pos */ + char p79 [2]; /* Created Pad */ + float p_wd; /* Scan Width */ + unsigned short p_fw; /* Freeze Width */ + char p80 [2]; /* Created Pad */ +}; + + + +/*************************** + Declare constants +***************************/ +#define DEF_WF_SIZE 100 +#define PVN_SIZE 40 +#define NUM_DYN_PVS 14 +#define MIN_MON 3 /* # of ticks between monitor postings. 3 = 50 ms */ + +#define A_BUFFER 0 +#define B_BUFFER 1 + +#define IDLE 0 +#define MOVE_MOTORS 1 +#define CHCK_MOTORS 2 +#define TRIG_DETCTRS 3 +#define READ_DETCTRS 4 + +#define CLEAR_MSG 0 +#define CHECK_LIMITS 1 + + +/* forward declarations */ + +static void checkMonitors(); +static void lookupPVs(); +static void initScan(); +static void contScan(); +static void endScan(); +static void doPuts(); +static void adjLinParms(); +static void changedNpts(); +static void checkScanLimits(); +static void drawPos1Scan(); +/* variables ... */ +long scanRecDebug=0; +long viewScanPos=0; + + +static long init_record(pscan,pass) + struct scanRecord *pscan; + int pass; +{ + struct recPvtStruct *precPvt = (struct recPvtStruct *)pscan->rpvt; + long status = 0; + + if (pass==0) { + pscan->vers = VERSION; + if(pscan->mpts < 100) pscan->mpts = DEF_WF_SIZE; + + pscan->p1db = calloc(1, sizeof(struct dbAddr)); + pscan->p2db = calloc(1, sizeof(struct dbAddr)); + pscan->p3db = calloc(1, sizeof(struct dbAddr)); + pscan->p4db = calloc(1, sizeof(struct dbAddr)); + pscan->r1db = calloc(1, sizeof(struct dbAddr)); + pscan->r2db = calloc(1, sizeof(struct dbAddr)); + pscan->r3db = calloc(1, sizeof(struct dbAddr)); + pscan->r4db = calloc(1, sizeof(struct dbAddr)); + pscan->t1db = calloc(1, sizeof(struct dbAddr)); + pscan->t2db = calloc(1, sizeof(struct dbAddr)); + pscan->d1db = calloc(1, sizeof(struct dbAddr)); + pscan->d2db = calloc(1, sizeof(struct dbAddr)); + pscan->d3db = calloc(1, sizeof(struct dbAddr)); + pscan->d4db = calloc(1, sizeof(struct dbAddr)); + + pscan->p1pa = (float *) calloc(pscan->mpts, sizeof(float)); + pscan->p2pa = (float *) calloc(pscan->mpts, sizeof(float)); + pscan->p3pa = (float *) calloc(pscan->mpts, sizeof(float)); + pscan->p4pa = (float *) calloc(pscan->mpts, sizeof(float)); + + /* First time through, rpvt needs initialized */ + pscan->rpvt = calloc(1, sizeof(struct recPvtStruct)); + precPvt = (struct recPvtStruct *)pscan->rpvt; + + precPvt->pdet1DataA = (float *) calloc(pscan->mpts, sizeof(float)); + precPvt->pdet1DataB = (float *) calloc(pscan->mpts, sizeof(float)); + precPvt->pdet2DataA = (float *) calloc(pscan->mpts, sizeof(float)); + precPvt->pdet2DataB = (float *) calloc(pscan->mpts, sizeof(float)); + precPvt->pdet3DataA = (float *) calloc(pscan->mpts, sizeof(float)); + precPvt->pdet3DataB = (float *) calloc(pscan->mpts, sizeof(float)); + precPvt->pdet4DataA = (float *) calloc(pscan->mpts, sizeof(float)); + precPvt->pdet4DataB = (float *) calloc(pscan->mpts, sizeof(float)); + + precPvt->pP1Limits = (struct p_limits *)calloc(1, sizeof(struct p_limits)); + precPvt->pP2Limits = (struct p_limits *)calloc(1, sizeof(struct p_limits)); + precPvt->pP3Limits = (struct p_limits *)calloc(1, sizeof(struct p_limits)); + precPvt->pP4Limits = (struct p_limits *)calloc(1, sizeof(struct p_limits)); + + /* initialize array fill pointers to buffer A, consider B_BUFFER valid */ + precPvt->pdet1Fill = precPvt->pdet1DataA; + precPvt->pdet2Fill = precPvt->pdet2DataA; + precPvt->pdet3Fill = precPvt->pdet3DataA; + precPvt->pdet4Fill = precPvt->pdet4DataA; + precPvt->validDataBuf = B_BUFFER; + pscan->d1da = precPvt->pdet1DataB; + pscan->d2da = precPvt->pdet2DataB; + pscan->d3da = precPvt->pdet3DataB; + pscan->d4da = precPvt->pdet4DataB; + return(0); + } + + callbackSetCallback(doPuts, &precPvt->doPutsCallback); + callbackSetPriority(pscan->prio, &precPvt->doPutsCallback); + + precPvt->pscan = pscan; + + lookupPVs(pscan); + + /* initialize all linear scan fields */ + precPvt->nptsCause = 0; /* resolve all positioner parameters */ + changedNpts(pscan); + + /* init field values */ + pscan->exsc = 0; + pscan->pxsc = 0; + return(0); +} + +static long process(pscan) + struct scanRecord *pscan; +{ + struct recPvtStruct *precPvt = (struct recPvtStruct *)pscan->rpvt; + long status = 0; + + /* Begin Scan cycle or continue scan cycle */ + if ((pscan->pxsc == 0) && (pscan->exsc == 1)) { + if(scanRecDebug) { + precPvt->tickStart = tickGet(); + } + initScan(pscan); + + } + else if ((pscan->pxsc == 1) && (pscan->exsc == 0)) { + sprintf(pscan->smsg,"Scan aborted by operator"); + db_post_events(pscan,&pscan->smsg,DBE_VALUE); + endScan(pscan); + } + else if (pscan->exsc == 1) { + contScan(pscan); + } + + checkMonitors(pscan); + + /* do forward link on last scan aquisition */ + if ((pscan->pxsc == 1) && (pscan->exsc == 0)) { + recGblFwdLink(pscan); /* process the forward scan link record */ + if(scanRecDebug) { + printf("Scan Time = %.2f ms\n", + (float)((tickGet()-(precPvt->tickStart))*16.67)); + } + + } + + pscan->pxsc = pscan->exsc; + pscan->pact = FALSE; + recGblResetAlarms(pscan); + return(status); +} + +static long special(paddr,after) + struct dbAddr *paddr; + int after; +{ + struct scanRecord *pscan = (struct scanRecord *)(paddr->precord); + struct recPvtStruct *precPvt = (struct recPvtStruct *)pscan->rpvt; + int special_type = paddr->special; + long status; + unsigned char prevAlrt; + + if(!after) { + return(0); + } + switch(special_type) { + case(SPC_MOD): + if(paddr->pfield==(void *)&pscan->exsc) { + pscan->alrt = 0; + db_post_events(pscan,&pscan->alrt, DBE_VALUE); + scanOnce(pscan); + return(0); + } else if(paddr->pfield==(void *)&pscan->cmnd) { + if(pscan->cmnd == CLEAR_MSG) { + sprintf(pscan->smsg,""); + db_post_events(pscan,&pscan->smsg,DBE_VALUE); + } + else if(pscan->cmnd == CHECK_LIMITS) { + prevAlrt = pscan->alrt; + pscan->alrt = 0; + checkScanLimits(pscan); + db_post_events(pscan,&pscan->smsg,DBE_VALUE); + if(pscan->alrt != prevAlrt) { + db_post_events(pscan,&pscan->alrt,DBE_VALUE); + } + } + return(0); + } else if((paddr->pfield >= (void *)pscan->p1pv) && + (paddr->pfield <= (void *)pscan->d4pv)) { + lookupPVs(pscan); + return(0); + } else if(paddr->pfield==(void *)&pscan->prio) { + callbackSetPriority(pscan->prio, &precPvt->doPutsCallback); + return(0); + } + break; + + case(SPC_SC_S): /* linear scan parameter change */ + case(SPC_SC_I): + case(SPC_SC_E): + case(SPC_SC_C): + case(SPC_SC_W): + /* resolve linear scan parameters affected by this fields change */ + prevAlrt = pscan->alrt; + pscan->alrt = 0; + sprintf(pscan->smsg,""); + adjLinParms(paddr); + db_post_events(pscan,&pscan->smsg,DBE_VALUE); + if(pscan->alrt != prevAlrt) { + db_post_events(pscan,&pscan->alrt,DBE_VALUE); + } + if(viewScanPos) { + drawPos1Scan(pscan); + } + break; + + case(SPC_SC_N): + /* adjust all linear scan parameters per new # of steps */ + if(pscan->npts > pscan->mpts) { + pscan->npts = pscan->mpts; + db_post_events(pscan,&pscan->npts,DBE_VALUE); + } + prevAlrt = pscan->alrt; + pscan->alrt = 0; + sprintf(pscan->smsg,""); + precPvt->nptsCause = 0; /* resolve all positioner parameters */ + changedNpts(pscan); + db_post_events(pscan,&pscan->smsg,DBE_VALUE); + if(pscan->alrt != prevAlrt) { + db_post_events(pscan,&pscan->alrt,DBE_VALUE); + } + if(viewScanPos) { + drawPos1Scan(pscan); + } + break; + + default: +/* recGblDbaddrError(S_db_badChoice,paddr,"scan: special"); + return(S_db_badChoice); +*/ + } +return(0); +} + +static long cvt_dbaddr(paddr) + struct dbAddr *paddr; +{ + struct scanRecord *pscan=(struct scanRecord *)paddr->precord; + + /* all arrays are floats */ + + if (paddr->pfield == &(pscan->p1pa)) { + paddr->pfield = (void *)(pscan->p1pa); + } else if (paddr->pfield == &(pscan->p2pa)) { + paddr->pfield = (void *)(pscan->p2pa); + } else if (paddr->pfield == &(pscan->p3pa)) { + paddr->pfield = (void *)(pscan->p3pa); + } else if (paddr->pfield == &(pscan->p4pa)) { + paddr->pfield = (void *)(pscan->p4pa); + } else if (paddr->pfield == &(pscan->d1da)) { + paddr->pfield = (void *)(pscan->d1da); + } else if (paddr->pfield == &(pscan->d2da)) { + paddr->pfield = (void *)(pscan->d2da); + } else if (paddr->pfield == &(pscan->d3da)) { + paddr->pfield = (void *)(pscan->d3da); + } else if (paddr->pfield == &(pscan->d4da)) { + paddr->pfield = (void *)(pscan->d4da); + } + + paddr->no_elements = pscan->mpts; + paddr->field_type = DBF_FLOAT; + paddr->field_size = sizeof(float); + paddr->dbr_field_type = DBF_FLOAT; + return(0); +} + +static long get_array_info(paddr,no_elements,offset) + struct dbAddr *paddr; + long *no_elements; + long *offset; +{ + struct scanRecord *pscan=(struct scanRecord *)paddr->precord; + struct recPvtStruct *precPvt = (struct recPvtStruct *)pscan->rpvt; + + /* if the paddr has a double buffer pointer, update it now */ + if ((paddr->pfield == precPvt->pdet1DataA) || + (paddr->pfield == precPvt->pdet1DataB)) { + paddr->pfield = (void *)(pscan->d1da); + *no_elements = pscan->mpts; + *offset = 0; + } else if ((paddr->pfield == precPvt->pdet2DataA) || + (paddr->pfield == precPvt->pdet2DataB)) { + paddr->pfield = (void *)(pscan->d2da); + *no_elements = pscan->mpts; + *offset = 0; + } else if ((paddr->pfield == precPvt->pdet3DataA) || + (paddr->pfield == precPvt->pdet3DataB)) { + paddr->pfield = (void *)(pscan->d3da); + *no_elements = pscan->mpts; + *offset = 0; + } else if ((paddr->pfield == precPvt->pdet4DataA) || + (paddr->pfield == precPvt->pdet4DataB)) { + paddr->pfield = (void *)(pscan->d4da); + *no_elements = pscan->mpts; + *offset = 0; + } else if (paddr->pfield == pscan->p1pa) { + *no_elements = pscan->mpts; + *offset = 0; + } else if (paddr->pfield == pscan->p2pa) { + *no_elements = pscan->mpts; + *offset = 0; + } else if (paddr->pfield == pscan->p3pa) { + *no_elements = pscan->mpts; + *offset = 0; + } else if (paddr->pfield == pscan->p4pa) { + *no_elements = pscan->mpts; + *offset = 0; + } else { + *no_elements = 0; + *offset = 0; + } + + return(0); +} + +static long put_array_info(paddr,nNew) + struct dbAddr *paddr; + long nNew; +{ + struct scanRecord *pscan=(struct scanRecord *)paddr->precord; + + if(nNew < pscan->npts) { + sprintf(pscan->smsg,"Pts in Table < # of Steps"); + db_post_events(pscan,&pscan->smsg,DBE_VALUE); + if(!pscan->alrt) { + pscan->alrt = 1; + db_post_events(pscan,&pscan->alrt,DBE_VALUE); + } + }else { + sprintf(pscan->smsg,""); + db_post_events(pscan,&pscan->smsg,DBE_VALUE); + if(pscan->alrt) { + pscan->alrt = 0; + db_post_events(pscan,&pscan->alrt,DBE_VALUE); + } + } + return(0); +} + + +static long get_enum_str(paddr,pstring) + struct dbAddr *paddr; + char *pstring; +{ + struct scanRecord *pscan=(struct scanRecord *)paddr->precord; + + if(paddr->pfield==(void *)&pscan->cmnd) + { + sprintf(pstring, "%d",pscan->cmnd); + } + else + { + strcpy(pstring,"No string"); + } + return(0); +} +static long get_enum_strs(paddr,pes) + struct dbAddr *paddr; + struct dbr_enumStrs *pes; +{ + struct scanRecord *pscan=(struct scanRecord *)paddr->precord; + + if(paddr->pfield==(void *)&pscan->cmnd) + { + memset(pes->strs,'\0',sizeof(pes->strs)); + strncpy(pes->strs[0],"0-Clear Msg",sizeof("0-Clear Msg")); + strncpy(pes->strs[1],"1-Check Limits",sizeof("1-Check Limits")); + pes->no_str = 2; + } + else + { + strcpy(pes->strs[0],"No string"); + pes->no_str=1; + } + + return(0); +} + +static long put_enum_str(paddr,pstring) + struct dbAddr *paddr; + char *pstring; +{ + struct scanRecord *pscan=(struct scanRecord *)paddr->precord; + + if(paddr->pfield==(void *)&pscan->cmnd) + { + if(sscanf(pstring,"%i",&pscan->cmnd)<=0) + return(S_db_badChoice); + } + else + { + return(S_db_badChoice); + } + + return(0); +} + + +static long get_value(pscan,pvdes) + struct scanRecord *pscan; + struct valueDes *pvdes; +{ + pvdes->field_type = DBF_DOUBLE; + pvdes->no_elements=1; + (double *)(pvdes->pvalue) = &pscan->p1dv; + return(0); +} + +static long get_units(paddr,units) + struct dbAddr *paddr; + char *units; +{ + struct scanRecord *pscan=(struct scanRecord *)paddr->precord; + return(0); +} + +static long get_precision(paddr,precision) + struct dbAddr *paddr; + long *precision; +{ + struct scanRecord *pscan=(struct scanRecord *)paddr->precord; + + if ((paddr->pfield >= (void *)&pscan->p1sm) && + (paddr->pfield <= (void *)&pscan->p1pa)) { + *precision = pscan->p1pr; + } + else if((paddr->pfield >= (void *)&pscan->p2sm) && + (paddr->pfield <= (void *)&pscan->p2pa)) { + *precision = pscan->p2pr; + } + else if((paddr->pfield >= (void *)&pscan->p3sm) && + (paddr->pfield <= (void *)&pscan->p3pa)) { + *precision = pscan->p3pr; + } + else if((paddr->pfield >= (void *)&pscan->p4sm) && + (paddr->pfield <= (void *)&pscan->p4pa)) { + *precision = pscan->p4pr; + } + else if((paddr->pfield >= (void *)&pscan->d1cv) && + (paddr->pfield <= (void *)&pscan->d1da)) { + *precision = pscan->d1pr; + } + else if((paddr->pfield >= (void *)&pscan->d2cv) && + (paddr->pfield <= (void *)&pscan->d2da)) { + *precision = pscan->d2pr; + } + else if((paddr->pfield >= (void *)&pscan->d3cv) && + (paddr->pfield <= (void *)&pscan->d3da)) { + *precision = pscan->d3pr; + } + else if((paddr->pfield >= (void *)&pscan->d4cv) && + (paddr->pfield <= (void *)&pscan->d4da)) { + *precision = pscan->d4pr; + } + else { + *precision = 2; + } + + return(0); +} + +static long get_graphic_double(paddr,pgd) + struct dbAddr *paddr; + struct dbr_grDouble *pgd; +{ + struct scanRecord *pscan=(struct scanRecord *)paddr->precord; + + if (((paddr->pfield >= (void *)&pscan->p1sm) && + (paddr->pfield <= (void *)&pscan->p1pa)) || + (paddr->pfield == pscan->p1pa)) { + pgd->upper_disp_limit = pscan->p1hr; + pgd->lower_disp_limit = pscan->p1lr; + } + else if(((paddr->pfield >= (void *)&pscan->p2sm) && + (paddr->pfield <= (void *)&pscan->p2pa)) || + (paddr->pfield == pscan->p2pa)) { + pgd->upper_disp_limit = pscan->p2hr; + pgd->lower_disp_limit = pscan->p2lr; + } + else if(((paddr->pfield >= (void *)&pscan->p3sm) && + (paddr->pfield <= (void *)&pscan->p3pa)) || + (paddr->pfield == pscan->p3pa)) { + pgd->upper_disp_limit = pscan->p3hr; + pgd->lower_disp_limit = pscan->p3lr; + } + else if(((paddr->pfield >= (void *)&pscan->p4sm) && + (paddr->pfield <= (void *)&pscan->p4pa)) || + (paddr->pfield == pscan->p4pa)) { + pgd->upper_disp_limit = pscan->p4hr; + pgd->lower_disp_limit = pscan->p4lr; + } + else if(((paddr->pfield >= (void *)&pscan->d1cv) && + (paddr->pfield <= (void *)&pscan->d1da)) || + (paddr->pfield == pscan->d1da)) { + pgd->upper_disp_limit = pscan->d1hr; + pgd->lower_disp_limit = pscan->d1lr; + } + else if(((paddr->pfield >= (void *)&pscan->d2cv) && + (paddr->pfield <= (void *)&pscan->d2da)) || + (paddr->pfield == pscan->d2da)) { + pgd->upper_disp_limit = pscan->d2hr; + pgd->lower_disp_limit = pscan->d2lr; + } + else if(((paddr->pfield >= (void *)&pscan->d3cv) && + (paddr->pfield <= (void *)&pscan->d3da)) || + (paddr->pfield == pscan->d3da)) { + pgd->upper_disp_limit = pscan->d3hr; + pgd->lower_disp_limit = pscan->d3lr; + } + else if(((paddr->pfield >= (void *)&pscan->d4cv) && + (paddr->pfield <= (void *)&pscan->d4da)) || + (paddr->pfield == pscan->d4da)) { + pgd->upper_disp_limit = pscan->d4hr; + pgd->lower_disp_limit = pscan->d4lr; + } + else recGblGetGraphicDouble(paddr,pgd); + return(0); +} + +static long get_control_double(paddr,pcd) + struct dbAddr *paddr; + struct dbr_ctrlDouble *pcd; +{ + struct scanRecord *pscan=(struct scanRecord *)paddr->precord; + recGblGetControlDouble(paddr,pcd); + return(0); +} + +static long get_alarm_double(paddr,pad) + struct dbAddr *paddr; + struct dbr_alDouble *pad; +{ + recGblGetAlarmDouble(paddr,pad); + return(0); +} + + +static void checkMonitors(pscan) + struct scanRecord *pscan; +{ + struct recPvtStruct *precPvt = (struct recPvtStruct *)pscan->rpvt; + unsigned long now; + + /* If last posting time is > MIN_MON, check to see if any dynamic fields + have changed (also post monitors on end of scan)*/ + + now=tickGet(); + if(((now - pscan->tolp) > MIN_MON) || + ((pscan->pxsc == 1) && (pscan->exsc == 0))) { + pscan->tolp = now; + if(pscan->pcpt != pscan->cpt) { + db_post_events(pscan,&pscan->cpt, DBE_VALUE); + pscan->pcpt = pscan->cpt; + } + if(fabs(pscan->p1lv - pscan->p1dv) > 0) { + db_post_events(pscan,&pscan->p1dv, DBE_VALUE); + pscan->p1lv = pscan->p1dv; + } + if(fabs(pscan->r1lv - pscan->r1cv) > 0) { + db_post_events(pscan,&pscan->r1cv, DBE_VALUE); + pscan->r1lv = pscan->r1cv; + } + if(fabs(pscan->p2lv - pscan->p2dv) > 0) { + db_post_events(pscan,&pscan->p2dv, DBE_VALUE); + pscan->p2lv = pscan->p2dv; + } + if(fabs(pscan->r2lv - pscan->r2cv) > 0) { + db_post_events(pscan,&pscan->r2cv, DBE_VALUE); + pscan->r2lv = pscan->r2cv; + } + if(fabs(pscan->p3lv - pscan->p3dv) > 0) { + db_post_events(pscan,&pscan->p3dv, DBE_VALUE); + pscan->p3lv = pscan->p3dv; + } + if(fabs(pscan->r3lv - pscan->r3cv) > 0) { + db_post_events(pscan,&pscan->r3cv, DBE_VALUE); + pscan->r3lv = pscan->r3cv; + } + if(fabs(pscan->p4lv - pscan->p4dv) > 0) { + db_post_events(pscan,&pscan->p4dv, DBE_VALUE); + pscan->p4lv = pscan->p4dv; + } + if(fabs(pscan->r4lv - pscan->r4cv) > 0) { + db_post_events(pscan,&pscan->r4cv, DBE_VALUE); + pscan->r4lv = pscan->r4cv; + } + if(fabs(pscan->d1lv - pscan->d1cv) > 0) { + db_post_events(pscan,&pscan->d1cv, DBE_VALUE); + pscan->d1lv = pscan->d1cv; + } + if(fabs(pscan->d2lv - pscan->d2cv) > 0) { + db_post_events(pscan,&pscan->d2cv, DBE_VALUE); + pscan->d2lv = pscan->d2cv; + } + if(fabs(pscan->d3lv - pscan->d3cv) > 0) { + db_post_events(pscan,&pscan->d3cv, DBE_VALUE); + pscan->d3lv = pscan->d3cv; + } + if(fabs(pscan->d4lv - pscan->d4cv) > 0) { + db_post_events(pscan,&pscan->d4cv, DBE_VALUE); + pscan->d4lv = pscan->d4cv; + } + } + + if (pscan->pxsc != pscan->exsc) + db_post_events(pscan,&pscan->exsc, DBE_VALUE); + + /* if this is the end of a scan, post data arrays */ + if ((pscan->pxsc == 1) && (pscan->exsc == 0)) { + db_post_events(pscan,pscan->p1pa, DBE_VALUE); + db_post_events(pscan,pscan->p2pa, DBE_VALUE); + db_post_events(pscan,pscan->p3pa, DBE_VALUE); + db_post_events(pscan,pscan->p4pa, DBE_VALUE); + + /* For the following arrays that are "double buffered", it is + currently necessary to post_events on both buffers because + of the way channel access determines "monitors" . + These arrays are posted even if the PV names are not valid, + because they might have changed from valid to non-valid and + the data needs updates. (remember, nothing will happen if + no one has a monitor set */ + + db_post_events(pscan,precPvt->pdet1DataA, DBE_VALUE); + db_post_events(pscan,precPvt->pdet1DataB, DBE_VALUE); + + db_post_events(pscan,precPvt->pdet2DataA, DBE_VALUE); + db_post_events(pscan,precPvt->pdet2DataB, DBE_VALUE); + + db_post_events(pscan,precPvt->pdet3DataA, DBE_VALUE); + db_post_events(pscan,precPvt->pdet3DataB, DBE_VALUE); + + db_post_events(pscan,precPvt->pdet4DataA, DBE_VALUE); + db_post_events(pscan,precPvt->pdet4DataB, DBE_VALUE); + + /* post alert if changed */ + if(precPvt->scanErr) { + pscan->alrt = precPvt->scanErr; + db_post_events(pscan,&pscan->alrt, DBE_VALUE); + } + } +} + + +static void lookupPVs(pscan) + struct scanRecord *pscan; +{ + struct recPvtStruct *precPvt = (struct recPvtStruct *)pscan->rpvt; + char *ppvn[PVN_SIZE]; + struct dbAddr **ppdbAddr; /* ptr to a ptr to dbAddr */ + long *paddrValid; + long prevValid; + short i; + + /* Look up all reassignable PV Names */ + + *ppvn = &pscan->p1pv[0]; + ppdbAddr = (struct dbAddr **)&pscan->p1db; + paddrValid = &pscan->p1nv; + + for(i=0;ir1nv || !pscan->r2nv || !pscan->r3nv || !pscan->r4nv) { + precPvt->validRbPvs = 1; + } + else { + precPvt->validRbPvs = 0; + } + if(!pscan->t1nv || !pscan->t2nv) { + precPvt->validDtPvs = 1; + } + else { + precPvt->validDtPvs = 0; + } + +} + + + +static void initScan(pscan) +struct scanRecord *pscan; +{ + struct recPvtStruct *precPvt = (struct recPvtStruct *)pscan->rpvt; + long status; + long nRequest = 1; + long options = 0; + + pscan->cpt = 0; + + /* Figure out starting positions for each positioner */ + if(pscan->p1sm == REC_SCAN_MO_TAB) { + pscan->p1dv = pscan->p1pa[0]; + } + else { + pscan->p1dv = pscan->p1sp; + pscan->p1pa[pscan->cpt] = pscan->p1dv; + } + if(pscan->p2sm == REC_SCAN_MO_TAB) { + pscan->p2dv = pscan->p2pa[0]; + } + else { + pscan->p2dv = pscan->p2sp; + pscan->p2pa[pscan->cpt] = pscan->p2dv; + } + if(pscan->p3sm == REC_SCAN_MO_TAB) { + pscan->p3dv = pscan->p3pa[0]; + } + else { + pscan->p3dv = pscan->p3sp; + pscan->p3pa[pscan->cpt] = pscan->p3dv; + } + if(pscan->p4sm == REC_SCAN_MO_TAB) { + pscan->p4dv = pscan->p4pa[0]; + } + else { + pscan->p4dv = pscan->p4sp; + pscan->p4pa[pscan->cpt] = pscan->p4dv; + } + + precPvt->phase = MOVE_MOTORS; + /* request callback to do dbPutFields */ + callbackRequest(&precPvt->doPutsCallback); + sprintf(pscan->smsg,"Scanning ..."); + db_post_events(pscan,&pscan->smsg,DBE_VALUE); + return; +} + +static void contScan(pscan) +struct scanRecord *pscan; +{ + struct recPvtStruct *precPvt = (struct recPvtStruct *)pscan->rpvt; + long status; + long nRequest = 1; + long options = 0; + long abortScan = 0; + + if(scanRecDebug > 4) { + printf("contScan; phase = %d\n", (int)precPvt->phase); + } + switch (precPvt->phase) { + case TRIG_DETCTRS: + /* request callback to do dbPutFields to detector trigger fields */ + callbackRequest(&precPvt->doPutsCallback); + return; + + case CHCK_MOTORS: + /* motors have stopped. Check readbacks and deadbands */ + if(!pscan->r1nv) { + status = dbGet(pscan->r1db, DBR_FLOAT, &(pscan->r1cv), + &options, &nRequest, NULL); + if((pscan->r1dl > 0) && + (fabs(pscan->p1dv - pscan->r1cv) > pscan->r1dl)) { + sprintf(pscan->smsg,"SCAN Aborted: P1 Readback > delta"); + db_post_events(pscan,&pscan->smsg,DBE_VALUE); + precPvt->scanErr = 1; + abortScan = 1; + } + } + if(!pscan->r2nv) { + status = dbGet(pscan->r2db, DBR_FLOAT, &(pscan->r2cv), + &options, &nRequest, NULL); + if((pscan->r2dl > 0) && + (fabs(pscan->p2dv - pscan->r2cv) > pscan->r2dl)) { + sprintf(pscan->smsg,"SCAN Aborted: P2 Readback > delta"); + db_post_events(pscan,&pscan->smsg,DBE_VALUE); + precPvt->scanErr = 1; + abortScan = 1; + } + } + if(!pscan->r3nv) { + status = dbGet(pscan->r3db, DBR_FLOAT, &(pscan->r3cv), + &options, &nRequest, NULL); + if((pscan->r3dl > 0) && + (fabs(pscan->p3dv - pscan->r3cv) > pscan->r3dl)) { + sprintf(pscan->smsg,"SCAN Aborted: P3 Readback > delta"); + db_post_events(pscan,&pscan->smsg,DBE_VALUE); + precPvt->scanErr = 1; + abortScan = 1; + } + } + if(!pscan->r4nv) { + status = dbGet(pscan->r4db, DBR_FLOAT, &(pscan->r4cv), + &options, &nRequest, NULL); + if((pscan->r4dl > 0) && + (fabs(pscan->p4dv - pscan->r4cv) > pscan->r4dl)) { + sprintf(pscan->smsg,"SCAN Aborted: P4 Readback > delta"); + db_post_events(pscan,&pscan->smsg,DBE_VALUE); + precPvt->scanErr = 1; + abortScan = 1; + } + } + + if(abortScan) { + endScan(pscan); + return; + } + + if(precPvt->validDtPvs) { + /* request callback to do dbPutFields to detector trigger fields */ + precPvt->phase = TRIG_DETCTRS; + callbackRequest(&precPvt->doPutsCallback); + return; + } + + /* if no validDtPvs, fall through to READ_DETCTRS */ + + case READ_DETCTRS: + /* read each valid detector PV, place data in buffered array */ + status = 0; + if(!pscan->d1nv) { + /* dbAddr is valid */ + status |= dbGet(pscan->d1db, DBR_FLOAT, &(pscan->d1cv), + &options, &nRequest, NULL); + } else pscan->d1cv = 0; + if(!pscan->d2nv) { + status |= dbGet(pscan->d2db, DBR_FLOAT, + &(pscan->d2cv), &options, &nRequest, NULL); + } else pscan->d2cv = 0; + if(!pscan->d3nv) { + status |= dbGet(pscan->d3db, DBR_FLOAT, &(pscan->d3cv), + &options, &nRequest, NULL); + } else pscan->d3cv = 0; + if(!pscan->d4nv) { + status |= dbGet(pscan->d4db, DBR_FLOAT, &(pscan->d4cv), + &options, &nRequest, NULL); + } else pscan->d4cv = 0; + + /* store the data using the Fill pointer */ + precPvt->pdet1Fill[pscan->cpt] = pscan->d1cv; + precPvt->pdet2Fill[pscan->cpt] = pscan->d2cv; + precPvt->pdet3Fill[pscan->cpt] = pscan->d3cv; + precPvt->pdet4Fill[pscan->cpt] = pscan->d4cv; + + pscan->udf=0; + + pscan->cpt++; + /* Has number of points been reached ? */ + if(pscan->cpt < (pscan->npts)) { + /* determine next desired position for each positioner */ + if(pscan->p1sm == REC_SCAN_MO_LIN) { + pscan->p1dv = pscan->p1dv + pscan->p1si; + pscan->p1pa[pscan->cpt] = pscan->p1dv; + } + else if(pscan->p1sm == REC_SCAN_MO_TAB) { + pscan->p1dv = pscan->p1pa[pscan->cpt]; + } + else { + /* this is on-the-fly, so set to second position */ + pscan->p1dv = pscan->p1sp + pscan->p1si; + pscan->p1pa[pscan->cpt] = pscan->p1dv; + } + if(pscan->p2sm == REC_SCAN_MO_LIN) { + pscan->p2dv = pscan->p2dv + pscan->p2si; + pscan->p2pa[pscan->cpt] = pscan->p2dv; + } + else if(pscan->p2sm == REC_SCAN_MO_TAB) { + pscan->p2dv = pscan->p2pa[pscan->cpt]; + } + else { + /* this is on-the-fly, so set to second position */ + pscan->p2dv = pscan->p2sp + pscan->p2si; + pscan->p2pa[pscan->cpt] = pscan->p2dv; + } + if(pscan->p3sm == REC_SCAN_MO_LIN) { + pscan->p3dv = pscan->p3dv + pscan->p3si; + pscan->p3pa[pscan->cpt] = pscan->p3dv; + } + else if(pscan->p3sm == REC_SCAN_MO_TAB) { + pscan->p3dv = pscan->p3pa[pscan->cpt]; + } + else { + /* this is on-the-fly, so set to second position */ + pscan->p3dv = pscan->p3sp + pscan->p3si; + pscan->p3pa[pscan->cpt] = pscan->p3dv; + } + if(pscan->p4sm == REC_SCAN_MO_LIN) { + pscan->p4dv = pscan->p4dv + pscan->p4si; + pscan->p4pa[pscan->cpt] = pscan->p4dv; + } + else if(pscan->p4sm == REC_SCAN_MO_TAB) { + pscan->p4dv = pscan->p4pa[pscan->cpt]; + } + else { + /* this is on-the-fly, so set to second position */ + pscan->p4dv = pscan->p4sp + pscan->p4si; + pscan->p4pa[pscan->cpt] = pscan->p4dv; + } + + /* request callback to move motors to new positions */ + precPvt->phase = MOVE_MOTORS; + callbackRequest(&precPvt->doPutsCallback); + return; + } + else { + endScan(pscan); /* scan is successfully complete */ + sprintf(pscan->smsg,"SCAN Complete"); + db_post_events(pscan,&pscan->smsg,DBE_VALUE); + precPvt->scanErr = 0; + return; + } + } +} + +static void endScan(pscan) +struct scanRecord *pscan; +{ + + struct recPvtStruct *precPvt = (struct recPvtStruct *)pscan->rpvt; + int counter; + + + /* Done with scan. Do we want to fill the remainder of the + array with 0 or something ? */ + /* It turns out that medm plots the whole array, so for it + to look right the remainder of the arrays will be filled + with the last values. This will cause medm to plot the + same point over and over again, but it will look correct */ + + counter = pscan->cpt; + if(scanRecDebug) { + printf("endScan(): Fill Counter - %d\n",counter); + } + while (counter < pscan->mpts) { + precPvt->pdet1Fill[counter] = pscan->d1cv; + precPvt->pdet2Fill[counter] = pscan->d2cv; + precPvt->pdet3Fill[counter] = pscan->d3cv; + precPvt->pdet4Fill[counter] = pscan->d4cv; + + if(pscan->p1sm != REC_SCAN_MO_TAB) { + pscan->p1pa[counter] = pscan->p1dv; + } + if(pscan->p2sm != REC_SCAN_MO_TAB) { + pscan->p2pa[counter] = pscan->p2dv; + } + if(pscan->p3sm != REC_SCAN_MO_TAB) { + pscan->p3pa[counter] = pscan->p3dv; + } + if(pscan->p4sm != REC_SCAN_MO_TAB) { + pscan->p4pa[counter] = pscan->p4dv; + } + + counter++; + } + + /* Switch the array pointers to the valid data */ + + if(precPvt->validDataBuf == A_BUFFER) { + pscan->d1da = precPvt->pdet1DataB; + pscan->d2da = precPvt->pdet2DataB; + pscan->d3da = precPvt->pdet3DataB; + pscan->d4da = precPvt->pdet4DataB; + /* Switch the Fill pointers for the next scan */ + precPvt->pdet1Fill = precPvt->pdet1DataA; + precPvt->pdet2Fill = precPvt->pdet2DataA; + precPvt->pdet3Fill = precPvt->pdet3DataA; + precPvt->pdet4Fill = precPvt->pdet4DataA; + precPvt->validDataBuf = B_BUFFER; + } + else { + pscan->d1da = precPvt->pdet1DataA; + pscan->d2da = precPvt->pdet2DataA; + pscan->d3da = precPvt->pdet3DataA; + pscan->d4da = precPvt->pdet4DataA; + /* Switch the Fill pointers for the next scan */ + precPvt->pdet1Fill = precPvt->pdet1DataB; + precPvt->pdet2Fill = precPvt->pdet2DataB; + precPvt->pdet3Fill = precPvt->pdet3DataB; + precPvt->pdet4Fill = precPvt->pdet4DataB; + precPvt->validDataBuf = A_BUFFER; + } + + pscan->exsc = 0; /* done with scan */ + return; +} + + + + +/****************************************************************************** + * + * This is the code that is executed by the callback task to initiate the next + * step in the scan or trigger detectors (does dbPutFields for the reassignable + * links). It is done with a separate task so one need not worry about lock + * sets. + * + *****************************************************************************/ +void doPuts(precPvt) + struct recPvtStruct *precPvt; +{ +static long status; +static long nRequest = 1; + + if(scanRecDebug > 4) { + printf("DoPuts; phase = %d\n", (int)precPvt->phase); + } + switch (precPvt->phase) { + case MOVE_MOTORS: + /* next processing of records means motors have stopped */ + /* Schedule the next phase depending on readback PV validity */ + /* This needs to come before moving motors */ + + if(precPvt->validRbPvs) { + precPvt->phase = CHCK_MOTORS; + } + else if(precPvt->validDtPvs) { + precPvt->phase = TRIG_DETCTRS; + } + else { + precPvt->phase = READ_DETCTRS; + } + + /* for each valid positioner, write the desired position */ + if(!precPvt->pscan->p1nv) { + status = dbPutField(precPvt->pscan->p1db,DBR_FLOAT, + &(precPvt->pscan->p1dv), 1); + } + if(!precPvt->pscan->p2nv) { + status = dbPutField(precPvt->pscan->p2db,DBR_FLOAT, + &(precPvt->pscan->p2dv), 1); + } + if(!precPvt->pscan->p3nv) { + status = dbPutField(precPvt->pscan->p3db,DBR_FLOAT, + &(precPvt->pscan->p3dv), 1); + } + if(!precPvt->pscan->p4nv) { + status = dbPutField(precPvt->pscan->p4db,DBR_FLOAT, + &(precPvt->pscan->p4dv), 1); + } + + break; + case TRIG_DETCTRS: + /* Schedule the next phase */ + precPvt->phase = READ_DETCTRS; + + /* for each valid detector trigger, write the desired value */ + if(!precPvt->pscan->t1nv) { + status = dbPutField(precPvt->pscan->t1db,DBR_FLOAT, + &(precPvt->pscan->t1cd), 1); + } + if(!precPvt->pscan->t2nv) { + status = dbPutField(precPvt->pscan->t2db,DBR_FLOAT, + &(precPvt->pscan->t2cd), 1); + } + + break; + default: + } +} + + + + +/* routine to resolve and adjust linear scan definition. + * Might get complicated !!! + */ + +static void adjLinParms(paddr) + struct dbAddr *paddr; +{ + struct scanRecord *pscan = (struct scanRecord *)(paddr->precord); + struct recPvtStruct *precPvt = (struct recPvtStruct *)pscan->rpvt; + struct linScanParms *pParms; + + int special_type = paddr->special; + int i; + + /* determine which positioner */ + if ((paddr->pfield >= (void *)&pscan->p1sp) && + (paddr->pfield <= (void *)&pscan->p1fw)) { + pParms = (struct linScanParms *)&pscan->p1sp; + i=1; + } + else if((paddr->pfield >= (void *)&pscan->p2sp) && + (paddr->pfield <= (void *)&pscan->p2fw)) { + pParms = (struct linScanParms *)&pscan->p2sp; + i=2; + } + else if((paddr->pfield >= (void *)&pscan->p3sp) && + (paddr->pfield <= (void *)&pscan->p3fw)) { + pParms = (struct linScanParms *)&pscan->p3sp; + i=3; + } + else if((paddr->pfield >= (void *)&pscan->p4sp) && + (paddr->pfield <= (void *)&pscan->p4fw)) { + pParms = (struct linScanParms *)&pscan->p4sp; + i=4; + } + else { + return; + } + + switch(special_type) { + case(SPC_SC_S): /* start position changed */ + /* if end/center/width are not frozen, change them */ + if(!pParms->p_fe && !pParms->p_fc && !pParms->p_fw) { + pParms->p_ep = pParms->p_sp + + ((pscan->npts - 1) * pParms->p_si); + db_post_events(pscan,&pParms->p_ep,DBE_VALUE); + pParms->p_cp = (pParms->p_ep + pParms->p_sp)/2; + db_post_events(pscan,&pParms->p_cp,DBE_VALUE); + pParms->p_wd = (pParms->p_ep - pParms->p_sp); + db_post_events(pscan,&pParms->p_wd,DBE_VALUE); + return; + /* if step increment/center/width are not frozen, change them */ + } else if(!pParms->p_fi && !pParms->p_fc && !pParms->p_fw) { + pParms->p_si = (pParms->p_ep - pParms->p_sp)/(pscan->npts - 1); + db_post_events(pscan,&pParms->p_si,DBE_VALUE); + pParms->p_cp = (pParms->p_ep + pParms->p_sp)/2; + db_post_events(pscan,&pParms->p_cp,DBE_VALUE); + pParms->p_wd = (pParms->p_ep - pParms->p_sp); + db_post_events(pscan,&pParms->p_wd,DBE_VALUE); + return; + /* if step increment/end/width are not frozen, change them */ + } else if(!pParms->p_fi && !pParms->p_fc && !pParms->p_fw) { + pParms->p_wd = (pParms->p_cp - pParms->p_sp) * 2; + db_post_events(pscan,&pParms->p_wd,DBE_VALUE); + pParms->p_si = pParms->p_wd/(pscan->npts - 1); + db_post_events(pscan,&pParms->p_si,DBE_VALUE); + pParms->p_ep = (pParms->p_sp + pParms->p_wd); + db_post_events(pscan,&pParms->p_ep,DBE_VALUE); + return; + /* if # of points/center/width are not frozen, change them */ + } else if(!pscan->fpts && !pParms->p_fc && !pParms->p_fw) { + pscan->npts = ((pParms->p_ep - pParms->p_sp)/(pParms->p_si)) + 1; + if(pscan->npts > pscan->mpts) { + pscan->npts = pscan->mpts; + sprintf(pscan->smsg,"P%1d Request Exceeded Maximum Points !",i); + /* adjust changed field to be consistent */ + pParms->p_sp = pParms->p_ep-(pParms->p_si * (pscan->npts - 1)); + db_post_events(pscan,&pParms->p_sp,DBE_VALUE); + pscan->alrt = 1; + } + db_post_events(pscan,&pscan->npts,DBE_VALUE); + pParms->p_cp = (pParms->p_ep + pParms->p_sp)/2; + db_post_events(pscan,&pParms->p_cp,DBE_VALUE); + pParms->p_wd = (pParms->p_ep - pParms->p_sp); + db_post_events(pscan,&pParms->p_wd,DBE_VALUE); + precPvt->nptsCause = i; /* indicate cause of # of points changed */ + changedNpts(pscan); + return; + /* if # of points/end/width are not frozen, change them */ + } else if(!pscan->fpts && !pParms->p_fe && !pParms->p_fw) { + pscan->npts = ((pParms->p_cp - pParms->p_sp)*2/(pParms->p_si)) + 1; + if(pscan->npts > pscan->mpts) { + pscan->npts = pscan->mpts; + sprintf(pscan->smsg,"P%1d Request Exceeded Maximum Points !",i); + /* adjust changed field to be consistent */ + pParms->p_sp=pParms->p_cp-((pParms->p_si*(pscan->npts - 1))/2); + db_post_events(pscan,&pParms->p_sp,DBE_VALUE); + pscan->alrt = 1; + } + db_post_events(pscan,&pscan->npts,DBE_VALUE); + pParms->p_ep = pParms->p_sp + ((pscan->npts - 1) * pParms->p_si); + db_post_events(pscan,&pParms->p_cp,DBE_VALUE); + pParms->p_wd = (pParms->p_ep - pParms->p_sp); + db_post_events(pscan,&pParms->p_wd,DBE_VALUE); + precPvt->nptsCause = i; /* indicate cause of # of points changed */ + changedNpts(pscan); + return; + /* if center/end are not frozen, change them */ + } else if(!pParms->p_fc && !pParms->p_fe) { + pParms->p_ep = pParms->p_sp + ((pscan->npts - 1) * pParms->p_si); + db_post_events(pscan,&pParms->p_ep,DBE_VALUE); + pParms->p_cp = (pParms->p_ep + pParms->p_sp)/2; + db_post_events(pscan,&pParms->p_cp,DBE_VALUE); + return; + } else { /* too constrained !! */ + pParms->p_sp = pParms->p_ep - ((pscan->npts - 1) * pParms->p_si); + db_post_events(pscan,&pParms->p_sp,DBE_VALUE); + sprintf(pscan->smsg,"P%1d SCAN Parameters Too Constrained !",i); + pscan->alrt = 1; + return; + } + break; + + case(SPC_SC_I): /* step increment changed */ + /* if end/center/width are not frozen, change them */ + if(!pParms->p_fe && !pParms->p_fc && !pParms->p_fw) { + pParms->p_ep = pParms->p_sp + ((pscan->npts - 1) * pParms->p_si); + db_post_events(pscan,&pParms->p_ep,DBE_VALUE); + pParms->p_cp = (pParms->p_ep + pParms->p_sp)/2; + db_post_events(pscan,&pParms->p_cp,DBE_VALUE); + pParms->p_wd = (pParms->p_ep - pParms->p_sp); + db_post_events(pscan,&pParms->p_wd,DBE_VALUE); + return; + /* if start/center/width are not frozen, change them */ + } else if(!pParms->p_fs && !pParms->p_fc && !pParms->p_fw) { + pParms->p_sp = pParms->p_ep - ((pscan->npts - 1) * pParms->p_si); + db_post_events(pscan,&pParms->p_sp,DBE_VALUE); + pParms->p_cp = (pParms->p_ep + pParms->p_sp)/2; + db_post_events(pscan,&pParms->p_cp,DBE_VALUE); + pParms->p_wd = (pParms->p_ep - pParms->p_sp); + db_post_events(pscan,&pParms->p_wd,DBE_VALUE); + return; + /* if start/end/width are not frozen, change them */ + } else if(!pParms->p_fs && !pParms->p_fe && !pParms->p_fw) { + pParms->p_sp = pParms->p_cp - ((pscan->npts - 1) * pParms->p_si)/2; + db_post_events(pscan,&pParms->p_sp,DBE_VALUE); + pParms->p_ep = pParms->p_sp + ((pscan->npts - 1) * pParms->p_si); + db_post_events(pscan,&pParms->p_ep,DBE_VALUE); + pParms->p_wd = (pParms->p_ep - pParms->p_sp); + db_post_events(pscan,&pParms->p_wd,DBE_VALUE); + return; + /* if # of points is not frozen, change it */ + } else if(!pscan->fpts) { + pscan->npts = ((pParms->p_ep - pParms->p_sp)/(pParms->p_si)) + 1; + if(pscan->npts > pscan->mpts) { + pscan->npts = pscan->mpts; + sprintf(pscan->smsg,"P%1d Request Exceeded Maximum Points !",i); + /* adjust changed field to be consistent */ + pParms->p_si = (pParms->p_ep - pParms->p_sp)/(pscan->npts - 1); + db_post_events(pscan,&pParms->p_si,DBE_VALUE); + pscan->alrt = 1; + } + db_post_events(pscan,&pscan->npts,DBE_VALUE); + precPvt->nptsCause = i; /* indicate cause of # of points changed */ + changedNpts(pscan); + return; + } else { /* too constrained !! */ + pParms->p_si = (pParms->p_ep - pParms->p_sp)/(pscan->npts - 1); + db_post_events(pscan,&pParms->p_si,DBE_VALUE); + sprintf(pscan->smsg,"P%1d SCAN Parameters Too Constrained !",i); + pscan->alrt = 1; + return; + } + break; + + case(SPC_SC_E): /* end position changed */ + /* if start/center/width are not frozen, change them */ + if(!pParms->p_fs && !pParms->p_fc && !pParms->p_fw) { + pParms->p_sp = pParms->p_ep - ((pscan->npts - 1) * pParms->p_si); + db_post_events(pscan,&pParms->p_sp,DBE_VALUE); + pParms->p_cp = (pParms->p_ep + pParms->p_sp)/2; + db_post_events(pscan,&pParms->p_cp,DBE_VALUE); + pParms->p_wd = (pParms->p_ep - pParms->p_sp); + db_post_events(pscan,&pParms->p_wd,DBE_VALUE); + return; + /* if step increment/center/width are not frozen, change them */ + } else if(!pParms->p_fi && !pParms->p_fc && !pParms->p_fw) { + pParms->p_si = (pParms->p_ep - pParms->p_sp)/(pscan->npts - 1); + db_post_events(pscan,&pParms->p_si,DBE_VALUE); + pParms->p_cp = (pParms->p_ep + pParms->p_sp)/2; + db_post_events(pscan,&pParms->p_cp,DBE_VALUE); + pParms->p_wd = (pParms->p_ep - pParms->p_sp); + db_post_events(pscan,&pParms->p_wd,DBE_VALUE); + return; + /* if step start/width/increment are not frozen, change them */ + } else if(!pParms->p_fs && !pParms->p_fw && !pParms->p_fi) { + pParms->p_wd = (pParms->p_ep - pParms->p_cp) * 2; + db_post_events(pscan,&pParms->p_wd,DBE_VALUE); + pParms->p_sp = pParms->p_ep - pParms->p_wd; + db_post_events(pscan,&pParms->p_sp,DBE_VALUE); + pParms->p_si = (pParms->p_ep - pParms->p_sp)/(pscan->npts - 1); + db_post_events(pscan,&pParms->p_si,DBE_VALUE); + return; + /* if # of points/start/width are not frozen, change them */ + } else if(!pscan->fpts && !pParms->p_fs && !pParms->p_fw) { + pscan->npts=(((pParms->p_ep - pParms->p_cp)*2)/(pParms->p_si)) + 1; + if(pscan->npts > pscan->mpts) { + pscan->npts = pscan->mpts; + sprintf(pscan->smsg,"P%1d Request Exceeded Maximum Points !",i); + /* adjust changed field to be consistent */ + pParms->p_ep=pParms->p_cp+(pParms->p_si * (pscan->npts - 1)/2); + db_post_events(pscan,&pParms->p_ep,DBE_VALUE); + pscan->alrt = 1; + } + db_post_events(pscan,&pscan->npts,DBE_VALUE); + pParms->p_wd = (pParms->p_ep - pParms->p_cp) * 2; + db_post_events(pscan,&pParms->p_wd,DBE_VALUE); + pParms->p_sp = pParms->p_ep - pParms->p_wd; + db_post_events(pscan,&pParms->p_sp,DBE_VALUE); + precPvt->nptsCause = i; /* indicate cause of # of points changed */ + changedNpts(pscan); + return; + /* if # of points/center/width are not frozen, change them */ + } else if(!pscan->fpts && !pParms->p_fc && !pParms->p_fw) { + pscan->npts = ((pParms->p_ep - pParms->p_sp)/(pParms->p_si)) + 1; + if(pscan->npts > pscan->mpts) { + pscan->npts = pscan->mpts; + sprintf(pscan->smsg,"P%1d Request Exceeded Maximum Points !",i); + /* adjust changed field to be consistent */ + pParms->p_ep=pParms->p_sp + (pParms->p_si * (pscan->npts - 1)); + db_post_events(pscan,&pParms->p_ep,DBE_VALUE); + pscan->alrt = 1; + } + db_post_events(pscan,&pscan->npts,DBE_VALUE); + pParms->p_cp = (pParms->p_ep + pParms->p_sp)/2; + db_post_events(pscan,&pParms->p_cp,DBE_VALUE); + pParms->p_wd = (pParms->p_ep - pParms->p_sp); + db_post_events(pscan,&pParms->p_wd,DBE_VALUE); + precPvt->nptsCause = i; /* indicate cause of # of points changed */ + changedNpts(pscan); + return; + /* if start/center are not frozen, change them */ + } else if(!pParms->p_fs && !pParms->p_fc) { + pParms->p_sp = pParms->p_ep - ((pscan->npts - 1) * pParms->p_si); + db_post_events(pscan,&pParms->p_sp,DBE_VALUE); + pParms->p_cp = (pParms->p_ep + pParms->p_sp)/2; + db_post_events(pscan,&pParms->p_cp,DBE_VALUE); + return; + } else { /* too constrained !! */ + pParms->p_ep = pParms->p_sp + ((pscan->npts - 1) * pParms->p_si); + db_post_events(pscan,&pParms->p_ep,DBE_VALUE); + sprintf(pscan->smsg,"P%1d SCAN Parameters Too Constrained !",i); + pscan->alrt = 1; + return; + } + break; + + case(SPC_SC_C): /* center position changed */ + /* if start/end are not frozen, change them */ + if(!pParms->p_fs && !pParms->p_fe) { + pParms->p_sp = pParms->p_cp - ((pscan->npts - 1) * pParms->p_si)/2; + db_post_events(pscan,&pParms->p_sp,DBE_VALUE); + pParms->p_ep = pParms->p_sp + ((pscan->npts - 1) * pParms->p_si); + db_post_events(pscan,&pParms->p_ep,DBE_VALUE); + return; + /* if start/inc/width are not frozen, change them */ + } else if(!pParms->p_fs && !pParms->p_fi && !pParms->p_fw) { + pParms->p_wd = (pParms->p_ep - pParms->p_cp)*2; + db_post_events(pscan,&pParms->p_wd,DBE_VALUE); + pParms->p_sp = pParms->p_ep - pParms->p_wd; + db_post_events(pscan,&pParms->p_sp,DBE_VALUE); + pParms->p_si = (pParms->p_ep - pParms->p_sp)/(pscan->npts - 1); + db_post_events(pscan,&pParms->p_si,DBE_VALUE); + return; + /* if end/inc/width are not frozen, change them */ + } else if(!pParms->p_fe && !pParms->p_fi && !pParms->p_fw) { + pParms->p_wd = (pParms->p_cp - pParms->p_sp)*2; + db_post_events(pscan,&pParms->p_wd,DBE_VALUE); + pParms->p_ep = pParms->p_sp + pParms->p_wd; + db_post_events(pscan,&pParms->p_ep,DBE_VALUE); + pParms->p_si = (pParms->p_ep - pParms->p_sp)/(pscan->npts - 1); + db_post_events(pscan,&pParms->p_si,DBE_VALUE); + return; + /* if # of points/start/width are not frozen, change them */ + } else if(!pscan->fpts && !pParms->p_fs && !pParms->p_fw) { + pscan->npts=(((pParms->p_ep - pParms->p_cp)*2)/(pParms->p_si)) + 1; + if(pscan->npts > pscan->mpts) { + pscan->npts = pscan->mpts; + sprintf(pscan->smsg,"P%1d Request Exceeded Maximum Points !",i); + /* adjust changed field to be consistent */ + pParms->p_cp=pParms->p_ep-(pParms->p_si * (pscan->npts - 1)/2); + db_post_events(pscan,&pParms->p_cp,DBE_VALUE); + pscan->alrt = 1; + } + db_post_events(pscan,&pscan->npts,DBE_VALUE); + pParms->p_wd = (pParms->p_ep - pParms->p_cp) * 2; + db_post_events(pscan,&pParms->p_wd,DBE_VALUE); + pParms->p_sp = pParms->p_ep - pParms->p_wd; + db_post_events(pscan,&pParms->p_sp,DBE_VALUE); + precPvt->nptsCause = i; /* indicate cause of # of points changed */ + changedNpts(pscan); + return; + /* if # of points/end/width are not frozen, change them */ + } else if(!pscan->fpts && !pParms->p_fe && !pParms->p_fw) { + pscan->npts=(((pParms->p_cp - pParms->p_sp)*2)/(pParms->p_si)) + 1; + if(pscan->npts > pscan->mpts) { + pscan->npts = pscan->mpts; + sprintf(pscan->smsg,"P%1d Request Exceeded Maximum Points !",i); + /* adjust changed field to be consistent */ + pParms->p_cp=pParms->p_sp+(pParms->p_si * (pscan->npts - 1)/2); + db_post_events(pscan,&pParms->p_cp,DBE_VALUE); + pscan->alrt = 1; + } + db_post_events(pscan,&pscan->npts,DBE_VALUE); + pParms->p_wd = (pParms->p_cp - pParms->p_sp) * 2; + db_post_events(pscan,&pParms->p_wd,DBE_VALUE); + pParms->p_ep = pParms->p_sp + pParms->p_wd; + db_post_events(pscan,&pParms->p_ep,DBE_VALUE); + precPvt->nptsCause = i; /* indicate cause of # of points changed */ + changedNpts(pscan); + return; + } else { /* too constrained !! */ + pParms->p_cp = pParms->p_sp + ((pscan->npts - 1) * pParms->p_si)/2; + db_post_events(pscan,&pParms->p_cp,DBE_VALUE); + sprintf(pscan->smsg,"P%1d SCAN Parameters Too Constrained !",i); + pscan->alrt = 1; + return; + } + break; + + case(SPC_SC_W): /* width position changed */ + /* if step start/inc/end are not frozen, change them */ + if(!pParms->p_fs && !pParms->p_fi && !pParms->p_fe) { + pParms->p_si = pParms->p_wd/(pscan->npts - 1); + db_post_events(pscan,&pParms->p_si,DBE_VALUE); + pParms->p_sp = pParms->p_cp - ((pscan->npts - 1) * pParms->p_si)/2; + db_post_events(pscan,&pParms->p_sp,DBE_VALUE); + pParms->p_ep = pParms->p_sp + ((pscan->npts - 1) * pParms->p_si); + db_post_events(pscan,&pParms->p_ep,DBE_VALUE); + return; + /* if center/end/inc are not frozen, change them */ + } else if(!pParms->p_fc && !pParms->p_fe && !pParms->p_fi) { + pParms->p_si = pParms->p_wd/(pscan->npts - 1); + db_post_events(pscan,&pParms->p_si,DBE_VALUE); + pParms->p_ep = pParms->p_sp + ((pscan->npts - 1) * pParms->p_si); + db_post_events(pscan,&pParms->p_ep,DBE_VALUE); + pParms->p_cp = (pParms->p_ep + pParms->p_sp)/2; + db_post_events(pscan,&pParms->p_cp,DBE_VALUE); + return; + /* if start/center/inc are not frozen, change them */ + } else if(!pParms->p_fs && !pParms->p_fc && !pParms->p_fi) { + pParms->p_si = pParms->p_wd/(pscan->npts - 1); + db_post_events(pscan,&pParms->p_si,DBE_VALUE); + pParms->p_sp = pParms->p_ep - ((pscan->npts - 1) * pParms->p_si); + db_post_events(pscan,&pParms->p_sp,DBE_VALUE); + pParms->p_cp = (pParms->p_ep + pParms->p_sp)/2; + db_post_events(pscan,&pParms->p_cp,DBE_VALUE); + return; + /* if # of points/start/end are not frozen, change them */ + } else if(!pscan->fpts && !pParms->p_fs && !pParms->p_fe) { + pscan->npts = (pParms->p_wd/pParms->p_si) + 1; + if(pscan->npts > pscan->mpts) { + pscan->npts = pscan->mpts; + sprintf(pscan->smsg,"P%1d Request Exceeded Maximum Points !",i); + /* adjust changed field to be consistent */ + pParms->p_wd = (pParms->p_si * (pscan->npts - 1)); + db_post_events(pscan,&pParms->p_wd,DBE_VALUE); + pscan->alrt = 1; + } + db_post_events(pscan,&pscan->npts,DBE_VALUE); + pParms->p_sp = pParms->p_cp - ((pscan->npts - 1) * pParms->p_si)/2; + db_post_events(pscan,&pParms->p_sp,DBE_VALUE); + pParms->p_ep = pParms->p_sp + ((pscan->npts - 1) * pParms->p_si); + db_post_events(pscan,&pParms->p_ep,DBE_VALUE); + precPvt->nptsCause = i; /* indicate cause of # of points changed */ + changedNpts(pscan); + return; + /* if # of points/center/end are not frozen, change them */ + } else if(!pscan->fpts && !pParms->p_fc && !pParms->p_fe) { + pscan->npts = (pParms->p_wd/pParms->p_si) + 1; + if(pscan->npts > pscan->mpts) { + pscan->npts = pscan->mpts; + sprintf(pscan->smsg,"P%1d Request Exceeded Maximum Points !",i); + /* adjust changed field to be consistent */ + pParms->p_wd = (pParms->p_si * (pscan->npts - 1)); + db_post_events(pscan,&pParms->p_wd,DBE_VALUE); + pscan->alrt = 1; + } + db_post_events(pscan,&pscan->npts,DBE_VALUE); + pParms->p_ep = pParms->p_sp + ((pscan->npts - 1) * pParms->p_si); + db_post_events(pscan,&pParms->p_ep,DBE_VALUE); + pParms->p_cp = (pParms->p_ep + pParms->p_sp)/2; + db_post_events(pscan,&pParms->p_cp,DBE_VALUE); + precPvt->nptsCause = i; /* indicate cause of # of points changed */ + changedNpts(pscan); + return; + /* if # of points/start/center are not frozen, change them */ + } else if(!pscan->fpts && !pParms->p_fs && !pParms->p_fc) { + pscan->npts = (pParms->p_wd/pParms->p_si) + 1; + if(pscan->npts > pscan->mpts) { + pscan->npts = pscan->mpts; + sprintf(pscan->smsg,"P%1d Request Exceeded Maximum Points !",i); + /* adjust changed field to be consistent */ + pParms->p_wd = (pParms->p_si * (pscan->npts - 1)); + db_post_events(pscan,&pParms->p_wd,DBE_VALUE); + pscan->alrt = 1; + } + db_post_events(pscan,&pscan->npts,DBE_VALUE); + pParms->p_sp = pParms->p_ep - ((pscan->npts - 1) * pParms->p_si); + db_post_events(pscan,&pParms->p_sp,DBE_VALUE); + pParms->p_cp = (pParms->p_ep + pParms->p_sp)/2; + db_post_events(pscan,&pParms->p_cp,DBE_VALUE); + precPvt->nptsCause = i; /* indicate cause of # of points changed */ + changedNpts(pscan); + return; + } else { /* too constrained !! */ + pParms->p_wd = (pParms->p_ep - pParms->p_sp); + db_post_events(pscan,&pParms->p_wd,DBE_VALUE); + sprintf(pscan->smsg,"P%1d SCAN Parameters Too Constrained !",i); + pscan->alrt = 1; + return; + } + break; + + default: + return; + } +} + + + +/* This routine attempts to bring all linear scan parameters into + * "consistency". It is used at init and when the # of pts changes. + * If the number of points changed because of a change in a Positioner's + * scan parameters, that positioner is skipped to make sure that there is + * no conflict with that logic. + * + */ + +static void changedNpts(pscan) + struct scanRecord *pscan; +{ + + struct recPvtStruct *precPvt = (struct recPvtStruct *)pscan->rpvt; + struct linScanParms *pParms; + int i; + unsigned short freezeState = 0; + + /* for each positioner, calculate scan params as best as we can */ + for(i=1; i <= 4; i++) { + /* Skip the positioner that caused this */ + if(i == precPvt->nptsCause) i++; + + if(i==1) + pParms = (struct linScanParms *)&pscan->p1sp; + else if(i==2) + pParms = (struct linScanParms *)&pscan->p2sp; + else if(i==3) + pParms = (struct linScanParms *)&pscan->p3sp; + else if(i==4) + pParms = (struct linScanParms *)&pscan->p4sp; + else + return; + + /* develop freezeState switching word ... */ + /* START_FRZ | STEP_FRZ | END_FRZ | CENTER_FRZ | WIDTH_FRZ */ + + freezeState = (pParms->p_fs << 4) | + (pParms->p_fi << 3) | + (pParms->p_fe << 2) | + (pParms->p_fc << 1) | + (pParms->p_fw); + + if(scanRecDebug) { + printf("Freeze State of P%1d = 0x%hx \n",i,freezeState); + } + + switch(freezeState) { + case(0): /* end/center/width unfrozen, change them */ + case(8): + case(16): + case(24): + pParms->p_ep = pParms->p_sp + ((pscan->npts - 1) * pParms->p_si); + db_post_events(pscan,&pParms->p_ep,DBE_VALUE); + pParms->p_cp = (pParms->p_ep + pParms->p_sp)/2; + db_post_events(pscan,&pParms->p_cp,DBE_VALUE); + pParms->p_wd = (pParms->p_ep - pParms->p_sp); + db_post_events(pscan,&pParms->p_wd,DBE_VALUE); + break; + + case(4): /* start/center/width are not frozen, change them */ + case(12): + pParms->p_sp = pParms->p_ep - ((pscan->npts - 1) * pParms->p_si); + db_post_events(pscan,&pParms->p_sp,DBE_VALUE); + pParms->p_cp = (pParms->p_ep + pParms->p_sp)/2; + db_post_events(pscan,&pParms->p_cp,DBE_VALUE); + pParms->p_wd = (pParms->p_ep - pParms->p_sp); + db_post_events(pscan,&pParms->p_wd,DBE_VALUE); + break; + + case(2): /* if center is frozen, but not width/start/end , ... */ + case(10): + pParms->p_sp = pParms->p_cp - ((pscan->npts - 1) * pParms->p_si)/2; + db_post_events(pscan,&pParms->p_sp,DBE_VALUE); + pParms->p_ep = pParms->p_sp + ((pscan->npts - 1) * pParms->p_si); + db_post_events(pscan,&pParms->p_ep,DBE_VALUE); + pParms->p_wd = (pParms->p_ep - pParms->p_sp); + db_post_events(pscan,&pParms->p_wd,DBE_VALUE); + break; + + case(1): /* if center or width is frozen, but not inc , ... */ + case(3): + case(5): /* if end/center or end/width are frozen, but not inc, */ + case(6): + case(7): + case(17): /* if start/center or start/width are frozen, but not inc*/ + case(18): + case(19): + case(20): + case(21): + case(22): + case(23): + pParms->p_si = (pParms->p_ep - pParms->p_sp)/(pscan->npts - 1); + db_post_events(pscan,&pParms->p_si,DBE_VALUE); + break; + + /* The following freezeStates are known to be "Too Constrained" */ + /* 9,11,13,14,15,25,26,27,28,29,30,31 */ + default: /* too constrained !! */ + sprintf(pscan->smsg,"P%1d SCAN Parameters Too Constrained !",i); + pscan->alrt = 1; + break; + } + + } +} + + + +static void checkScanLimits(pscan) + struct scanRecord *pscan; +{ + + struct recPvtStruct *precPvt = (struct recPvtStruct *)pscan->rpvt; + + + /* for each valid positioner, fetch control limits */ + long status; + long nRequest = 1; + long options = DBR_CTRL_DOUBLE; + long abortScan = 0; + int i; + double value; + + /* for each valid positioner, fetch control limits */ + if(!pscan->p1nv) { + status = dbGet(pscan->p1db, DBR_FLOAT, precPvt->pP1Limits, + &options, &nRequest, NULL); + } + if(!pscan->p2nv) { + status = dbGet(pscan->p2db, DBR_FLOAT, precPvt->pP2Limits, + &options, &nRequest, NULL); + } + if(!pscan->p3nv) { + status = dbGet(pscan->p3db, DBR_FLOAT, precPvt->pP3Limits, + &options, &nRequest, NULL); + } + if(!pscan->p4nv) { + status = dbGet(pscan->p4db, DBR_FLOAT, precPvt->pP4Limits, + &options, &nRequest, NULL); + } + + if(scanRecDebug) { + if(!pscan->p1nv) + printf("P1 Control Limits : %.4f %.4f\n", + precPvt->pP1Limits->lower_ctrl_limit, + precPvt->pP1Limits->upper_ctrl_limit); + if(!pscan->p2nv) + printf("P2 Control Limits : %.4f %.4f\n", + precPvt->pP2Limits->lower_ctrl_limit, + precPvt->pP2Limits->upper_ctrl_limit); + if(!pscan->p3nv) + printf("P3 Control Limits : %.4f %.4f\n", + precPvt->pP3Limits->lower_ctrl_limit, + precPvt->pP3Limits->upper_ctrl_limit); + if(!pscan->p4nv) + printf("P4 Control Limits : %.4f %.4f\n", + precPvt->pP4Limits->lower_ctrl_limit, + precPvt->pP4Limits->upper_ctrl_limit); + } + + /* check each point of scan against control limits. */ + /* Stop on first error */ + + for(i=0; inpts; i++) { + if(!pscan->p1nv) { + /* determine next desired position for each positioner */ + if(pscan->p1sm == REC_SCAN_MO_LIN) { + value = pscan->p1sp + (i * pscan->p1si); + } + else if(pscan->p1sm == REC_SCAN_MO_TAB) { + value = pscan->p1pa[i]; + } + else { + /* this is on-the-fly, so set to end position */ + if(i == 0) value = pscan->p1sp; + else value = pscan->p1sp + pscan->p1si; + } + + if(value < precPvt->pP1Limits->lower_ctrl_limit) { + sprintf(pscan->smsg,"P1 Value < LO_Limit @ point %1d",i); + pscan->alrt = 1; + return; + } + else if(value > precPvt->pP1Limits->upper_ctrl_limit) { + sprintf(pscan->smsg,"P1 Value > HI_Limit @ point %1d",i); + pscan->alrt = 1; + return; + } + } + + if(!pscan->p2nv) { + /* determine next desired position for each positioner */ + if(pscan->p2sm == REC_SCAN_MO_LIN) { + value = pscan->p2sp + (i * pscan->p2si); + } + else if(pscan->p2sm == REC_SCAN_MO_TAB) { + value = pscan->p2pa[i]; + } + else { + /* this is on-the-fly, so set to end position */ + if(i == 0) value = pscan->p2sp; + else value = pscan->p2sp + pscan->p2si; + } + + if(value < precPvt->pP2Limits->lower_ctrl_limit) { + sprintf(pscan->smsg,"P2 Value < LO_Limit @ point %1d",i); + pscan->alrt = 1; + return; + } + else if(value > precPvt->pP2Limits->upper_ctrl_limit) { + sprintf(pscan->smsg,"P2 Value > HI_Limit @ point %1d",i); + pscan->alrt = 1; + return; + } + } + + if(!pscan->p3nv) { + /* determine next desired position for each positioner */ + if(pscan->p3sm == REC_SCAN_MO_LIN) { + value = pscan->p3sp + (i * pscan->p3si); + } + else if(pscan->p3sm == REC_SCAN_MO_TAB) { + value = pscan->p3pa[i]; + } + else { + /* this is on-the-fly, so set to end position */ + if(i == 0) value = pscan->p3sp; + else value = pscan->p3sp + pscan->p3si; + } + + if(value < precPvt->pP3Limits->lower_ctrl_limit) { + sprintf(pscan->smsg,"P3 Value < LO_Limit @ point %1d",i); + pscan->alrt = 1; + return; + } + else if(value > precPvt->pP3Limits->upper_ctrl_limit) { + sprintf(pscan->smsg,"P3 Value > HI_Limit @ point %1d",i); + pscan->alrt = 1; + return; + } + } + + if(!pscan->p4nv) { + /* determine next desired position for each positioner */ + if(pscan->p4sm == REC_SCAN_MO_LIN) { + value = pscan->p4sp + (i * pscan->p4si); + } + else if(pscan->p4sm == REC_SCAN_MO_TAB) { + value = pscan->p4pa[i]; + } + else { + /* this is on-the-fly, so set to end position */ + if(i == 0) value = pscan->p4sp; + else value = pscan->p4sp + pscan->p4si; + } + + if(value < precPvt->pP4Limits->lower_ctrl_limit) { + sprintf(pscan->smsg,"P4 Value < LO_Limit @ point %1d",i); + pscan->alrt = 1; + return; + } + else if(value > precPvt->pP4Limits->upper_ctrl_limit) { + sprintf(pscan->smsg,"P4 Value > HI_Limit @ point %1d",i); + pscan->alrt = 1; + return; + } + } + + } + + /* No errors if we made it here ... */ + sprintf(pscan->smsg,"SCAN Values within limits"); + +} + + +/* This routine fills the position 1 array with the scan positions + * and fills the detector 1 array with 1's. If the detector 1 array + * is plotted against the position 1 array, a plot is generated + * showing the scan range specified. This provides a graphical + * view of the scan range while changing scan paramters. + * + */ + +static void drawPos1Scan(pscan) + struct scanRecord *pscan; +{ + + struct recPvtStruct *precPvt = (struct recPvtStruct *)pscan->rpvt; + struct linScanParms *pParms; + int i; + unsigned short freezeState = 0; + + float desValue; + + desValue = pscan->p1sp; + + for(i=0; inpts; i++) { + pscan->p1pa[i] = desValue + (i * pscan->p1si); + pscan->d1da[i] = 1; + } + + /* fill array with last position */ + for(i=i; impts;i++) { + pscan->p1pa[i] = pscan->p1pa[i-1]; + pscan->d1da[i] = 1; + } + + db_post_events(pscan,pscan->p1pa, DBE_VALUE); + db_post_events(pscan,precPvt->pdet1DataA, DBE_VALUE); + db_post_events(pscan,precPvt->pdet1DataB, DBE_VALUE); + +} + + diff --git a/src/rec/recSub.c b/src/rec/recSub.c index 9d46c8ace..f9878976d 100644 --- a/src/rec/recSub.c +++ b/src/rec/recSub.c @@ -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); diff --git a/src/rec/recWait.c b/src/rec/recWait.c new file mode 100644 index 000000000..a50e046b1 --- /dev/null +++ b/src/rec/recWait.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +/* 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;icbst)->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;ioutv = 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;icbst)->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;icbst)->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;ipfield==*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;icbst)->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;ipfield==*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; isiml.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; + ipwait->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); + } +}