diff --git a/src/rec/recScan.c b/src/rec/recScan.c index 1d130d25f..9c74bd02e 100644 --- a/src/rec/recScan.c +++ b/src/rec/recScan.c @@ -1,4 +1,3 @@ -/* recScan.c */ /* * Original Author: Ned D. Arnold * Date: 07-18-94 @@ -27,43 +26,62 @@ * * 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. - * .07 10-21-94 nda changed linear scan parameter algorithms so changing - * start/end modifies step/width unless frozen. This - * seems more intuitive. - * .08 12-06-94 nda added support for .FFO .When set to 1, frzFlag values - * are saved in recPvtStruct. Restored when FFO set to 0. - * .09 02-02-95 nda fixed order of posting monitors to be what people - * expect (i.e. .cpt, .pxdv, .dxcv) - * .10 02-10-95 nda fixed on-the-fly so 1st step is to end position - * .11 02-21-95 nda added "Return To Start" flag. If set, positioners - * will be commanded to the start pos after the scan. - * .12 03-02-95 nda added positioner readback arrays (PxRA). These arrays - * will contain actual readback positions (if RxPV are - * defined. If not, the desired positions will be loaded - * into them. - * .13 03-02-95 nda Post .val field when a new point is complete during a - * scan. This will assist in poin by point plots. - * .14 03-02-95 nda Bug fix on filling PxRA's. ALWAYS CALL CHCK_MOTORS. - * .15 03-15-95 nda If no readback PV (RxPV) is specified, copy desired - * value (PxDV) to current value (RxCV). Now, plotting - * programs can always monitor RxCV. - * .16 04-03-95 nda If PV field = DESC, change to VAL + * .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. + * .07 10-21-94 nda changed linear scan parameter algorithms so changing + * start/end modifies step/width unless frozen. This + * seems more intuitive. + * .08 12-06-94 nda added support for .FFO .When set to 1, frzFlag values + * are saved in recPvtStruct. Restored when FFO set to 0. + * .09 02-02-95 nda fixed order of posting monitors to be what people + * expect (i.e. .cpt, .pxdv, .dxcv) + * .10 02-10-95 nda fixed on-the-fly so 1st step is to end position + * .11 02-21-95 nda added "Return To Start" flag. If set, positioners + * will be commanded to the start pos after the scan. + * .12 03-02-95 nda added positioner readback arrays (PxRA). These arrays + * will contain actual readback positions (if RxPV are + * defined. If not, the desired positions will be loaded + * into them. + * .13 03-02-95 nda Post .val field when a new point is complete during a + * scan. This will assist in poin by point plots. + * .14 03-02-95 nda Bug fix on filling PxRA's. ALWAYS CALL CHECK_MOTORS. + * .15 03-15-95 nda If no readback PV (RxPV) is specified, copy desired + * value (PxDV) to current value (RxCV). Now, plotting + * programs can always monitor RxCV. + * .16 04-03-95 nda If PV field = DESC, change to VAL + * + * 3.00 08-28-95 nda > Significant rewrite to add Channel Access + * for dynamic links using recDynLink.c . All + * inputs are now "monitored" via Channel Access. + * > Name Valid field is used to keep track of PV + * connection status: 0-PV_OK, + * 1-NotConnected, 2-NO_PV + * > added relative/absolute mode on positioners + * > added retrace options of stay/start/prior + * > supports 15 detectors + * > added "preview scan" + * > added "Before Scan" and "After Scan" links + * > fetch DRVL/DRVH/prec/egu from dynamic links + * > when posting arrays at end of scan, use DBE_LOG, too + * > Record timeStamp only at beginning of scan + * > Record positioner readbacks when reading detectors + * > "TIME" or "time" in a readback PV records time + * + * */ -#define VERSION 1.16 +#define VERSION 3.00 @@ -81,6 +99,7 @@ #include #include #include +#include #include #include #include @@ -92,6 +111,84 @@ #include #include #include +#include /* also includes timers.h and tsDefs.h */ + +#include + + +/*************************** + Declare constants +***************************/ +#define DEF_WF_SIZE 100 +#define PVN_SIZE 40 + +#define POSITIONER 0 +#define READBACK 1 +#define DETECTOR 2 +#define TRIGGER 3 +#define FWD_LINK 4 + +#define NUM_POS 4 +#define NUM_RDKS 4 +#define NUM_DET 15 +#define NUM_TRGS 2 +#define NUM_MISC 2 /* Before Scan PV, After Scan PV */ +#define NUM_PVS (NUM_POS + NUM_RDKS + NUM_DET + NUM_TRGS + NUM_MISC) +/* Determine total # of dynLinks (each positioner requires two: IN & OUT */ +#define NUM_LINKS (NUM_PVS + NUM_POS) + +/* Define special type constants for first and last dynamic PV name */ +#define FIRST_PV REC_SC_P1 +#define LAST_PV REC_SC_AS + +/* Predefine some index numbers */ +#define P1_IN 0 +#define P2_IN 1 +#define P3_IN 2 +#define P4_IN 3 +#define R1_IN (NUM_POS) +#define R2_IN (NUM_POS + 1) +#define R3_IN (NUM_POS + 2) +#define R4_IN (NUM_POS + 3) +#define D1_IN (NUM_POS + NUM_RDKS) + +#define T1_OUT (D1_IN + NUM_DET) +#define T2_OUT (T1_OUT + 1) + +#define BS_OUT (T1_OUT + NUM_TRGS) +#define AS_OUT (BS_OUT + 1) + +/* Added four recDynLinks at the end of PV's for positioner outs */ +#define P1_OUT (NUM_PVS) +#define P2_OUT (P1_OUT + 1) +#define P3_OUT (P2_OUT + 1) +#define P4_OUT (P3_OUT + 1) + +#define MIN_MON 3 /* # of ticks between monitor postings. 3 = 50 ms */ + +#define PV_OK REC_SCAN_DYNL_OK /* from choiceScan.h */ +#define PV_NC REC_SCAN_DYNL_NC /* from choiceScan.h */ +#define NO_PV REC_SCAN_DYNL_NO_PV /* from choiceScan.h */ + +#define A_BUFFER 0 +#define B_BUFFER 1 + +#define IDLE 0 +#define INIT_SCAN 1 +#define BEFORE_SCAN 2 +#define MOVE_MOTORS 3 +#define CHECK_MOTORS 4 +#define TRIG_DETCTRS 5 +#define READ_DETCTRS 6 +#define AFTER_SCAN 7 +#define PREVIEW 8 + +#define CLEAR_MSG 0 +#define CHECK_LIMITS 1 +#define PREVIEW_SCAN 2 /* Preview the SCAN positions */ + +#define DBE_VAL_LOG (DBE_VALUE | DBE_LOG) + /* Create RSET - Record Support Entry Table*/ #define report NULL @@ -133,205 +230,250 @@ struct rset scanRSET={ get_alarm_double }; -struct p_limits { +typedef struct recDynLinkPvt { + struct scanRecord *pscan; /* pointer to scan record */ + unsigned short linkIndex; /* specifies which dynamic link */ + unsigned short linkType; /* Positioner, Rdbk, Trig, Det */ + struct dbAddr *pAddr; /* Pointer to dbAddr for local PV's */ + long dbAddrNv; /* Zero if dbNameToAddr succeeded */ + unsigned long nelem; /* # of elements for this PV */ + unsigned short ts; /* if 1, use timestamp as value */ + short fldOffset; /* For arrays, offset from pscan, used + for get_array_info, cvt_dbaddr */ +}recDynLinkPvt; + +typedef struct dynLinkInfo { + DBRunits + DBRprecision + DBRgrDouble 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; - short pffo; /* previouss state of ffo */ - short fpts; /* backup copy of all freeze flags */ - short p1fs; - short p1fi; - short p1fc; - short p1fe; - short p1fw; - short p2fs; - short p2fi; - short p2fc; - short p2fe; - short p2fw; - short p3fs; - short p3fi; - short p3fc; - short p3fe; - short p3fw; - short p4fs; - short p4fi; - short p4fc; - short p4fe; - short p4fw; - 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*/ -}; +}dynLinkInfo; +typedef struct posBuffers { + double *pFill; + double *pBufA; + double *pBufB; +} posBuffers; + +typedef struct detBuffers { + float *pFill; + float *pBufA; + float *pBufB; + int size; + short vector; +} detBuffers; + /* 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 */ -}; +typedef struct posFields { + double p_pp; /* P1 Previous Position */ + double p_cv; /* P1 Current Value */ + double p_dv; /* P1 Desired Value */ + double p_lv; /* P1 Last Value Posted */ + double p_sp; /* P1 Start Position */ + double p_si; /* P1 Step Increment */ + double p_ep; /* P1 End Position */ + double p_cp; /* P1 Center Position */ + double p_wd; /* P1 Scan Width */ + double r_cv; /* P1 Readback Value */ + double r_lv; /* P1 Rdbk Last Val Pst */ + double r_dl; /* P1 Readback Delta */ + double p_hr; /* P1 High Oper Range */ + double p_lr; /* P1 Low Oper Range */ + double * p_pa; /* P1 Step Array */ + double * p_ra; /* P1 Readback Array */ + unsigned short p_fs; /* P1 Freeze Start Pos */ + unsigned short p_fi; /* P1 Freeze Step Inc */ + unsigned short p_fe; /* P1 Freeze End Pos */ + unsigned short p_fc; /* P1 Freeze Center Pos */ + unsigned short p_fw; /* P1 Freeze Width */ + unsigned short p_sm; /* P1 Step Mode */ + unsigned short p_ar; /* P1 Absolute/Relative */ + char p_eu[16]; /* P1 Engineering Units */ + short p_pr; /* P1 Display Precision */ +}posFields; - +/* the following structure must match EXACTLY with the order and type of + fields defined in scanRecord.h for each detector (even including + the "Created Pad"s */ -/*************************** - 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 */ +typedef struct detFields { + double d_hr; /* D1 High Oper Range */ + double d_lr; /* D1 Low Oper Range */ + float * d_da; /* D1 Data Array */ + float d_cv; /* D1 Current Value */ + float d_lv; /* D1 Last Value Posted */ + unsigned long d_ne; /* D1 # of Elements/Pt */ + char d_eu[16]; /* D1 Engineering Units */ + short d_pr; /* D1 Display Precision */ + char p81 [6]; /* Created Pad */ +}detFields; -#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 +typedef struct recPvtStruct { + /* THE CODE ASSUMES doPutsCallback is THE FIRST THING IN THIS STRUCTURE!*/ + 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 validBuf; /* which data array buffer is valid */ + recDynLink caLinkStruct[NUM_LINKS]; /* req'd for recDynLink */ + posBuffers posBufPtr[NUM_POS]; + detBuffers detBufPtr[NUM_DET]; + unsigned short valPosPvs; /* # of valid positioners */ + unsigned short valRdbkPvs; /* # of valid Readbacks */ + unsigned short valDetPvs; /* # of valid Detectors */ + unsigned short valTrigPvs; /* # of valid Det Triggers */ + dynLinkInfo *pDynLinkInfo; + short pffo; /* previous state of ffo */ + short fpts; /* backup copy of all freeze flags */ + unsigned short prevSm[NUM_POS]; /* previous states of p_sm */ + posFields posParms[NUM_POS]; /* backup copy of all pos. parms */ + unsigned long tablePts[NUM_POS]; /* # of pts loaded in P_PA */ + short onTheFly; + float *nullArray; + unsigned long tickStart; /* used to time the scan */ + char movPos[NUM_POS]; /* used to indicate interactive move */ + unsigned char scanErr; + char nptsCause; /* who caused the "# of points to change: + -1:operator; 0-3 Positioners*/ +}recPvtStruct; /* forward declarations */ static void checkMonitors(); -static void lookupPVs(); -static void initScan(); +static long initScan(); static void contScan(); static void endScan(); static void doPuts(); static void adjLinParms(); static void changedNpts(); -static void checkScanLimits(); -static void drawPos1Scan(); +static long checkScanLimits(); static void saveFrzFlags(); static void resetFrzFlags(); static void restoreFrzFlags(); + +static void previewScan(struct scanRecord *pscan); + +static void lookupPV(struct scanRecord *pscan, unsigned short i); +static void pvSearchCallback(recDynLink *precDynLink); +static void pvMonitorCallback(recDynLink *precDynLink); +static void posMonCallback(recDynLink *precDynLink); +static void restorePosParms(struct scanRecord *pscan, unsigned short i); +static void savePosParms(struct scanRecord *pscan, unsigned short i); +static void zeroPosParms(struct scanRecord *pscan, unsigned short i); + /* variables ... */ -long scanRecDebug=0; -long viewScanPos=0; +long recScanDebug=0; +long recScanViewPos=0; +long recScanDontCheckLimits=0; static long init_record(pscan,pass) struct scanRecord *pscan; int pass; { - struct recPvtStruct *precPvt = (struct recPvtStruct *)pscan->rpvt; + recPvtStruct *precPvt = (recPvtStruct *)pscan->rpvt; + posFields *pPosFields; + detFields *pDetFields; long status = 0; + char *ppvn[PVN_SIZE]; + unsigned short *pPvStat; + unsigned short i; + + recDynLinkPvt *puserPvt; + + 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)); - - pscan->p1ra = (float *) calloc(pscan->mpts, sizeof(float)); - pscan->p2ra = (float *) calloc(pscan->mpts, sizeof(float)); - pscan->p3ra = (float *) calloc(pscan->mpts, sizeof(float)); - pscan->p4ra = (float *) calloc(pscan->mpts, sizeof(float)); - /* First time through, rpvt needs initialized */ - pscan->rpvt = calloc(1, sizeof(struct recPvtStruct)); - precPvt = (struct recPvtStruct *)pscan->rpvt; + pscan->rpvt = calloc(1, sizeof(recPvtStruct)); + precPvt = (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->phase = IDLE; - 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)); + precPvt->prevSm[0] = pscan->p1sm; + precPvt->prevSm[1] = pscan->p2sm; + precPvt->prevSm[2] = pscan->p3sm; + precPvt->prevSm[3] = pscan->p4sm; + + precPvt->pscan = pscan; + + precPvt->pDynLinkInfo = (dynLinkInfo *)calloc(1, sizeof(dynLinkInfo)); + + /* init the private area of the caLinkStruct's */ + for(i=0;i<(NUM_LINKS); i++) { + precPvt->caLinkStruct[i].puserPvt + = calloc(1,sizeof(struct recDynLinkPvt)); + puserPvt = (recDynLinkPvt *)precPvt->caLinkStruct[i].puserPvt; + puserPvt->pscan = pscan; + puserPvt->linkIndex = i; + puserPvt->pAddr = calloc(1, sizeof(struct dbAddr)); + puserPvt->dbAddrNv = -1; + if (i < R1_IN) puserPvt->linkType = POSITIONER; + else if(i < D1_IN) puserPvt->linkType = READBACK; + else if(i < T1_OUT) puserPvt->linkType = DETECTOR; + else if(i < BS_OUT) puserPvt->linkType = TRIGGER; + else if(i < P1_OUT) puserPvt->linkType = FWD_LINK; + } + + pscan->p1pa = (double *) calloc(pscan->mpts, sizeof(double)); + pscan->p2pa = (double *) calloc(pscan->mpts, sizeof(double)); + pscan->p3pa = (double *) calloc(pscan->mpts, sizeof(double)); + pscan->p4pa = (double *) calloc(pscan->mpts, sizeof(double)); + + /* Readbacks need double buffering. Allocate space and initialize */ + /* fill pointer and readback array pointers */ + precPvt->validBuf = A_BUFFER; + pPosFields = (posFields *)&pscan->p1pp; + for(i=0; iposBufPtr[i].pBufA = + (double *) calloc(pscan->mpts, sizeof(double)); + precPvt->posBufPtr[i].pBufB = + (double *) calloc(pscan->mpts, sizeof(double)); + + pPosFields->p_ra = precPvt->posBufPtr[i].pBufA; + precPvt->posBufPtr[i].pFill = precPvt->posBufPtr[i].pBufB; + } + + /* allocate arrays for 4 detectors assuming nelem = 1 */ + /* (previewScan uses the first four detectors) */ + /* For now, just point other detectors to a NULL array */ + + precPvt->nullArray = (float *) calloc(pscan->mpts, sizeof(float)); + pDetFields = (detFields *)&pscan->d1hr; + for(i=0; icaLinkStruct[D1_IN+i].puserPvt; + if(i<4) { + precPvt->detBufPtr[i].pBufA = + (float *) calloc(pscan->mpts, sizeof(float)); + precPvt->detBufPtr[i].pBufB = + (float *) calloc(pscan->mpts, sizeof(float)); + puserPvt->nelem = 1; + } + else { + precPvt->detBufPtr[i].pBufA = precPvt->nullArray; + precPvt->detBufPtr[i].pBufB = precPvt->nullArray; + puserPvt->nelem = 0; + } + pDetFields->d_da = precPvt->detBufPtr[i].pBufA; + precPvt->detBufPtr[i].pFill = precPvt->detBufPtr[i].pBufB; + } - /* 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 */ + precPvt->nptsCause = -1; /* resolve all positioner parameters */ changedNpts(pscan); if(pscan->ffo) { @@ -342,31 +484,52 @@ static long init_record(pscan,pass) /* init field values */ pscan->exsc = 0; pscan->pxsc = 0; + + *ppvn = &pscan->p1pv[0]; + pPvStat = &pscan->p1nv; + + /* check all dynLink PV's for non-NULL */ + for(i=0;irpvt; + recPvtStruct *precPvt = (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(); - } - pscan->cpt = 0; /* reset point counter */ - initScan(pscan); - sprintf(pscan->smsg,"Scanning ..."); - db_post_events(pscan,&pscan->smsg,DBE_VALUE); - + + /* Decide what to do. */ + /* Brand new scan */ + if ((pscan->pxsc == 0) && (pscan->exsc == 1)) { + precPvt->phase = INIT_SCAN; + /* use TimeStamp to record beginning of scan */ + recGblGetTimeStamp(pscan); + initScan(pscan); } + + /* Before Scan Fwd Link is complete, initScan again */ + else if(precPvt->phase == BEFORE_SCAN) { + 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); } @@ -375,17 +538,16 @@ static long process(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)); - } + recGblFwdLink(pscan); /* process the forward scan link record */ + if(recScanDebug) { + printf("Scan Time = %.2f ms\n", + (float)((tickGet()-(precPvt->tickStart))*16.67)); + } } pscan->pxsc = pscan->exsc; recGblResetAlarms(pscan); - recGblGetTimeStamp(pscan); pscan->pact = FALSE; return(status); @@ -396,10 +558,16 @@ static long special(paddr,after) int after; { struct scanRecord *pscan = (struct scanRecord *)(paddr->precord); - struct recPvtStruct *precPvt = (struct recPvtStruct *)pscan->rpvt; - int special_type = paddr->special; + recPvtStruct *precPvt = (recPvtStruct *)pscan->rpvt; + recDynLinkPvt *puserPvt; + posFields *pPosFields; + int special_type = paddr->special; + char *ppvn[PVN_SIZE]; + unsigned short *pPvStat; + unsigned short oldStat; + short i = -1; long status; - unsigned char prevAlrt; + unsigned char prevAlrt; if(!after) { precPvt->pffo = pscan->ffo; /* save previous ffo flag */ @@ -410,14 +578,20 @@ static long special(paddr,after) if(paddr->pfield==(void *)&pscan->exsc) { pscan->alrt = 0; db_post_events(pscan,&pscan->alrt, DBE_VALUE); - scanOnce(pscan); + /* Only scanOnce if aborting OR IDLE OR PREVIEW */ + if((!pscan->exsc) || (precPvt->phase == IDLE) || + (precPvt->phase == PREVIEW)) { + scanOnce(pscan); + } return(0); } else if(paddr->pfield==(void *)&pscan->cmnd) { if(pscan->cmnd == CLEAR_MSG) { + pscan->alrt = 0; + db_post_events(pscan,&pscan->alrt,DBE_VALUE); sprintf(pscan->smsg,""); db_post_events(pscan,&pscan->smsg,DBE_VALUE); } - else if(pscan->cmnd == CHECK_LIMITS) { + else if((pscan->cmnd == CHECK_LIMITS) && !(pscan->exsc)) { prevAlrt = pscan->alrt; pscan->alrt = 0; checkScanLimits(pscan); @@ -426,17 +600,80 @@ static long special(paddr,after) 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); + else if((pscan->cmnd == PREVIEW_SCAN) && !(pscan->exsc)) { + /* get_array_info() needs to know that we're previewing */ + precPvt->phase = PREVIEW; + previewScan(pscan); + } + else if(paddr->pfield==(void *)&pscan->prio) { + callbackSetPriority(pscan->prio, &precPvt->doPutsCallback); + return(0); + } return(0); } + /* Check to see if it was a command to send to the positioner */ + else if(paddr->pfield==(void *)&pscan->p1dv) i = P1_IN; + else if(paddr->pfield==(void *)&pscan->p2dv) i = P2_IN; + else if(paddr->pfield==(void *)&pscan->p3dv) i = P3_IN; + else if(paddr->pfield==(void *)&pscan->p4dv) i = P4_IN; + + /* if a positioner command and not scanning .... */ + if((i>=0) && ((precPvt->phase==IDLE) || (precPvt->phase==PREVIEW))) { + pPvStat = &precPvt->pscan->p1nv + i; + pPosFields = (posFields *)&precPvt->pscan->p1pp + i; + if(*pPvStat == PV_OK) { + puserPvt = precPvt->caLinkStruct[i].puserPvt; + if(puserPvt->dbAddrNv) { + status = recDynLinkPut(&precPvt->caLinkStruct[i+P1_OUT], + &(pPosFields->p_dv), 1); + } else { + /* Must use the callback task ... */ + precPvt->movPos[i] = 1; + callbackRequest(&precPvt->doPutsCallback); + } + } + } + + break; + case(SPC_SC_MO): /* Step Mode changed for a positioner */ + + pPosFields = (posFields *)&precPvt->pscan->p1pp; + for(i=0; ipfield==(void *)&pPosFields->p_sm) { + /* Entering Table mode ? */ + if((pPosFields->p_sm == REC_SCAN_MO_TAB) && + (precPvt->prevSm[i] != REC_SCAN_MO_TAB)) { + savePosParms(pscan, (unsigned short) i); + zeroPosParms(pscan, (unsigned short) i); + precPvt->prevSm[i] = pPosFields->p_sm; + if(precPvt->tablePts[i] < pscan->npts) { + sprintf(pscan->smsg,"Pts in P%d Table < # of Steps",i+1); + db_post_events(pscan,&pscan->smsg,DBE_VALUE); + if(!pscan->alrt) { + pscan->alrt = 1; + db_post_events(pscan,&pscan->alrt,DBE_VALUE); + } + } + } + /* Leaving Table mode ? */ + else if((pPosFields->p_sm != REC_SCAN_MO_TAB) && + (precPvt->prevSm[i] == REC_SCAN_MO_TAB)) { + restorePosParms(pscan, (unsigned short) i); + prevAlrt = pscan->alrt; + precPvt->nptsCause = -1; + changedNpts(pscan); + db_post_events(pscan,&pscan->smsg,DBE_VALUE); + if(pscan->alrt != prevAlrt) { + db_post_events(pscan,&pscan->alrt,DBE_VALUE); + } + precPvt->prevSm[i] = pPosFields->p_sm; + } + } + } + break; + case(SPC_SC_S): /* linear scan parameter change */ case(SPC_SC_I): case(SPC_SC_E): @@ -451,9 +688,9 @@ static long special(paddr,after) if(pscan->alrt != prevAlrt) { db_post_events(pscan,&pscan->alrt,DBE_VALUE); } - if(viewScanPos) { - drawPos1Scan(pscan); - } + if(recScanViewPos) { + previewScan(pscan); + } break; case(SPC_SC_N): @@ -465,14 +702,14 @@ static long special(paddr,after) prevAlrt = pscan->alrt; pscan->alrt = 0; sprintf(pscan->smsg,""); - precPvt->nptsCause = 0; /* resolve all positioner parameters */ + precPvt->nptsCause = -1; /* 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); + if(recScanViewPos) { + previewScan(pscan); } break; @@ -496,9 +733,42 @@ static long special(paddr,after) default: -/* recGblDbaddrError(S_db_badChoice,paddr,"scan: special"); - return(S_db_badChoice); -*/ + /* Check for a dynamic link PV change */ + if((special_type >= FIRST_PV) && (special_type <= LAST_PV)) { + i = special_type - FIRST_PV; + puserPvt = (recDynLinkPvt *)precPvt->caLinkStruct[i].puserPvt; + pPvStat = &pscan->p1nv + i; /* pointer arithmetic */ + oldStat = *pPvStat; + *ppvn = &pscan->p1pv[0] + (i*PVN_SIZE); + if(*ppvn[0] != NULL) { + if(recScanDebug > 5) printf("Search during special \n"); + *pPvStat = PV_NC; + /* need to post_event before recDynLinkAddXxx because + SearchCallback could happen immediatley */ + if(*pPvStat != oldStat) { + db_post_events(pscan,pPvStat,DBE_VALUE); + } + lookupPV(pscan, i); + } + else if(*pPvStat != NO_PV) { + /* PV is now NULL but didn't used to be */ + *pPvStat = NO_PV; /* PV just cleared */ + if(*pPvStat != oldStat) { + db_post_events(pscan,pPvStat,DBE_VALUE); + } + if(puserPvt->dbAddrNv) { /*Clear if non-local */ + recDynLinkClear(&precPvt->caLinkStruct[i]); + /* Positioners have two recDynLinks */ + if(icaLinkStruct[i+NUM_PVS]); + } + else puserPvt->dbAddrNv = -1; + } + else { + /* PV is NULL, but previously MAY have been "time" */ + puserPvt->ts = 0; + } + } } return(0); } @@ -508,38 +778,43 @@ static long cvt_dbaddr(paddr) { struct scanRecord *pscan=(struct scanRecord *)paddr->precord; - /* all arrays are floats */ + recPvtStruct *precPvt = (recPvtStruct *)pscan->rpvt; + posFields *pPosFields = (posFields *)&pscan->p1pp; + detFields *pDetFields = (detFields *)&pscan->d1hr; + short fieldOffset; + unsigned short i; - 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->p1ra)) { - paddr->pfield = (void *)(pscan->p1ra); - } else if (paddr->pfield == &(pscan->p2ra)) { - paddr->pfield = (void *)(pscan->p2ra); - } else if (paddr->pfield == &(pscan->p3ra)) { - paddr->pfield = (void *)(pscan->p3ra); - } else if (paddr->pfield == &(pscan->p4ra)) { - paddr->pfield = (void *)(pscan->p4ra); - } 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); + fieldOffset = ((struct fldDes *)(paddr->pfldDes))->offset; + + /* for the double buffered arrays, must use the field offset + because you don't know what the pointer will be */ + + for(i=0; i < NUM_DET; i++, pDetFields++) { + if(((char *)&pDetFields->d_da - (char *)pscan) == fieldOffset) { + paddr->pfield = pDetFields->d_da; + paddr->no_elements = pscan->mpts; + paddr->field_type = DBF_FLOAT; + paddr->field_size = sizeof(float); + paddr->dbr_field_type = DBF_FLOAT; + return(0); + } } - paddr->no_elements = pscan->mpts; - paddr->field_type = DBF_FLOAT; - paddr->field_size = sizeof(float); - paddr->dbr_field_type = DBF_FLOAT; + for(i=0; i < NUM_POS; i++, pPosFields++) { + if(((char *)&pPosFields->p_pa - (char *)pscan) == fieldOffset) { + paddr->pfield = (void *)(pPosFields->p_pa); + paddr->no_elements = pscan->mpts; + paddr->field_type = DBF_DOUBLE; + paddr->field_size = sizeof(double); + paddr->dbr_field_type = DBF_DOUBLE; + } else if(((char *)&pPosFields->p_ra - (char *)pscan) == fieldOffset) { + paddr->pfield = (void *)(pPosFields->p_ra); + paddr->no_elements = pscan->mpts; + paddr->field_type = DBF_DOUBLE; + paddr->field_size = sizeof(double); + paddr->dbr_field_type = DBF_DOUBLE; + } + } return(0); } @@ -548,31 +823,51 @@ static long get_array_info(paddr,no_elements,offset) long *no_elements; long *offset; { - struct scanRecord *pscan=(struct scanRecord *)paddr->precord; - struct recPvtStruct *precPvt = (struct recPvtStruct *)pscan->rpvt; + struct scanRecord *pscan=(struct scanRecord *)paddr->precord; + recPvtStruct *precPvt = (recPvtStruct *)pscan->rpvt; + detFields *pDetFields = (detFields *)&pscan->d1hr; + posFields *pPosFields = (posFields *)&pscan->p1pp; + short fieldOffset; + unsigned short *pPvStat; + unsigned short i; - /* 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) { + /* This routine is called because someone wants an array. Determine + which array they are interested by comparing the address of the + field to the array pointers */ + + fieldOffset = ((struct fldDes *)(paddr->pfldDes))->offset; + + pPvStat = &precPvt->pscan->d1nv; + for(i=0; i < NUM_DET; i++, pDetFields++, pPvStat++) { + if(((char *)&pDetFields->d_da - (char *)pscan) == fieldOffset) { + if((*pPvStat == PV_OK) || + ((iphase == PREVIEW))) { + if(precPvt->validBuf) + paddr->pfield = precPvt->detBufPtr[i].pBufB; + else + paddr->pfield = precPvt->detBufPtr[i].pBufA; + } else { + paddr->pfield = precPvt->nullArray; + } + *no_elements = pscan->mpts; + *offset = 0; + return(0); + } + } + for(i=0; i < NUM_POS; i++, pPosFields++) { + if(((char *)&pPosFields->p_ra - (char *)pscan) == fieldOffset) { + if(precPvt->validBuf) + paddr->pfield = precPvt->posBufPtr[i].pBufB; + else + paddr->pfield = precPvt->posBufPtr[i].pBufA; + + *no_elements = pscan->mpts; + *offset = 0; + return(0); + } + } + + if (paddr->pfield == pscan->p1pa) { *no_elements = pscan->mpts; *offset = 0; } else if (paddr->pfield == pscan->p2pa) { @@ -584,18 +879,6 @@ static long get_array_info(paddr,no_elements,offset) } else if (paddr->pfield == pscan->p4pa) { *no_elements = pscan->mpts; *offset = 0; - } else if (paddr->pfield == pscan->p1ra) { - *no_elements = pscan->mpts; - *offset = 0; - } else if (paddr->pfield == pscan->p2ra) { - *no_elements = pscan->mpts; - *offset = 0; - } else if (paddr->pfield == pscan->p3ra) { - *no_elements = pscan->mpts; - *offset = 0; - } else if (paddr->pfield == pscan->p4ra) { - *no_elements = pscan->mpts; - *offset = 0; } else { *no_elements = 0; *offset = 0; @@ -608,21 +891,38 @@ static long put_array_info(paddr,nNew) struct dbAddr *paddr; long nNew; { - struct scanRecord *pscan=(struct scanRecord *)paddr->precord; + struct scanRecord *pscan=(struct scanRecord *)paddr->precord; + recPvtStruct *precPvt = (recPvtStruct *)pscan->rpvt; + posFields *pPosFields = (posFields *)&pscan->p1pp; + short fieldOffset; + unsigned short *pPvStat; + unsigned short i; + + /* This routine is called because someone wrote a table to the + "positioner" array p_pa. Determine which positioner and store + nelem for future use. Also check against current npts */ + + fieldOffset = ((struct fldDes *)(paddr->pfldDes))->offset; - 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); + for(i=0; i < NUM_POS; i++, pPosFields++) { + if(((char *)&pPosFields->p_pa - (char *)pscan) == fieldOffset) { + precPvt->tablePts[i] = nNew; + if(nNew < pscan->npts) { + sprintf(pscan->smsg,"Pts in P%d Table < # of Steps", i+1); + 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); } } return(0); @@ -701,7 +1001,33 @@ static long get_units(paddr,units) struct dbAddr *paddr; char *units; { - struct scanRecord *pscan=(struct scanRecord *)paddr->precord; + struct scanRecord *pscan=(struct scanRecord *)paddr->precord; + posFields *pPosFields = (posFields *)&pscan->p1pp; + detFields *pDetFields = (detFields *)&pscan->d1hr; + short fieldOffset; + short i; + + + /* Use the field offset to see which detector or positioner it is */ + fieldOffset = ((struct fldDes *)(paddr->pfldDes))->offset; + + for(i=0; i < NUM_POS; i++, pPosFields++) { + if((fieldOffset >= ((char *)&pPosFields->p_pp - (char *)pscan)) && + (fieldOffset <= ((char *)&pPosFields->p_pr - (char *)pscan))) { + strncpy(units, pPosFields->p_eu, 7); + units[7] = NULL; + return(0); + } + } + for(i=0; i < NUM_DET; i++, pDetFields++) { + if((fieldOffset >= ((char *)&pDetFields->d_hr - (char *)pscan)) && + (fieldOffset <= ((char *)&pDetFields->d_pr - (char *)pscan))) { + strncpy(units, pDetFields->d_eu, 7); + units[7] = NULL; + return(0); + } + } + return(0); } @@ -709,44 +1035,32 @@ static long get_precision(paddr,precision) struct dbAddr *paddr; long *precision; { - struct scanRecord *pscan=(struct scanRecord *)paddr->precord; + struct scanRecord *pscan=(struct scanRecord *)paddr->precord; + posFields *pPosFields = (posFields *)&pscan->p1pp; + detFields *pDetFields = (detFields *)&pscan->d1hr; + short fieldOffset; + short i; - 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; - } + + /* Use the field offset to see which detector or positioner it is */ + fieldOffset = ((struct fldDes *)(paddr->pfldDes))->offset; + for(i=0; i < NUM_POS; i++, pPosFields++) { + if((fieldOffset >= ((char *)&pPosFields->p_pp - (char *)pscan)) && + (fieldOffset <= ((char *)&pPosFields->p_pr - (char *)pscan))) { + *precision = pPosFields->p_pr; + return(0); + } + } + for(i=0; i < NUM_DET; i++, pDetFields++) { + if((fieldOffset >= ((char *)&pDetFields->d_hr - (char *)pscan)) && + (fieldOffset <= ((char *)&pDetFields->d_pr - (char *)pscan))) { + *precision = pDetFields->d_pr; + return(0); + } + } + + *precision = 2; return(0); } @@ -754,57 +1068,34 @@ static long get_graphic_double(paddr,pgd) struct dbAddr *paddr; struct dbr_grDouble *pgd; { - struct scanRecord *pscan=(struct scanRecord *)paddr->precord; + struct scanRecord *pscan=(struct scanRecord *)paddr->precord; + posFields *pPosFields = (posFields *)&pscan->p1pp; + detFields *pDetFields = (detFields *)&pscan->d1hr; + short fieldOffset; + short i; - 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; + + /* Use the field offset to see which detector or positioner it is */ + fieldOffset = ((struct fldDes *)(paddr->pfldDes))->offset; + + for(i=0; i < NUM_POS; i++, pPosFields++) { + if((fieldOffset >= ((char *)&pPosFields->p_pp - (char *)pscan)) && + (fieldOffset <= ((char *)&pPosFields->p_pr - (char *)pscan))) { + pgd->upper_disp_limit = pPosFields->p_hr; + pgd->lower_disp_limit = pPosFields->p_lr; + return(0); + } } - 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; + for(i=0; i < NUM_DET; i++, pDetFields++) { + if((fieldOffset >= ((char *)&pDetFields->d_hr - (char *)pscan)) && + (fieldOffset <= ((char *)&pDetFields->d_pr - (char *)pscan))) { + pgd->upper_disp_limit = pDetFields->d_hr; + pgd->lower_disp_limit = pDetFields->d_lr; + return(0); + } } - 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); + + recGblGetGraphicDouble(paddr,pgd); return(0); } @@ -812,8 +1103,15 @@ static long get_control_double(paddr,pcd) struct dbAddr *paddr; struct dbr_ctrlDouble *pcd; { - struct scanRecord *pscan=(struct scanRecord *)paddr->precord; - recGblGetControlDouble(paddr,pcd); + /* for testing .... */ + /* return upper_disp_limit and lower_disp_limit as control limits */ + struct dbr_grDouble grDblStruct; + long status; + + status = get_graphic_double(paddr,&grDblStruct); + pcd->upper_ctrl_limit = grDblStruct.upper_disp_limit; + pcd->lower_ctrl_limit = grDblStruct.lower_disp_limit; + return(0); } @@ -829,8 +1127,11 @@ static long get_alarm_double(paddr,pad) static void checkMonitors(pscan) struct scanRecord *pscan; { - struct recPvtStruct *precPvt = (struct recPvtStruct *)pscan->rpvt; + recPvtStruct *precPvt = (recPvtStruct *)pscan->rpvt; + detFields *pDetFields = (detFields *)&pscan->d1hr; + posFields *pPosFields = (posFields *)&pscan->p1pp; unsigned long now; + int i; /* If last posting time is > MIN_MON, check to see if any dynamic fields have changed (also post monitors on end of scan)*/ @@ -839,335 +1140,626 @@ static void checkMonitors(pscan) if(((now - pscan->tolp) > MIN_MON) || ((pscan->pxsc == 1) && (pscan->exsc == 0))) { pscan->tolp = now; - if(fabs(pscan->d1lv - pscan->d1cv) > 0) { - db_post_events(pscan,&pscan->d1cv, DBE_VALUE); - pscan->d1lv = pscan->d1cv; + + /* check all detectors */ + for(i=0; i < NUM_DET; i++, pDetFields++) { + if(fabs(pDetFields->d_lv - pDetFields->d_cv) > 0) { + db_post_events(pscan,&pDetFields->d_cv, DBE_VALUE); + pDetFields->d_lv = pDetFields->d_cv; + } } - 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; + + /* check all positioners and readbacks */ + for(i=0; i < NUM_POS; i++, pPosFields++) { + if(fabs(pPosFields->p_lv - pPosFields->p_dv) > 0) { + db_post_events(pscan,&pPosFields->p_dv, DBE_VALUE); + pPosFields->p_lv = pPosFields->p_dv; + } + if(fabs(pPosFields->r_lv - pPosFields->r_cv) > 0) { + db_post_events(pscan,&pPosFields->r_cv, DBE_VALUE); + pPosFields->r_lv = pPosFields->r_cv; + } } + 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; - } /* Post a monitor on VAL to indicate new point */ - if(pscan->exsc) { - db_post_events(pscan,&pscan->val, DBE_VALUE); + /* (checking pxsc skips the first pass when D_CV's are + not valid and also catches the last point after exsc == 0 */ + if(pscan->pxsc) { + db_post_events(pscan,&pscan->val, DBE_VALUE); } } - if (pscan->pxsc != pscan->exsc) - db_post_events(pscan,&pscan->exsc, DBE_VALUE); - /* if this is the end of a scan, post data arrays */ + /* post these with DBE_LOG option for archiver */ 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); - db_post_events(pscan,pscan->p1ra, DBE_VALUE); - db_post_events(pscan,pscan->p2ra, DBE_VALUE); - db_post_events(pscan,pscan->p3ra, DBE_VALUE); - db_post_events(pscan,pscan->p4ra, DBE_VALUE); + + /* Must post events on both pointers, since toggle */ + db_post_events(pscan,precPvt->posBufPtr[0].pBufA, DBE_VAL_LOG); + db_post_events(pscan,precPvt->posBufPtr[0].pBufB, DBE_VAL_LOG); + db_post_events(pscan,precPvt->posBufPtr[1].pBufA, DBE_VAL_LOG); + db_post_events(pscan,precPvt->posBufPtr[1].pBufB, DBE_VAL_LOG); + db_post_events(pscan,precPvt->posBufPtr[2].pBufA, DBE_VAL_LOG); + db_post_events(pscan,precPvt->posBufPtr[2].pBufB, DBE_VAL_LOG); + db_post_events(pscan,precPvt->posBufPtr[3].pBufA, DBE_VAL_LOG); + db_post_events(pscan,precPvt->posBufPtr[3].pBufB, DBE_VAL_LOG); - /* 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); + for(i=0; idetBufPtr[i].pBufA, DBE_VAL_LOG); + db_post_events(pscan,precPvt->detBufPtr[i].pBufB, DBE_VAL_LOG); + } + /* I must also post a monitor on the NULL array, because some + clients connected to D?PV's without valid PV's ! */ + db_post_events(pscan, precPvt->nullArray, DBE_VALUE); /* post alert if changed */ if(precPvt->scanErr) { pscan->alrt = precPvt->scanErr; db_post_events(pscan,&pscan->alrt, DBE_VALUE); } + + if (pscan->pxsc != pscan->exsc) + db_post_events(pscan,&pscan->exsc, DBE_VALUE); + } } -static void lookupPVs(pscan) - struct scanRecord *pscan; +/************************************************************** + * lookupPV() + * This is the routine that looks up newly entered "dynamic" + * links. A dbNameToAddr call is done first to + * see if the PV resides on this IOC. Much better performance is + * obtained by using dbGet/dbPutField rather than the recDynLink + * library for local PV's. If the dbNameToAddr fails, + * recDynLinkAddInput is used. + * + * For positioners: + * If the PV is local, the dbAddr is used for puts and gets ( + * to get the "previous positioner" before a scan starts. A + * recDynLinkInput is also used to monitor the positioner + * for changes made from other places. + * This value is stored in p_cv. + * If the PV is not local, a recDynLinkOutput and a + * recDynLinkInput are used. The recDynLinkInput has a + * monitor callback routine for p_cv, but a get is used + * to find the previous position. + * + * For Readbacks: + * If the PV name starts with TIME or time, set a flag that + * indicates that the timestamp should be used as the + * readback value. + * Otherwise, do a PV lookup. + **************************************************************/ +static void lookupPV(struct scanRecord *pscan, unsigned short i) { - struct recPvtStruct *precPvt = (struct recPvtStruct *)pscan->rpvt; + recPvtStruct *precPvt = (recPvtStruct *)pscan->rpvt; + recDynLinkPvt *puserPvt; char *ppvn[PVN_SIZE]; char *pdesc = ".DESC"; char *pval = ".VAL"; + char *pTIME = "TIME"; + char *ptime = "time"; char *pdot; - struct dbAddr **ppdbAddr; /* ptr to a ptr to dbAddr */ - long *paddrValid; - long prevValid; - short i; + unsigned short *pPvStat; - /* Look up all reassignable PV Names */ + /* Point to correct places by using index i */ + *ppvn = &pscan->p1pv[0] + (i * PVN_SIZE); + pPvStat = &pscan->p1nv + i; /* pointer arithmetic */ + puserPvt = (recDynLinkPvt *)precPvt->caLinkStruct[i].puserPvt; - *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; + /* See if it's a local PV */ + puserPvt->dbAddrNv = dbNameToAddr(*ppvn, puserPvt->pAddr); + if(recScanDebug) { + printf("PV: %s ,dbNameToAddr returned %lx\n",*ppvn, puserPvt->dbAddrNv); } + switch(puserPvt->linkType) { + case POSITIONER: + if(puserPvt->dbAddrNv) { + recDynLinkAddOutput(&precPvt->caLinkStruct[i+NUM_PVS], *ppvn, + DBR_DOUBLE, rdlSCALAR, pvSearchCallback); + recDynLinkAddInput(&precPvt->caLinkStruct[i], *ppvn, + DBR_DOUBLE, rdlSCALAR, pvSearchCallback, posMonCallback); + }else { + /* Add a monitor anyway, so p_cv can be kept up to date */ + recDynLinkAddInput(&precPvt->caLinkStruct[i], *ppvn, + DBR_DOUBLE, rdlSCALAR, pvSearchCallback, posMonCallback); + } + break; + + case READBACK: + /* Check to see if it equals "time" */ + if((strncmp(*ppvn, pTIME, 4)==0) || (strncmp(*ppvn, ptime, 4)==0)) { + puserPvt->ts = 1; + *pPvStat = NO_PV; + db_post_events(pscan, pPvStat, DBE_VALUE); + break; /* don't do lookups or pvSearchCallback */ + } else { + puserPvt->ts = 0; + } + if(puserPvt->dbAddrNv) { + recDynLinkAddInput(&precPvt->caLinkStruct[i], *ppvn, + DBR_DOUBLE, rdlSCALAR, pvSearchCallback, NULL); + }else { + pvSearchCallback(&precPvt->caLinkStruct[i]); + } + break; + + case DETECTOR: + if(puserPvt->dbAddrNv) { + recDynLinkAddInput(&precPvt->caLinkStruct[i], *ppvn, + DBR_FLOAT, NULL, pvSearchCallback, NULL); + }else { + pvSearchCallback(&precPvt->caLinkStruct[i]); + } + break; + + case TRIGGER: + case FWD_LINK: + if(puserPvt->dbAddrNv) { + recDynLinkAddOutput(&precPvt->caLinkStruct[i], *ppvn, + DBR_FLOAT, rdlSCALAR, pvSearchCallback); + }else { + pvSearchCallback(&precPvt->caLinkStruct[i]); + } + break; + } } + +LOCAL void pvSearchCallback(recDynLink *precDynLink) +{ + + recDynLinkPvt *puserPvt = (recDynLinkPvt *)precDynLink->puserPvt; + struct scanRecord *pscan = puserPvt->pscan; + recPvtStruct *precPvt = (recPvtStruct *)pscan->rpvt; + posFields *pPosFields = (posFields *)&pscan->p1pp; + detFields *pDetFields = (detFields *)&pscan->d1hr; + unsigned short index = puserPvt->linkIndex; + unsigned short detIndex; + unsigned short *pPvStat; + unsigned short oldValid; + size_t nelem; + long status; + long nRequest = 1; + long options = DBR_UNITS | DBR_PRECISION | DBR_GR_DOUBLE | + DBR_CTRL_DOUBLE ; + int precision; + + pPvStat = &pscan->p1nv + index; /* pointer arithmetic */ + + oldValid = *pPvStat; + if(puserPvt->dbAddrNv && recDynLinkConnectionStatus(precDynLink)) { + *pPvStat = PV_NC; + if(recScanDebug) printf("Search Callback: No Connection\n"); + } + else { + *pPvStat = PV_OK; + if(recScanDebug) printf("Search Callback: Success\n"); + } + if(*pPvStat != oldValid) { + db_post_events(pscan, pPvStat, DBE_VALUE); + } + + /* Do other stuff, depending on the Link Type */ + switch(puserPvt->linkType) { + case POSITIONER: /* indexes 0,1,2,3 and 25,26,27,28 */ + /* Positioners have an IN and an OUT. Only do the in's */ + if(index > P4_IN) + break; + else { + pPosFields += index; + } + + /* Get control limits, precision, and egu */ + if(puserPvt->dbAddrNv) { + /* use the recDynLink lib */ + recDynLinkGetUnits(precDynLink, pPosFields->p_eu, 8); + recDynLinkGetPrecision(precDynLink, &precision); + pPosFields->p_pr = precision; + recDynLinkGetControlLimits(precDynLink, + &pPosFields->p_lr, &pPosFields->p_hr); + } else { + status = dbGet(puserPvt->pAddr, DBR_FLOAT, + precPvt->pDynLinkInfo, + &options, &nRequest, NULL); + if(status == OK) { + strcpy(pPosFields->p_eu, precPvt->pDynLinkInfo->units); + pPosFields->p_pr = precPvt->pDynLinkInfo->precision; + pPosFields->p_hr = precPvt->pDynLinkInfo->upper_ctrl_limit; + pPosFields->p_lr = precPvt->pDynLinkInfo->lower_ctrl_limit; + } + } + db_post_events(pscan,&pPosFields->p_eu, DBE_VALUE); + db_post_events(pscan,&pPosFields->p_pr, DBE_VALUE); + db_post_events(pscan,&pPosFields->p_hr, DBE_VALUE); + db_post_events(pscan,&pPosFields->p_lr, DBE_VALUE); + + break; + + case READBACK: + break; + + case DETECTOR: + /* Derive pointer to appropriate detector fields */ + detIndex = index - D1_IN; + pDetFields += detIndex; /* pointer arithmetic */ + + /* Get display limits, precision, and egu */ + if(puserPvt->dbAddrNv) { + /* use the recDynLink lib */ + recDynLinkGetUnits(precDynLink, pDetFields->d_eu, 8); + recDynLinkGetPrecision(precDynLink, &precision); + pDetFields->d_pr = precision; + recDynLinkGetGraphicLimits(precDynLink, + &pDetFields->d_lr, &pDetFields->d_hr); + } else { + status = dbGet(puserPvt->pAddr, DBR_FLOAT, + precPvt->pDynLinkInfo, + &options, &nRequest, NULL); + if(status == OK) { + strcpy(pDetFields->d_eu, precPvt->pDynLinkInfo->units); + pDetFields->d_pr = precPvt->pDynLinkInfo->precision; + pDetFields->d_hr = precPvt->pDynLinkInfo->upper_disp_limit; + pDetFields->d_lr = precPvt->pDynLinkInfo->lower_disp_limit; + } + } + db_post_events(pscan,&pDetFields->d_eu, DBE_VALUE); + db_post_events(pscan,&pDetFields->d_pr, DBE_VALUE); + db_post_events(pscan,&pDetFields->d_hr, DBE_VALUE); + db_post_events(pscan,&pDetFields->d_lr, DBE_VALUE); + + /* get # of elements, re-allocate array as necessary */ + if(puserPvt->dbAddrNv) { + status = recDynLinkGetNelem(precDynLink, &nelem); + } + else { + nelem = puserPvt->pAddr->no_elements; + } + + if(nelem > 1) { + printf("NOT READY FOR VECTORS YET !!!\n"); + nelem = 1; /* force it to be a scalar for now */ + } + if(nelem > puserPvt->nelem) { + /* + if(puserPvt->nelem) { + printf("Freeing memory for dynLink %d \n", index); + /* free(pDetFields->d_da); + } + */ + + printf("Allocating memory for dynLink %d\n ", index); + pDetFields->d_da=(float *)calloc(pscan->mpts*nelem,sizeof(float)); + precPvt->detBufPtr[detIndex].pBufA = + (float *) calloc(pscan->mpts, sizeof(float)); + precPvt->detBufPtr[detIndex].pBufB = + (float *) calloc(pscan->mpts, sizeof(float)); + + if(!(precPvt->detBufPtr[detIndex].pBufA) || + !(precPvt->detBufPtr[detIndex].pBufB)) { + /* MEMORY ALLOCATION FAILED */ + printf("MEMORY ALLOCATION FAILED \n"); + puserPvt->nelem = 0; + } + else { + puserPvt->nelem = nelem; + if(precPvt->validBuf) + precPvt->detBufPtr[detIndex].pFill = + precPvt->detBufPtr[detIndex].pBufA; + else + precPvt->detBufPtr[detIndex].pFill = + precPvt->detBufPtr[detIndex].pBufB; + } + } + break; + + case TRIGGER: + case FWD_LINK: + break; + } + + +} + +LOCAL void posMonCallback(recDynLink *precDynLink) +{ + + recDynLinkPvt *puserPvt = (recDynLinkPvt *)precDynLink->puserPvt; + struct scanRecord *pscan = puserPvt->pscan; + recPvtStruct *precPvt = (recPvtStruct *)pscan->rpvt; + unsigned short index = puserPvt->linkIndex; + posFields *pPosFields = (posFields *)&pscan->p1pp + index; + long status; + long nRequest = 1; + long options = 0; -static void initScan(pscan) + /* update p_cv with current positioner value */ + /* NOTE: For fast scans, these will get lost, because it is the low + priority channel access task that is doing these callbacks */ + status = recDynLinkGet(&precPvt->caLinkStruct[index], + &pPosFields->p_cv, &nRequest, 0, 0, 0); + db_post_events(pscan,&pPosFields->p_cv, DBE_VALUE); +} + + +/********************** SCAN Initialization ********************************/ +/* + * If a "Before Scan Link PV" is defined, this routine will be called twice, + * once before the link is processed and once after. The starting positions + * and limits are calculated each time, in case the link caused something to + * change. + * + */ +static long initScan(pscan) struct scanRecord *pscan; { - struct recPvtStruct *precPvt = (struct recPvtStruct *)pscan->rpvt; + recPvtStruct *precPvt = (recPvtStruct *)pscan->rpvt; + recDynLinkPvt *puserPvt; + posFields *pPosFields; long status; long nRequest = 1; long options = 0; + unsigned short *pPvStat; + int i; - /* 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; + + /* General initialization ... */ + if(recScanDebug) { + precPvt->tickStart = tickGet(); } - precPvt->phase = MOVE_MOTORS; + pscan->cpt = 0; /* reset point counter */ + precPvt->scanErr = 0; + + /* determine highest valid positioner, readback, trigger, and detector */ + precPvt->valPosPvs = 0; + precPvt->valRdbkPvs = 0; + precPvt->valDetPvs = 0; + precPvt->valTrigPvs = 0; + pPvStat = &pscan->p1nv; + + for(i=1; i <= NUM_POS; i++, pPvStat++) { + if(*pPvStat == PV_OK) precPvt->valPosPvs = i; + } + /* let pPvStat continue to increment into Readbacks */ + for(i=1; i <= NUM_POS; i++, pPvStat++) { + if(*pPvStat == PV_OK) precPvt->valRdbkPvs = i; + } + /* let pPvStat continue to increment into Detectors */ + for(i=1; i <= NUM_DET; i++, pPvStat++) { + if(*pPvStat == PV_OK) precPvt->valDetPvs = i; + } + /* let pPvStat continue to increment into Triggers */ + for(i=1; i <= NUM_TRGS; i++, pPvStat++) { + if(*pPvStat == PV_OK) precPvt->valTrigPvs = i; + } + + /* if more readbacks than positioners, set valPosPvs to valRdbkPvs */ + if(precPvt->valRdbkPvs > precPvt->valPosPvs) { + precPvt->valPosPvs = precPvt->valRdbkPvs; + } + + if(recScanDebug > 10) { + printf("Positioners : %u\n",precPvt->valPosPvs); + printf("Readbacks : %u\n",precPvt->valRdbkPvs); + printf("Detectors : %u\n",precPvt->valDetPvs); + printf("Triggers : %u\n",precPvt->valTrigPvs); + } + + /* checkScanLimits must be called to update the current value of each + positioner into p_pp. If recScanDontCheckLimits is set, it will return + successful w/o actually checking */ + + if(status = checkScanLimits(pscan)) { + pscan->exsc = 0; /* limits didn't pass, abort scan */ + db_post_events(pscan,&pscan->smsg,DBE_VALUE); + db_post_events(pscan,&pscan->alrt,DBE_VALUE); + db_post_events(pscan,&pscan->exsc,DBE_VALUE); + precPvt->phase = IDLE; + return(status); + } + + /* Then calculate the starting position */ + precPvt->onTheFly = 0; /* clear onTheFly flag */ + pPvStat = &pscan->p1nv; + pPosFields = (posFields *)&pscan->p1pp; + for(i=0; i < precPvt->valPosPvs; i++, pPosFields++, pPvStat++) { + if(*pPvStat == PV_OK) { + /* Figure out starting positions for each positioner */ + if(pPosFields->p_sm == REC_SCAN_MO_TAB) { + if(pPosFields->p_ar) { + pPosFields->p_dv = pPosFields->p_pp + pPosFields->p_pa[0]; + } + else { + pPosFields->p_dv = pPosFields->p_pa[0]; + } + } + else { + if(pPosFields->p_ar) { + pPosFields->p_dv = pPosFields->p_pp + pPosFields->p_sp; + } + else { + pPosFields->p_dv = pPosFields->p_sp; + } + } + db_post_events(pscan,&pPosFields->p_dv,DBE_VALUE); + if(pPosFields->p_sm == REC_SCAN_MO_OTF) { + precPvt->onTheFly |= 1; /* set flag if onTheFly */ + } + } + } + + if((pscan->bsnv == PV_OK) && (precPvt->phase == INIT_SCAN)) { + precPvt->phase = BEFORE_SCAN; + sprintf(pscan->smsg,"Before Scan FLNK ..."); + db_post_events(pscan,&pscan->smsg,DBE_VALUE); + } + else { + precPvt->phase = MOVE_MOTORS; + sprintf(pscan->smsg,"Scanning ..."); + db_post_events(pscan,&pscan->smsg,DBE_VALUE); + } /* request callback to do dbPutFields */ callbackRequest(&precPvt->doPutsCallback); - return; + return(OK); } static void contScan(pscan) struct scanRecord *pscan; { - struct recPvtStruct *precPvt = (struct recPvtStruct *)pscan->rpvt; + recPvtStruct *precPvt = (recPvtStruct *)pscan->rpvt; + posFields *pPosFields = (posFields *)&pscan->p1pp; + detFields *pDetFields = (detFields *)&pscan->d1hr; + recDynLinkPvt *puserPvt; + TS_STAMP currentTs; + unsigned short *pPvStat; + unsigned short *pPvStatPos; + unsigned short i; 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 */ + /* go output to detector trigger fields */ callbackRequest(&precPvt->doPutsCallback); return; - case CHCK_MOTORS: - /* motors have stopped. Check readbacks and deadbands */ - /* Also fill in PxRA (readback array) from RxCV or PxDV */ - if(!pscan->r1nv) { - status = dbGet(pscan->r1db, DBR_FLOAT, &(pscan->r1cv), - &options, &nRequest, NULL); - pscan->p1ra[pscan->cpt] = pscan->r1cv; - if((pscan->r1dl > 0) && - (fabs(pscan->p1dv - pscan->r1cv) > pscan->r1dl)) { + case CHECK_MOTORS: + if(recScanDebug >=5) { + printf("CHECK_MOTORS - Point %d\n",precPvt->pscan->cpt); + } + /* check if a readback PV and a delta are specified */ + pPvStat = &pscan->r1nv; + pPvStatPos = &pscan->p1nv; + for(i=0; i < NUM_POS; i++, pPosFields++, pPvStatPos++, pPvStat++) { + if((pPosFields->r_dl != 0) && + (*pPvStat == PV_OK) && + (*pPvStatPos == PV_OK)) { + puserPvt = precPvt->caLinkStruct[i+NUM_POS].puserPvt; + if(puserPvt->dbAddrNv) { + status = recDynLinkGet(&precPvt->caLinkStruct[i+NUM_POS], + &pPosFields->r_cv, &nRequest, 0, 0, 0); + } + else { + status = dbGet(puserPvt->pAddr,DBR_DOUBLE, &pPosFields->r_cv, + &options, &nRequest,NULL); + } + + if((pPosFields->r_dl > 0) && + (fabs(pPosFields->p_dv-pPosFields->r_cv) > pPosFields->r_dl)) { sprintf(pscan->smsg,"SCAN Aborted: P1 Readback > delta"); db_post_events(pscan,&pscan->smsg,DBE_VALUE); precPvt->scanErr = 1; - abortScan = 1; + endScan(pscan); + return; } - } else { - pscan->r1cv = pscan->p1dv; - pscan->p1ra[pscan->cpt] = pscan->p1dv; - } - if(!pscan->r2nv) { - nRequest = 1; - status = dbGet(pscan->r2db, DBR_FLOAT, &(pscan->r2cv), - &options, &nRequest, NULL); - pscan->p2ra[pscan->cpt] = pscan->r2cv; - 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; - } - } else { /* no readback PV, stuff with desired value */ - pscan->r2cv = pscan->p2dv; - pscan->p2ra[pscan->cpt] = pscan->p2dv; - } - if(!pscan->r3nv) { - nRequest = 1; - status = dbGet(pscan->r3db, DBR_FLOAT, &(pscan->r3cv), - &options, &nRequest, NULL); - pscan->p3ra[pscan->cpt] = pscan->r3cv; - 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; - } - } else { /* no readback PV, stuff with desired value */ - pscan->r3cv = pscan->p3dv; - pscan->p3ra[pscan->cpt] = pscan->p3dv; - } - if(!pscan->r4nv) { - nRequest = 1; - status = dbGet(pscan->r4db, DBR_FLOAT, &(pscan->r4cv), - &options, &nRequest, NULL); - pscan->p4ra[pscan->cpt] = pscan->r4cv; - 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; - } - } else { /* no readback PV, stuff with desired value */ - pscan->r4cv = pscan->p4dv; - pscan->p4ra[pscan->cpt] = pscan->p4dv; + } } - if(abortScan) { - endScan(pscan); - return; - } - - if(precPvt->validDtPvs) { - /* request callback to do dbPutFields to detector trigger fields */ + /* if there is a valid detector trigger ... */ + /* AND we are NOT in onTheFly */ + /* OR we are doing Point 0 */ + /* go trigger detectors and wait for the next process */ + if(precPvt->valTrigPvs && (!precPvt->onTheFly || (pscan->cpt==0))) { + /* do detector trigger fields */ precPvt->phase = TRIG_DETCTRS; callbackRequest(&precPvt->doPutsCallback); return; } - /* if no validDtPvs, fall through to READ_DETCTRS */ + /* if no validTrigPvs, fall through to READ_DETCTRS */ + /* if on-the-fly mode, fall through to READ_DETCTRS */ - case READ_DETCTRS: + case READ_DETCTRS: + if(recScanDebug >=5) { + printf("READ_DETCTRS - Point %d\n",precPvt->pscan->cpt); + } + /* Store the appropriate value into the positioner readback array */ + /* from RxCV or PxDV or TIME */ + pPvStat = &pscan->r1nv; + pPvStatPos = &pscan->p1nv; + pPosFields = (posFields *)&pscan->p1pp; + for(i=0; i < NUM_POS; i++, pPosFields++, pPvStatPos++, pPvStat++) { + /* if readback PV is OK, use that value */ + if(*pPvStat == PV_OK) { + puserPvt = precPvt->caLinkStruct[i+NUM_POS].puserPvt; + if(puserPvt->dbAddrNv) { + status = recDynLinkGet(&precPvt->caLinkStruct[i+NUM_POS], + &pPosFields->r_cv, &nRequest, 0, 0, 0); + } + else { + status = dbGet(puserPvt->pAddr,DBR_DOUBLE, &pPosFields->r_cv, + &options, &nRequest,NULL); + } + + precPvt->posBufPtr[i].pFill[pscan->cpt] = pPosFields->r_cv; + + } + + /* Does the readback PV = "time" ? */ + else if(((recDynLinkPvt *) + (precPvt->caLinkStruct[i+NUM_POS].puserPvt))->ts) { + TSgetTimeStamp((int)precPvt->pscan->tse, + (struct timespec*)¤tTs); + TsDiffAsDouble(&pPosFields->r_cv, ¤tTs, &pscan->time); + precPvt->posBufPtr[i].pFill[pscan->cpt] = pPosFields->r_cv; + } + + /* Is the positioner PV valid ? */ + else if(*pPvStatPos == PV_OK) { + /* stuff array with desired value */ + /* if onTheFly and cpt>0,add the step increment to the previous*/ + if((pPosFields->p_sm != REC_SCAN_MO_OTF) || (pscan->cpt == 0)) { + pPosFields->r_cv = pPosFields->p_dv; + precPvt->posBufPtr[i].pFill[pscan->cpt] = pPosFields->r_cv; + } else { + pPosFields->r_cv = + precPvt->posBufPtr[i].pFill[pscan->cpt-1] + pPosFields->p_si; + precPvt->posBufPtr[i].pFill[pscan->cpt] = pPosFields->r_cv; + } + } + else { + /* Neither PV is valid, store a 0 */ + pPosFields->r_cv = 0; + precPvt->posBufPtr[i].pFill[pscan->cpt] = pPosFields->r_cv; + } + } + /* read each valid detector PV, place data in buffered array */ status = 0; - if(!pscan->d1nv) { - /* dbAddr is valid */ - nRequest = 1; - status |= dbGet(pscan->d1db, DBR_FLOAT, &(pscan->d1cv), - &options, &nRequest, NULL); - } else pscan->d1cv = 0; - if(!pscan->d2nv) { - nRequest = 1; - status |= dbGet(pscan->d2db, DBR_FLOAT, - &(pscan->d2cv), &options, &nRequest, NULL); - } else pscan->d2cv = 0; - if(!pscan->d3nv) { - nRequest = 1; - status |= dbGet(pscan->d3db, DBR_FLOAT, &(pscan->d3cv), - &options, &nRequest, NULL); - } else pscan->d3cv = 0; - if(!pscan->d4nv) { - nRequest = 1; - 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; + pPvStat = &pscan->d1nv; + pDetFields = (detFields *)&pscan->d1hr; + for(i=0; i < precPvt->valDetPvs; i++, pDetFields++, pPvStat++) { + if((*pPvStat == PV_OK) && (precPvt->detBufPtr[i].pFill != NULL)) { + puserPvt = precPvt->caLinkStruct[i+D1_IN].puserPvt; + if(puserPvt->dbAddrNv) { + status |= recDynLinkGet(&precPvt->caLinkStruct[i+D1_IN], + &pDetFields->d_cv, &nRequest, 0, 0, 0); + } + else { + status |= dbGet(puserPvt->pAddr, DBR_FLOAT, &pDetFields->d_cv, + &options, &nRequest, NULL); + } + precPvt->detBufPtr[i].pFill[pscan->cpt] = pDetFields->d_cv; + } + } pscan->udf=0; @@ -1175,57 +1767,42 @@ struct scanRecord *pscan; /* 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 end position */ - pscan->p1dv = pscan->p1ep; - 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 end position */ - pscan->p2dv = pscan->p2ep; - 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 end position */ - pscan->p3dv = pscan->p3ep; - 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 end position */ - pscan->p4dv = pscan->p4ep; - pscan->p4pa[pscan->cpt] = pscan->p4dv; + pPosFields = (posFields *)&pscan->p1pp; + pPvStat = &pscan->p1nv; + + /* figure out next position */ + for(i=0; i < precPvt->valPosPvs; i++, pPosFields++, pPvStat++) { + if(*pPvStat == PV_OK) { + switch(pPosFields->p_sm) { + case REC_SCAN_MO_LIN: + pPosFields->p_dv = pPosFields->p_dv + pPosFields->p_si; + break; + case REC_SCAN_MO_TAB: + if(pPosFields->p_ar) { + pPosFields->p_dv = pPosFields->p_pp + + pPosFields->p_pa[pscan->cpt]; + } + else { + pPosFields->p_dv = pPosFields->p_pa[pscan->cpt]; + } + break; + case REC_SCAN_MO_OTF: + if(pPosFields->p_ar) { + pPosFields->p_dv = pPosFields->p_pp + + pPosFields->p_ep; + } + else { + pPosFields->p_dv = pPosFields->p_ep; + } + break; + } + } } /* request callback to move motors to new positions */ precPvt->phase = MOVE_MOTORS; + /* For onTheFly, it will fall through to TRIG_DETCTRS */ + /* after MOVE_MOTORS */ callbackRequest(&precPvt->doPutsCallback); return; } @@ -1236,15 +1813,18 @@ struct scanRecord *pscan; precPvt->scanErr = 0; return; } - } + } } static void endScan(pscan) struct scanRecord *pscan; { - struct recPvtStruct *precPvt = (struct recPvtStruct *)pscan->rpvt; - int counter; + recPvtStruct *precPvt = (recPvtStruct *)pscan->rpvt; + int counter; + unsigned short *pPvStat, i; + detFields *pDetFields; + posFields *pPosFields; /* Done with scan. Do we want to fill the remainder of the @@ -1255,152 +1835,253 @@ struct scanRecord *pscan; same point over and over again, but it will look correct */ counter = pscan->cpt; - if(scanRecDebug) { + if(recScanDebug) { 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; + while (counter < pscan->mpts) { + /* Fill valid detector arrays with last value */ + pDetFields = (detFields *)&pscan->d1hr; + pPvStat = &pscan->d1nv; + for(i=0; i < precPvt->valDetPvs; i++, pDetFields++, pPvStat++) { + if(*pPvStat == PV_OK) { + precPvt->detBufPtr[i].pFill[counter] = pDetFields->d_cv; + } } + /* Fill in the readback arrays with last values */ + precPvt->posBufPtr[0].pFill[counter] = + precPvt->posBufPtr[0].pFill[counter-1]; - if(!pscan->r1nv) - pscan->p1ra[counter] = pscan->r1cv; - else - pscan->p1ra[counter] = pscan->p1dv; + precPvt->posBufPtr[1].pFill[counter] = + precPvt->posBufPtr[1].pFill[counter-1]; - if(!pscan->r2nv) - pscan->p2ra[counter] = pscan->r2cv; - else - pscan->p2ra[counter] = pscan->p2dv; + precPvt->posBufPtr[2].pFill[counter] = + precPvt->posBufPtr[2].pFill[counter-1]; - if(!pscan->r3nv) - pscan->p3ra[counter] = pscan->r3cv; - else - pscan->p3ra[counter] = pscan->p3dv; + precPvt->posBufPtr[3].pFill[counter] = + precPvt->posBufPtr[3].pFill[counter-1]; - if(!pscan->r4nv) - pscan->p4ra[counter] = pscan->r4cv; - else - pscan->p4ra[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; + /* Switch validBuf flag and fill pointers */ + if(precPvt->validBuf == A_BUFFER) { + precPvt->validBuf = B_BUFFER; + precPvt->posBufPtr[0].pFill = precPvt->posBufPtr[0].pBufA; + precPvt->posBufPtr[1].pFill = precPvt->posBufPtr[1].pBufA; + precPvt->posBufPtr[2].pFill = precPvt->posBufPtr[2].pBufA; + precPvt->posBufPtr[3].pFill = precPvt->posBufPtr[3].pBufA; + for(i=0; i < NUM_DET; i++) { + precPvt->detBufPtr[i].pFill = precPvt->detBufPtr[i].pBufA; + } + } else { + precPvt->validBuf = A_BUFFER; + precPvt->posBufPtr[0].pFill = precPvt->posBufPtr[0].pBufB; + precPvt->posBufPtr[1].pFill = precPvt->posBufPtr[1].pBufB; + precPvt->posBufPtr[2].pFill = precPvt->posBufPtr[2].pBufB; + precPvt->posBufPtr[3].pFill = precPvt->posBufPtr[3].pBufB; + for(i=0; i < NUM_DET; i++) { + precPvt->detBufPtr[i].pFill = precPvt->detBufPtr[i].pBufB; + } } - 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 */ - /* if the "Return To Start: flag is set, command positioners - to their start positions via initScan */ + /* Check the "after scan flag to see what to do about the positioners */ + /* Also see if there is an After Scan Link to process */ - if(pscan->rtst) { - initScan(pscan); + if(pscan->pasm || (pscan->asnv == PV_OK)) { + precPvt->phase = AFTER_SCAN; + /* request callback to do dbPutFields */ + callbackRequest(&precPvt->doPutsCallback); + } + else { + precPvt->phase = IDLE; } - 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. + * This is the code that is executed to initiate the next + * step in the scan or trigger detectors (does the "puts" to the + * reassignable links). Since the recDynLinkPut request is actually + * done with a separate task, one need not worry about lock sets. + * + * Note that the argument (which is the address of the CALLBACK structure), + * is interpreted to be a pointer to the record private area. * - *****************************************************************************/ + ***************************************************************************/ void doPuts(precPvt) - struct recPvtStruct *precPvt; + recPvtStruct *precPvt; { -static long status; -static long nRequest = 1; + recDynLinkPvt *puserPvt; + posFields *pPosFields; + unsigned short *pPvStat; + int i; + long status; + 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 as CHCK_MOTORS */ - /* This needs to come before moving motors */ + if(recScanDebug >=5) { + printf("MOVE_MOTORS - Point %d\n",precPvt->pscan->cpt); + } + /* Schedule the next phase as CHECK_MOTORS */ + precPvt->phase = CHECK_MOTORS; - precPvt->phase = CHCK_MOTORS; + pPosFields = (posFields *)&precPvt->pscan->p1pp; + pPvStat = &precPvt->pscan->p1nv; /* 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); + /* if positioner is "on-the-fly", only write if step 0 or 1 */ + for(i=0; i < precPvt->valPosPvs; i++, pPosFields++, pPvStat++) { + if((*pPvStat == PV_OK) && + (!((pPosFields->p_sm == REC_SCAN_MO_OTF) && + (precPvt->pscan->cpt > 1)) || precPvt->phase == AFTER_SCAN)) { + puserPvt = precPvt->caLinkStruct[i].puserPvt; + if(puserPvt->dbAddrNv) { + status = recDynLinkPut(&precPvt->caLinkStruct[i+P1_OUT], + &(pPosFields->p_dv), 1); + } else { + status = dbPutField(puserPvt->pAddr,DBF_DOUBLE, + &(pPosFields->p_dv), 1); + } + } } - break; + if(!(precPvt->onTheFly && precPvt->pscan->cpt)) + break; + /* Fall through to TRIG_DETCTRS if in onTheFly mode and flying */ + case TRIG_DETCTRS: + if(recScanDebug >=5) { + printf("TRIG_DETCTRS - Point %d\n",precPvt->pscan->cpt); + } /* Schedule the next phase */ - precPvt->phase = READ_DETCTRS; + if(!precPvt->onTheFly || (precPvt->pscan->cpt == 0)) { + precPvt->phase = READ_DETCTRS; + } + else { + precPvt->phase = CHECK_MOTORS; + } /* for each valid detector trigger, write the desired value */ if(!precPvt->pscan->t1nv) { - status = dbPutField(precPvt->pscan->t1db,DBR_FLOAT, - &(precPvt->pscan->t1cd), 1); + puserPvt = precPvt->caLinkStruct[T1_OUT].puserPvt; + if(puserPvt->dbAddrNv) { + status = recDynLinkPut(&precPvt->caLinkStruct[T1_OUT], + &(precPvt->pscan->t1cd), 1); + } else { + status = dbPutField(puserPvt->pAddr,DBF_FLOAT, + &(precPvt->pscan->t1cd), 1); + } } if(!precPvt->pscan->t2nv) { - status = dbPutField(precPvt->pscan->t2db,DBR_FLOAT, - &(precPvt->pscan->t2cd), 1); + puserPvt = precPvt->caLinkStruct[T2_OUT].puserPvt; + if(puserPvt->dbAddrNv) { + status = recDynLinkPut(&precPvt->caLinkStruct[T2_OUT], + &(precPvt->pscan->t2cd), 1); + } else { + status = dbPutField(puserPvt->pAddr,DBF_FLOAT, + &(precPvt->pscan->t2cd), 1); + } } - break; + + case BEFORE_SCAN: + if(recScanDebug >=5) printf("BEFORE_SCAN Fwd Lnk\n"); + if(precPvt->pscan->bsnv == OK) { + puserPvt = precPvt->caLinkStruct[BS_OUT].puserPvt; + if(puserPvt->dbAddrNv) { + status = recDynLinkPut(&precPvt->caLinkStruct[BS_OUT], + &(precPvt->pscan->bscd), 1); + } else { + status = dbPutField(puserPvt->pAddr,DBF_FLOAT, + &(precPvt->pscan->bscd), 1); + } + } + /* Leave the phase at BEFORE_SCAN */ + break; + + case AFTER_SCAN: + /* If Retrace indicates motors must move ... */ + if(precPvt->pscan->pasm) { + if(recScanDebug >=5) printf("RETRACE\n"); + pPosFields = (posFields *)&precPvt->pscan->p1pp; + pPvStat = &precPvt->pscan->p1nv; + for(i=0; i < precPvt->valPosPvs; i++, pPosFields++, pPvStat++) { + if(*pPvStat == PV_OK) { + /* Figure out where to go ... */ + if(precPvt->pscan->pasm == REC_SCAN_AS_BS) { + pPosFields->p_dv = pPosFields->p_pp; + } else { + if(pPosFields->p_sm == REC_SCAN_MO_TAB) { + if(pPosFields->p_ar) { + pPosFields->p_dv = + pPosFields->p_pp + pPosFields->p_pa[0]; + } + else { + pPosFields->p_dv = pPosFields->p_pa[0]; + } + } + else { + if(pPosFields->p_ar) { + pPosFields->p_dv = + pPosFields->p_pp + pPosFields->p_sp; + } + else { + pPosFields->p_dv = pPosFields->p_sp; + } + } + } + + /* Command motor */ + puserPvt = precPvt->caLinkStruct[i].puserPvt; + if(puserPvt->dbAddrNv) { + status = recDynLinkPut(&precPvt->caLinkStruct[i+P1_OUT], + &(pPosFields->p_dv), 1); + } else { + status = dbPutField(puserPvt->pAddr,DBF_DOUBLE, + &(pPosFields->p_dv), 1); + } + } + } + } + + /* If an After Scan Link PV is valid, execute it */ + if(precPvt->pscan->asnv == PV_OK) { + if(recScanDebug >=5) printf("AFTER_SCAN Fwd Lnk\n"); + puserPvt = precPvt->caLinkStruct[AS_OUT].puserPvt; + if(puserPvt->dbAddrNv) { + status = recDynLinkPut(&precPvt->caLinkStruct[AS_OUT], + &(precPvt->pscan->ascd), 1); + } else { + status = dbPutField(puserPvt->pAddr,DBF_FLOAT, + &(precPvt->pscan->ascd), 1); + } + } + + precPvt->phase = IDLE; + break; + + case IDLE: + case PREVIEW: + /* This must be a request to move a positioner interactivly ... */ + + pPvStat = &precPvt->pscan->p1nv; + pPosFields = (posFields *)&precPvt->pscan->p1pp; + for(i=0; i < NUM_POS; i++, pPosFields++, pPvStat++) { + if((*pPvStat == PV_OK) && precPvt->movPos[i]) { + puserPvt = precPvt->caLinkStruct[i].puserPvt; + status = dbPutField(puserPvt->pAddr,DBF_DOUBLE, + &(pPosFields->p_dv), 1); + precPvt->movPos[i] = 0; + } + } + break; + default: } } @@ -1415,38 +2096,34 @@ static long nRequest = 1; static void adjLinParms(paddr) struct dbAddr *paddr; { - struct scanRecord *pscan = (struct scanRecord *)(paddr->precord); - struct recPvtStruct *precPvt = (struct recPvtStruct *)pscan->rpvt; - struct linScanParms *pParms; + struct scanRecord *pscan = (struct scanRecord *)(paddr->precord); + recPvtStruct *precPvt = (recPvtStruct *)pscan->rpvt; + struct posFields *pParms = (posFields *)&precPvt->pscan->p1pp; int special_type = paddr->special; int i; + int foundOne = 0; /* determine which positioner */ - if ((paddr->pfield >= (void *)&pscan->p1sp) && - (paddr->pfield <= (void *)&pscan->p1fw)) { - pParms = (struct linScanParms *)&pscan->p1sp; - i=1; + for(i=0; ipfield >= (void *)&pParms->p_pp) && + (paddr->pfield <= (void *)&pParms->p_pr)) { + + foundOne = 1; + break; + } } - 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 { + if(!foundOne) return; /* couldn't determine positioner */ + + if(pParms->p_sm == REC_SCAN_MO_TAB) { + /* if positioner is in table mode, zero parms and return */ + zeroPosParms(pscan, (unsigned short) i); + sprintf(pscan->smsg,"Positioner #%1d is in Table Mode !",i+1); + pscan->alrt = 1; return; } + if(recScanDebug) printf("Positioner %d\n",i); switch(special_type) { case(SPC_SC_S): /* start position changed */ /* if step increment/center/width are not frozen, change them */ @@ -1479,12 +2156,12 @@ static void adjLinParms(paddr) } 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; + pscan->npts = pscan->mpts; + sprintf(pscan->smsg,"P%1d Request Exceeded Maximum Points!",i+1); + /* 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; @@ -1498,12 +2175,12 @@ static void adjLinParms(paddr) } 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; + pscan->npts = pscan->mpts; + sprintf(pscan->smsg,"P%1d Request Exceeded Maximum Points!",i+1); + /* 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); @@ -1523,7 +2200,7 @@ static void adjLinParms(paddr) } 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); + sprintf(pscan->smsg,"P%1d SCAN Parameters Too Constrained !",i+1); pscan->alrt = 1; return; } @@ -1561,12 +2238,12 @@ static void adjLinParms(paddr) } 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; + pscan->npts = pscan->mpts; + sprintf(pscan->smsg,"P%1d Request Exceeded Maximum Points !",i+1); + /* 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 */ @@ -1575,7 +2252,7 @@ static void adjLinParms(paddr) } 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); + sprintf(pscan->smsg,"P%1d SCAN Parameters Too Constrained !",i+1); pscan->alrt = 1; return; } @@ -1613,12 +2290,12 @@ static void adjLinParms(paddr) } 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; + pscan->npts = pscan->mpts; + sprintf(pscan->smsg,"P%1d Request Exceeded Maximum Points !",i+1); + /* 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; @@ -1632,12 +2309,12 @@ static void adjLinParms(paddr) } 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; + pscan->npts = pscan->mpts; + sprintf(pscan->smsg,"P%1d Request Exceeded Maximum Points !",i+1); + /* 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; @@ -1657,7 +2334,7 @@ static void adjLinParms(paddr) } 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); + sprintf(pscan->smsg,"P%1d SCAN Parameters Too Constrained !",i+1); pscan->alrt = 1; return; } @@ -1693,12 +2370,12 @@ static void adjLinParms(paddr) } 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; + pscan->npts = pscan->mpts; + sprintf(pscan->smsg,"P%1d Request Exceeded Maximum Points !",i+1); + /* 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; @@ -1712,12 +2389,12 @@ static void adjLinParms(paddr) } 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; + pscan->npts = pscan->mpts; + sprintf(pscan->smsg,"P%1d Request Exceeded Maximum Points !",i+1); + /* 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; @@ -1730,7 +2407,7 @@ static void adjLinParms(paddr) } 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); + sprintf(pscan->smsg,"P%1d SCAN Parameters Too Constrained !",i+1); pscan->alrt = 1; return; } @@ -1768,12 +2445,12 @@ static void adjLinParms(paddr) } 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; + pscan->npts = pscan->mpts; + sprintf(pscan->smsg,"P%1d Request Exceeded Maximum Points !",i+1); + /* 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; @@ -1787,12 +2464,12 @@ static void adjLinParms(paddr) } 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; + pscan->npts = pscan->mpts; + sprintf(pscan->smsg,"P%1d Request Exceeded Maximum Points !",i+1); + /* 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); @@ -1806,12 +2483,12 @@ static void adjLinParms(paddr) } 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; + pscan->npts = pscan->mpts; + sprintf(pscan->smsg,"P%1d Request Exceeded Maximum Points !",i+1); + /* 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); @@ -1824,7 +2501,7 @@ static void adjLinParms(paddr) } 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); + sprintf(pscan->smsg,"P%1d SCAN Parameters Too Constrained !",i+1); pscan->alrt = 1; return; } @@ -1841,7 +2518,11 @@ static void adjLinParms(paddr) * "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. + * no conflict with that logic. Any positioner in TABLE mode is also skipped. + * + * Any positioner that is in TABLE mode is checked to make sure the last + * table loaded into p_pa had enough points for the new npts. If not, the + * operator is warned * */ @@ -1849,26 +2530,26 @@ static void changedNpts(pscan) struct scanRecord *pscan; { - struct recPvtStruct *precPvt = (struct recPvtStruct *)pscan->rpvt; - struct linScanParms *pParms; + recPvtStruct *precPvt = (recPvtStruct *)pscan->rpvt; + posFields *pParms = (posFields *)&pscan->p1pp; 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; + /* if the positioner is in table mode, don't touch linear scan parms !*/ + for(i=0; ip_sm == REC_SCAN_MO_TAB) { + if(precPvt->tablePts[i] < pscan->npts) { + sprintf(pscan->smsg,"Pts in P%d Table < # of Steps",i+1); + if(!pscan->alrt) { + pscan->alrt = 1; + } + } + } + /* Skip the positioner that caused this */ + else if(i != precPvt->nptsCause) { + /* Adjust linear scan params as best we can */ /* develop freezeState switching word ... */ /* START_FRZ | STEP_FRZ | END_FRZ | CENTER_FRZ | WIDTH_FRZ */ @@ -1879,7 +2560,7 @@ static void changedNpts(pscan) (pParms->p_fc << 1) | (pParms->p_fw); - if(scanRecDebug) { + if(recScanDebug) { printf("Freeze State of P%1d = 0x%hx \n",i,freezeState); } @@ -1921,7 +2602,7 @@ static void changedNpts(pscan) 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(17): /*if start/center or start/width are frozen, but not inc*/ case(18): case(19): case(20): @@ -1935,261 +2616,321 @@ static void changedNpts(pscan) /* 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); + sprintf(pscan->smsg,"P%1d SCAN Parameters Too Constrained !",i+1); pscan->alrt = 1; break; } + } } } -static void checkScanLimits(pscan) +static long checkScanLimits(pscan) struct scanRecord *pscan; { - struct recPvtStruct *precPvt = (struct recPvtStruct *)pscan->rpvt; + recDynLinkPvt *puserPvt; + recPvtStruct *precPvt = (recPvtStruct *)pscan->rpvt; + posFields *pPosFields = (posFields *)&pscan->p1pp; + unsigned short *pPvStat = &pscan->p1nv; /* for each valid positioner, fetch control limits */ long status; long nRequest = 1; - long options = DBR_CTRL_DOUBLE; - long abortScan = 0; - int i; + long options = 0; + int i,j; 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) { - nRequest = 1; - status = dbGet(pscan->p2db, DBR_FLOAT, precPvt->pP2Limits, - &options, &nRequest, NULL); - } - if(!pscan->p3nv) { - nRequest = 1; - status = dbGet(pscan->p3db, DBR_FLOAT, precPvt->pP3Limits, - &options, &nRequest, NULL); - } - if(!pscan->p4nv) { - nRequest = 1; - status = dbGet(pscan->p4db, DBR_FLOAT, precPvt->pP4Limits, - &options, &nRequest, NULL); - } - - if(scanRecDebug) { + if(recScanDebug) { if(!pscan->p1nv) printf("P1 Control Limits : %.4f %.4f\n", - precPvt->pP1Limits->lower_ctrl_limit, - precPvt->pP1Limits->upper_ctrl_limit); + pscan->p1lr, pscan->p1hr); if(!pscan->p2nv) printf("P2 Control Limits : %.4f %.4f\n", - precPvt->pP2Limits->lower_ctrl_limit, - precPvt->pP2Limits->upper_ctrl_limit); + pscan->p2lr, pscan->p2hr); if(!pscan->p3nv) printf("P3 Control Limits : %.4f %.4f\n", - precPvt->pP3Limits->lower_ctrl_limit, - precPvt->pP3Limits->upper_ctrl_limit); + pscan->p3lr, pscan->p3hr); if(!pscan->p4nv) printf("P4 Control Limits : %.4f %.4f\n", - precPvt->pP4Limits->lower_ctrl_limit, - precPvt->pP4Limits->upper_ctrl_limit); + pscan->p4lr, pscan->p4hr); + } + + /* Update "previous position" of positioners to use in relative mode */ + pPvStat = &pscan->p1nv; + pPosFields = (posFields *)&pscan->p1pp; + for(i=0; i < NUM_POS; i++, pPosFields++, pPvStat++) { + if(*pPvStat == PV_OK) { + puserPvt = precPvt->caLinkStruct[i].puserPvt; + if(puserPvt->dbAddrNv) { + status |= recDynLinkGet(&precPvt->caLinkStruct[i], + &pPosFields->p_pp, &nRequest, 0, 0, 0); + } + else { + status |= dbGet(puserPvt->pAddr, DBR_DOUBLE, &pPosFields->p_pp, + &options, &nRequest, NULL); + } + db_post_events(pscan,&pPosFields->p_pp,DBE_VALUE); + } + } + + /* If recScanDontCheckLimits flag is set and EXSC = 1, don't proceed */ + if(recScanDontCheckLimits && pscan->exsc) return(OK); + + /* First check if any pos'rs are in Table mode with insufficient points*/ + pPvStat = &pscan->p1nv; + pPosFields = (posFields *)&pscan->p1pp; + for(i=0; i < NUM_POS; i++, pPosFields++, pPvStat++) { + if((*pPvStat == PV_OK) && + (pPosFields->p_sm == REC_SCAN_MO_TAB) && + (precPvt->tablePts[i] < pscan->npts)) { + sprintf(pscan->smsg,"Pts in P%d Table < # of Steps",i+1); + db_post_events(pscan,&pscan->smsg,DBE_VALUE); + if(!pscan->alrt) { + pscan->alrt = 1; + db_post_events(pscan,&pscan->alrt,DBE_VALUE); + } + return(ERROR); + } } /* check each point of scan against control limits. */ /* Stop on first error */ - for(i=0; inpts; i++) { - if(!pscan->p1nv) { + pPvStat = &pscan->p1nv; + pPosFields = (posFields *)&pscan->p1pp; + for(i=0; i < NUM_POS; i++, pPosFields++, pPvStat++) { + if(*pPvStat == PV_OK) { + for(j=0; jnpts; j++) { /* 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; + switch(pPosFields->p_sm) { + case REC_SCAN_MO_LIN: + if(pPosFields->p_ar) { + value = (pPosFields->p_pp + pPosFields->p_sp) + + (j * pPosFields->p_si); + } else { + value = pPosFields->p_sp + (j * pPosFields->p_si); + } + break; + + case REC_SCAN_MO_TAB: + if(pPosFields->p_ar) { + value = pPosFields->p_pp + pPosFields->p_pa[j]; + } else { + value = pPosFields->p_pa[j]; + } + break; + + case REC_SCAN_MO_OTF: + if(pPosFields->p_ar) { + if(j == 0) value = pPosFields->p_pp + pPosFields->p_sp; + else value = pPosFields->p_pp + pPosFields->p_ep; + } else { + if(j == 0) value = pPosFields->p_sp; + else value = pPosFields->p_ep; + } + break; + + default: + value = 0; } - if(value < precPvt->pP1Limits->lower_ctrl_limit) { - sprintf(pscan->smsg,"P1 Value < LO_Limit @ point %1d",i); + if((pPosFields->p_lr != 0) && (value < pPosFields->p_lr)) { + sprintf(pscan->smsg,"P%-d Value < LO_Limit @ point %1d",i+1,j); pscan->alrt = 1; - return; + return(ERROR); } - else if(value > precPvt->pP1Limits->upper_ctrl_limit) { - sprintf(pscan->smsg,"P1 Value > HI_Limit @ point %1d",i); + else if((pPosFields->p_hr != 0) && (value > pPosFields->p_hr)) { + sprintf(pscan->smsg,"P%-d Value > HI_Limit @ point %1d",i+1,j); pscan->alrt = 1; - return; + return(ERROR); } } - - 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"); + return(OK); } -/* 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. +/* This routine show a "preview" of the scan positions by + * loading the detector arrays (d_da) with the scan positions at each + * point and loading the readback arrays (p_ra) with the step #. + * A plot of d_da vs p_ra will provide a graphical view of the scan + * ranges. * */ -static void drawPos1Scan(pscan) +static void previewScan(pscan) struct scanRecord *pscan; { - struct recPvtStruct *precPvt = (struct recPvtStruct *)pscan->rpvt; - struct linScanParms *pParms; - int i; - unsigned short freezeState = 0; + recPvtStruct *precPvt = (recPvtStruct *)pscan->rpvt; + recDynLinkPvt *puserPvt; + posFields *pPosFields; + detFields *pDetFields; + unsigned short *pPvStat; + double *pPosBuf; + float *pDetBuf; + float value; + int i,j; + long status; + long nRequest = 1; + long options = 0; - float desValue; - - desValue = pscan->p1sp; - - for(i=0; inpts; i++) { - pscan->p1pa[i] = desValue + (i * pscan->p1si); - pscan->d1da[i] = 1; + /* Update "previous position" of positioners to use in relative mode */ + pPvStat = &pscan->p1nv; + pPosFields = (posFields *)&pscan->p1pp; + for(i=0; i < NUM_POS; i++, pPosFields++, pPvStat++) { + if(*pPvStat == PV_OK) { + puserPvt = precPvt->caLinkStruct[i].puserPvt; + if(puserPvt->dbAddrNv) { + status |= recDynLinkGet(&precPvt->caLinkStruct[i], + &pPosFields->p_pp, &nRequest, 0, 0, 0); + } + else { + status |= dbGet(puserPvt->pAddr, DBR_DOUBLE, &pPosFields->p_pp, + &options, &nRequest, NULL); + } + db_post_events(pscan,&pPosFields->p_pp,DBE_VALUE); } + } - /* fill array with last position */ - for(i=i; impts;i++) { - pscan->p1pa[i] = pscan->p1pa[i-1]; - pscan->d1da[i] = 1; + /* Run through entire scan for each valid positioner */ + pPvStat = &pscan->p1nv; + pPosFields = (posFields *)&pscan->p1pp; + pDetFields = (detFields *)&pscan->d1hr; + for(i=0; i < NUM_POS; i++, pPosFields++, pPvStat++, pDetFields++) { + if(*pPvStat == PV_OK) { + /* must use the current buffer pointer */ + if(precPvt->validBuf) { + pPosBuf = precPvt->posBufPtr[i].pBufB; + pDetBuf = precPvt->detBufPtr[i].pBufB; + } + else { + pPosBuf = precPvt->posBufPtr[i].pBufA; + pDetBuf = precPvt->detBufPtr[i].pBufA; + } + for(j=0; jnpts; j++) { + /* determine next desired position for each positioner */ + switch(pPosFields->p_sm) { + case REC_SCAN_MO_LIN: + if(pPosFields->p_ar) { + value = (pPosFields->p_pp + pPosFields->p_sp) + + (j * pPosFields->p_si); + } else { + value = pPosFields->p_sp + (j * pPosFields->p_si); + } + break; + + case REC_SCAN_MO_TAB: + if(pPosFields->p_ar) { + value = pPosFields->p_pp + pPosFields->p_pa[j]; + } else { + value = pPosFields->p_pa[j]; + } + break; + + case REC_SCAN_MO_OTF: + if(pPosFields->p_ar) { + if(j == 0) value = pPosFields->p_pp + pPosFields->p_sp; + else value = pPosFields->p_pp + pPosFields->p_ep; + } else { + if(j == 0) value = pPosFields->p_sp; + else value = pPosFields->p_ep; + } + break; + + default: + value = 0; + } + pPosBuf[j] = j; + pDetBuf[j] = value; + } + /* now fill the rest of the array(s) with the last values */ + for(j=j; jmpts;j++) { + pPosBuf[j] = pPosBuf[j-1]; + pDetBuf[j] = pDetBuf[j-1]; + } + db_post_events(pscan, precPvt->posBufPtr[i].pBufA, DBE_VALUE); + db_post_events(pscan, precPvt->posBufPtr[i].pBufB, DBE_VALUE); + db_post_events(pscan, precPvt->detBufPtr[i].pBufA, DBE_VALUE); + db_post_events(pscan, precPvt->detBufPtr[i].pBufB, DBE_VALUE); + /* I must also post a monitor on the NULL array, because some + clients connected to D?PV's without valid PV's ! */ + db_post_events(pscan, precPvt->nullArray, DBE_VALUE); } - - db_post_events(pscan,pscan->p1pa, DBE_VALUE); - db_post_events(pscan,precPvt->pdet1DataA, DBE_VALUE); - db_post_events(pscan,precPvt->pdet1DataB, DBE_VALUE); - + } } - static void saveFrzFlags(pscan) struct scanRecord *pscan; { - struct recPvtStruct *precPvt = (struct recPvtStruct *)pscan->rpvt; + recPvtStruct *precPvt = (recPvtStruct *)pscan->rpvt; + posFields *pPosFields = (posFields *)&pscan->p1pp; + int i; + /* save state of each freeze flag */ precPvt->fpts = pscan->fpts; - precPvt->p1fs = pscan->p1fs; - precPvt->p1fi = pscan->p1fi; - precPvt->p1fc = pscan->p1fc; - precPvt->p1fe = pscan->p1fe; - precPvt->p1fw = pscan->p1fw; - precPvt->p2fs = pscan->p2fs; - precPvt->p2fi = pscan->p2fi; - precPvt->p2fc = pscan->p2fc; - precPvt->p2fe = pscan->p2fe; - precPvt->p2fw = pscan->p2fw; - precPvt->p3fs = pscan->p3fs; - precPvt->p3fi = pscan->p3fi; - precPvt->p3fc = pscan->p3fc; - precPvt->p3fe = pscan->p3fe; - precPvt->p3fw = pscan->p3fw; - precPvt->p4fs = pscan->p4fs; - precPvt->p4fi = pscan->p4fi; - precPvt->p4fc = pscan->p4fc; - precPvt->p4fe = pscan->p4fe; - precPvt->p4fw = pscan->p4fw; + for(i=0; iposParms[i].p_fs = pPosFields->p_fs; + precPvt->posParms[i].p_fi = pPosFields->p_fi; + precPvt->posParms[i].p_fc = pPosFields->p_fc; + precPvt->posParms[i].p_fe = pPosFields->p_fe; + precPvt->posParms[i].p_fw = pPosFields->p_fw; + } +} + +static void savePosParms(struct scanRecord *pscan, unsigned short i) +{ + + recPvtStruct *precPvt = (recPvtStruct *)pscan->rpvt; + posFields *pPosFields = (posFields *)&pscan->p1pp + i; + + /* save state of linear scan parameters 0 */ + /* Do this when in table mode so operator is not confused */ + precPvt->posParms[i].p_sp = pPosFields->p_sp; + precPvt->posParms[i].p_si = pPosFields->p_si; + precPvt->posParms[i].p_ep = pPosFields->p_ep; + precPvt->posParms[i].p_cp = pPosFields->p_cp; + precPvt->posParms[i].p_wd = pPosFields->p_wd; +} + +static void zeroPosParms(struct scanRecord *pscan, unsigned short i) +{ + + recPvtStruct *precPvt = (recPvtStruct *)pscan->rpvt; + posFields *pPosFields = (posFields *)&pscan->p1pp + i; + + /* set them to 0 */ + /* Do this when in table mode so operator is not confused */ + pPosFields->p_sp = 0; + db_post_events(pscan,&pPosFields->p_sp, DBE_VALUE); + pPosFields->p_si = 0; + db_post_events(pscan,&pPosFields->p_si, DBE_VALUE); + pPosFields->p_ep = 0; + db_post_events(pscan,&pPosFields->p_ep, DBE_VALUE); + pPosFields->p_cp = 0; + db_post_events(pscan,&pPosFields->p_cp, DBE_VALUE); + pPosFields->p_wd = 0; + db_post_events(pscan,&pPosFields->p_wd, DBE_VALUE); } static void resetFrzFlags(pscan) struct scanRecord *pscan; { - struct recPvtStruct *precPvt = (struct recPvtStruct *)pscan->rpvt; + recPvtStruct *precPvt = (recPvtStruct *)pscan->rpvt; + posFields *pPosFields = (posFields *)&pscan->p1pp; + int i; /* reset each frzFlag, post monitor if changed */ @@ -2198,117 +2939,44 @@ static void resetFrzFlags(pscan) db_post_events(pscan,&pscan->fpts, DBE_VALUE); } - if(pscan->p1fs) { - pscan->p1fs = 0; - db_post_events(pscan,&pscan->p1fs, DBE_VALUE); - } + for(i=0; ip_fs) { + pPosFields->p_fs = 0; + db_post_events(pscan,&pPosFields->p_fs, DBE_VALUE); + } - if(pscan->p1fi) { - pscan->p1fi = 0; - db_post_events(pscan,&pscan->p1fi, DBE_VALUE); - } + if(pPosFields->p_fi) { + pPosFields->p_fi = 0; + db_post_events(pscan,&pPosFields->p_fi, DBE_VALUE); + } - if(pscan->p1fc) { - pscan->p1fc = 0; - db_post_events(pscan,&pscan->p1fc, DBE_VALUE); - } + if(pPosFields->p_fc) { + pPosFields->p_fc = 0; + db_post_events(pscan,&pPosFields->p_fc, DBE_VALUE); + } - if(pscan->p1fe) { - pscan->p1fe = 0; - db_post_events(pscan,&pscan->p1fe, DBE_VALUE); - } + if(pPosFields->p_fe) { + pPosFields->p_fe = 0; + db_post_events(pscan,&pPosFields->p_fe, DBE_VALUE); + } - if(pscan->p1fw) { - pscan->p1fw = 0; - db_post_events(pscan,&pscan->p1fw, DBE_VALUE); - } - - if(pscan->p2fs) { - pscan->p2fs = 0; - db_post_events(pscan,&pscan->p2fs, DBE_VALUE); - } - - if(pscan->p2fi) { - pscan->p2fi = 0; - db_post_events(pscan,&pscan->p2fi, DBE_VALUE); - } - - if(pscan->p2fc) { - pscan->p2fc = 0; - db_post_events(pscan,&pscan->p2fc, DBE_VALUE); - } - - if(pscan->p2fe) { - pscan->p2fe = 0; - db_post_events(pscan,&pscan->p2fe, DBE_VALUE); - } - - if(pscan->p2fw) { - pscan->p2fw = 0; - db_post_events(pscan,&pscan->p2fw, DBE_VALUE); - } - - if(pscan->p3fs) { - pscan->p3fs = 0; - db_post_events(pscan,&pscan->p3fs, DBE_VALUE); - } - - if(pscan->p3fi) { - pscan->p3fi = 0; - db_post_events(pscan,&pscan->p3fi, DBE_VALUE); - } - - if(pscan->p3fc) { - pscan->p3fc = 0; - db_post_events(pscan,&pscan->p3fc, DBE_VALUE); - } - - if(pscan->p3fe) { - pscan->p3fe = 0; - db_post_events(pscan,&pscan->p3fe, DBE_VALUE); - } - - if(pscan->p3fw) { - pscan->p3fw = 0; - db_post_events(pscan,&pscan->p3fw, DBE_VALUE); - } - - if(pscan->p4fs) { - pscan->p4fs = 0; - db_post_events(pscan,&pscan->p4fs, DBE_VALUE); - } - - if(pscan->p4fi) { - pscan->p4fi = 0; - db_post_events(pscan,&pscan->p4fi, DBE_VALUE); - } - - if(pscan->p4fc) { - pscan->p4fc = 0; - db_post_events(pscan,&pscan->p4fc, DBE_VALUE); - } - - if(pscan->p4fe) { - pscan->p4fe = 0; - db_post_events(pscan,&pscan->p4fe, DBE_VALUE); - } - - if(pscan->p4fw) { - pscan->p4fw = 0; - db_post_events(pscan,&pscan->p4fw, DBE_VALUE); + if(pPosFields->p_fw) { + pPosFields->p_fw = 0; + db_post_events(pscan,&pPosFields->p_fw, DBE_VALUE); + } } } - - - /* Restores Freeze Flags to the state they were in */ static void restoreFrzFlags(pscan) struct scanRecord *pscan; { - struct recPvtStruct *precPvt = (struct recPvtStruct *)pscan->rpvt; + recPvtStruct *precPvt = (recPvtStruct *)pscan->rpvt; + posFields *pPosFields = (posFields *)&pscan->p1pp; + int i; + /* restore state of each freeze flag, post if changed */ pscan->fpts = precPvt->fpts; @@ -2316,105 +2984,56 @@ static void restoreFrzFlags(pscan) db_post_events(pscan,&pscan->fpts, DBE_VALUE); } - pscan->p1fs = precPvt->p1fs; - if(pscan->p1fs) { - db_post_events(pscan,&pscan->p1fs, DBE_VALUE); - } + for(i=0; ip_fs = precPvt->posParms[i].p_fs; + if(pPosFields->p_fs) { + db_post_events(pscan,&pPosFields->p_fs, DBE_VALUE); + } - pscan->p1fi = precPvt->p1fi; - if(pscan->p1fi) { - db_post_events(pscan,&pscan->p1fi, DBE_VALUE); - } + pPosFields->p_fi = precPvt->posParms[i].p_fi; + if(pPosFields->p_fi) { + db_post_events(pscan,&pPosFields->p_fi, DBE_VALUE); + } - pscan->p1fc = precPvt->p1fc; - if(pscan->p1fc) { - db_post_events(pscan,&pscan->p1fc, DBE_VALUE); - } + pPosFields->p_fc = precPvt->posParms[i].p_fc; + if(pPosFields->p_fc) { + db_post_events(pscan,&pPosFields->p_fc, DBE_VALUE); + } - pscan->p1fe = precPvt->p1fe; - if(pscan->p1fe) { - db_post_events(pscan,&pscan->p1fe, DBE_VALUE); - } + pPosFields->p_fe = precPvt->posParms[i].p_fe; + if(pPosFields->p_fe) { + db_post_events(pscan,&pPosFields->p_fe, DBE_VALUE); + } - pscan->p1fw = precPvt->p1fw; - if(pscan->p1fw) { - db_post_events(pscan,&pscan->p1fw, DBE_VALUE); - } + pPosFields->p_fw = precPvt->posParms[i].p_fw; + if(pPosFields->p_fw) { + db_post_events(pscan,&pPosFields->p_fw, DBE_VALUE); + } - pscan->p2fs = precPvt->p2fs; - if(pscan->p2fs) { - db_post_events(pscan,&pscan->p2fs, DBE_VALUE); } +} - pscan->p2fi = precPvt->p2fi; - if(pscan->p2fi) { - db_post_events(pscan,&pscan->p2fi, DBE_VALUE); - } +/* Restores Position Parms after leaving table mode (for 1 positioner) */ +static void restorePosParms(struct scanRecord *pscan, unsigned short i) +{ - pscan->p2fc = precPvt->p2fc; - if(pscan->p2fc) { - db_post_events(pscan,&pscan->p2fc, DBE_VALUE); - } + recPvtStruct *precPvt = (recPvtStruct *)pscan->rpvt; + posFields *pPosFields = (posFields *)&pscan->p1pp + i; - pscan->p2fe = precPvt->p2fe; - if(pscan->p2fe) { - db_post_events(pscan,&pscan->p2fe, DBE_VALUE); - } + pPosFields->p_sp = precPvt->posParms[i].p_sp; + db_post_events(pscan,&pPosFields->p_sp, DBE_VALUE); - pscan->p2fw = precPvt->p2fw; - if(pscan->p2fw) { - db_post_events(pscan,&pscan->p2fw, DBE_VALUE); - } + pPosFields->p_si = precPvt->posParms[i].p_si; + db_post_events(pscan,&pPosFields->p_si, DBE_VALUE); - pscan->p3fs = precPvt->p3fs; - if(pscan->p3fs) { - db_post_events(pscan,&pscan->p3fs, DBE_VALUE); - } + pPosFields->p_ep = precPvt->posParms[i].p_ep; + db_post_events(pscan,&pPosFields->p_ep, DBE_VALUE); - pscan->p3fi = precPvt->p3fi; - if(pscan->p3fi) { - db_post_events(pscan,&pscan->p3fi, DBE_VALUE); - } + pPosFields->p_cp = precPvt->posParms[i].p_cp; + db_post_events(pscan,&pPosFields->p_cp, DBE_VALUE); - pscan->p3fc = precPvt->p3fc; - if(pscan->p3fc) { - db_post_events(pscan,&pscan->p3fc, DBE_VALUE); - } - - pscan->p3fe = precPvt->p3fe; - if(pscan->p3fe) { - db_post_events(pscan,&pscan->p3fe, DBE_VALUE); - } - - pscan->p3fw = precPvt->p3fw; - if(pscan->p3fw) { - db_post_events(pscan,&pscan->p3fw, DBE_VALUE); - } - - pscan->p4fs = precPvt->p4fs; - if(pscan->p4fs) { - db_post_events(pscan,&pscan->p4fs, DBE_VALUE); - } - - pscan->p4fi = precPvt->p4fi; - if(pscan->p4fi) { - db_post_events(pscan,&pscan->p4fi, DBE_VALUE); - } - - pscan->p4fc = precPvt->p4fc; - if(pscan->p4fc) { - db_post_events(pscan,&pscan->p4fc, DBE_VALUE); - } - - pscan->p4fe = precPvt->p4fe; - if(pscan->p4fe) { - db_post_events(pscan,&pscan->p4fe, DBE_VALUE); - } - - pscan->p4fw = precPvt->p4fw; - if(pscan->p4fw) { - db_post_events(pscan,&pscan->p4fw, DBE_VALUE); - } + pPosFields->p_wd = precPvt->posParms[i].p_wd; + db_post_events(pscan,&pPosFields->p_wd, DBE_VALUE); }