3041 lines
112 KiB
C
3041 lines
112 KiB
C
/*
|
|
* Original Author: Ned D. Arnold
|
|
* Date: 07-18-94
|
|
*
|
|
* Experimental Physics and Industrial Control System (EPICS)
|
|
*
|
|
* Copyright 1991, the Regents of the University of California,
|
|
* and the University of Chicago Board of Governors.
|
|
*
|
|
* This software was produced under U.S. Government contracts:
|
|
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
|
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
|
*
|
|
* Initial development by:
|
|
* The Controls and Automation Group (AT-8)
|
|
* Ground Test Accelerator
|
|
* Accelerator Technology Division
|
|
* Los Alamos National Laboratory
|
|
*
|
|
* Co-developed with
|
|
* The Controls and Computing Group
|
|
* Accelerator Systems Division
|
|
* Advanced Photon Source
|
|
* Argonne National Laboratory
|
|
*
|
|
*
|
|
* Modification Log:
|
|
* -----------------
|
|
* .01 07-18-94 nda significantly expanded functionality from prototype
|
|
* .02 08-18-94 nda Starting with R3.11.6, dbGetField locks the record
|
|
* before fetching the data. This can cause deadlocks
|
|
* within a database. Change all dbGetField() to dbGet()
|
|
* .03 08-23-94 nda added code for checking/adjusting linear scan
|
|
* params (it gets a little messy !)
|
|
* .04 08-25-94 nda Added check of scan positions vs Positioner Control
|
|
* Limits
|
|
* .05 08-29-94 nda Added "viewScanPos" that puts desired positions
|
|
* in D1 array any time a scan parameter is changed
|
|
* .06 10-03-94 nda added code for enumerated string .CMND. Changed
|
|
* .EXSC to a SHORT in record definition. Added VERSION
|
|
* for .VERS field (1.06) to keep track of version.
|
|
* .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 3.00
|
|
|
|
|
|
|
|
#include <vxWorks.h>
|
|
#include <types.h>
|
|
#include <stdioLib.h>
|
|
#include <lstLib.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
#include <tickLib.h>
|
|
#include <semLib.h>
|
|
#include <taskLib.h>
|
|
|
|
#include <alarm.h>
|
|
#include <cvtTable.h>
|
|
#include <dbDefs.h>
|
|
#include <dbAccess.h>
|
|
#include <dbRecDes.h>
|
|
#include <dbScan.h>
|
|
#include <dbDefs.h>
|
|
#include <dbFldTypes.h>
|
|
#include <devSup.h>
|
|
#include <errMdef.h>
|
|
#include <recSup.h>
|
|
#include <special.h>
|
|
#include <choiceScan.h>
|
|
#include <scanRecord.h>
|
|
#include <callback.h>
|
|
#include <taskwd.h>
|
|
#include <drvTS.h> /* also includes timers.h and tsDefs.h */
|
|
|
|
#include <recDynLink.h>
|
|
|
|
|
|
/***************************
|
|
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
|
|
#define initialize NULL
|
|
static long init_record();
|
|
static long process();
|
|
static long special();
|
|
static long get_value();
|
|
static long cvt_dbaddr();
|
|
static long get_array_info();
|
|
static long put_array_info();
|
|
static long get_units();
|
|
static long get_precision();
|
|
static long get_enum_str();
|
|
static long get_enum_strs();
|
|
static long put_enum_str();
|
|
static long get_graphic_double();
|
|
static long get_control_double();
|
|
static long get_alarm_double();
|
|
|
|
struct rset scanRSET={
|
|
RSETNUMBER,
|
|
report,
|
|
initialize,
|
|
init_record,
|
|
process,
|
|
special,
|
|
get_value,
|
|
cvt_dbaddr,
|
|
get_array_info,
|
|
put_array_info,
|
|
get_units,
|
|
get_precision,
|
|
get_enum_str,
|
|
get_enum_strs,
|
|
put_enum_str,
|
|
get_graphic_double,
|
|
get_control_double,
|
|
get_alarm_double
|
|
};
|
|
|
|
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;
|
|
}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 */
|
|
|
|
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 */
|
|
|
|
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;
|
|
|
|
|
|
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 long initScan();
|
|
static void contScan();
|
|
static void endScan();
|
|
static void doPuts();
|
|
static void adjLinParms();
|
|
static void changedNpts();
|
|
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 recScanDebug=0;
|
|
long recScanViewPos=0;
|
|
long recScanDontCheckLimits=0;
|
|
|
|
|
|
static long init_record(pscan,pass)
|
|
struct scanRecord *pscan;
|
|
int pass;
|
|
{
|
|
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;
|
|
|
|
/* First time through, rpvt needs initialized */
|
|
pscan->rpvt = calloc(1, sizeof(recPvtStruct));
|
|
precPvt = (recPvtStruct *)pscan->rpvt;
|
|
|
|
precPvt->phase = IDLE;
|
|
|
|
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; i<NUM_RDKS; i++, pPosFields++) {
|
|
precPvt->posBufPtr[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; i<NUM_DET; i++, pDetFields++) {
|
|
puserPvt = (recDynLinkPvt *)precPvt->caLinkStruct[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;
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
callbackSetCallback(doPuts, &precPvt->doPutsCallback);
|
|
callbackSetPriority(pscan->prio, &precPvt->doPutsCallback);
|
|
|
|
/* initialize all linear scan fields */
|
|
precPvt->nptsCause = -1; /* resolve all positioner parameters */
|
|
changedNpts(pscan);
|
|
|
|
if(pscan->ffo) {
|
|
saveFrzFlags(pscan);
|
|
resetFrzFlags(pscan);
|
|
}
|
|
|
|
/* 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;i<NUM_PVS; i++, pPvStat++, *ppvn += PVN_SIZE) {
|
|
if(*ppvn[0] != NULL) {
|
|
*pPvStat = PV_NC;
|
|
lookupPV(pscan, i);
|
|
}
|
|
else {
|
|
*pPvStat = NO_PV;
|
|
}
|
|
}
|
|
|
|
|
|
return(0);
|
|
}
|
|
|
|
static long process(pscan)
|
|
struct scanRecord *pscan;
|
|
{
|
|
recPvtStruct *precPvt = (recPvtStruct *)pscan->rpvt;
|
|
long status = 0;
|
|
|
|
|
|
/* 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);
|
|
}
|
|
|
|
checkMonitors(pscan);
|
|
|
|
/* do forward link on last scan aquisition */
|
|
if ((pscan->pxsc == 1) && (pscan->exsc == 0)) {
|
|
recGblFwdLink(pscan); /* process the forward scan link record */
|
|
if(recScanDebug) {
|
|
printf("Scan Time = %.2f ms\n",
|
|
(float)((tickGet()-(precPvt->tickStart))*16.67));
|
|
}
|
|
|
|
}
|
|
|
|
pscan->pxsc = pscan->exsc;
|
|
recGblResetAlarms(pscan);
|
|
|
|
pscan->pact = FALSE;
|
|
return(status);
|
|
}
|
|
|
|
static long special(paddr,after)
|
|
struct dbAddr *paddr;
|
|
int after;
|
|
{
|
|
struct scanRecord *pscan = (struct scanRecord *)(paddr->precord);
|
|
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;
|
|
|
|
if(!after) {
|
|
precPvt->pffo = pscan->ffo; /* save previous ffo flag */
|
|
return(0);
|
|
}
|
|
switch(special_type) {
|
|
case(SPC_MOD):
|
|
if(paddr->pfield==(void *)&pscan->exsc) {
|
|
pscan->alrt = 0;
|
|
db_post_events(pscan,&pscan->alrt, DBE_VALUE);
|
|
/* 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) && !(pscan->exsc)) {
|
|
prevAlrt = pscan->alrt;
|
|
pscan->alrt = 0;
|
|
checkScanLimits(pscan);
|
|
db_post_events(pscan,&pscan->smsg,DBE_VALUE);
|
|
if(pscan->alrt != prevAlrt) {
|
|
db_post_events(pscan,&pscan->alrt,DBE_VALUE);
|
|
}
|
|
}
|
|
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; i<NUM_POS; i++, pPosFields++) {
|
|
if(paddr->pfield==(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):
|
|
case(SPC_SC_C):
|
|
case(SPC_SC_W):
|
|
/* resolve linear scan parameters affected by this fields change */
|
|
prevAlrt = pscan->alrt;
|
|
pscan->alrt = 0;
|
|
sprintf(pscan->smsg,"");
|
|
adjLinParms(paddr);
|
|
db_post_events(pscan,&pscan->smsg,DBE_VALUE);
|
|
if(pscan->alrt != prevAlrt) {
|
|
db_post_events(pscan,&pscan->alrt,DBE_VALUE);
|
|
}
|
|
if(recScanViewPos) {
|
|
previewScan(pscan);
|
|
}
|
|
break;
|
|
|
|
case(SPC_SC_N):
|
|
/* adjust all linear scan parameters per new # of steps */
|
|
if(pscan->npts > pscan->mpts) {
|
|
pscan->npts = pscan->mpts;
|
|
db_post_events(pscan,&pscan->npts,DBE_VALUE);
|
|
}
|
|
prevAlrt = pscan->alrt;
|
|
pscan->alrt = 0;
|
|
sprintf(pscan->smsg,"");
|
|
precPvt->nptsCause = -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(recScanViewPos) {
|
|
previewScan(pscan);
|
|
}
|
|
break;
|
|
|
|
case(SPC_SC_FFO):
|
|
/* Freeze Flag Override field */
|
|
if((pscan->ffo) && (!precPvt->pffo)) {
|
|
saveFrzFlags(pscan);
|
|
resetFrzFlags(pscan);
|
|
}
|
|
else if(!pscan->ffo && precPvt->pffo) /* only on 1->0 */
|
|
restoreFrzFlags(pscan);
|
|
|
|
break;
|
|
|
|
case(SPC_SC_F):
|
|
/* Freeze Flag Override field */
|
|
if(pscan->ffo)
|
|
resetFrzFlags(pscan);
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
/* 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(i<NUM_POS)
|
|
recDynLinkClear(&precPvt->caLinkStruct[i+NUM_PVS]);
|
|
}
|
|
else puserPvt->dbAddrNv = -1;
|
|
}
|
|
else {
|
|
/* PV is NULL, but previously MAY have been "time" */
|
|
puserPvt->ts = 0;
|
|
}
|
|
}
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
static long cvt_dbaddr(paddr)
|
|
struct dbAddr *paddr;
|
|
{
|
|
struct scanRecord *pscan=(struct scanRecord *)paddr->precord;
|
|
|
|
recPvtStruct *precPvt = (recPvtStruct *)pscan->rpvt;
|
|
posFields *pPosFields = (posFields *)&pscan->p1pp;
|
|
detFields *pDetFields = (detFields *)&pscan->d1hr;
|
|
short fieldOffset;
|
|
unsigned short i;
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
static long get_array_info(paddr,no_elements,offset)
|
|
struct dbAddr *paddr;
|
|
long *no_elements;
|
|
long *offset;
|
|
{
|
|
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;
|
|
|
|
/* 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) ||
|
|
((i<NUM_POS) && (precPvt->phase == 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) {
|
|
*no_elements = pscan->mpts;
|
|
*offset = 0;
|
|
} else if (paddr->pfield == pscan->p3pa) {
|
|
*no_elements = pscan->mpts;
|
|
*offset = 0;
|
|
} else if (paddr->pfield == pscan->p4pa) {
|
|
*no_elements = pscan->mpts;
|
|
*offset = 0;
|
|
} else {
|
|
*no_elements = 0;
|
|
*offset = 0;
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
static long put_array_info(paddr,nNew)
|
|
struct dbAddr *paddr;
|
|
long nNew;
|
|
{
|
|
struct scanRecord *pscan=(struct scanRecord *)paddr->precord;
|
|
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;
|
|
|
|
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);
|
|
}
|
|
|
|
|
|
static long get_enum_str(paddr,pstring)
|
|
struct dbAddr *paddr;
|
|
char *pstring;
|
|
{
|
|
struct scanRecord *pscan=(struct scanRecord *)paddr->precord;
|
|
|
|
if(paddr->pfield==(void *)&pscan->cmnd)
|
|
{
|
|
sprintf(pstring, "%d",pscan->cmnd);
|
|
}
|
|
else
|
|
{
|
|
strcpy(pstring,"No string");
|
|
}
|
|
return(0);
|
|
}
|
|
static long get_enum_strs(paddr,pes)
|
|
struct dbAddr *paddr;
|
|
struct dbr_enumStrs *pes;
|
|
{
|
|
struct scanRecord *pscan=(struct scanRecord *)paddr->precord;
|
|
|
|
if(paddr->pfield==(void *)&pscan->cmnd)
|
|
{
|
|
memset(pes->strs,'\0',sizeof(pes->strs));
|
|
strncpy(pes->strs[0],"0-Clear Msg",sizeof("0-Clear Msg"));
|
|
strncpy(pes->strs[1],"1-Check Limits",sizeof("1-Check Limits"));
|
|
pes->no_str = 2;
|
|
}
|
|
else
|
|
{
|
|
strcpy(pes->strs[0],"No string");
|
|
pes->no_str=1;
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
static long put_enum_str(paddr,pstring)
|
|
struct dbAddr *paddr;
|
|
char *pstring;
|
|
{
|
|
struct scanRecord *pscan=(struct scanRecord *)paddr->precord;
|
|
|
|
if(paddr->pfield==(void *)&pscan->cmnd)
|
|
{
|
|
if(sscanf(pstring,"%i",&pscan->cmnd)<=0)
|
|
return(S_db_badChoice);
|
|
}
|
|
else
|
|
{
|
|
return(S_db_badChoice);
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
static long get_value(pscan,pvdes)
|
|
struct scanRecord *pscan;
|
|
struct valueDes *pvdes;
|
|
{
|
|
pvdes->field_type = DBF_DOUBLE;
|
|
pvdes->no_elements=1;
|
|
(double *)(pvdes->pvalue) = &pscan->p1dv;
|
|
return(0);
|
|
}
|
|
|
|
static long get_units(paddr,units)
|
|
struct dbAddr *paddr;
|
|
char *units;
|
|
{
|
|
struct scanRecord *pscan=(struct scanRecord *)paddr->precord;
|
|
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);
|
|
}
|
|
|
|
static long get_precision(paddr,precision)
|
|
struct dbAddr *paddr;
|
|
long *precision;
|
|
{
|
|
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))) {
|
|
*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);
|
|
}
|
|
|
|
static long get_graphic_double(paddr,pgd)
|
|
struct dbAddr *paddr;
|
|
struct dbr_grDouble *pgd;
|
|
{
|
|
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))) {
|
|
pgd->upper_disp_limit = pPosFields->p_hr;
|
|
pgd->lower_disp_limit = pPosFields->p_lr;
|
|
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))) {
|
|
pgd->upper_disp_limit = pDetFields->d_hr;
|
|
pgd->lower_disp_limit = pDetFields->d_lr;
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
recGblGetGraphicDouble(paddr,pgd);
|
|
return(0);
|
|
}
|
|
|
|
static long get_control_double(paddr,pcd)
|
|
struct dbAddr *paddr;
|
|
struct dbr_ctrlDouble *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);
|
|
}
|
|
|
|
static long get_alarm_double(paddr,pad)
|
|
struct dbAddr *paddr;
|
|
struct dbr_alDouble *pad;
|
|
{
|
|
recGblGetAlarmDouble(paddr,pad);
|
|
return(0);
|
|
}
|
|
|
|
|
|
static void checkMonitors(pscan)
|
|
struct scanRecord *pscan;
|
|
{
|
|
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)*/
|
|
|
|
now=tickGet();
|
|
if(((now - pscan->tolp) > MIN_MON) ||
|
|
((pscan->pxsc == 1) && (pscan->exsc == 0))) {
|
|
pscan->tolp = now;
|
|
|
|
/* 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;
|
|
}
|
|
}
|
|
|
|
/* 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;
|
|
}
|
|
|
|
/* Post a monitor on VAL to indicate new point */
|
|
/* (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 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)) {
|
|
|
|
/* 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(i=0; i<NUM_DET; i++) {
|
|
db_post_events(pscan,precPvt->detBufPtr[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);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/**************************************************************
|
|
* 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)
|
|
{
|
|
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;
|
|
unsigned short *pPvStat;
|
|
|
|
/* 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;
|
|
|
|
/* If PV field name = DESC, change to VAL */
|
|
pdot = strrchr(*ppvn, '.');
|
|
if(pdot!=NULL) {
|
|
if(strncmp(pdot, pdesc, 5) == 0) {
|
|
strcpy(pdot, pval);
|
|
db_post_events(pscan, *ppvn, DBE_VALUE);
|
|
}
|
|
}
|
|
|
|
/* 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;
|
|
|
|
|
|
/* 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;
|
|
{
|
|
recPvtStruct *precPvt = (recPvtStruct *)pscan->rpvt;
|
|
recDynLinkPvt *puserPvt;
|
|
posFields *pPosFields;
|
|
long status;
|
|
long nRequest = 1;
|
|
long options = 0;
|
|
unsigned short *pPvStat;
|
|
int i;
|
|
|
|
|
|
/* General initialization ... */
|
|
if(recScanDebug) {
|
|
precPvt->tickStart = tickGet();
|
|
}
|
|
|
|
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(OK);
|
|
}
|
|
|
|
static void contScan(pscan)
|
|
struct scanRecord *pscan;
|
|
{
|
|
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;
|
|
|
|
switch (precPvt->phase) {
|
|
case TRIG_DETCTRS:
|
|
/* go output to detector trigger fields */
|
|
callbackRequest(&precPvt->doPutsCallback);
|
|
return;
|
|
|
|
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;
|
|
endScan(pscan);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* 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 validTrigPvs, fall through to READ_DETCTRS */
|
|
/* if on-the-fly mode, fall through to 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;
|
|
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;
|
|
|
|
pscan->cpt++;
|
|
/* Has number of points been reached ? */
|
|
if(pscan->cpt < (pscan->npts)) {
|
|
/* determine next desired position for each positioner */
|
|
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;
|
|
}
|
|
else {
|
|
endScan(pscan); /* scan is successfully complete */
|
|
sprintf(pscan->smsg,"SCAN Complete");
|
|
db_post_events(pscan,&pscan->smsg,DBE_VALUE);
|
|
precPvt->scanErr = 0;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void endScan(pscan)
|
|
struct scanRecord *pscan;
|
|
{
|
|
|
|
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
|
|
array with 0 or something ? */
|
|
/* It turns out that medm plots the whole array, so for it
|
|
to look right the remainder of the arrays will be filled
|
|
with the last values. This will cause medm to plot the
|
|
same point over and over again, but it will look correct */
|
|
|
|
counter = pscan->cpt;
|
|
if(recScanDebug) {
|
|
printf("endScan(): Fill Counter - %d\n",counter);
|
|
}
|
|
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];
|
|
|
|
precPvt->posBufPtr[1].pFill[counter] =
|
|
precPvt->posBufPtr[1].pFill[counter-1];
|
|
|
|
precPvt->posBufPtr[2].pFill[counter] =
|
|
precPvt->posBufPtr[2].pFill[counter-1];
|
|
|
|
precPvt->posBufPtr[3].pFill[counter] =
|
|
precPvt->posBufPtr[3].pFill[counter-1];
|
|
|
|
counter++;
|
|
}
|
|
|
|
/* 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;
|
|
}
|
|
}
|
|
|
|
pscan->exsc = 0; /* done with scan */
|
|
|
|
/* 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->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 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)
|
|
recPvtStruct *precPvt;
|
|
{
|
|
recDynLinkPvt *puserPvt;
|
|
posFields *pPosFields;
|
|
unsigned short *pPvStat;
|
|
int i;
|
|
long status;
|
|
long nRequest = 1;
|
|
|
|
switch (precPvt->phase) {
|
|
case MOVE_MOTORS:
|
|
if(recScanDebug >=5) {
|
|
printf("MOVE_MOTORS - Point %d\n",precPvt->pscan->cpt);
|
|
}
|
|
/* Schedule the next phase as CHECK_MOTORS */
|
|
precPvt->phase = CHECK_MOTORS;
|
|
|
|
pPosFields = (posFields *)&precPvt->pscan->p1pp;
|
|
pPvStat = &precPvt->pscan->p1nv;
|
|
|
|
/* for each valid positioner, write the desired position */
|
|
/* 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);
|
|
}
|
|
}
|
|
}
|
|
|
|
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 */
|
|
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) {
|
|
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) {
|
|
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:
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/* routine to resolve and adjust linear scan definition.
|
|
* Might get complicated !!!
|
|
*/
|
|
|
|
static void adjLinParms(paddr)
|
|
struct dbAddr *paddr;
|
|
{
|
|
struct scanRecord *pscan = (struct scanRecord *)(paddr->precord);
|
|
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 */
|
|
for(i=0; i<NUM_POS; i++, pParms++) {
|
|
if ((paddr->pfield >= (void *)&pParms->p_pp) &&
|
|
(paddr->pfield <= (void *)&pParms->p_pr)) {
|
|
|
|
foundOne = 1;
|
|
break;
|
|
}
|
|
}
|
|
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 */
|
|
if(!pParms->p_fi && !pParms->p_fc && !pParms->p_fw) {
|
|
pParms->p_si = (pParms->p_ep - pParms->p_sp)/(pscan->npts - 1);
|
|
db_post_events(pscan,&pParms->p_si,DBE_VALUE);
|
|
pParms->p_cp = (pParms->p_ep + pParms->p_sp)/2;
|
|
db_post_events(pscan,&pParms->p_cp,DBE_VALUE);
|
|
pParms->p_wd = (pParms->p_ep - pParms->p_sp);
|
|
db_post_events(pscan,&pParms->p_wd,DBE_VALUE);
|
|
return;
|
|
/* if end/center are not frozen, change them */
|
|
} else if(!pParms->p_fe && !pParms->p_fc) {
|
|
pParms->p_ep = pParms->p_sp +
|
|
((pscan->npts - 1) * pParms->p_si);
|
|
db_post_events(pscan,&pParms->p_ep,DBE_VALUE);
|
|
pParms->p_cp = (pParms->p_ep + pParms->p_sp)/2;
|
|
db_post_events(pscan,&pParms->p_cp,DBE_VALUE);
|
|
return;
|
|
/* if step increment/end/width are not frozen, change them */
|
|
} else if(!pParms->p_fi && !pParms->p_fe && !pParms->p_fw) {
|
|
pParms->p_wd = (pParms->p_cp - pParms->p_sp) * 2;
|
|
db_post_events(pscan,&pParms->p_wd,DBE_VALUE);
|
|
pParms->p_si = pParms->p_wd/(pscan->npts - 1);
|
|
db_post_events(pscan,&pParms->p_si,DBE_VALUE);
|
|
pParms->p_ep = (pParms->p_sp + pParms->p_wd);
|
|
db_post_events(pscan,&pParms->p_ep,DBE_VALUE);
|
|
return;
|
|
/* if # of points/center/width are not frozen, change them */
|
|
} else if(!pscan->fpts && !pParms->p_fc && !pParms->p_fw) {
|
|
pscan->npts = ((pParms->p_ep - pParms->p_sp)/(pParms->p_si)) + 1;
|
|
if(pscan->npts > pscan->mpts) {
|
|
pscan->npts = pscan->mpts;
|
|
sprintf(pscan->smsg,"P%1d Request Exceeded Maximum Points!",i+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;
|
|
db_post_events(pscan,&pParms->p_cp,DBE_VALUE);
|
|
pParms->p_wd = (pParms->p_ep - pParms->p_sp);
|
|
db_post_events(pscan,&pParms->p_wd,DBE_VALUE);
|
|
precPvt->nptsCause = i; /* indicate cause of # of points changed */
|
|
changedNpts(pscan);
|
|
return;
|
|
/* if # of points/end/width are not frozen, change them */
|
|
} else if(!pscan->fpts && !pParms->p_fe && !pParms->p_fw) {
|
|
pscan->npts = ((pParms->p_cp - pParms->p_sp)*2/(pParms->p_si)) + 1;
|
|
if(pscan->npts > pscan->mpts) {
|
|
pscan->npts = pscan->mpts;
|
|
sprintf(pscan->smsg,"P%1d Request Exceeded Maximum Points!",i+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);
|
|
db_post_events(pscan,&pParms->p_cp,DBE_VALUE);
|
|
pParms->p_wd = (pParms->p_ep - pParms->p_sp);
|
|
db_post_events(pscan,&pParms->p_wd,DBE_VALUE);
|
|
precPvt->nptsCause = i; /* indicate cause of # of points changed */
|
|
changedNpts(pscan);
|
|
return;
|
|
/* if center/end are not frozen, change them */
|
|
} else if(!pParms->p_fc && !pParms->p_fe) {
|
|
pParms->p_ep = pParms->p_sp + ((pscan->npts - 1) * pParms->p_si);
|
|
db_post_events(pscan,&pParms->p_ep,DBE_VALUE);
|
|
pParms->p_cp = (pParms->p_ep + pParms->p_sp)/2;
|
|
db_post_events(pscan,&pParms->p_cp,DBE_VALUE);
|
|
return;
|
|
} else { /* too constrained !! */
|
|
pParms->p_sp = pParms->p_ep - ((pscan->npts - 1) * pParms->p_si);
|
|
db_post_events(pscan,&pParms->p_sp,DBE_VALUE);
|
|
sprintf(pscan->smsg,"P%1d SCAN Parameters Too Constrained !",i+1);
|
|
pscan->alrt = 1;
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case(SPC_SC_I): /* step increment changed */
|
|
/* if end/center/width are not frozen, change them */
|
|
if(!pParms->p_fe && !pParms->p_fc && !pParms->p_fw) {
|
|
pParms->p_ep = pParms->p_sp + ((pscan->npts - 1) * pParms->p_si);
|
|
db_post_events(pscan,&pParms->p_ep,DBE_VALUE);
|
|
pParms->p_cp = (pParms->p_ep + pParms->p_sp)/2;
|
|
db_post_events(pscan,&pParms->p_cp,DBE_VALUE);
|
|
pParms->p_wd = (pParms->p_ep - pParms->p_sp);
|
|
db_post_events(pscan,&pParms->p_wd,DBE_VALUE);
|
|
return;
|
|
/* if start/center/width are not frozen, change them */
|
|
} else if(!pParms->p_fs && !pParms->p_fc && !pParms->p_fw) {
|
|
pParms->p_sp = pParms->p_ep - ((pscan->npts - 1) * pParms->p_si);
|
|
db_post_events(pscan,&pParms->p_sp,DBE_VALUE);
|
|
pParms->p_cp = (pParms->p_ep + pParms->p_sp)/2;
|
|
db_post_events(pscan,&pParms->p_cp,DBE_VALUE);
|
|
pParms->p_wd = (pParms->p_ep - pParms->p_sp);
|
|
db_post_events(pscan,&pParms->p_wd,DBE_VALUE);
|
|
return;
|
|
/* if start/end/width are not frozen, change them */
|
|
} else if(!pParms->p_fs && !pParms->p_fe && !pParms->p_fw) {
|
|
pParms->p_sp = pParms->p_cp - ((pscan->npts - 1) * pParms->p_si)/2;
|
|
db_post_events(pscan,&pParms->p_sp,DBE_VALUE);
|
|
pParms->p_ep = pParms->p_sp + ((pscan->npts - 1) * pParms->p_si);
|
|
db_post_events(pscan,&pParms->p_ep,DBE_VALUE);
|
|
pParms->p_wd = (pParms->p_ep - pParms->p_sp);
|
|
db_post_events(pscan,&pParms->p_wd,DBE_VALUE);
|
|
return;
|
|
/* if # of points is not frozen, change it */
|
|
} else if(!pscan->fpts) {
|
|
pscan->npts = ((pParms->p_ep - pParms->p_sp)/(pParms->p_si)) + 1;
|
|
if(pscan->npts > pscan->mpts) {
|
|
pscan->npts = pscan->mpts;
|
|
sprintf(pscan->smsg,"P%1d Request Exceeded Maximum Points !",i+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 */
|
|
changedNpts(pscan);
|
|
return;
|
|
} else { /* too constrained !! */
|
|
pParms->p_si = (pParms->p_ep - pParms->p_sp)/(pscan->npts - 1);
|
|
db_post_events(pscan,&pParms->p_si,DBE_VALUE);
|
|
sprintf(pscan->smsg,"P%1d SCAN Parameters Too Constrained !",i+1);
|
|
pscan->alrt = 1;
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case(SPC_SC_E): /* end position changed */
|
|
/* if step increment/center/width are not frozen, change them */
|
|
if(!pParms->p_fi && !pParms->p_fc && !pParms->p_fw) {
|
|
pParms->p_si = (pParms->p_ep - pParms->p_sp)/(pscan->npts - 1);
|
|
db_post_events(pscan,&pParms->p_si,DBE_VALUE);
|
|
pParms->p_cp = (pParms->p_ep + pParms->p_sp)/2;
|
|
db_post_events(pscan,&pParms->p_cp,DBE_VALUE);
|
|
pParms->p_wd = (pParms->p_ep - pParms->p_sp);
|
|
db_post_events(pscan,&pParms->p_wd,DBE_VALUE);
|
|
return;
|
|
/* if start/center/width are not frozen, change them */
|
|
} else if(!pParms->p_fs && !pParms->p_fc && !pParms->p_fw) {
|
|
pParms->p_sp = pParms->p_ep - ((pscan->npts - 1) * pParms->p_si);
|
|
db_post_events(pscan,&pParms->p_sp,DBE_VALUE);
|
|
pParms->p_cp = (pParms->p_ep + pParms->p_sp)/2;
|
|
db_post_events(pscan,&pParms->p_cp,DBE_VALUE);
|
|
pParms->p_wd = (pParms->p_ep - pParms->p_sp);
|
|
db_post_events(pscan,&pParms->p_wd,DBE_VALUE);
|
|
return;
|
|
/* if step start/width/increment are not frozen, change them */
|
|
} else if(!pParms->p_fs && !pParms->p_fw && !pParms->p_fi) {
|
|
pParms->p_wd = (pParms->p_ep - pParms->p_cp) * 2;
|
|
db_post_events(pscan,&pParms->p_wd,DBE_VALUE);
|
|
pParms->p_sp = pParms->p_ep - pParms->p_wd;
|
|
db_post_events(pscan,&pParms->p_sp,DBE_VALUE);
|
|
pParms->p_si = (pParms->p_ep - pParms->p_sp)/(pscan->npts - 1);
|
|
db_post_events(pscan,&pParms->p_si,DBE_VALUE);
|
|
return;
|
|
/* if # of points/start/width are not frozen, change them */
|
|
} else if(!pscan->fpts && !pParms->p_fs && !pParms->p_fw) {
|
|
pscan->npts=(((pParms->p_ep - pParms->p_cp)*2)/(pParms->p_si)) + 1;
|
|
if(pscan->npts > pscan->mpts) {
|
|
pscan->npts = pscan->mpts;
|
|
sprintf(pscan->smsg,"P%1d Request Exceeded Maximum Points !",i+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;
|
|
db_post_events(pscan,&pParms->p_wd,DBE_VALUE);
|
|
pParms->p_sp = pParms->p_ep - pParms->p_wd;
|
|
db_post_events(pscan,&pParms->p_sp,DBE_VALUE);
|
|
precPvt->nptsCause = i; /* indicate cause of # of points changed */
|
|
changedNpts(pscan);
|
|
return;
|
|
/* if # of points/center/width are not frozen, change them */
|
|
} else if(!pscan->fpts && !pParms->p_fc && !pParms->p_fw) {
|
|
pscan->npts = ((pParms->p_ep - pParms->p_sp)/(pParms->p_si)) + 1;
|
|
if(pscan->npts > pscan->mpts) {
|
|
pscan->npts = pscan->mpts;
|
|
sprintf(pscan->smsg,"P%1d Request Exceeded Maximum Points !",i+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;
|
|
db_post_events(pscan,&pParms->p_cp,DBE_VALUE);
|
|
pParms->p_wd = (pParms->p_ep - pParms->p_sp);
|
|
db_post_events(pscan,&pParms->p_wd,DBE_VALUE);
|
|
precPvt->nptsCause = i; /* indicate cause of # of points changed */
|
|
changedNpts(pscan);
|
|
return;
|
|
/* if start/center are not frozen, change them */
|
|
} else if(!pParms->p_fs && !pParms->p_fc) {
|
|
pParms->p_sp = pParms->p_ep - ((pscan->npts - 1) * pParms->p_si);
|
|
db_post_events(pscan,&pParms->p_sp,DBE_VALUE);
|
|
pParms->p_cp = (pParms->p_ep + pParms->p_sp)/2;
|
|
db_post_events(pscan,&pParms->p_cp,DBE_VALUE);
|
|
return;
|
|
} else { /* too constrained !! */
|
|
pParms->p_ep = pParms->p_sp + ((pscan->npts - 1) * pParms->p_si);
|
|
db_post_events(pscan,&pParms->p_ep,DBE_VALUE);
|
|
sprintf(pscan->smsg,"P%1d SCAN Parameters Too Constrained !",i+1);
|
|
pscan->alrt = 1;
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case(SPC_SC_C): /* center position changed */
|
|
/* if start/end are not frozen, change them */
|
|
if(!pParms->p_fs && !pParms->p_fe) {
|
|
pParms->p_sp = pParms->p_cp - ((pscan->npts - 1) * pParms->p_si)/2;
|
|
db_post_events(pscan,&pParms->p_sp,DBE_VALUE);
|
|
pParms->p_ep = pParms->p_sp + ((pscan->npts - 1) * pParms->p_si);
|
|
db_post_events(pscan,&pParms->p_ep,DBE_VALUE);
|
|
return;
|
|
/* if start/inc/width are not frozen, change them */
|
|
} else if(!pParms->p_fs && !pParms->p_fi && !pParms->p_fw) {
|
|
pParms->p_wd = (pParms->p_ep - pParms->p_cp)*2;
|
|
db_post_events(pscan,&pParms->p_wd,DBE_VALUE);
|
|
pParms->p_sp = pParms->p_ep - pParms->p_wd;
|
|
db_post_events(pscan,&pParms->p_sp,DBE_VALUE);
|
|
pParms->p_si = (pParms->p_ep - pParms->p_sp)/(pscan->npts - 1);
|
|
db_post_events(pscan,&pParms->p_si,DBE_VALUE);
|
|
return;
|
|
/* if end/inc/width are not frozen, change them */
|
|
} else if(!pParms->p_fe && !pParms->p_fi && !pParms->p_fw) {
|
|
pParms->p_wd = (pParms->p_cp - pParms->p_sp)*2;
|
|
db_post_events(pscan,&pParms->p_wd,DBE_VALUE);
|
|
pParms->p_ep = pParms->p_sp + pParms->p_wd;
|
|
db_post_events(pscan,&pParms->p_ep,DBE_VALUE);
|
|
pParms->p_si = (pParms->p_ep - pParms->p_sp)/(pscan->npts - 1);
|
|
db_post_events(pscan,&pParms->p_si,DBE_VALUE);
|
|
return;
|
|
/* if # of points/start/width are not frozen, change them */
|
|
} else if(!pscan->fpts && !pParms->p_fs && !pParms->p_fw) {
|
|
pscan->npts=(((pParms->p_ep - pParms->p_cp)*2)/(pParms->p_si)) + 1;
|
|
if(pscan->npts > pscan->mpts) {
|
|
pscan->npts = pscan->mpts;
|
|
sprintf(pscan->smsg,"P%1d Request Exceeded Maximum Points !",i+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;
|
|
db_post_events(pscan,&pParms->p_wd,DBE_VALUE);
|
|
pParms->p_sp = pParms->p_ep - pParms->p_wd;
|
|
db_post_events(pscan,&pParms->p_sp,DBE_VALUE);
|
|
precPvt->nptsCause = i; /* indicate cause of # of points changed */
|
|
changedNpts(pscan);
|
|
return;
|
|
/* if # of points/end/width are not frozen, change them */
|
|
} else if(!pscan->fpts && !pParms->p_fe && !pParms->p_fw) {
|
|
pscan->npts=(((pParms->p_cp - pParms->p_sp)*2)/(pParms->p_si)) + 1;
|
|
if(pscan->npts > pscan->mpts) {
|
|
pscan->npts = pscan->mpts;
|
|
sprintf(pscan->smsg,"P%1d Request Exceeded Maximum Points !",i+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;
|
|
db_post_events(pscan,&pParms->p_wd,DBE_VALUE);
|
|
pParms->p_ep = pParms->p_sp + pParms->p_wd;
|
|
db_post_events(pscan,&pParms->p_ep,DBE_VALUE);
|
|
precPvt->nptsCause = i; /* indicate cause of # of points changed */
|
|
changedNpts(pscan);
|
|
return;
|
|
} else { /* too constrained !! */
|
|
pParms->p_cp = pParms->p_sp + ((pscan->npts - 1) * pParms->p_si)/2;
|
|
db_post_events(pscan,&pParms->p_cp,DBE_VALUE);
|
|
sprintf(pscan->smsg,"P%1d SCAN Parameters Too Constrained !",i+1);
|
|
pscan->alrt = 1;
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case(SPC_SC_W): /* width position changed */
|
|
/* if step start/inc/end are not frozen, change them */
|
|
if(!pParms->p_fs && !pParms->p_fi && !pParms->p_fe) {
|
|
pParms->p_si = pParms->p_wd/(pscan->npts - 1);
|
|
db_post_events(pscan,&pParms->p_si,DBE_VALUE);
|
|
pParms->p_sp = pParms->p_cp - ((pscan->npts - 1) * pParms->p_si)/2;
|
|
db_post_events(pscan,&pParms->p_sp,DBE_VALUE);
|
|
pParms->p_ep = pParms->p_sp + ((pscan->npts - 1) * pParms->p_si);
|
|
db_post_events(pscan,&pParms->p_ep,DBE_VALUE);
|
|
return;
|
|
/* if center/end/inc are not frozen, change them */
|
|
} else if(!pParms->p_fc && !pParms->p_fe && !pParms->p_fi) {
|
|
pParms->p_si = pParms->p_wd/(pscan->npts - 1);
|
|
db_post_events(pscan,&pParms->p_si,DBE_VALUE);
|
|
pParms->p_ep = pParms->p_sp + ((pscan->npts - 1) * pParms->p_si);
|
|
db_post_events(pscan,&pParms->p_ep,DBE_VALUE);
|
|
pParms->p_cp = (pParms->p_ep + pParms->p_sp)/2;
|
|
db_post_events(pscan,&pParms->p_cp,DBE_VALUE);
|
|
return;
|
|
/* if start/center/inc are not frozen, change them */
|
|
} else if(!pParms->p_fs && !pParms->p_fc && !pParms->p_fi) {
|
|
pParms->p_si = pParms->p_wd/(pscan->npts - 1);
|
|
db_post_events(pscan,&pParms->p_si,DBE_VALUE);
|
|
pParms->p_sp = pParms->p_ep - ((pscan->npts - 1) * pParms->p_si);
|
|
db_post_events(pscan,&pParms->p_sp,DBE_VALUE);
|
|
pParms->p_cp = (pParms->p_ep + pParms->p_sp)/2;
|
|
db_post_events(pscan,&pParms->p_cp,DBE_VALUE);
|
|
return;
|
|
/* if # of points/start/end are not frozen, change them */
|
|
} else if(!pscan->fpts && !pParms->p_fs && !pParms->p_fe) {
|
|
pscan->npts = (pParms->p_wd/pParms->p_si) + 1;
|
|
if(pscan->npts > pscan->mpts) {
|
|
pscan->npts = pscan->mpts;
|
|
sprintf(pscan->smsg,"P%1d Request Exceeded Maximum Points !",i+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;
|
|
db_post_events(pscan,&pParms->p_sp,DBE_VALUE);
|
|
pParms->p_ep = pParms->p_sp + ((pscan->npts - 1) * pParms->p_si);
|
|
db_post_events(pscan,&pParms->p_ep,DBE_VALUE);
|
|
precPvt->nptsCause = i; /* indicate cause of # of points changed */
|
|
changedNpts(pscan);
|
|
return;
|
|
/* if # of points/center/end are not frozen, change them */
|
|
} else if(!pscan->fpts && !pParms->p_fc && !pParms->p_fe) {
|
|
pscan->npts = (pParms->p_wd/pParms->p_si) + 1;
|
|
if(pscan->npts > pscan->mpts) {
|
|
pscan->npts = pscan->mpts;
|
|
sprintf(pscan->smsg,"P%1d Request Exceeded Maximum Points !",i+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);
|
|
db_post_events(pscan,&pParms->p_ep,DBE_VALUE);
|
|
pParms->p_cp = (pParms->p_ep + pParms->p_sp)/2;
|
|
db_post_events(pscan,&pParms->p_cp,DBE_VALUE);
|
|
precPvt->nptsCause = i; /* indicate cause of # of points changed */
|
|
changedNpts(pscan);
|
|
return;
|
|
/* if # of points/start/center are not frozen, change them */
|
|
} else if(!pscan->fpts && !pParms->p_fs && !pParms->p_fc) {
|
|
pscan->npts = (pParms->p_wd/pParms->p_si) + 1;
|
|
if(pscan->npts > pscan->mpts) {
|
|
pscan->npts = pscan->mpts;
|
|
sprintf(pscan->smsg,"P%1d Request Exceeded Maximum Points !",i+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);
|
|
db_post_events(pscan,&pParms->p_sp,DBE_VALUE);
|
|
pParms->p_cp = (pParms->p_ep + pParms->p_sp)/2;
|
|
db_post_events(pscan,&pParms->p_cp,DBE_VALUE);
|
|
precPvt->nptsCause = i; /* indicate cause of # of points changed */
|
|
changedNpts(pscan);
|
|
return;
|
|
} else { /* too constrained !! */
|
|
pParms->p_wd = (pParms->p_ep - pParms->p_sp);
|
|
db_post_events(pscan,&pParms->p_wd,DBE_VALUE);
|
|
sprintf(pscan->smsg,"P%1d SCAN Parameters Too Constrained !",i+1);
|
|
pscan->alrt = 1;
|
|
return;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* This routine attempts to bring all linear scan parameters into
|
|
* "consistency". It is used at init and when the # of pts changes.
|
|
* If the number of points changed because of a change in a Positioner's
|
|
* scan parameters, that positioner is skipped to make sure that there is
|
|
* no conflict with that logic. 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
|
|
*
|
|
*/
|
|
|
|
static void changedNpts(pscan)
|
|
struct scanRecord *pscan;
|
|
{
|
|
|
|
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 */
|
|
/* if the positioner is in table mode, don't touch linear scan parms !*/
|
|
for(i=0; i<NUM_POS; i++, pParms++) {
|
|
/* Check if Positioner is in TABLE Mode */
|
|
if(pParms->p_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 */
|
|
|
|
freezeState = (pParms->p_fs << 4) |
|
|
(pParms->p_fi << 3) |
|
|
(pParms->p_fe << 2) |
|
|
(pParms->p_fc << 1) |
|
|
(pParms->p_fw);
|
|
|
|
if(recScanDebug) {
|
|
printf("Freeze State of P%1d = 0x%hx \n",i,freezeState);
|
|
}
|
|
|
|
switch(freezeState) {
|
|
case(0): /* end/center/width unfrozen, change them */
|
|
case(8):
|
|
case(16):
|
|
case(24):
|
|
pParms->p_ep = pParms->p_sp + ((pscan->npts - 1) * pParms->p_si);
|
|
db_post_events(pscan,&pParms->p_ep,DBE_VALUE);
|
|
pParms->p_cp = (pParms->p_ep + pParms->p_sp)/2;
|
|
db_post_events(pscan,&pParms->p_cp,DBE_VALUE);
|
|
pParms->p_wd = (pParms->p_ep - pParms->p_sp);
|
|
db_post_events(pscan,&pParms->p_wd,DBE_VALUE);
|
|
break;
|
|
|
|
case(4): /* start/center/width are not frozen, change them */
|
|
case(12):
|
|
pParms->p_sp = pParms->p_ep - ((pscan->npts - 1) * pParms->p_si);
|
|
db_post_events(pscan,&pParms->p_sp,DBE_VALUE);
|
|
pParms->p_cp = (pParms->p_ep + pParms->p_sp)/2;
|
|
db_post_events(pscan,&pParms->p_cp,DBE_VALUE);
|
|
pParms->p_wd = (pParms->p_ep - pParms->p_sp);
|
|
db_post_events(pscan,&pParms->p_wd,DBE_VALUE);
|
|
break;
|
|
|
|
case(2): /* if center is frozen, but not width/start/end , ... */
|
|
case(10):
|
|
pParms->p_sp = pParms->p_cp - ((pscan->npts - 1) * pParms->p_si)/2;
|
|
db_post_events(pscan,&pParms->p_sp,DBE_VALUE);
|
|
pParms->p_ep = pParms->p_sp + ((pscan->npts - 1) * pParms->p_si);
|
|
db_post_events(pscan,&pParms->p_ep,DBE_VALUE);
|
|
pParms->p_wd = (pParms->p_ep - pParms->p_sp);
|
|
db_post_events(pscan,&pParms->p_wd,DBE_VALUE);
|
|
break;
|
|
|
|
case(1): /* if center or width is frozen, but not inc , ... */
|
|
case(3):
|
|
case(5): /* if end/center or end/width are frozen, but not inc, */
|
|
case(6):
|
|
case(7):
|
|
case(17): /*if start/center or start/width are frozen, but not inc*/
|
|
case(18):
|
|
case(19):
|
|
case(20):
|
|
case(21):
|
|
case(22):
|
|
case(23):
|
|
pParms->p_si = (pParms->p_ep - pParms->p_sp)/(pscan->npts - 1);
|
|
db_post_events(pscan,&pParms->p_si,DBE_VALUE);
|
|
break;
|
|
|
|
/* The following freezeStates are known to be "Too Constrained" */
|
|
/* 9,11,13,14,15,25,26,27,28,29,30,31 */
|
|
default: /* too constrained !! */
|
|
sprintf(pscan->smsg,"P%1d SCAN Parameters Too Constrained !",i+1);
|
|
pscan->alrt = 1;
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static long checkScanLimits(pscan)
|
|
struct scanRecord *pscan;
|
|
{
|
|
|
|
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 = 0;
|
|
int i,j;
|
|
double value;
|
|
|
|
if(recScanDebug) {
|
|
if(!pscan->p1nv)
|
|
printf("P1 Control Limits : %.4f %.4f\n",
|
|
pscan->p1lr, pscan->p1hr);
|
|
if(!pscan->p2nv)
|
|
printf("P2 Control Limits : %.4f %.4f\n",
|
|
pscan->p2lr, pscan->p2hr);
|
|
if(!pscan->p3nv)
|
|
printf("P3 Control Limits : %.4f %.4f\n",
|
|
pscan->p3lr, pscan->p3hr);
|
|
if(!pscan->p4nv)
|
|
printf("P4 Control Limits : %.4f %.4f\n",
|
|
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 */
|
|
|
|
pPvStat = &pscan->p1nv;
|
|
pPosFields = (posFields *)&pscan->p1pp;
|
|
for(i=0; i < NUM_POS; i++, pPosFields++, pPvStat++) {
|
|
if(*pPvStat == PV_OK) {
|
|
for(j=0; j<pscan->npts; 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;
|
|
}
|
|
|
|
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(ERROR);
|
|
}
|
|
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(ERROR);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* No errors if we made it here ... */
|
|
sprintf(pscan->smsg,"SCAN Values within limits");
|
|
return(OK);
|
|
|
|
}
|
|
|
|
|
|
/* 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 previewScan(pscan)
|
|
struct scanRecord *pscan;
|
|
{
|
|
|
|
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;
|
|
|
|
/* 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);
|
|
}
|
|
}
|
|
|
|
/* 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; j<pscan->npts; 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; j<pscan->mpts;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);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void saveFrzFlags(pscan)
|
|
struct scanRecord *pscan;
|
|
{
|
|
|
|
recPvtStruct *precPvt = (recPvtStruct *)pscan->rpvt;
|
|
posFields *pPosFields = (posFields *)&pscan->p1pp;
|
|
int i;
|
|
|
|
|
|
/* save state of each freeze flag */
|
|
precPvt->fpts = pscan->fpts;
|
|
for(i=0; i<NUM_POS; i++, pPosFields++) {
|
|
precPvt->posParms[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;
|
|
{
|
|
|
|
recPvtStruct *precPvt = (recPvtStruct *)pscan->rpvt;
|
|
posFields *pPosFields = (posFields *)&pscan->p1pp;
|
|
int i;
|
|
|
|
/* reset each frzFlag, post monitor if changed */
|
|
|
|
if(pscan->fpts) {
|
|
pscan->fpts = 0;
|
|
db_post_events(pscan,&pscan->fpts, DBE_VALUE);
|
|
}
|
|
|
|
for(i=0; i<NUM_POS; i++, pPosFields++) {
|
|
if(pPosFields->p_fs) {
|
|
pPosFields->p_fs = 0;
|
|
db_post_events(pscan,&pPosFields->p_fs, DBE_VALUE);
|
|
}
|
|
|
|
if(pPosFields->p_fi) {
|
|
pPosFields->p_fi = 0;
|
|
db_post_events(pscan,&pPosFields->p_fi, DBE_VALUE);
|
|
}
|
|
|
|
if(pPosFields->p_fc) {
|
|
pPosFields->p_fc = 0;
|
|
db_post_events(pscan,&pPosFields->p_fc, DBE_VALUE);
|
|
}
|
|
|
|
if(pPosFields->p_fe) {
|
|
pPosFields->p_fe = 0;
|
|
db_post_events(pscan,&pPosFields->p_fe, 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;
|
|
{
|
|
|
|
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;
|
|
if(pscan->fpts) {
|
|
db_post_events(pscan,&pscan->fpts, DBE_VALUE);
|
|
}
|
|
|
|
for(i=0; i<NUM_POS; i++, pPosFields++) {
|
|
pPosFields->p_fs = precPvt->posParms[i].p_fs;
|
|
if(pPosFields->p_fs) {
|
|
db_post_events(pscan,&pPosFields->p_fs, DBE_VALUE);
|
|
}
|
|
|
|
pPosFields->p_fi = precPvt->posParms[i].p_fi;
|
|
if(pPosFields->p_fi) {
|
|
db_post_events(pscan,&pPosFields->p_fi, DBE_VALUE);
|
|
}
|
|
|
|
pPosFields->p_fc = precPvt->posParms[i].p_fc;
|
|
if(pPosFields->p_fc) {
|
|
db_post_events(pscan,&pPosFields->p_fc, DBE_VALUE);
|
|
}
|
|
|
|
pPosFields->p_fe = precPvt->posParms[i].p_fe;
|
|
if(pPosFields->p_fe) {
|
|
db_post_events(pscan,&pPosFields->p_fe, DBE_VALUE);
|
|
}
|
|
|
|
pPosFields->p_fw = precPvt->posParms[i].p_fw;
|
|
if(pPosFields->p_fw) {
|
|
db_post_events(pscan,&pPosFields->p_fw, DBE_VALUE);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
/* Restores Position Parms after leaving table mode (for 1 positioner) */
|
|
static void restorePosParms(struct scanRecord *pscan, unsigned short i)
|
|
{
|
|
|
|
recPvtStruct *precPvt = (recPvtStruct *)pscan->rpvt;
|
|
posFields *pPosFields = (posFields *)&pscan->p1pp + i;
|
|
|
|
pPosFields->p_sp = precPvt->posParms[i].p_sp;
|
|
db_post_events(pscan,&pPosFields->p_sp, DBE_VALUE);
|
|
|
|
pPosFields->p_si = precPvt->posParms[i].p_si;
|
|
db_post_events(pscan,&pPosFields->p_si, DBE_VALUE);
|
|
|
|
pPosFields->p_ep = precPvt->posParms[i].p_ep;
|
|
db_post_events(pscan,&pPosFields->p_ep, DBE_VALUE);
|
|
|
|
pPosFields->p_cp = precPvt->posParms[i].p_cp;
|
|
db_post_events(pscan,&pPosFields->p_cp, DBE_VALUE);
|
|
|
|
pPosFields->p_wd = precPvt->posParms[i].p_wd;
|
|
db_post_events(pscan,&pPosFields->p_wd, DBE_VALUE);
|
|
|
|
}
|
|
|
|
|