/* devXxHvpsGpib.c */ /* share/src/devOpt $Id$ */ /* * Author: Bob Daly * Date: 10-21-91 * * 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 10-27-91 winans converted to conform to *NEW* gpib driver * * BUGS: * GPIBSOFT type commands should NOT be processed by the link task. They * should be handled by a callback task! */ /* Includes support for the following device types : * "devAiHvpsGpib" * "devAoHvpsGpib" * "devBiHvpsGpib" * "devBoHvpsGpib" * "devMbbiHvpsGpib" * "devMbbiHvpsGpib" * "devStrinHvpsGpib" * "devStroutHvpsGpib" */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern struct drvGpibSet drvGpib; /* entry points to driver functions */ long init_dev_sup(); long init_rec_ai(); long read_ai(); long init_rec_ao(); long write_ao(); long init_rec_bi(); long read_bi(); long init_rec_bo(); long write_bo(); long init_rec_xx(); long init_rec_stringin(); long read_stringin(); long init_rec_stringout(); long write_stringout(); void aiGpibWork(); void aoGpibWork(); void biGpibWork(); void boGpibWork(); void soGpibWork(); void siGpibWork(); void processCallback(); int xxGpibWork(); /****************************************************************************** * * Define all the dset's. * ******************************************************************************/ /* Generic dset structure */ typedef struct { long number; DEVSUPFUN f1; DEVSUPFUN f2; DEVSUPFUN f3; DEVSUPFUN f4; DEVSUPFUN f5; DEVSUPFUN f6; } gDset; gDset devAiHvps = {6, NULL, init_dev_sup, init_rec_ai, NULL, read_ai, NULL}; gDset devSiHvps = {5, NULL, NULL, init_rec_stringin, NULL, read_stringin}; gDset devAoHvps = {6, NULL, NULL, init_rec_ao, NULL, write_ao, NULL }; gDset devSoHvps = {5, NULL, NULL, init_rec_stringout, NULL, write_stringout}; gDset devBiHvps = {5, NULL, NULL, init_rec_bi, NULL, read_bi}; gDset devBoHvps = {5, NULL, NULL, init_rec_bo, NULL, write_bo}; /*#define _SRQSUPPORT_ */ /*NO SRQ SUPPORT*/ #define RESPONDS_2_WRITES #define GPIBREAD 1 #define GPIBWRITE 2 #define GPIBCMD 3 #define GPIBCNTL 4 #define GPIBSOFT 5 #define GPIBINIT 6 /* BUG - dynamically allocate the hvpsTmoTable, don't hard-code this! */ /* BUG - this is really based on the number of power supplies, not the links */ #define MAXGPIBLINKS 2 /* array for determining elapsed timesince last node timeout */ static unsigned long hvpsTmoTable[MAXGPIBLINKS][2]; /*********************************************************** * * device common stuff * ************************************************************/ int HvpsDebug = 0; #define UNDEFINED 1e-37 static char UDF[10] = "Undefined"; static char pOK[3] = "OK"; /********************************************************** * * Hvps specific stuff * ***********************************************************/ /* initialization and secondary commands*/ /* The operating mode of the HVPS*/ #define MANUAL 0 #define REMOTE 1 /* Response char in all returned messages from hvps */ #define NAK 0x15 #define ACK 0x6 /* Local data settable from the shell */ int hvpsGpibDelay = 0; struct msgMetered { char acknak; float data[20]; }meteredData,lastData,onTimerData,countsData; struct msgChar { char acknak; char data[80]; }statusData,htrTimerdata,htrStatusData; /* binary in strings */ char *modeStrs[] = {"Local", "Remote", NULL}; /* binary out strings */ char *resetStrs[] = {NULL, "RESET\r"}; char *onStrs[] = {NULL, "HV_ON\r"}; char *offStrs[] = {NULL, "HV_OFF\r"}; /* device initialization string sent one time during iocInit */ static char *pDevInit = NULL; /* forward declarations of some custom convert routines */ int inMode(); int inData(); int getInData(); int inOnTimers(); int getInTimers(); int inCounts(); int getInCounts(); int inStatus(); int getInStatus(); int getRespStr(); int inSetpt(); int setPvSevr(); /**************** Hvps Declarations *****************/ /****************************************************************************** * * This structure will be attached to each pv (via psub->dpvt) to store the * appropriate gpibWork pointer, callback address to record support, * gpib link #, listen address, talk address and command information. * ******************************************************************************/ struct hvpsDpvt { struct dpvtGpibHead head; short parm; /* parameter index into gpib commands */ char *rsp; /* for read/write message error Responses*/ char *msg; /* for read/write messages */ struct dbCommon *precord; /* record this dpvt is part of */ void (*process)(); /* callback to perform forward db processing */ int processPri; /* process callback's priority */ long linkType; /* GPIB_IO, BBGPIB_IO... */ }; /****************************************************************************** * * Record type enumerations used by init routines for cross-checking * ******************************************************************************/ #define GPIB_AO 0 #define GPIB_AI 1 #define GPIB_BO 2 #define GPIB_BI 3 #define GPIB_MBBO 4 #define GPIB_MBBI 5 #define GPIB_SO 6 #define GPIB_SI 7 /****************************************************************************** * * GPIB work routines associated with record types * ******************************************************************************/ #define mbboGpibWork NULL #define mbbiGpibWork NULL typedef void (*GPIBSUPFUN)(); /* pointer to gpib support functions*/ static GPIBSUPFUN pgpibWork[] = { aoGpibWork, aiGpibWork, boGpibWork, biGpibWork, mbboGpibWork, mbbiGpibWork, soGpibWork, siGpibWork }; /****************************************************************************** * * The next structure defines the GPIB command and format statements to * extract or send data to a GPIB Instrument. Each transaction type is * described below : * * GPIBREAD : (1) The cmd string is sent to the instrument * (2) Data is read from the inst into a buffer (hvpsDpvt.msg) * (3) The important data is extracted from the buffer using the * format string. * * GPIBREADW : (1) The cmd string is sent to the instrument * (2) Wait for SRQ * (3) Data is read from the inst into a buffer (hvpsDpvt.msg) * (4) The important data is extracted from the buffer using the * format string. * * GPIBWRITE: (1) An ascii string is generated using the format string and * contents of the hvpsDpvt->precord->val * (2) The ascii string is sent to the instrument * * GPIBCMND : (1) The cmd string is sent to the instrument * * GPIBCNTL : (1) The control string is sent to the instrument (ATN active) * * GPIBSOFT : (1) No GPIB activity involved - normally retrieves internal data * * GPIBINIT : (1) The instrument is send SDC with command string * * If a particular GPIB message does not fit one of these formats, a custom * routine may be provided. Store a pointer to this routine in the .convert * field to use it rather than the above approaches. * ******************************************************************************/ struct hvpsGpibCmd { int recType ; /* enum - GPIB_AI, GPIB_AO ... */ int type; /* enum - GPIBREAD, GPIBWRITE, GPIBCMND */ short pri; /* priority of gpib request--IB_Q_HIGH or IB_Q_LOW*/ char *sta; /* status string */ char *cmd; /* CONSTANT STRING to send to instrument */ char *format; /* string used to generate or interpret msg*/ short rspLen; /* room for response error message*/ short msgLen; /* room for return data message length*/ int (*convert)(); /* custom routine for wierd conversions */ int P1; /* parameter used in convert*/ int P2; /* parameter user in convert*/ char **P3; /* pointer to array containing pointers to strings */ struct names *namelist; /* for bx and mbbx record's name fields */ }; # define FILL {10,0,IB_Q_LOW,UDF,NULL,NULL,0,0,NULL,0,0,NULL,NULL } # define FILL10 FILL,FILL,FILL,FILL,FILL,FILL,FILL,FILL,FILL,FILL static struct hvpsGpibCmd hvpsGpibCmds[] = { /* ai records */ /* 0 ->59 */ {GPIB_AI, GPIBREAD, IB_Q_LOW, UDF, "RD_DATA\r", NULL, 80, 80, inData, 0 ,0, NULL, NULL}, {GPIB_AI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInData, 0, 0, NULL, NULL}, {GPIB_AI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInData, 1, 0, NULL, NULL}, {GPIB_AI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInData, 2, 0, NULL, NULL}, {GPIB_AI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInData, 3, 0, NULL, NULL}, {GPIB_AI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInData, 4, 0, NULL, NULL}, {GPIB_AI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInData, 5, 0, NULL, NULL}, {GPIB_AI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInData, 6, 0, NULL, NULL}, {GPIB_AI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInData, 7, 0, NULL, NULL}, {GPIB_AI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInData, 8, 0, NULL, NULL}, /*10*/ {GPIB_AI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInData, 9, 0, NULL, NULL}, {GPIB_AI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInData, 10, 0, NULL, NULL}, {GPIB_AI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInData, 11, 0, NULL, NULL}, {GPIB_AI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInData, 12, 0, NULL, NULL}, {GPIB_AI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInData, 13, 0, NULL, NULL}, {GPIB_AI, GPIBREAD, IB_Q_LOW, UDF, "RD_TMRS\r", "%f%f", 80, 80, inOnTimers, 0 ,0, NULL, NULL}, {GPIB_AI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInTimers, 0, 0, NULL, NULL}, {GPIB_AI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInTimers, 1, 0, NULL, NULL}, {GPIB_AI, GPIBREAD, IB_Q_LOW, UDF, "RD_CNTS\r", "%f%f", 80, 80, inCounts, 0 ,0, NULL, NULL}, {GPIB_AI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInCounts, 0, 0, NULL, NULL}, /*10*/ {GPIB_AI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInCounts, 1, 0, NULL, NULL}, {GPIB_AI, GPIBREAD, IB_Q_LOW, UDF, "RD_SETPT HV_VOLTS\r", "%lf", 80, 80, inSetpt, 0 ,0, NULL, NULL}, {GPIB_AI, GPIBREAD, IB_Q_LOW, UDF, "RD_SETPT MA_VOLTS\r","%lf", 80, 80, inSetpt, 0 ,0, NULL, NULL}, {GPIB_AI, GPIBREAD, IB_Q_LOW, UDF, "RD_SETPT KLHTR_VOLTS\r", "%lf", 80, 80, inSetpt, 0 ,0, NULL, NULL}, {GPIB_AI, GPIBREAD, IB_Q_LOW, UDF, "RD_SETPT KLMAG_AMPS\r", "%lf", 80, 80, inSetpt, 0 ,0, NULL, NULL}, FILL,FILL,FILL,FILL,FILL, /*10*/ FILL10, /*10*/ FILL10, /*10*/ FILL10, /* bi records */ /*start 60 ->119*/ {GPIB_BI, GPIBREAD, IB_Q_LOW, UDF, "RD_STATUS\r", NULL, 80, 80, inStatus, 0, 0, NULL, NULL}, {GPIB_BI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInStatus, 0, 0x1, NULL, NULL}, {GPIB_BI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInStatus, 0, 0x2, NULL, NULL}, {GPIB_BI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInStatus, 0, 0x4, NULL, NULL}, {GPIB_BI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInStatus, 0, 0x8, NULL, NULL}, {GPIB_BI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInStatus, 0, 0x10, NULL, NULL}, {GPIB_BI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInStatus, 0, 0x20, NULL, NULL}, {GPIB_BI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInStatus, 0, 0x40, NULL, NULL}, {GPIB_BI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInStatus, 0, 0x80, NULL, NULL}, {GPIB_BI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInStatus, 1, 0x1, NULL, NULL}, /*10*/ {GPIB_BI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInStatus, 1, 0x2, NULL, NULL}, {GPIB_BI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInStatus, 1, 0x4, NULL, NULL}, {GPIB_BI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInStatus, 1, 0x8, NULL, NULL}, {GPIB_BI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInStatus, 1, 0x10, NULL, NULL}, {GPIB_BI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInStatus, 1, 0x20, NULL, NULL}, {GPIB_BI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInStatus, 1, 0x40, NULL, NULL}, {GPIB_BI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInStatus, 1, 0x80, NULL, NULL}, {GPIB_BI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInStatus, 2, 0x1, NULL, NULL}, {GPIB_BI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInStatus, 2, 0x2, NULL, NULL}, {GPIB_BI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInStatus, 2, 0x4, NULL, NULL}, /*10*/ {GPIB_BI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInStatus, 2, 0x8, NULL, NULL}, {GPIB_BI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInStatus, 2, 0x10, NULL, NULL}, {GPIB_BI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInStatus, 2, 0x20, NULL, NULL}, {GPIB_BI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInStatus, 2, 0x40, NULL, NULL}, {GPIB_BI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInStatus, 2, 0x80, NULL, NULL}, {GPIB_BI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInStatus, 3, 0x1, NULL, NULL}, {GPIB_BI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInStatus, 3, 0x2, NULL, NULL}, {GPIB_BI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInStatus, 3, 0x4, NULL, NULL}, {GPIB_BI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInStatus, 3, 0x8, NULL, NULL}, {GPIB_BI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInStatus, 3, 0x10, NULL, NULL}, /*10*/ {GPIB_BI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInStatus, 3, 0x20, NULL, NULL}, {GPIB_BI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInStatus, 3, 0x40, NULL, NULL}, {GPIB_BI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInStatus, 3, 0x80, NULL, NULL}, {GPIB_BI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInStatus, 4, 0x1, NULL, NULL}, {GPIB_BI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInStatus, 4, 0x2, NULL, NULL}, {GPIB_BI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInStatus, 4, 0x4, NULL, NULL}, {GPIB_BI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInStatus, 4, 0x8, NULL, NULL}, {GPIB_BI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInStatus, 4, 0x10, NULL, NULL}, {GPIB_BI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInStatus, 4, 0x20, NULL, NULL}, {GPIB_BI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInStatus, 4, 0x40, NULL, NULL}, /*10*/ {GPIB_BI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 0, 0, getInStatus, 4, 0x80, NULL, NULL}, {GPIB_BI, GPIBREAD, IB_Q_LOW, UDF, "RD_MODE\r", NULL, 40,40, NULL, 0 ,0, modeStrs, NULL}, FILL,FILL,FILL, FILL,FILL,FILL,FILL,FILL, /*10*/ FILL10, /* ao records */ /* start 120->159*/ {GPIB_AO, GPIBWRITE, IB_Q_LOW, UDF, NULL, "LD_SETPT HV_VOLTS %10.3E\r", 40, 40, NULL, 0, 0, NULL, NULL}, {GPIB_AO, GPIBWRITE, IB_Q_LOW, UDF, NULL, "LD_SETPT MA_VOLTS %10.3E\r", 40, 40, NULL, 0, 0, NULL, NULL}, {GPIB_AO, GPIBWRITE, IB_Q_LOW, UDF, NULL, "LD_SETPT KLHTR_VOLTS %10.3E\r", 40, 40, NULL, 0, 0, NULL, NULL}, {GPIB_AO, GPIBWRITE, IB_Q_LOW, UDF, NULL, "LD_SETPT KLMAG_AMPS %10.3E\r", 40, 40, NULL, 0, 0, NULL, NULL}, FILL, FILL,FILL,FILL,FILL,FILL, /*10*/ FILL10, /*10*/ FILL10, /*10*/ FILL10, /* bo records */ /*start 160->179*/ {GPIB_BO, GPIBWRITE, IB_Q_LOW, UDF, NULL, NULL, 80, 80, NULL, 0, 0, resetStrs, NULL}, {GPIB_BO, GPIBWRITE, IB_Q_LOW, UDF, NULL, NULL, 80, 80, NULL, 0, 0, onStrs, NULL}, {GPIB_BO, GPIBWRITE, IB_Q_LOW, UDF, NULL, NULL, 80, 80, NULL, 0, 0, offStrs, NULL}, FILL,FILL, FILL,FILL,FILL,FILL,FILL, /*10*/ FILL10, /* stringin records */ /*start 180->199*/ {GPIB_SI, GPIBREAD, IB_Q_LOW, UDF, "RD_HTR_STATUS\r", NULL, 40,40, NULL, 0 ,0, NULL, NULL}, {GPIB_SI, GPIBREAD, IB_Q_LOW, UDF, "RD_WARMUP\r", NULL, 40,40, NULL, 0 ,0, NULL, NULL}, {GPIB_SI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 40,40, getRespStr, 101 ,0, NULL, NULL}, {GPIB_SI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 40,40, getRespStr, 102 ,0, NULL, NULL}, {GPIB_SI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 40,40, getRespStr, 103 ,0, NULL, NULL}, {GPIB_SI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 40,40, getRespStr, 160 ,0, NULL, NULL}, {GPIB_SI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 40,40, getRespStr, 161 ,0, NULL, NULL}, {GPIB_SI, GPIBSOFT, IB_Q_LOW, UDF, NULL, NULL, 40,40, getRespStr, 162 ,0, NULL, NULL}, FILL, FILL, /*10*/ FILL10, /* stringout records */ /*start 200->209*/ {GPIB_SO, GPIBWRITE, IB_Q_LOW, UDF, NULL, NULL, 40,40, NULL, 0 ,0, NULL, NULL} }; #define NUMHVPSPARAMS sizeof(hvpsGpibCmds)/sizeof(struct hvpsGpibCmd) /****************************************************************************** * * Initialization for Hvps device support * ******************************************************************************/ static long init_dev_sup() { static char firstInitCall = 0; /* check to see if we have been here before */ if (firstInitCall) { return(OK); /* if already initialized, return */ } firstInitCall = 1; /* continue initalizations */ logMsg("Hvps Device Support Initializing ...\n"); return(OK); } /****************************************************************************** * * Initialization routines for each record specifying a Hvps Device Type * ******************************************************************************/ /****************************************************************************** * * ai record init * ******************************************************************************/ static long init_rec_ai(pai, process) struct aiRecord *pai; void (*process)(); { /* do common initialization */ return(init_rec_xx((caddr_t) pai, &pai->inp, GPIB_AI)); } /****************************************************************************** * * ao record init * ******************************************************************************/ static long init_rec_ao(pao, process) struct aoRecord *pao; void (*process)(); { /* do common initialization */ return(init_rec_xx((caddr_t) pao, &pao->out, GPIB_AO)); } /****************************************************************************** * * stringin record init * ******************************************************************************/ static long init_rec_stringin(pstringin, process) struct stringinRecord *pstringin; void (*process)(); { /* do common initialization */ return( init_rec_xx((caddr_t) pstringin, &pstringin->inp, GPIB_SI)); } /****************************************************************************** * * stringout record init * ******************************************************************************/ static long init_rec_stringout(pstringout, process) struct stringoutRecord *pstringout; void (*process)(); { /* do common initialization */ return(init_rec_xx((caddr_t) pstringout, &pstringout->out, GPIB_SO)); } /****************************************************************************** * * bi record init * ******************************************************************************/ static long init_rec_bi(pbi, process) struct biRecord *pbi; void (*process)(); { /* do common initialization */ return(init_rec_xx((caddr_t) pbi, &pbi->inp, GPIB_BI)); /* BUG - what about the button labels?? */ } /* bo record init */ static long init_rec_bo(pbo, process) struct boRecord *pbo; void (*process)(); { /* do common initialization */ return(init_rec_xx((caddr_t) pbo, &pbo->out, GPIB_BO)); /* BUG - what about the button labels?? */ } /****************************************************************************** * * This init routine is common to all record types * ******************************************************************************/ static long init_rec_xx(prec, plink, recType) struct dbCommon *prec; struct link *plink; int recType; { static short firstTime = TRUE; struct hvpsDpvt *pdpvt; struct dbCommon *pdbCommon = (struct dbCommon *)prec; char message[100]; struct hvpsGpibCmd *pCmd; char subType; if (HvpsDebug) logMsg("hvps init_rec_xx(): entered\n"); /* allocate space for the private structure */ pdpvt = (struct hvpsDpvt *) malloc(sizeof(struct hvpsDpvt)); prec->dpvt = (void *) pdpvt; pdpvt->precord = prec; pdpvt->head.workStart = pgpibWork[recType]; pdpvt->parm = -1; /* In case the sscanf fails */ pdpvt->linkType = plink->type; switch (plink->type) { case GPIB_IO: /* Is a straight Network Instruments link */ /* BUG - this should be a driver supplied function to fill in the header */ pdpvt->head.link = plink->value.gpibio.link; /* NI link number */ pdpvt->head.device = plink->value.gpibio.addr; /* gpib dev address */ sscanf(plink->value.gpibio.parm, "%hd", &(pdpvt->parm)); pdpvt->head.bitBusDpvt = NULL; /* no bitbus data needed */ break; case BBGPIB_IO: /* Is a bitbus -> gpib link */ /* BUG - this should be a driver supplied function to fill in the header */ pdpvt->head.device = plink->value.bbgpibio.gpibaddr; /* gpib dev address */ sscanf(plink->value.bbgpibio.parm, "%hd", &(pdpvt->parm)); pdpvt->head.bitBusDpvt = (struct dpvtBitBusHead *) malloc(sizeof(struct dpvtBitBusHead)); pdpvt->head.bitBusDpvt->txMsg = (struct bitBusMsg *) malloc(sizeof(struct bitBusMsg)); pdpvt->head.bitBusDpvt->rxMsg = (struct bitBusMsg *) malloc(sizeof(struct bitBusMsg)); pdpvt->head.bitBusDpvt->txMsg->node = plink->value.bbgpibio.bbaddr; /* bug node address */ pdpvt->head.bitBusDpvt->link = plink->value.bbgpibio.link; /* bug link number */ pdpvt->head.link = plink->value.bbgpibio.link; pdpvt->head.bitBusDpvt->rxMaxLen = sizeof(struct bitBusMsg); break; default: strcpy(message, pdbCommon->name); strcat(message,": init_record : GPIB link type is invalid"); errMessage(S_db_badField, message); return(S_db_badField); break; } /* check for valid GPIB addr */ if ((pdpvt->head.device < 0) || (pdpvt->head.device >= IBAPERLINK)) { strcpy(message, pdbCommon->name); strcat(message,": init_record : GPIB address out of range"); errMessage(S_db_badField,message); return(S_db_badField); } /* check for valid param entry */ if ((pdpvt->parm < 0) || (pdpvt->parm > NUMHVPSPARAMS)) { strcpy(message, pdbCommon->name); strcat(message,": init_record : Parameter # out of range"); errMessage(S_db_badField,message); return(S_db_badField); } /* check record type*/ if(hvpsGpibCmds[pdpvt->parm].recType != recType ) { strcpy(message, pdbCommon->name); strcat(message,": init_record : record type invalid for parameter"); errMessage(S_db_badField,message); return(S_db_badField); } pCmd = &hvpsGpibCmds[pdpvt->parm]; if(pCmd->msgLen > 0) pdpvt->msg = (char *)(calloc(pCmd->msgLen,1)); if(pCmd->rspLen > 0) pdpvt->rsp = (char *)(calloc(pCmd->rspLen,1)); /* BUG this init logic is wrong for multi-devices... */ /* BUG - it should be on a per-device address basis */ /* - fix it when dynamically allocating the per-device structures. */ /* BUG!!! this HAS to be done via qGpibReq!!!! */ if( firstTime && pDevInit != NULL ) { if( (*(drvGpib.writeIb))(pdpvt->head.link, pdpvt->head.device, pDevInit, strlen(pDevInit)) == ERROR) { logMsg("Hvps device initialization-GPIB setup error\n"); return(ERROR); } } /* fill in the required stuff for the callback task */ pdpvt->process = processCallback; pdpvt->processPri = priorityLow; return(0); } /****************************************************************************** * * These are the device support routne entry points called by record support. * ******************************************************************************/ static long read_ai(pai) struct aiRecord *pai; { struct hvpsDpvt *pdpvt = (struct hvpsDpvt *)(pai->dpvt); struct hvpsGpibCmd *pCmd; pCmd = &hvpsGpibCmds[pdpvt->parm]; if (pai->pact) { if(HvpsDebug) logMsg("read_ai with PACT = 1\n"); return(2); /* work is all done, return '2' to indicate val */ } else if (pCmd->type == GPIBSOFT) { (*pCmd->convert)(pdpvt,pCmd->P1,pCmd->P2, pCmd->P3); return(2); } else { /* put pointer to dvpt field on ring buffer */ if(HvpsDebug) logMsg("read_ai with PACT = 0\n"); if((*(drvGpib.qGpibReq))(pdpvt->linkType, pdpvt->head.link, pdpvt, pCmd->pri) == ERROR) { setPvSevr(pai,MAJOR_ALARM,VALID_ALARM); return(0); } return(1); } } static long write_ao(pao) struct aoRecord *pao; { struct hvpsDpvt *pdpvt = (struct hvpsDpvt *)(pao->dpvt); struct hvpsGpibCmd *pCmd; pCmd = &hvpsGpibCmds[pdpvt->parm]; if(HvpsDebug) logMsg("Hvps-write_ao entered type: %d format %s\n",pCmd->type,pCmd->format); if (pao->pact) return(2); /* work is all done, finish processing */ else if (pCmd->type == GPIBSOFT) { (*pCmd->convert)(pdpvt,pCmd->P1,pCmd->P2, pCmd->P3); return(0); } else { /* put pointer to dvpt field on ring buffer */ if((*(drvGpib.qGpibReq))(pdpvt->linkType, pdpvt->head.link, pdpvt, pCmd->pri) == ERROR) { setPvSevr(pao,WRITE_ALARM,VALID_ALARM); return(0); } return(1); } } static long read_stringin(pstringin) struct stringinRecord *pstringin; { struct hvpsDpvt *pdpvt = (struct hvpsDpvt *)(pstringin->dpvt); struct hvpsGpibCmd *pCmd; pCmd = &hvpsGpibCmds[pdpvt->parm]; if (pstringin->pact) { if(HvpsDebug) logMsg("read_stringin with PACT = 1\n"); return(2); /* work is all done, return '2' to indicate val */ } else if (pCmd->type == GPIBSOFT) { (*pCmd->convert)(pdpvt,pCmd->P1,pCmd->P2, pCmd->P3); return(0); } else { /* put pointer to dvpt field on ring buffer */ if(HvpsDebug) logMsg("read_stringin with PACT = 0\n"); if((*(drvGpib.qGpibReq))(pdpvt->linkType, pdpvt->head.link, pdpvt, pCmd->pri) == ERROR) { setPvSevr(pstringin,MAJOR_ALARM,VALID_ALARM); return(0); } return(1); } } static long write_stringout(pstringout) struct stringoutRecord *pstringout; { struct hvpsDpvt *pdpvt = (struct hvpsDpvt *)(pstringout->dpvt); struct hvpsGpibCmd *pCmd; pCmd = &hvpsGpibCmds[pdpvt->parm]; if(HvpsDebug) logMsg("stringout entered string %s\n",pstringout->val); if (pstringout->pact) { return(0); /* work is all done, finish processing */ } else if (pCmd->type == GPIBSOFT) { (*pCmd->convert)(pdpvt,pCmd->P1,pCmd->P2, pCmd->P3); return(0); } else { /* put pointer to dvpt field on ring buffer */ if((*(drvGpib.qGpibReq))(pdpvt->linkType, pdpvt->head.link, pdpvt, pCmd->pri) == ERROR) { setPvSevr(pstringout,WRITE_ALARM,VALID_ALARM); return(0); } return(1); } } static long read_bi(pbi) struct biRecord *pbi; { struct hvpsDpvt *pdpvt = (struct hvpsDpvt *)(pbi->dpvt); struct hvpsGpibCmd *pCmd; pCmd = &hvpsGpibCmds[pdpvt->parm]; if (pbi->pact) return(2); /* work is all done, finish processing */ else if (pCmd->type == GPIBSOFT) { (*pCmd->convert)(pdpvt,pCmd->P1,pCmd->P2, pCmd->P3); return(2); } else { /* put pointer to dvpt field on ring buffer */ if((*(drvGpib.qGpibReq))(pdpvt->linkType, pdpvt->head.link, pdpvt, pCmd->pri) == ERROR) { setPvSevr(pbi,READ_ALARM,VALID_ALARM); return(0); } return(1); } } static long write_bo(pbo) struct boRecord *pbo; { struct hvpsDpvt *pdpvt = (struct hvpsDpvt *)(pbo->dpvt); struct hvpsGpibCmd *pCmd; pCmd = &hvpsGpibCmds[pdpvt->parm]; if (pbo->pact) return(2); /* work is all done, finish processing */ else if (pCmd->type == GPIBSOFT) { (*pCmd->convert)(pdpvt,pCmd->P1,pCmd->P2, pCmd->P3); return(0); } else { /* put pointer to dvpt field on ring buffer */ if((*(drvGpib.qGpibReq))(pdpvt->linkType, pdpvt->head.link, pdpvt, pCmd->pri) == ERROR) { setPvSevr(pbo,WRITE_ALARM,VALID_ALARM); return(0); } return(1); } } /****************************************************************************** * * Routines to do the real GPIB work. * * These functions are invoked by the GPIB link task. As such, they should not * do any expensive operations within the context of that task. If expensive * non-I/O related things are to be done, they should be done by scheduling a * callbackRequest for an other function to handle it. * ******************************************************************************/ static void aiGpibWork(pdpvt) struct hvpsDpvt *pdpvt; { double value; struct aiRecord *pai= ((struct aiRecord *)(pdpvt->precord)); struct hvpsGpibCmd *pCmd = &hvpsGpibCmds[pdpvt->parm]; /* go send predefined cmd msg and read response into msg[] */ if(HvpsDebug) logMsg("aiGpibWork: starting ...\n"); if (xxGpibWork(pdpvt) == ERROR) { if(HvpsDebug) logMsg("aiGpibWork: error in xxGpibWork ...\n"); setPvSevr(pai,READ_ALARM,VALID_ALARM); } else /* interpret response that came back */ { /* call convert routine, if defined */ if (pCmd->convert != NULL) { if(HvpsDebug) logMsg("aiGpibWork: calling convert ...\n"); (*(pCmd->convert))(pdpvt,pCmd->P1,pCmd->P2, pCmd->P3); if(HvpsDebug) logMsg("aiGpibWork: returned from convert ...\n"); } else /* interpret msg with predefined format and write into .val */ { /* scan response string, return value will be 1 if successful */ if(sscanf(pdpvt->msg,pCmd->format,&value)) { pai->val = value; } else /* sscanf did not find or assign the parameter */ { setPvSevr(pai,READ_ALARM,VALID_ALARM); } } } if(HvpsDebug) logMsg("aiGpibWork: calling process ...\n"); pdpvt->head.header.callback.finishProc = pdpvt->process; pdpvt->head.header.callback.priority = pdpvt->processPri; callbackRequest(pdpvt); /* jrw */ } static void siGpibWork(pdpvt) struct hvpsDpvt *pdpvt; { struct stringinRecord *pstringin= ((struct stringinRecord *)(pdpvt->precord)); struct hvpsGpibCmd *pCmd = &hvpsGpibCmds[pdpvt->parm]; /* go send predefined cmd msg and read response into msg[] */ if(HvpsDebug) logMsg("stringinGpibWork: starting ...\n"); if (xxGpibWork(pdpvt) == ERROR) { if(HvpsDebug) logMsg("stringinGpibWork: error in xxGpibWork ...\n"); setPvSevr(pstringin,READ_ALARM,VALID_ALARM); } else /* interpret response that came back */ { /* call convert routine, if defined */ if (pCmd->convert != NULL) { if(HvpsDebug) logMsg("stringinGpibWork: calling convert ...\n"); (*(pCmd->convert))(pdpvt,pCmd->P1,pCmd->P2, pCmd->P3); if(HvpsDebug) logMsg("stringinGpibWork: returned from convert ...\n"); } else /* copy up to 39 characters into .val + null terminator */ { strncpy(pstringin->val,pdpvt->msg,39); pstringin->val[40] = '\0'; pstringin->udf = FALSE; } } if(HvpsDebug) logMsg("siGpibWork: calling process ...\n"); pdpvt->head.header.callback.finishProc = pdpvt->process; pdpvt->head.header.callback.priority = pdpvt->processPri; callbackRequest(pdpvt); /* jrw */ } static void aoGpibWork(pdpvt) struct hvpsDpvt *pdpvt; { int cnvrtStat = OK; struct aoRecord *pao= ((struct aoRecord *)(pdpvt->precord)); struct hvpsGpibCmd *pCmd = &hvpsGpibCmds[pdpvt->parm]; /* generate command string to be sent */ /* call convert routine, if defined */ if (pCmd->convert != NULL) { cnvrtStat = (*(pCmd->convert))(pdpvt, pCmd->P1,pCmd->P2, pCmd->P3); } else /* generate msg using predefined format and current val */ { sprintf(pdpvt->msg, pCmd->format, pao->val); } /* go access board with this message, unless convert was unsuccessful */ if ((cnvrtStat == ERROR) || (xxGpibWork(pdpvt) == ERROR)) { setPvSevr(pao,WRITE_ALARM,VALID_ALARM); } else if(pdpvt->rsp[0] == NAK) { pCmd->sta = &pdpvt->rsp[1]; setPvSevr(pao,WRITE_ALARM,VALID_ALARM); } else { pCmd->sta = pOK; } if(HvpsDebug) logMsg("aoGpibWork: calling process ...\n"); pdpvt->head.header.callback.finishProc = pdpvt->process; pdpvt->head.header.callback.priority = pdpvt->processPri; callbackRequest(pdpvt); /* jrw */ } static void soGpibWork(pdpvt) struct hvpsDpvt *pdpvt; { int cnvrtStat = OK; struct stringoutRecord *pstringout= ((struct stringoutRecord *)(pdpvt->precord)); struct hvpsGpibCmd *pCmd = &hvpsGpibCmds[pdpvt->parm]; /* generate command string to be sent */ /* call convert routine, if defined */ if (pCmd->convert != NULL) { cnvrtStat = (*(pCmd->convert))(pdpvt, pCmd->P1,pCmd->P2, pCmd->P3); } else /* generate msg using predefined format and current val */ { pstringout->udf = FALSE; strncpy(pdpvt->msg,pstringout->val,40 ); logMsg("parameter %d message %s type %d \n",pdpvt->parm,pdpvt->msg,pCmd->type); } /* go access board with this message, unless convert was unsuccessful */ if ((cnvrtStat == ERROR) || (xxGpibWork(pdpvt) == ERROR)) { setPvSevr(pstringout,WRITE_ALARM,VALID_ALARM); } if(HvpsDebug) logMsg("aiGpibWork: calling process ...\n"); pdpvt->head.header.callback.finishProc = pdpvt->process; pdpvt->head.header.callback.priority = pdpvt->processPri; callbackRequest(pdpvt); /* jrw */ } /* BUG -- use the convertion routine for the mode string stuff */ static void biGpibWork(pdpvt) struct hvpsDpvt *pdpvt; { unsigned long value; struct biRecord *pbi= ((struct biRecord *)(pdpvt->precord)); struct hvpsGpibCmd *pCmd = &hvpsGpibCmds[pdpvt->parm]; short strIndex; struct msgChar *pMsg = ( struct msgChar *)pdpvt->msg; /* go send predefined cmd msg and read response into msg[] */ if (xxGpibWork(pdpvt) == ERROR) { setPvSevr(pbi,READ_ALARM,VALID_ALARM); } else /* interpret response that came back */ { /* call convert routine, if defined */ if (pCmd->convert != NULL) { if(HvpsDebug) logMsg("biGpibWork calling convert routine\n"); (*(pCmd->convert))(pdpvt,pCmd->P1,pCmd->P2, pCmd->P3); if(HvpsDebug) logMsg("biGpibWork return from convert routine\n"); } else if (pCmd->P3 != NULL) /* compare with expected strings */ { strIndex = 0; while(pCmd->P3[strIndex] != NULL) { if( strncmp(pCmd->P3[strIndex],pMsg->data,strlen(pCmd->P3[strIndex])) == 0 ) break ; strIndex++; if(HvpsDebug) logMsg("biGpibWork:string index:%d\n",strIndex); } if(pCmd->P3[strIndex] != NULL & strIndex < 2) { pbi->udf = FALSE; pbi->val = strIndex; if(HvpsDebug) logMsg("biGpibWork: matched string index:%d\n",strIndex); } else { pbi->udf = TRUE; setPvSevr(pbi,READ_ALARM,VALID_ALARM); } } else /* interpret msg with predefined format and write into .rval */ { /* scan response string, return value will be 1 if successful */ if(sscanf(pdpvt->msg,pCmd->format, &value)) { pbi->rval = value; } else /* sscanf did not find or assign the parameter */ { setPvSevr(pbi,READ_ALARM,VALID_ALARM); } }/*else*/ }/*else*/ if(HvpsDebug) logMsg("biGpibWork calling final callback routine\n"); pdpvt->head.header.callback.finishProc = pdpvt->process; pdpvt->head.header.callback.priority = pdpvt->processPri; callbackRequest(pdpvt); /* jrw */ } static void boGpibWork(pdpvt) struct hvpsDpvt *pdpvt; { int cnvrtStat = OK; int strStat = OK; struct boRecord *pbo= ((struct boRecord *)(pdpvt->precord)); struct hvpsGpibCmd *pCmd = &hvpsGpibCmds[pdpvt->parm]; /* generate command string to be sent */ /* call convert routine, if defined */ if (pCmd->convert != NULL) { cnvrtStat = (*(pCmd->convert))(pdpvt,pCmd->P1,pCmd->P2, pCmd->P3); } else if(pbo->val == 0 || pbo->val == 1) { /* generate msg using predefined format and current val */ pbo->udf = FALSE; if(pCmd->P3[pbo->val] != NULL) { strncpy(pdpvt->msg, pCmd->P3[pbo->val],(pCmd->msgLen)-1); pdpvt->msg[pCmd->msgLen] = NULL; } else strStat = ERROR; } else cnvrtStat = ERROR; if(strStat == OK) { /* go access board with this message, unless convert was unsuccessful */ if ((cnvrtStat == ERROR) || (xxGpibWork(pdpvt) == ERROR)) { setPvSevr(pbo,WRITE_ALARM,MAJOR_ALARM); } else if(pdpvt->rsp[0] == NAK) { pCmd->sta = &pdpvt->rsp[1]; setPvSevr(pbo,WRITE_ALARM,MAJOR_ALARM); } else { pCmd->sta = pOK; } }/*strStat*/ if(HvpsDebug) logMsg("boGpibWork: calling process ...\n"); pdpvt->head.header.callback.finishProc = pdpvt->process; pdpvt->head.header.callback.priority = pdpvt->processPri; callbackRequest(pdpvt); /* jrw */ } /****************************************************************************** * * General GPIB work function. * This is the only place (after initialization) that any GPIB message commands * are issued. * ******************************************************************************/ static int xxGpibWork(pdpvt) struct hvpsDpvt *pdpvt; { int status; /* for GPIBREAD, contains ERROR or # of bytes read */ struct hvpsGpibCmd *pCmd = &hvpsGpibCmds[pdpvt->parm]; short ibnode = pdpvt->head.device; short bbnode; /* If is a BBGPIB_IO link, the bug address is needed */ if (pdpvt->linkType == BBGPIB_IO) bbnode = pdpvt->head.bitBusDpvt->txMsg->node; if (HvpsDebug) logMsg("Hvps - xxGpibWork(%08.8X): device = %d, link = %d\n", pdpvt, pdpvt->head.device, pdpvt->head.link); /* * check to see if this node has timed out within last 10 sec */ /* BUG -- loose the hard-coded ticks and fix refs to the tmoTable */ if(hvpsTmoTable[pdpvt->head.link][1] != 0) { if(tickGet() < (hvpsTmoTable[pdpvt->head.link][0] +600) ) { if (HvpsDebug) logMsg("Hvps-xxGpibWork(): timeout flush\n"); return(ERROR); } } switch (pCmd->type) { case GPIBWRITE: /* write the message to the GPIB listen adrs */ if(HvpsDebug) logMsg("xxGpibWork : processing GPIBWRITE\n"); status = (*(drvGpib.writeIb))(pdpvt->linkType, pdpvt->head.link, bbnode, ibnode, pdpvt->msg, strlen(pdpvt->msg)); /* * use for devices which respond to write commands */ #ifdef RESPONDS_2_WRITES if (status == ERROR) { break; } if(hvpsGpibDelay) taskDelay(hvpsGpibDelay); status = (*(drvGpib.readIb))(pdpvt->linkType, pdpvt->head.link, bbnode, ibnode, pdpvt->rsp, pCmd->rspLen); #endif break; case GPIBREAD: /* write the command string */ if(HvpsDebug) logMsg("xxGpibWork : processing GPIBREAD\n"); status = (*(drvGpib.writeIb))(pdpvt->linkType, pdpvt->head.link, bbnode, ibnode, pCmd->cmd, strlen(pCmd->cmd)); if (status == ERROR) break; /* read the instrument */ if(hvpsGpibDelay) taskDelay(hvpsGpibDelay); status = (*(drvGpib.readIb))(pdpvt->linkType, pdpvt->head.link, bbnode, ibnode, pdpvt->msg, pCmd->msgLen); if (status == ERROR) break; else if (status >( (pCmd->msgLen) - 1) ) /* check length of resp */ { logMsg("GPIB Response length equaled allocated space !!!\n"); pdpvt->msg[(pCmd->msgLen)-1] = '\0'; /* place \0 at end */ } else { pdpvt->msg[status] = '\0'; /* terminate response with \0 */ } break; /* BUG - this srq stuff is not right at all */ #ifdef _SRQSUPPORT_ case GPIBREADW: /* write the command string */ if(HvpsDebug) logMsg("xxGpibWork : processing GPIBREADW\n"); /*enable SRQ to set semaphore*/ srqTable.active = TRUE; srqTable.status = 0; status = (*(drvGpib.writeIb))( pdpvt->link,pdpvt->lad, pCmd->cmd, strlen(pCmd->cmd)); if (status == ERROR) break; /*wait for SRQ on measurement completion*/ /* BUG -this should be via callbackRequest span */ semTake(HvpsSrqSEM); logMsg("srq startus %x\n",srqTable.status); /* read the instrument */ status = (*(drvGpib.readIb))(pdpvt->link,pdpvt->tad, pdpvt->msg, pCmd->msgLen); if (status == ERROR) break; else if (status >( (pCmd->msgLen) - 1) ) /* check length of resp */ { logMsg("GPIB Response length equaled allocated space !!!\n"); pdpvt->msg[(pCmd->msgLen)-1] = '\0'; /* place \0 at end */ } else { pdpvt->msg[status] = '\0'; /* terminate response with \0 */ } break; #endif /* _SRQSUPPORT_ */ case GPIBCMD: /* write the cmd to the GPIB listen adrs */ status = (*(drvGpib.writeIb))(pdpvt->linkType, pdpvt->head.link, bbnode, ibnode, pCmd->cmd, strlen(pCmd->cmd)); break; /* BUG - this is not supported... yet */ #ifdef I_CANT_DO_THIS case GPIBINIT: /* write the cmd & SDC to GPIB listen adrs */ status = initib(pdpvt->head.device, pCmd->cmd, strlen(pCmd->cmd)); break; #endif } if(HvpsDebug) logMsg("xxGpibWork : done, status = %d\n",status); /* if error occurrs then mark it with time */ if(status == ERROR) { hvpsTmoTable[pdpvt->head.link][0] = tickGet(); hvpsTmoTable[pdpvt->head.link][1]++; } return(status); } /****************************************************************************** * * This function is called by the callback task. The callback task * calls it after being given the 'go ahead' by callbackRequest() * function calls made in the xxxWork routines defined above. * * The reason it is done this way is because the process() call may * recursively call itself when records are chained and the callback * task's stack is larger... just for this purpose. (jrw) * ******************************************************************************/ void processCallback(pDpvt) struct hvpsDpvt *pDpvt; { if(HvpsDebug) logMsg("processCallback: locking %08.8X\n", pDpvt->precord); dbScanLock(pDpvt->precord); if(HvpsDebug) logMsg("processCallback: calling process\n"); (*(struct rset *)(pDpvt->precord->rset)).process(pDpvt->precord->pdba); if(HvpsDebug) logMsg("processCallback: unlocking %08.8X\n", pDpvt->precord); dbScanUnlock(pDpvt->precord); } /****************************************************************************** * * Convert routines for the Hvps * ******************************************************************************/ /* BUG - deal with hard-coded lengths, they are bad as well as wrong */ static int inMode(pdpvt,P1,P2,P3) struct hvpsDpvt *pdpvt; int P1; int P2; char **P3; { strncpy(((struct stringinRecord *)(pdpvt->precord))->val, pdpvt->msg,39); ((struct stringinRecord *)(pdpvt->precord))->val[39] = '\0'; } static int getRespStr(pdpvt,P1,P2,P3) struct hvpsDpvt *pdpvt; int P1; int P2; char **P3; { struct stringinRecord *pstringin= (struct stringinRecord *)(pdpvt->precord); struct hvpsGpibCmd *pCmd = &hvpsGpibCmds[P1]; pstringin->udf = FALSE; strncpy(pstringin->val,pCmd->sta,39); pstringin->val[40] = '\0'; } static int inData(pdpvt,P1,P2,P3) struct hvpsDpvt *pdpvt; int P1; int P2; char **P3; { short i; char *pFirstDataByte; struct aiRecord *pai= (struct aiRecord *)(pdpvt->precord); struct msgMetered *pMsg = ( struct msgMetered *)pdpvt->msg; pai->udf = FALSE; if(pMsg->acknak == ACK) { pFirstDataByte = (pdpvt->msg)+1; bcopy(pFirstDataByte,meteredData.data,56); /* for(i=0;i<=13;i++) meteredData.data[i] = pMsg->data[i];*/ meteredData.acknak = ACK; } else if(pMsg->acknak == NAK) { for(i=0;i<=13;i++) meteredData.data[i] = UNDEFINED; meteredData.acknak = NAK; setPvSevr(pai,MAJOR_ALARM,VALID_ALARM); } } static int getInData(pdpvt,P1,P2,P3) struct hvpsDpvt *pdpvt; int P1; int P2; char **P3; { struct aiRecord *pai= (struct aiRecord *)(pdpvt->precord); struct msgMetered *pMsg = &meteredData; pai->udf = FALSE; pai->val = pMsg->data[P1]; if(pMsg->acknak == NAK) setPvSevr(pai,MAJOR_ALARM,VALID_ALARM); } static int inStatus(pdpvt,P1,P2,P3) struct hvpsDpvt *pdpvt; int P1; int P2; char **P3; { short i; struct biRecord *pbi= (struct biRecord *)(pdpvt->precord); struct msgChar *pMsg = (struct msgChar *)pdpvt->msg; pbi->udf = FALSE; if(pMsg->acknak == ACK) { if(HvpsDebug) logMsg("inStatus entered with ACK\n"); for(i=0;i<=4;i++) statusData.data[i] = pMsg->data[i]; statusData.acknak = ACK; } else if(pMsg->acknak == NAK) { if(HvpsDebug) logMsg("inStatus entered with NAK\n"); statusData.acknak = NAK; setPvSevr(pbi,MAJOR_ALARM,VALID_ALARM); } } static int getInStatus(pdpvt,P1,P2,P3) struct hvpsDpvt *pdpvt; int P1; int P2; char **P3; { struct biRecord *pbi= (struct biRecord *)(pdpvt->precord); struct msgChar *pMsg = &statusData; pbi->udf = FALSE; pbi->val = ( (pMsg->data[P1]) & P2 ) ? 1:0; if(pMsg->acknak == NAK) setPvSevr(pbi,MAJOR_ALARM,VALID_ALARM); } static int inOnTimers(pdpvt,P1,P2,P3) struct hvpsDpvt *pdpvt; int P1; int P2; char **P3; { short i; struct aiRecord *pai= (struct aiRecord *)(pdpvt->precord); struct msgChar *pMsg = (struct msgChar *)pdpvt->msg; struct hvpsGpibCmd *pCmd = &hvpsGpibCmds[pdpvt->parm]; pai->udf = FALSE; if(pMsg->acknak == ACK) { sscanf(pMsg->data,pCmd->format,&onTimerData.data[0], &onTimerData.data[1] ); onTimerData.acknak = ACK; } else if(pMsg->acknak == NAK) { for(i=0;i<=1;i++) onTimerData.data[i] = UNDEFINED; strncpy(pdpvt->rsp, pdpvt->msg,(pCmd->rspLen)-1); pdpvt->rsp[pCmd->rspLen] = '\0'; onTimerData.acknak = NAK; setPvSevr(pai,MAJOR_ALARM,VALID_ALARM); } } static int getInTimers(pdpvt,P1,P2,P3) struct hvpsDpvt *pdpvt; int P1; int P2; char **P3; { struct aiRecord *pai= (struct aiRecord *)(pdpvt->precord); struct msgMetered *pMsg = &onTimerData; pai->udf = FALSE; pai->val = pMsg->data[P1]; if(pMsg->acknak == NAK) setPvSevr(pai,MAJOR_ALARM,VALID_ALARM); } static int inCounts(pdpvt,P1,P2,P3) struct hvpsDpvt *pdpvt; int P1; int P2; char **P3; { short i; struct aiRecord *pai= (struct aiRecord *)(pdpvt->precord); struct msgChar *pMsg = (struct msgChar *)pdpvt->msg; struct hvpsGpibCmd *pCmd = &hvpsGpibCmds[pdpvt->parm]; pai->udf = FALSE; if(pMsg->acknak == ACK) { sscanf(pMsg->data,pCmd->format,&countsData.data[0], &countsData.data[1] ); countsData.acknak = ACK; } else if(pMsg->acknak == NAK) { for(i=0;i<=1;i++) countsData.data[i] = UNDEFINED; strncpy(pdpvt->rsp, pdpvt->msg,(pCmd->rspLen)-1); pdpvt->rsp[pCmd->rspLen] = '\0'; countsData.acknak = NAK; setPvSevr(pai,MAJOR_ALARM,VALID_ALARM); } } static int getInCounts(pdpvt,P1,P2,P3) struct hvpsDpvt *pdpvt; int P1; int P2; char **P3; { struct aiRecord *pai= (struct aiRecord *)(pdpvt->precord); struct msgMetered *pMsg = &countsData; pai->udf = FALSE; pai->val = pMsg->data[P1]; if(pMsg->acknak == NAK) setPvSevr(pai,MAJOR_ALARM,VALID_ALARM); } static int inSetpt(pdpvt,P1,P2,P3) struct hvpsDpvt *pdpvt; int P1; int P2; char **P3; { short i; float temp; struct aiRecord *pai= (struct aiRecord *)(pdpvt->precord); struct msgChar *pMsg = (struct msgChar *)pdpvt->msg; struct hvpsGpibCmd *pCmd = &hvpsGpibCmds[pdpvt->parm]; pai->udf = FALSE; if(pMsg->acknak == ACK) { sscanf(pMsg->data,pCmd->format,&(pai->val)); pCmd->sta = pOK; } else if(pMsg->acknak == NAK) { strncpy(pdpvt->rsp, pdpvt->msg,(pCmd->rspLen)-1); pdpvt->rsp[pCmd->rspLen] = '\0'; pCmd->sta = pdpvt->rsp; setPvSevr(pai,MAJOR_ALARM,VALID_ALARM); } } static int setPvSevr(pPv, status,severity) struct dbCommon *pPv; short severity; short status; { if (severity > pPv->nsev) { pPv->nsta = status; pPv->nsev = severity; } }