diff --git a/src/devOpt/devXxDg535Gpib.c b/src/devOpt/devXxDg535Gpib.c new file mode 100644 index 000000000..eb43dc513 --- /dev/null +++ b/src/devOpt/devXxDg535Gpib.c @@ -0,0 +1,2405 @@ +/* devXxDg535Gpib.c */ +/* share/src/devOpt $Id$ */ +/* + * Author: Ned D. Arnold + * Date: 05-28-91 + * + * Experimental Physics and Industrial Control System (EPICS) + * + * Copyright 1988, 1989, 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 + * + * All rights reserved. No part of this publication may be reproduced, + * stored in a retrieval system, transmitted, in any form or by any + * means, electronic, mechanical, photocopying, recording, or otherwise + * without prior written permission of Los Alamos National Laboratory + * and Argonne National Laboratory. + * + * Modification Log: + * ----------------- + * .01 05-30-91 nda Initial Release + * .02 06-18-91 nda init_rec_mbbo must return(2) if no init value + * .03 07-02-91 nda renamed String/StringOut DSET's to Si/So + * .04 07-11-91 jrw added the callbackRequest to process() + * .05 07-15-91 jrw redesigned init processing... more generic + * .06 11-01-91 jrw major rework to fit into new GPIB driver + * .07 11-11-91 jrw added new version of SRQ support + * ... + */ + + +/* devDg535Gpib.c - Device Support Routines */ +/* includes support for the following device types : */ + +#define DSET_AI devAiDg535Gpib +#define DSET_AO devAoDg535Gpib +#define DSET_BI devBiDg535Gpib +#define DSET_BO devBoDg535Gpib +#define DSET_MBBO devMbbiDg535Gpib +#define DSET_MBBI devMbboDg535Gpib +#define DSET_SI devSiDg535Gpib +#define DSET_SO devSoDg535Gpib + +#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 { + long number; + DRVSUPFUN report; + DRVSUPFUN init; + int (*qGpibReq)(); + int (*registerSrqCallback)(); + int (*writeIb)(); + int (*readIb)(); + int (*writeIbCmd)(); + int (*ioctl)(); +} drvGpib; + +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_mbbi(); +long read_mbbi(); +long init_rec_mbbo(); +long write_mbbo(); +long init_rec_stringin(); +long read_stringin(); +long init_rec_stringout(); +long write_stringout(); +long init_rec_xx(); + +long report(); + +int aiGpibWork(), aiGpibSrq(), aiGpibFinish(); +int aoGpibWork(); +int biGpibWork(), biGpibSrq(), biGpibFinish(); +int boGpibWork(); +int mbbiGpibWork(), mbbiGpibSrq(), mbbiGpibFinish(); +int mbboGpibWork(); +int stringinGpibWork(), stringinGpibSrq(), stringinGpibFinish(); +int stringoutGpibWork(); +int xxGpibWork(); + +int srqHandler(); + +void processCallback(); +void callbackRequest(); + +/****************************************************************************** + * + * Define all the dset's. + * + * Note that the dset names are provided via the #define lines at the top of + * the file. + * + * Other than for the debugging flag, these DSETs are the only items that + * will appear in the global name space within the IOC. + * + ******************************************************************************/ +/* ai dset*/ +typedef struct { + long number; + DEVSUPFUN report; + DEVSUPFUN init; + DEVSUPFUN init_record; + DEVSUPFUN get_ioint_info; + DEVSUPFUN read_ai; + DEVSUPFUN special_linconv; +} gDset; + +gDset DSET_AI = { 6, report, init_dev_sup, init_rec_ai, NULL, read_ai, NULL }; +gDset DSET_AO = { 6, NULL, NULL, init_rec_ao, NULL, write_ao, NULL }; +gDset DSET_BI = { 5, NULL, NULL, init_rec_bi, NULL, read_bi }; +gDset DSET_BO = { 5, NULL, NULL, init_rec_bo, NULL, write_bo }; +gDset DSET_MBBI = { 5, NULL, NULL, init_rec_mbbi, NULL, read_mbbi }; +gDset DSET_MBBO = { 5, NULL, NULL, init_rec_mbbo, NULL, write_mbbo }; +gDset DSET_SI = { 5, NULL, NULL, init_rec_stringin, NULL, read_stringin }; +gDset DSET_SO = { 5, NULL, NULL, init_rec_stringout, NULL, write_stringout }; + +/****************************************************************************** + * + * This section defines any device-type specific data areas. + * + ******************************************************************************/ +/*#define RESPONDS_2_WRITES */ /* if GPIB machine responds to writes */ +#define _SRQSUPPORT_ /* for srq support */ + +#define TIME_WINDOW 600 /* 10 seconds on a getTick call */ + +int dg535Debug = 0; +extern int ibSrqDebug; + +static char UDF[10] = "Undefined"; +static char pOK[3] = "OK"; + +/* forward declarations of some custom convert routines */ + +int setDelay(); /* used to set delay */ +int rdDelay(); /* used to place string in .DESC field */ + +/****************************************************************************** + * + * This structure holds device-related data on a per-device basis and is + * referenced by the gpibDpvt structures. They are built using a linked + * list entered from hwpvtHead. This linked list is only for this specific + * device type (other gpib devices may have their own lists.) + * + ******************************************************************************/ +struct hwpvt { + struct hwpvt *next; /* to next structure for same type device */ + + int linkType; /* is a GPIB_IO, BBGPIB_IO... from link.h */ + int link; /* link number */ + int bug; /* used only on BBGPIB_IO links */ + int device; /* gpib device number */ + + unsigned long tmoVal; /* time last timeout occurred */ + unsigned long tmoCount; /* total number of timeouts since boot time */ + + /* No semaphore guards here because can inly be mod'd by the linkTask */ + int (*srqCallback)(); /* filled by cmds expecting SRQ callbacks */ + caddr_t parm; /* filled in by cmds expecting SRQ callbacks */ +}; +static struct hwpvt *hwpvtHead = NULL; /* pointer to first hwpvt in chain */ + +/****************************************************************************** + * + * This structure will be attached to each pv (via psub->dpvt) to store the + * appropriate head.workStart pointer, callback address to record support, + * gpib link #, device address, and command information. + * + ******************************************************************************/ + +struct gpibDpvt { + struct dpvtGpibHead head; /* fields used by the GPIB driver */ + + 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... */ + struct hwpvt *phwpvt; /* pointer to per-device private area */ +}; + +/****************************************************************************** + * + * This is used to define the strings that are used for button labels. + * These strings are put into the record's znam & onam foelds if the + * record is a BI or BO type and into the zrst, onst... fields of an + * MBBI or MBBO record. + * + * Before these strings are placed into the record, the record is + * check to see if there is already a string defined (could be user-entered + * with DCT.) If there is already a string present, it will be preserved. + * + * There MUST ALWAYS be 2 and only 2 entries in the names.item list + * for BI and BO records if a name list is being specified for them here. + * The names.count field is ignored for BI and BO record types, but + * should be properly specified as 2 for future compatibility. + * + * NOTE: + * If a name string is filled in an an MBBI/MBBO record, it's corresponding + * value will be filled in as well. For this reason, there MUST be + * a value array and a valid nobt value for every MBBI/MBBO record that + * contains an item array! + * + ******************************************************************************/ + +struct names { + int count; /* CURRENTLY only used for MBBI and MBBO */ + char **item; + unsigned long *value; /* CURRENTLY only used for MBBI and MBBO */ + short nobt; /* CURRENTLY only used for MBBI and MBBO */ +}; + +static char *offOnList[] = { "Off", "On" }; +static struct names offOn = { 2, offOnList, NULL, 1 }; + +static char *disableEnableList[] = { "Disable", "Enable" }; +static struct names disableEnable = { 2, disableEnableList, NULL, 1 }; + +static char *resetList[] = { "Reset", "Reset" }; +static struct names reset = { 2, resetList, NULL, 1 }; + +static char *lozHizList[] = { "50 OHM", "IB_Q_HIGH Z" }; +static struct names lozHiz = {2, lozHizList, NULL, 1}; + +static char *invertNormList[] = { "INVERT", "NORM" }; +static struct names invertNorm = { 2, invertNormList, NULL, 1 }; + +static char *fallingRisingList[] = { "FALLING", "RISING" }; +static struct names fallingRising = { 2, fallingRisingList, NULL, 1 }; + +static char *singleShotList[] = { "SINGLE", "SHOT" }; +static struct names singleShot = { 2, singleShotList, NULL, 1 }; + +static char *clearList[] = { "CLEAR", "CLEAR" }; +static struct names clear = { 2, clearList, NULL, 1 }; + +static char *tABCDList[] = { "T", "A", "B", "C", "D" }; +static unsigned long tABCDVal[] = { 1, 2, 3, 5, 6 }; +static struct names tABCD = { 5, tABCDList, tABCDVal, 3 }; + +static char *ttlNimEclVarList[] = { "TTL", "NIM", "ECL", "VAR" }; +static unsigned long ttlNimEclVarVal[] = { 0, 1, 2, 3 }; +static struct names ttlNimEclVar = { 4, ttlNimEclVarList, + ttlNimEclVarVal, 2 }; + +static char *intExtSsBmStopList[] = { "INTERNAL", "EXTERNAL", + "SINGLE SHOT", "BURST MODE", "STOP" }; +static unsigned long intExtSsBmStopVal[] = { 0, 1, 2, 3, 2 }; +static struct names intExtSsBm = { 4, intExtSsBmStopList, + intExtSsBmStopVal, 2 }; +static struct names intExtSsBmStop = { 5, intExtSsBmStopList, + intExtSsBmStopVal, 3 }; + +/* Channel Names, used to derive string representation of programmed delay */ + +char *pchanName[8] = {" ", "T + ", "A + ", "B + ", " ", "C + ", "D + ", " "}; + +/****************************************************************************** + * + * The following #define statements enumerate the record types that + * are supported by this device support module. These are used by the init + * routines when they to type checking against the records that have + * been defined for use with this type of GPIB device. + * + ******************************************************************************/ + +#define GPIB_AO 1 +#define GPIB_AI 2 +#define GPIB_BO 3 +#define GPIB_BI 4 +#define GPIB_MBBO 5 +#define GPIB_MBBI 6 +#define GPIB_SI 7 +#define GPIB_SO 8 + +/****************************************************************************** + * + * Enumeration of gpib command types supported by this device type. + * + ******************************************************************************/ + +#define GPIBREAD 1 +#define GPIBWRITE 2 +#define GPIBCMD 3 +#define GPIBCNTL 4 +#define GPIBSOFT 5 +#define GPIBREADW 6 +#define GPIBRAWREAD 7 + +/****************************************************************************** + * + * 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 (gpibDpvt.msg) + * (3) 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 gpibDpvt->dbAddr->precord->val + * (2) The ascii string is sent to the instrument + * + * GPIBCMD : (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 + * + * GPIBREADW : (1) The cmd string is sent to the instrument + * (2) Wait for SRQ + * (3) Data is read from the inst into a buffer (gpibDpvt.msg) + * (4) The important data is extracted from the buffer using the + * format string. + * + * GPIBRAWREAD: Used internally with GPIBREADW. Not useful from cmd table. + * + * 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 + * gpibCmd.convert field to use it rather than the above approaches. + * + ******************************************************************************/ + +struct gpibCmd { + int rec_typ; /* enum - GPIB_AO GPIB_AI GPIB_BO... */ + 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; /* pointer to button label strings */ +}; + +/****************************************************************************** + * + * Array of structures that define all GPIB messages + * supported for this type of instrument. + * + ******************************************************************************/ + +#define FILL {0,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 gpibCmd gpibCmds[] = +{ + /* Param 0, (model) */ +FILL, + + /* Channel A Delay and Output */ + /* Param 1, write A delay */ + {GPIB_AO, GPIBWRITE, IB_Q_HIGH, UDF, "DT 2\n", "DT 2,?,%.12lf\n", 0, 32, + setDelay, 0, 0, NULL, NULL}, + + /* Param 2, currently undefined */ + FILL, + + /* Param 3, read A Delay */ + {GPIB_AI, GPIBREAD, IB_Q_LOW, UDF, "DT 2\n", NULL, 0, 32, + rdDelay, 0, 0, NULL, NULL }, + + /* Param 4, not yet implemented */ + FILL, + + /* Param 5, set A delay reference channel */ + {GPIB_MBBO, GPIBWRITE, IB_Q_HIGH, UDF, "DT 2\n", "DT 2,%u,", 0, 32, + setDelay, 0, 0, NULL, &tABCD}, + + /* Param 6, read A delay reference */ + {GPIB_MBBI, GPIBREAD, IB_Q_LOW, UDF, "DT 2\n", NULL, 0, 32, + rdDelay, 0, 0, NULL, &tABCD}, + + /* Param 7, set A output mode */ + {GPIB_MBBO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "OM 2,%u\n", 0, 32, + NULL, 0, 0, NULL, &ttlNimEclVar}, + + /* Param 8, read A output mode */ + {GPIB_MBBI, GPIBREAD, IB_Q_LOW, UDF, "OM 2\n", "%lu", 0, 32, + NULL, 0, 0, NULL, &ttlNimEclVar}, + + /* Param 9, set A output amplitude */ + {GPIB_AO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "OA 2,%.1f\n", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 10, read A output amplitude */ + {GPIB_AI, GPIBREAD, IB_Q_LOW, UDF, "OA 2\n", "%lf", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 11, set A output offset */ + {GPIB_AO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "OO 2,%.1f\n", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 12, read A output offset */ + {GPIB_AI, GPIBREAD, IB_Q_LOW, UDF, "OO 2\n", "%lf", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 13, set A output Termination */ + {GPIB_BO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "TZ 2,%u\n", 0, 32, + NULL, 0, 0, NULL, &lozHiz}, + + /* Param 14, read A output Termination */ + {GPIB_BI, GPIBREAD, IB_Q_LOW, UDF, "TZ 2\n", "%lu", 0, 32, + NULL, 0, 0, NULL, &lozHiz}, + + /* Param 15, set A output Polarity */ + {GPIB_BO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "OP 2,%u\n", 0, 32, + NULL, 0, 0, NULL, &invertNorm}, + + /* Param 16, read A output Polarity */ + {GPIB_BI, GPIBREAD, IB_Q_LOW, UDF, "OP 2\n", "%lu", 0, 32, + NULL, 0, 0, NULL, NULL}, + +/* Channel B Delay and Output */ + /* Param 17, write B delay */ + {GPIB_AO, GPIBWRITE, IB_Q_HIGH, UDF, "DT 3\n", "DT 3,?,%.12lf\n", 0, 32, + setDelay, 0, 0, NULL, NULL}, + + /* Param 18, currently undefined */ + FILL, + + /* Param 19, read B Delay */ + {GPIB_AI, GPIBREAD, IB_Q_LOW, UDF, "DT 3\n", NULL, 0, 32, + rdDelay, 0, 0, NULL, NULL}, + + /* Param 20, not yet implemented */ + FILL, + + /* Param 21, set B delay reference channel */ + {GPIB_MBBO, GPIBWRITE, IB_Q_HIGH, UDF, "DT 3\n", "DT 3,%u,", 0, 32, + setDelay, 0, 0, NULL, &tABCD}, + + /* Param 22, read B delay reference */ + {GPIB_MBBI, GPIBREAD, IB_Q_LOW, UDF, "DT 3\n", NULL, 0, 32, + rdDelay, 0 ,0, NULL, &tABCD}, + + /* Param 23, set B output mode */ + {GPIB_MBBO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "OM 3,%u\n", 0, 32, + NULL, 0, 0, NULL, &ttlNimEclVar}, + + /* Param 24, read B output mode */ + {GPIB_MBBI, GPIBREAD, IB_Q_LOW, UDF, "OM 3\n", "%lu", 0 ,32, + NULL, 0, 0, NULL, &ttlNimEclVar}, + + /* Param 25, set B output amplitude */ + {GPIB_AO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "OA 3,%.1f\n", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 26, read B output amplitude */ + {GPIB_AI, GPIBREAD, IB_Q_LOW, UDF, "OA 3\n", "%lf", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 27, set B output offset */ + {GPIB_AO, GPIBWRITE, IB_Q_HIGH, NULL, "OO 3,%.1f\n", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 28, read B output offset */ + {GPIB_AI, GPIBREAD, IB_Q_LOW, UDF, "OO 3\n", "%lf", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 29, set B output Termination */ + {GPIB_BO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "TZ 3,%u\n", 0, 32, + NULL, 0, 0, NULL, &lozHiz}, + + /* Param 30, read B output Termination */ + {GPIB_BI, GPIBREAD, IB_Q_LOW, UDF, "TZ 3\n", "%lu", 0, 32, + NULL, 0, 0, NULL, &lozHiz}, + + /* Param 31, set B output Polarity */ + {GPIB_BO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "OP 3,%u\n", 0, 32, + NULL, 0, 0, NULL, &invertNorm}, + + /* Param 32, read B output Polarity */ + {GPIB_BI, GPIBREAD, IB_Q_LOW, UDF, "OP 3\n", "%lu", 0, 32, + NULL, 0, 0, NULL, NULL}, + +/* Channel AB Outputs */ + /* Param 33, set AB output mode */ + {GPIB_MBBO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "OM 4,%u\n", 0, 32, + NULL, 0, 0, NULL, &ttlNimEclVar}, + + /* Param 34, read AB output mode */ + {GPIB_MBBI, GPIBREAD, IB_Q_LOW, UDF, "OM 4\n", "%lu", 0, 32, + NULL, 0, 0, NULL, &ttlNimEclVar}, + + /* Param 35, set AB output amplitude */ + {GPIB_AO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "OA 4,%.1f\n", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 36, read AB output amplitude */ + {GPIB_AI, GPIBREAD, IB_Q_LOW, UDF, "OA 4\n", "%lf", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 37, set AB output offset */ + {GPIB_AO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "OO 4,%.1f\n", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 38, read AB output offset */ + {GPIB_AI, GPIBREAD, IB_Q_LOW, UDF, "OO 4\n", "%lf", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 39, set AB output Termination */ + {GPIB_BO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "TZ 4,%u\n", 0, 32, + NULL, 0, 0, NULL, &lozHiz}, + + /* Param 40, read AB output Termination */ + {GPIB_BI, GPIBREAD, IB_Q_LOW, UDF, "TZ 4\n", "%lu", 0, 32, + NULL, 0, 0, NULL, &lozHiz}, + + /* Param 41, set AB output Polarity */ + {GPIB_BO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "OP 4,%u\n", 0, 32, + NULL, 0, 0, NULL, &invertNorm}, + + /* Param 42, read AB output Polarity */ + {GPIB_BI, GPIBREAD, IB_Q_LOW, UDF, "OP 4\n", "%lu", 0, 32, + NULL, 0, 0, NULL, NULL}, + +/* Channel C Delay and Output */ + /* Param 43, write C delay */ + {GPIB_AO, GPIBWRITE, IB_Q_HIGH, UDF, "DT 5\n", "DT 5,?,%.12lf\n", 0, 32, + setDelay, 0, 0, NULL, NULL}, + + /* Param 44, currently undefined */ + FILL, + + /* Param 45, read C Delay */ + {GPIB_AI, GPIBREAD, IB_Q_LOW, UDF, "DT 5\n", NULL, 0, 32, + rdDelay, 0, 0, NULL, NULL}, + + /* Param 46, not yet implemented */ + FILL, + + /* Param 47, set C delay reference channel */ + {GPIB_MBBO, GPIBWRITE, IB_Q_HIGH, UDF, "DT 5\n", "DT 5,%u,", 0, 32, + setDelay, 0, 0, NULL, &tABCD}, + + /* Param 48, read C delay reference */ + {GPIB_MBBI, GPIBREAD, IB_Q_LOW, UDF, "DT 5\n", NULL, 0, 32, + rdDelay, 0, 0, NULL, &tABCD}, + + /* Param 49, set C output mode */ + {GPIB_MBBO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "OM 5,%u\n", 0, 32, + NULL, 0, 0, NULL, &ttlNimEclVar}, + + /* Param 50, read C output mode */ + {GPIB_MBBI, GPIBREAD, IB_Q_LOW, UDF, "OM 5\n", "%lu", 0, 32, + NULL, 0, 0, NULL, &ttlNimEclVar}, + + /* Param 51, set C output amplitude */ + {GPIB_AO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "OA 5,%.1f\n", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 52, read C output amplitude */ + {GPIB_AI, GPIBREAD, IB_Q_LOW, UDF, "OA 5\n", "%lf", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 53, set C output offset */ + {GPIB_AI, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "OO 5,%.1f\n", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 54, read C output offset */ + {GPIB_AI, GPIBREAD, IB_Q_LOW, UDF, "OO 5\n", "%lf", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 55, set C output Termination */ + {GPIB_BO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "TZ 5,%u\n", 0, 32, + NULL, 0, 0, NULL, &lozHiz}, + + /* Param 56, read C utput Termination */ + {GPIB_BI, GPIBREAD, IB_Q_LOW, UDF, "TZ 5\n", "%lu", 0, 32, + NULL, 0, 0, NULL, &lozHiz}, + + /* Param 57, set C output Polarity */ + {GPIB_BO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "OP 5,%u\n", 0, 32, + NULL, 0, 0, NULL, &invertNorm}, + + /* Param 58, read C output Polarity */ + {GPIB_BI, GPIBREAD, IB_Q_LOW, UDF, "OP 5\n", "%lu", 0, 32, + NULL, 0, 0, NULL, NULL}, + +/* Channel D Delay and Output */ + /* Param 59, write D delay */ + {GPIB_AO, GPIBWRITE, IB_Q_HIGH, UDF, "DT 6\n", "DT 6,?,%.12lf\n", 0, 32, + setDelay, 0, 0, NULL, NULL}, + + /* Param 60, currently undefined */ + FILL, + + /* Param 61, read D Delay */ + {GPIB_AI, GPIBREAD, IB_Q_LOW, UDF, "DT 6\n", NULL, 0, 32, + rdDelay, 0, 0, NULL, NULL}, + + /* Param 62, not yet implemented */ + FILL, + + /* Param 63, set D delay reference channel */ + {GPIB_MBBO, GPIBWRITE, IB_Q_HIGH, UDF, "DT 6\n", "DT 6,%u,", 0, 32, + setDelay, 0, 0, NULL, &tABCD}, + + /* Param 64, read D delay reference */ + {GPIB_MBBI, GPIBREAD, IB_Q_LOW, UDF, "DT 6\n", NULL, 0, 32, + rdDelay, 0 ,0, NULL, &tABCD}, + + /* Param 65, set D output mode */ + {GPIB_MBBI, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "OM 6,%u\n", 0, 32, + NULL, 0, 0, NULL, &ttlNimEclVar}, + + /* Param 66, read D output mode */ + {GPIB_MBBI, GPIBREAD, IB_Q_LOW, UDF, "OM 6\n", "%lu", 0, 32, + NULL, 0, 0, NULL, &ttlNimEclVar}, + + /* Param 67, set D output amplitude */ + {GPIB_AO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "OA 6,%.1f\n", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 68, read D output amplitude */ + {GPIB_AI, GPIBREAD, IB_Q_LOW, UDF, "OA 6\n", "%lf", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 69, set D output offset */ + {GPIB_AO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "OO 6,%.1f\n", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 70, read D output offset */ + {GPIB_AI, GPIBREAD, IB_Q_LOW, UDF, "OO 6\n", "%lf", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 71, set D output Termination */ + {GPIB_BO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "TZ 6,%u\n", 0, 32, + NULL, 0, 0, NULL, &lozHiz}, + + /* Param 72, read D output Termination */ + {GPIB_BI, GPIBREAD, IB_Q_LOW, UDF, "TZ 6\n", "%lu", 0, 32, + NULL, 0, 0, NULL, &lozHiz}, + + /* Param 73, set D output Polarity */ + {GPIB_BO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "OP 6,%u\n", 0, 32, + NULL, 0, 0, NULL, &invertNorm}, + + /* Param 74, read D output Polarity */ + {GPIB_BI, GPIBREAD, IB_Q_LOW, UDF, "OP 6\n", "%lu", 0, 32, + NULL, 0, 0, NULL, NULL}, + +/* Channel CD Outputs */ + /* Param 75, set CD output mode */ + {GPIB_MBBO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "OM 7,%u\n", 0, 32, + NULL, 0, 0, NULL, &ttlNimEclVar}, + + /* Param 76, read CD output mode */ + {GPIB_MBBI, GPIBREAD, IB_Q_LOW, UDF, "OM 7\n", "%lu", 0, 32, + NULL, 0, 0, NULL, &ttlNimEclVar}, + + /* Param 77, set CD output amplitude */ + {GPIB_AO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "OA 7,%.1f\n", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 78, read CD output amplitude */ + {GPIB_AI, GPIBREAD, IB_Q_LOW, UDF, "OA 7\n", "%lf", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 79, set CD output offset */ + {GPIB_AI, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "OO 7,%.1f\n", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 80, read CD output offset */ + {GPIB_AI, GPIBREAD, IB_Q_LOW, UDF, "OO 7\n", "%lf", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 81, set CD output Termination */ + {GPIB_BO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "TZ 7,%u\n", 0, 32, + NULL, 0, 0, NULL, &lozHiz}, + + /* Param 82, read CD output Termination */ + {GPIB_BI, GPIBREAD, IB_Q_LOW, UDF, "TZ 7\n", "%lu", 0, 32, + NULL, 0, 0, NULL, &lozHiz}, + + /* Param 83, set CD output Polarity */ + {GPIB_BO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "OP 7,%u\n", 0, 32, + NULL, 0, 0, NULL, &invertNorm}, + + /* Param 84, read CD output Polarity */ + {GPIB_BI, GPIBREAD, IB_Q_LOW, UDF, "OP 7\n", "%lu", 0, 32, + NULL, 0, 0, NULL, NULL}, + +/* Trigger Settings */ + /* Param 85, set Trig Mode */ + {GPIB_MBBO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "TM %u\n", 0, 32, + NULL, 0, 0, NULL, &intExtSsBmStop}, + + /* Param 86, read Trig Mode */ + {GPIB_MBBI, GPIBREAD, IB_Q_LOW, UDF, "TM \n", "%lu", 0, 32, + NULL, 0, 0, NULL, &intExtSsBm}, + + /* Param 87, set Trig Rate */ + {GPIB_AO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "TR 0,%.3lf\n", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 88, read Trig Rate */ + {GPIB_AI, GPIBREAD, IB_Q_LOW, UDF, "TR 0\n", "%lf", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 89, set Burst Rate */ + {GPIB_AO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "TR 1,%.3lf\n", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 90, read Burst Rate */ + {GPIB_AI, GPIBREAD, IB_Q_LOW, UDF, "TR 1\n", "%lf", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 91, set Burst Count */ + {GPIB_AO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "BC %01.0lf\n", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 92, read Burst Count */ + {GPIB_AI, GPIBREAD, IB_Q_LOW, UDF, "BC \n", "%lf", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 93, set Burst Period */ + {GPIB_AO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "BP %01.0lf\n", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 94, read Burst Period */ + {GPIB_AI, GPIBREAD, IB_Q_LOW, UDF, "BP \n", "%lf", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 95, set Trig Input Z */ + {GPIB_BO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "TZ 0,%u\n", 0, 32, + NULL, 0, 0, NULL, &lozHiz}, + + /* Param 96, read Trig Input Z */ + {GPIB_BI, GPIBREAD, IB_Q_LOW, UDF, "TZ 0\n", "%lu", 0, 32, + NULL, 0, 0, NULL, &lozHiz}, + + /* Param 97, set Trig Input slope */ + {GPIB_BO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "TS %u\n", 0, 32, + NULL, 0, 0, NULL, &fallingRising}, + + /* Param 98, read Trig Input slope */ + {GPIB_BI, GPIBREAD, IB_Q_LOW, UDF, "TS \n", "%lu", 0, 32, + NULL, 0, 0, NULL, &fallingRising}, + + /* Param 99, set Trig Input level */ + {GPIB_AO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "TL %.2lf\n", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 100, read Trig Input Level */ + {GPIB_AI, GPIBREAD, IB_Q_LOW, UDF, "TL \n", "%lf", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 101, generate Single Trig */ + {GPIB_BO, GPIBCMD, IB_Q_HIGH, UDF, "SS \n", NULL, 0, 32, + NULL, 0, 0, NULL, &singleShot}, + + /* Param 102, Store Setting # */ + {GPIB_AO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "ST %01.0lf\n", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 103, Recall Setting # */ + {GPIB_AO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "RC %01.0lf\n", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 104, Recall Setting # */ + {GPIB_BO, GPIBCMD, IB_Q_HIGH, UDF, "CL \n", NULL, 0, 32, + NULL, 0, 0, NULL, &clear} +}; + + +/* The following is the number of elements in the command array above. */ +#define NUMPARAMS sizeof(gpibCmds)/sizeof(struct gpibCmd) + +#define GPIBMSGLENGTH 32 /* used by the delay routines only */ + +/****************************************************************************** + * + * Unique message interpretaion for reading Channel Delays : + * The command to read the delay setting returns a string with two arguments. + * This routine extracts both arguments and assigns them appropriately. Also, + * a string is generated with the format CHAN + xxx.xxxxxxxxxxxx and stored + * in the .DESC field of the ai record. (ex: T + .000000500000) If either + * parameter has changed, a db_post_event is issued for the .DESC field (ai + * record only). + * + ******************************************************************************/ + +static int rdDelay(pdpvt) +struct gpibDpvt *pdpvt; +{ + int status; + double delay; + unsigned long chan; + unsigned short monitor_mask = 0; + + struct aiRecord *pai= (struct aiRecord *)(pdpvt->precord); + struct mbbiRecord *pmbbi= (struct mbbiRecord *)(pdpvt->precord); + + if(dg535Debug) + logMsg("rdDelay : returned msg :%s\n",pdpvt->msg); + + /* Change the "," in returned string to a " " to separate fields */ + pdpvt->msg[1] = 0x20; + + /* scan response string for chan reference & delay value */ + status = sscanf(pdpvt->msg, "%ld%lf", &chan, &delay); + + if(dg535Debug) + logMsg("rdDelay :sscanf status = %d\n",status); + + switch (pdpvt->parm) + { + case 3: /* A Delay monitor, must be an ai record */ + case 19: /* B Delay monitor, must be an ai record */ + case 45: /* C Delay monitor, must be an ai record */ + case 61: /* D Delay monitor, must be an ai record */ + if (status == 2) /* make sure both parameters were assigned */ + { + /* check if delay or reference channel has changed */ + if ((pai->val != delay) || (pai->desc[0] != pchanName[chan][0])) + { + monitor_mask = DBE_VALUE; + } + /* assign new delay to value field*/ + pai->val = delay; + strcpy(pai->desc, pchanName[chan]); + strcat(pai->desc, &((pdpvt->msg)[3])); + if(dg535Debug) + logMsg("rdDelay : %s",pai->desc); + if (monitor_mask) + { + db_post_events(pai, pai->desc, monitor_mask); + } + } + else + { + if (pai->nsev < VALID_ALARM) + { + pai->nsev = VALID_ALARM; + pai->nsta = READ_ALARM; + } + } + break; + + case 6: /* A Delay Reference monitor, must be an mbbi record */ + case 22: /* B Delay Reference monitor, must be an mbbi record */ + case 48: /* C Delay Reference monitor, must be an mbbi record */ + case 64: /* D Delay Reference monitor, must be an mbbi record */ + if (status == 2) /* make sure both parameters were assigned */ + { + pmbbi->rval = chan; + } + else + { + if (pmbbi->nsev < VALID_ALARM) + { + pmbbi->nsev = VALID_ALARM; + pmbbi->nsta = READ_ALARM; + } + } + break; + } + return(OK); +} + +/****************************************************************************** + * + * Unique message generation for writing channel Delays : + * The command to set the channel delay requires two parameters: The channel + * # to reference from and the time delay. Since changing either of these + * parameters requires the command to be sent, the current state of other + * parameter must be determined. This is done by reading the delay (which + * returns both parameters), changing one of the paramaters, and sending + * the command back. + * + * WARNING!!!!! + * This function modifies the gpibCmds table!!! This is not a very nice + * thing to do! It is OK to do if only one dg535 is out there. But it will NOT + * work if there are more because modifying the gpibCmds table removes + * the re-entrant properties of this routine!!!! This should be + * re-designed to use a local temporary storage area. + * + ******************************************************************************/ + +static int setDelay(pdpvt) +struct gpibDpvt *pdpvt; +{ + int status; + char curChan; + char tempMsg[GPIBMSGLENGTH]; + + struct aoRecord *pao= (struct aoRecord *)(pdpvt->precord); + struct mbboRecord *pmbbo= (struct mbboRecord *)(pdpvt->precord); + + if(dg535Debug) + logMsg("setDelay : returned msg :%s\n",pdpvt->msg); + + /* adjust the gpibCmd to do a GPIBREAD of the current + * delay setting first. + */ + + gpibCmds[pdpvt->parm].type = GPIBREAD; + + /* go read the current delay setting */ + if(xxGpibWork(pdpvt, gpibCmds[pdpvt->parm].type) == ERROR) + { /* abort operation if read failed */ + gpibCmds[pdpvt->parm].type = GPIBWRITE; /* set back to write */ + return(ERROR); /* return, signalling an error */ + } + + /* Due to a fluke in the DG535, read again to insure accurate data */ + + if(xxGpibWork(pdpvt, gpibCmds[pdpvt->parm].type) == ERROR) /* go read the current delay setting */ + { /* abort operation if read failed */ + gpibCmds[pdpvt->parm].type = GPIBWRITE; /* set back to write */ + return(ERROR); /* return, signalling an error */ + } + + /* change one of the two parameters ... */ + + switch(pdpvt->parm) + { + case 1: /* changing time delay */ + case 17: + case 43: + case 59: + curChan = pdpvt->msg[0]; /* save current chan reference */ + /* generate new delay string (correct rounding error) */ + sprintf(pdpvt->msg,gpibCmds[pdpvt->parm].format, (pao->val + 1.0e-13)); + pdpvt->msg[5] = curChan; /* replace "?" with current chan */ + break; + + case 5: /* changing reference channel */ + case 21: + case 47: + case 63: + strcpy(tempMsg, &((pdpvt->msg)[3])); /* save current delay setting */ + /* generate new channel reference */ + sprintf(pdpvt->msg, gpibCmds[pdpvt->parm].format, (unsigned int)pmbbo->rval); + strcat(pdpvt->msg, tempMsg); /* append current delay setting */ + break; + } + + gpibCmds[pdpvt->parm].type = GPIBWRITE; /* set cmnd back to write */ + + return(OK); /* aoGpibWork or mbboGpibWork will call xxGpibWork */ +} +/************************************************************************** + * + * This should be the end of device specific modifications. + * + **************************************************************************/ + +/****************************************************************************** + * + * Print a report of operating statistics for all devices supported by this + * module. + * + ******************************************************************************/ +static long +report() +{ + struct hwpvt *phwpvt; + + printf("DG535 device support loaded:\n"); + + phwpvt = hwpvtHead; + + while (phwpvt != NULL) + { + if (phwpvt->linkType == GPIB_IO) + printf(" NI-link %d, node %d, timeouts %ld\n", phwpvt->link, phwpvt->device, phwpvt->tmoCount); + else if (phwpvt->linkType == BBGPIB_IO) + printf(" BB-link %d, bug %d, node %d, timeouts %ld\n", phwpvt->link, phwpvt->bug, phwpvt->device, phwpvt->tmoCount); + + phwpvt = phwpvt->next; + } + return(0); +} + + +/****************************************************************************** + * + * Initialization for device support + * This is called one time before any records are initialized with a parm + * value of 0. And then again AFTER all record-level init is complete + * with a param value of 1. + * + ******************************************************************************/ +static long +init_dev_sup() +{ + + static char firstTime = 1; + + if (!firstTime) + { + return(OK); + } + firstTime = 0; + logMsg("dg535 Device Support Initializing ...\n"); + + return(OK); +} + +/****************************************************************************** + * + * Initialization routines. + * + ******************************************************************************/ +/****************************************************************************** + * + * ai record init + * + ******************************************************************************/ + +static long +init_rec_ai(pai, process) +struct aiRecord *pai; +void (*process)(); +{ + long result; + + /* Do common initialization */ + if (result = init_rec_xx((caddr_t) pai, &pai->inp, GPIB_AI)) + { + return(result); + } + /* Do initialization of other fields in the record that are unique + * to this record type */ + + ((struct gpibDpvt *)pai->dpvt)->head.workStart = aiGpibWork; + + return(0); +} + +/****************************************************************************** + * + * ao record init + * + ******************************************************************************/ + +static long +init_rec_ao(pao, process) +struct aoRecord *pao; +void (*process)(); +{ + long result; + + /* do common initialization */ + if (result = init_rec_xx((caddr_t) pao, &pao->out, GPIB_AO)) + { + return(result); + } + /* do initialization of other fields in the record that are unique + * to this record type */ + + ((struct gpibDpvt *)pao->dpvt)->head.workStart = aoGpibWork; + + return(0); +} + +/****************************************************************************** + * + * bi record init + * + ******************************************************************************/ + +static long +init_rec_bi(pbi, process) +struct biRecord *pbi; +void (*process)(); +{ + long result; + + /* Do common initialization */ + if (result = init_rec_xx((caddr_t) pbi, &pbi->inp, GPIB_BI)) + { + return(result); + } + /* Do initialization of other fields in the record that are unique + * to this record type */ + + ((struct gpibDpvt *)pbi->dpvt)->head.workStart = biGpibWork; + + /* See if there are names asociated with the record that should */ + /* be filled in */ + if (gpibCmds[((struct gpibDpvt *)pbi->dpvt)->parm].namelist != NULL) + { + if (pbi->znam[0] == '\0') + { + strcpy(pbi->znam, gpibCmds[((struct gpibDpvt *)pbi->dpvt)->parm].namelist->item[0]); + } + if (pbi->onam[0] == '\0') + { + strcpy(pbi->onam, gpibCmds[((struct gpibDpvt *)pbi->dpvt)->parm].namelist->item[1]); + } + } + return(0); +} + +/****************************************************************************** + * + * bo record init + * + ******************************************************************************/ + +static long +init_rec_bo(pbo, process) +struct boRecord *pbo; +void (*process)(); +{ + long result; + + /* do common initialization */ + if (result = init_rec_xx((caddr_t) pbo, &pbo->out, GPIB_BO)) + { + return(result); + } + /* do initialization of other fields in the record that are unique + * to this record type */ + + ((struct gpibDpvt *)pbo->dpvt)->head.workStart = boGpibWork; + + /* see if there are names asociated with the record that should */ + /* be filled in */ + if (gpibCmds[((struct gpibDpvt *)pbo->dpvt)->parm].namelist != NULL) + { + if (pbo->znam[0] == '\0') + { + strcpy(pbo->znam, gpibCmds[((struct gpibDpvt *)pbo->dpvt)->parm].namelist->item[0]); + } + if (pbo->onam[0] == '\0') + { + strcpy(pbo->onam, gpibCmds[((struct gpibDpvt *)pbo->dpvt)->parm].namelist->item[1]); + } + } + return(0); +} + +/****************************************************************************** + * + * mbbi record init + * + ******************************************************************************/ + +static long +init_rec_mbbi(pmbbi, process) +struct mbbiRecord *pmbbi; +void (*process)(); +{ + long result; + char message[100]; + struct gpibDpvt *dpvt; /* pointer to gpibDpvt, not yet assigned */ + int name_ct; /* for filling in the name strings */ + char *name_ptr; /* index into name list array */ + unsigned long *val_ptr; /* indev into the value list array */ + + /* do common initialization */ + if (result = init_rec_xx((caddr_t)pmbbi, &pmbbi->inp, GPIB_MBBI)) + { + return(result); + } + + dpvt = (struct gpibDpvt *)pmbbi->dpvt; /* init pointer to gpibDpvt */ + + /* do initialization of other fields in the record that are unique + * to this record type */ + + dpvt->head.workStart = mbbiGpibWork; + + /* see if there are names asociated with the record that should */ + /* be filled in */ + if (gpibCmds[dpvt->parm].namelist != NULL) + { + if (gpibCmds[dpvt->parm].namelist->value == NULL) + { + sprintf(message, "devDg535Gpib: MBBI value list wrong for param #%d\n", dpvt->parm); + logMsg(message); + return(ERROR); + } + pmbbi->nobt = gpibCmds[dpvt->parm].namelist->nobt; + name_ct = 0; /* current name string element */ + name_ptr = pmbbi->zrst; /* first name string element */ + val_ptr = &(pmbbi->zrvl); /* first value element */ + while (name_ct < gpibCmds[dpvt->parm].namelist->count) + { + if (name_ptr[0] == '\0') + { + strcpy(name_ptr, gpibCmds[dpvt->parm].namelist->item[name_ct]); + *val_ptr = gpibCmds[dpvt->parm].namelist->value[name_ct]; + } + name_ct++; + name_ptr += sizeof(pmbbi->zrst); + val_ptr++; + } + } + return(0); +} + +/****************************************************************************** + * + * mbbo record init + * + ******************************************************************************/ + +static long +init_rec_mbbo(pmbbo, process) +struct mbboRecord *pmbbo; +void (*process)(); +{ + long result; + char message[100]; + struct gpibDpvt *dpvt; /* pointer to gpibDpvt, not yet assigned */ + int name_ct; /* for filling in the name strings */ + char *name_ptr; /* index into name list array */ + unsigned long *val_ptr; /* indev into the value list array */ + + /* do common initialization */ + if (result = init_rec_xx((caddr_t)pmbbo, &pmbbo->out, GPIB_MBBO)) + { + return(result); + } + + dpvt = (struct gpibDpvt *)pmbbo->dpvt; /* init pointer to gpibDpvt */ + + /* do initialization of other fields in the record that are unique + * to this record type */ + + dpvt->head.workStart = mbboGpibWork; + + /* see if there are names asociated with the record that should */ + /* be filled in */ + if (gpibCmds[dpvt->parm].namelist != NULL) + { + if (gpibCmds[dpvt->parm].namelist->value == NULL) + { + sprintf(message, "devDg535Gpib: MBBO value list wrong for param #%d\ +n", dpvt->parm); + logMsg(message); + return(ERROR); + } + + pmbbo->nobt = gpibCmds[dpvt->parm].namelist->nobt; + name_ct = 0; /* current name string element */ + name_ptr = pmbbo->zrst; /* first name string element */ + val_ptr = &(pmbbo->zrvl); /* first value element */ + while (name_ct < gpibCmds[dpvt->parm].namelist->count) + { + if (name_ptr[0] == '\0') + { + strcpy(name_ptr, gpibCmds[dpvt->parm].namelist->item[name_ct]); + *val_ptr = gpibCmds[dpvt->parm].namelist->value[name_ct]; + } + name_ct++; + name_ptr += sizeof(pmbbo->zrst); + val_ptr++; + } + } + return(2); +} + +/****************************************************************************** + * + * stringin record init + * + ******************************************************************************/ + +static long +init_rec_stringin(pstringin, process) +struct stringinRecord *pstringin; +void (*process)(); +{ + long result; + struct gpibDpvt *dpvt; /* pointer to gpibDpvt, not yet assigned */ + + /* do common initialization */ + if (result = init_rec_xx((caddr_t) pstringin, &pstringin->inp, GPIB_SI)) + { + return(result); + } + dpvt = (struct gpibDpvt *)pstringin->dpvt; /* init pointer to gpibDpvt */ + + /* do initialization of other fields in the record that are unique + * to this record type */ + + dpvt->head.workStart = stringinGpibWork; + + return(0); +} + +/****************************************************************************** + * + * stringout record init + * + ******************************************************************************/ + +static long +init_rec_stringout(pstringout, process) +struct stringoutRecord *pstringout; +void (*process)(); +{ + long result; + struct gpibDpvt *dpvt; /* pointer to gpibDpvt, not yet assigned */ + + /* do common initialization */ + if (result = init_rec_xx((caddr_t) pstringout, &pstringout->out, GPIB_SO)) + { + return(result); + } + + dpvt = (struct gpibDpvt *)pstringout->dpvt; /* init pointer to gpibDpvt */ + + /* do initialization of other fields in the record that are unique + * to this record type */ + + dpvt->head.workStart = stringoutGpibWork; + + return(0); +} + +/****************************************************************************** + * + * This init routine is common to all record types + * + ******************************************************************************/ +static long +init_rec_xx(prec, plink, rec_typ) +struct dbCommon *prec; +struct link *plink; +int rec_typ; +{ + struct gpibDpvt *pdpvt; + struct dbCommon *pdbCommon = (struct dbCommon *)prec; + char message[100]; + struct gpibCmd *pCmd; + char foundIt; + int bbnode; + + /* allocate space for the private structure */ + pdpvt = (struct gpibDpvt *) malloc(sizeof(struct gpibDpvt)); + prec->dpvt = (void *) pdpvt; + + pdpvt->precord = prec; + pdpvt->parm = -1; /* In case the sscanf fails */ + pdpvt->linkType = plink->type; + + switch (plink->type) { + case GPIB_IO: /* Is a straight Network Instruments link */ + 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 */ + bbnode = -1; + break; + + case BBGPIB_IO: /* Is a bitbus -> gpib link */ + pdpvt->head.device = plink->value.bbgpibio.gpibaddr; /* 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 */ + bbnode = plink->value.bbgpibio.bbaddr; + 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; + } + /* Try to find the hardware private structure */ + foundIt = 0; + pdpvt->phwpvt = hwpvtHead; + while ((pdpvt->phwpvt != NULL) && !foundIt) + { + if (pdpvt->phwpvt->linkType == plink->type && + pdpvt->phwpvt->link == pdpvt->head.link && + pdpvt->phwpvt->device == pdpvt->head.device) + if (plink->type == BBGPIB_IO) + { + if (pdpvt->phwpvt->bug == pdpvt->head.bitBusDpvt->txMsg->node) + foundIt = 1; + } + else + foundIt = 1; + else + pdpvt->phwpvt = pdpvt->phwpvt->next; /* check the next one */ + } + if (!foundIt) + { /* I couldn't find it. Allocate a new one */ + pdpvt->phwpvt = (struct hwpvt *) malloc(sizeof (struct hwpvt)); + pdpvt->phwpvt->next = hwpvtHead; /* put at the top of the list */ + hwpvtHead = pdpvt->phwpvt; + + pdpvt->phwpvt->linkType = plink->type; + pdpvt->phwpvt->link = pdpvt->head.link; + pdpvt->phwpvt->device = pdpvt->head.device; + + if (pdpvt->phwpvt->linkType == BBGPIB_IO) + pdpvt->phwpvt->bug = pdpvt->head.bitBusDpvt->txMsg->node; + + pdpvt->phwpvt->tmoVal = 0; + pdpvt->phwpvt->tmoCount = 0; + pdpvt->phwpvt->srqCallback = NULL; + pdpvt->phwpvt->parm = (caddr_t)NULL; + } + + /* Check for valid GPIB address */ + 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 > NUMPARAMS)) + { + strcpy(message, pdbCommon->name); + strcat(message,": init_record : Parameter # out of range"); + errMessage(S_db_badField,message); + return(S_db_badField); + } + + /* make sure that the record type matches the GPIB port type (jrw) */ + if (gpibCmds[pdpvt->parm].rec_typ != rec_typ ) + { + strcpy(message, pdbCommon->name); + strcat(message,": init_record: record type invalid for spec'd param #"); + errMessage(S_db_badField,message); + return(S_db_badField); + } + + pCmd = &gpibCmds[pdpvt->parm]; + if(pCmd->msgLen > 0) + pdpvt->msg = (char *)(malloc(pCmd->msgLen)); + if(pCmd->rspLen > 0) + pdpvt->rsp = (char *)(malloc(pCmd->rspLen)); + +#ifdef _SRQSUPPORT_ +/* + * Ok to re-register a handler for the same device, just don't do it after + * init time is over! + */ + (*(drvGpib.registerSrqCallback))(pdpvt->linkType, pdpvt->head.link, + bbnode, pdpvt->head.device, srqHandler, pdpvt->phwpvt); +#endif + + /* fill in the required stuff for the callcack task (jrw) */ + pdpvt->process = processCallback; + pdpvt->processPri = priorityLow; + + return(0); +} + +/****************************************************************************** + * + * These are the functions that are called to actually communicate with + * the GPIB device. + * + ******************************************************************************/ +static long +read_ai(pai) +struct aiRecord *pai; +{ + struct gpibDpvt *pdpvt = (struct gpibDpvt *)(pai->dpvt); + struct gpibCmd *pCmd; + + pCmd = &gpibCmds[pdpvt->parm]; + if (pai->pact) + { + if (dg535Debug) + 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(0); + } + else + { /* put pointer to dpvt field on ring buffer */ + if (dg535Debug) + 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 gpibDpvt *pdpvt = (struct gpibDpvt *)(pao->dpvt); + struct gpibCmd *pCmd; + + pCmd = &gpibCmds[pdpvt->parm]; + + if (pao->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(pao,WRITE_ALARM,VALID_ALARM); + return(0); + } + return(1); + } +} + +static long +read_bi(pbi) +struct biRecord *pbi; +{ + struct gpibDpvt *pdpvt = (struct gpibDpvt *)(pbi->dpvt); + struct gpibCmd *pCmd; + + pCmd = &gpibCmds[pdpvt->parm]; + + if (pbi->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(pbi,READ_ALARM,VALID_ALARM); + return(0); + } + return(1); + } +} + + +static long +write_bo(pbo) +struct boRecord *pbo; +{ + struct gpibDpvt *pdpvt = (struct gpibDpvt *)(pbo->dpvt); + struct gpibCmd *pCmd; + + pCmd = &gpibCmds[pdpvt->parm]; + + if (pbo->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(pbo,WRITE_ALARM,VALID_ALARM); + return(0); + } + return(1); + } +} + +static long +read_mbbi(pmbbi) +struct mbbiRecord *pmbbi; +{ + struct gpibDpvt *pdpvt = (struct gpibDpvt *)(pmbbi->dpvt); + struct gpibCmd *pCmd; + + pCmd = &gpibCmds[pdpvt->parm]; + + if (pmbbi->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(pmbbi,READ_ALARM,VALID_ALARM); + return(0); + } + return(1); + } +} + + +static long +write_mbbo(pmbbo) +struct mbboRecord *pmbbo; +{ + struct gpibDpvt *pdpvt = (struct gpibDpvt *)(pmbbo->dpvt); + struct gpibCmd *pCmd; + + pCmd = &gpibCmds[pdpvt->parm]; + + if (pmbbo->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(pmbbo,WRITE_ALARM,VALID_ALARM); + return(0); + } + return(1); + } +} + +static long +read_stringin(pstringin) +struct stringinRecord *pstringin; +{ + struct gpibDpvt *pdpvt = (struct gpibDpvt *)(pstringin->dpvt); + struct gpibCmd *pCmd; + + pCmd = &gpibCmds[pdpvt->parm]; + if (pstringin->pact) + { + if (dg535Debug) + 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 (dg535Debug) + 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 gpibDpvt *pdpvt = (struct gpibDpvt *)(pstringout->dpvt); + struct gpibCmd *pCmd; + + pCmd = &gpibCmds[pdpvt->parm]; + + 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); + } +} + +/****************************************************************************** + * + * Routines that do the actual GPIB work. They are called by the linkTask. + * + ******************************************************************************/ + +static int +aiGpibWork(pdpvt) +struct gpibDpvt *pdpvt; +{ + struct aiRecord *pai= ((struct aiRecord *)(pdpvt->precord)); + struct gpibCmd *pCmd = &gpibCmds[pdpvt->parm]; + + /* go send predefined cmd msg and read response into msg[] */ + + if(dg535Debug) + logMsg("aiGpibWork: starting ...\n"); + + if (xxGpibWork(pdpvt, pCmd->type) == ERROR) + { + setPvSevr(pai,READ_ALARM,VALID_ALARM); + + if(dg535Debug) + logMsg("aiGpibWork: calling process ...\n"); + + pdpvt->head.header.callback.finishProc = pdpvt->process; + pdpvt->head.header.callback.priority = pdpvt->processPri; + callbackRequest(pdpvt); + } + else + { + if (pCmd->type != GPIBREADW) + aiGpibFinish(pdpvt); /* If not waiting on SRQ, finish */ + else + { + pdpvt->phwpvt->srqCallback = aiGpibSrq; /* mark the handler */ + pdpvt->phwpvt->parm = (caddr_t)pdpvt; /* mark the handler */ + return(BUSY); /* indicate device still in use */ + } + } + return(IDLE); /* indicate device is now idle */ +} + +static int +aiGpibSrq(pdpvt, srqStatus) +struct gpibDpvt *pdpvt; +int srqStatus; +{ + if (dg535Debug || ibSrqDebug) + logMsg("aiGpibSrq(0x%08.8X, 0x%02.2X): processing srq\n", pdpvt, srqStatus); + + /* do actual SRQ processing in here */ + + pdpvt->phwpvt->srqCallback = NULL; /* unmark the handler */ + pdpvt->phwpvt->parm = (caddr_t)NULL; + + aiGpibFinish(pdpvt); /* and finish the processing */ + return(IDLE); /* indicate device now idle */ +} + +static int +aiGpibFinish(pdpvt) +struct gpibDpvt *pdpvt; +{ + double value; + struct aiRecord *pai = ((struct aiRecord *)(pdpvt->precord)); + struct gpibCmd *pCmd = &gpibCmds[pdpvt->parm]; + + if (pCmd->convert != NULL) + { + if(dg535Debug) + logMsg("aiGpibWork: calling convert ...\n"); + (*(pCmd->convert))(pdpvt,pCmd->P1,pCmd->P2, pCmd->P3); + if(dg535Debug) + 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(dg535Debug) + logMsg("aiGpibWork: calling process ...\n"); + + pdpvt->head.header.callback.finishProc = pdpvt->process; + pdpvt->head.header.callback.priority = pdpvt->processPri; + callbackRequest(pdpvt); + + return(0); +} + +static int +aoGpibWork(pdpvt) +struct gpibDpvt *pdpvt; +{ + int cnvrtStat = OK; + struct aoRecord *pao= ((struct aoRecord *)(pdpvt->precord)); + struct gpibCmd *pCmd = &gpibCmds[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, pCmd->type) == ERROR)) + { + setPvSevr(pao,WRITE_ALARM,VALID_ALARM); + } + + pdpvt->head.header.callback.finishProc = pdpvt->process; + pdpvt->head.header.callback.priority = pdpvt->processPri; + callbackRequest(pdpvt); /* jrw */ +} + +static int +biGpibWork(pdpvt) +struct gpibDpvt *pdpvt; +{ + struct biRecord *pbi= ((struct biRecord *)(pdpvt->precord)); + struct gpibCmd *pCmd = &gpibCmds[pdpvt->parm]; + + /* go send predefined cmd msg and read response into msg[] */ + + if (xxGpibWork(pdpvt, pCmd->type) == ERROR) + { + setPvSevr(pbi,READ_ALARM,VALID_ALARM); + + if(dg535Debug) + logMsg("aiGpibWork: calling process ...\n"); + + pdpvt->head.header.callback.finishProc = pdpvt->process; + pdpvt->head.header.callback.priority = pdpvt->processPri; + callbackRequest(pdpvt); + } + else /* interpret response that came back */ + { + if (pCmd->type != GPIBREADW) + biGpibFinish(pdpvt); /* If not waiting on SRQ, finish */ + else + { + pdpvt->phwpvt->srqCallback = biGpibSrq; /* mark the handler */ + pdpvt->phwpvt->parm = (caddr_t)pdpvt; /* mark the handler */ + return(BUSY); /* indicate device still in use */ + } + } + return(IDLE); +} + +static int +biGpibSrq(pdpvt, srqStatus) +struct gpibDpvt *pdpvt; +int srqStatus; +{ + if (dg535Debug || ibSrqDebug) + logMsg("biGpibSrq(0x%08.8X, 0x%02.2X): processing srq\n", pdpvt, srqStatus); + + /* do actual SRQ processing in here */ + + pdpvt->phwpvt->srqCallback = NULL; /* unmark the handler */ + pdpvt->phwpvt->parm = (caddr_t)NULL; /* unmark the handler */ + + biGpibFinish(pdpvt); /* and finish the processing */ + return(IDLE); /* indicate device now idle */ +} + +static int +biGpibFinish(pdpvt) +struct gpibDpvt *pdpvt; +{ + unsigned long value; + struct biRecord *pbi= ((struct biRecord *)(pdpvt->precord)); + struct gpibCmd *pCmd = &gpibCmds[pdpvt->parm]; + + if (pCmd->convert != NULL) + { + (*(pCmd->convert))(pdpvt,pCmd->P1,pCmd->P2, pCmd->P3); + } + 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); + } + } + + pdpvt->head.header.callback.finishProc = pdpvt->process; + pdpvt->head.header.callback.priority = pdpvt->processPri; + callbackRequest(pdpvt); /* jrw */ + + return(0); +} + + +static int +boGpibWork(pdpvt) +struct gpibDpvt *pdpvt; +{ + int cnvrtStat = OK; + int strStat = OK; + struct boRecord *pbo= ((struct boRecord *)(pdpvt->precord)); + struct gpibCmd *pCmd = &gpibCmds[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, (unsigned int)pbo->val); + } + + /* go access board with this message, unless convert was unsuccessful */ + if ((cnvrtStat == ERROR) || (xxGpibWork(pdpvt, pCmd->type) == ERROR)) + { + setPvSevr(pbo,WRITE_ALARM,VALID_ALARM); + } + + pdpvt->head.header.callback.finishProc = pdpvt->process; + pdpvt->head.header.callback.priority = pdpvt->processPri; + callbackRequest(pdpvt); +} + +static int +mbbiGpibWork(pdpvt) +struct gpibDpvt *pdpvt; +{ + struct mbbiRecord *pmbbi= ((struct mbbiRecord *)(pdpvt->precord)); + struct gpibCmd *pCmd = &gpibCmds[pdpvt->parm]; + + /* go send predefined cmd msg and read string response into msg[] */ + + if (xxGpibWork(pdpvt, pCmd->type) == ERROR) + { + setPvSevr(pmbbi,WRITE_ALARM,VALID_ALARM); + + if(dg535Debug) + logMsg("mbbiGpibWork: calling process ...\n"); + + pdpvt->head.header.callback.finishProc = pdpvt->process; + pdpvt->head.header.callback.priority = pdpvt->processPri; + callbackRequest(pdpvt); + } + else + { + if (pCmd->type != GPIBREADW) + mbbiGpibFinish(pdpvt); /* If not waiting on SRQ, finish */ + else + { + pdpvt->phwpvt->srqCallback = mbbiGpibSrq; /* mark the handler */ + pdpvt->phwpvt->parm = (caddr_t)pdpvt; /* mark the handler */ + return(BUSY); /* indicate device still in use */ + } + } + return(IDLE); +} + +static int +mbbiGpibSrq(pdpvt, srqStatus) +struct gpibDpvt *pdpvt; +int srqStatus; +{ + if (dg535Debug || ibSrqDebug) + logMsg("mbbiGpibSrq(0x%08.8X, 0x%02.2X): processing srq\n", pdpvt, srqStatus); + + /* do actual SRQ processing in here */ + + pdpvt->phwpvt->srqCallback = NULL; /* unmark the handler */ + pdpvt->phwpvt->parm = (caddr_t)NULL; /* unmark the handler */ + + mbbiGpibFinish(pdpvt); /* and finish the processing */ + return(IDLE); /* indicate device now idle */ +} + +static int +mbbiGpibFinish(pdpvt) +struct gpibDpvt *pdpvt; +{ + unsigned long value; + struct mbbiRecord *pmbbi= ((struct mbbiRecord *)(pdpvt->precord)); + struct gpibCmd *pCmd = &gpibCmds[pdpvt->parm]; + + if (pCmd->convert != NULL) + { + (*(pCmd->convert))(pdpvt,pCmd->P1,pCmd->P2, pCmd->P3); + } + 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)) + { + pmbbi->rval = value; + } + else /* sscanf did not find or assign the parameter */ + { + setPvSevr(pmbbi,READ_ALARM,VALID_ALARM); + } + } + pdpvt->head.header.callback.finishProc = pdpvt->process; + pdpvt->head.header.callback.priority = pdpvt->processPri; + callbackRequest(pdpvt); + + return(0); +} + +static int +mbboGpibWork(pdpvt) +struct gpibDpvt *pdpvt; +{ + int cnvrtStat = OK; + int strStat = OK; + struct mbboRecord *pmbbo= ((struct mbboRecord *)(pdpvt->precord)); + struct gpibCmd *pCmd = &gpibCmds[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, (unsigned int)pmbbo->rval); + } + + /* go access board with this message, unless convert was unsuccessful */ + if ((cnvrtStat == ERROR) || (xxGpibWork(pdpvt, pCmd->type) == ERROR)) + { + setPvSevr(pmbbo,WRITE_ALARM,VALID_ALARM); + } + + pdpvt->head.header.callback.finishProc = pdpvt->process; + pdpvt->head.header.callback.priority = pdpvt->processPri; + callbackRequest(pdpvt); /* jrw */ +} + +static int +stringinGpibWork(pdpvt) +struct gpibDpvt *pdpvt; +{ + struct stringinRecord *pstringin=((struct stringinRecord*)(pdpvt->precord)); + struct gpibCmd *pCmd = &gpibCmds[pdpvt->parm]; + + /* go send predefined cmd msg and read response into msg[] */ + + if(dg535Debug) + logMsg("stringinGpibWork: starting ...\n"); + + if (xxGpibWork(pdpvt, pCmd->type) == ERROR) + { + if(dg535Debug) + logMsg("stringinGpibWork: error in xxGpibWork ...\n"); + setPvSevr(pstringin,READ_ALARM,VALID_ALARM); + + pdpvt->head.header.callback.finishProc = pdpvt->process; + pdpvt->head.header.callback.priority = pdpvt->processPri; + callbackRequest(pdpvt); /* jrw */ + } + else + { + if (pCmd->type != GPIBREADW) + stringinGpibFinish(pdpvt); /* If not waiting on SRQ, finish */ + else + { + pdpvt->phwpvt->srqCallback = stringinGpibSrq; /* mark the handler */ + pdpvt->phwpvt->parm = (caddr_t)pdpvt; /* mark the handler */ + return(BUSY); /* indicate device still in use */ + } + } + return(IDLE); +} + +static int +stringinGpibSrq(pdpvt, srqStatus) +struct gpibDpvt *pdpvt; +int srqStatus; +{ + if (dg535Debug || ibSrqDebug) + logMsg("stringinGpibSrq(0x%08.8X, 0x%02.2X): processing srq\n", pdpvt, srqStatus); + + /* do actual SRQ processing in here */ + + pdpvt->phwpvt->srqCallback = NULL; /* unmark the handler */ + pdpvt->phwpvt->parm = (caddr_t)NULL; /* unmark the handler */ + + stringinGpibFinish(pdpvt); /* and finish the processing */ + return(IDLE); /* indicate device now idle */ +} + +static int +stringinGpibFinish(pdpvt) +struct gpibDpvt *pdpvt; +{ + struct stringinRecord *pstringin=((struct stringinRecord*)(pdpvt->precord)); + struct gpibCmd *pCmd = &gpibCmds[pdpvt->parm]; + + if (pCmd->convert != NULL) + { + if(dg535Debug) + logMsg("stringinGpibWork: calling convert ...\n"); + (*(pCmd->convert))(pdpvt,pCmd->P1,pCmd->P2, pCmd->P3); + if(dg535Debug) + logMsg("stringinGpibWork: returned from convert ...\n"); + } + else /* interpret msg with predefined format and write into .val */ + { + /* scan response string, return value will be 1 if successful */ + strncpy(pstringin->val,pdpvt->msg,39); + pstringin->val[40] = '\0'; + } + pdpvt->head.header.callback.finishProc = pdpvt->process; + pdpvt->head.header.callback.priority = pdpvt->processPri; + callbackRequest(pdpvt); /* jrw */ + + return(0); +} + +static int +stringoutGpibWork(pdpvt) +struct gpibDpvt *pdpvt; +{ + int cnvrtStat = OK; + struct stringoutRecord *pstringout= ((struct stringoutRecord *)(pdpvt->precord)); + struct gpibCmd *pCmd = &gpibCmds[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 */ + { + strncpy(pdpvt->msg, pstringout->val, 40); + } + + /* go access board with this message, unless convert was unsuccessful */ + if ((cnvrtStat == ERROR) || (xxGpibWork(pdpvt, pCmd->type) == ERROR)) + { + setPvSevr(pstringout,WRITE_ALARM,VALID_ALARM); + } + + pdpvt->head.header.callback.finishProc = pdpvt->process; + pdpvt->head.header.callback.priority = pdpvt->processPri; + callbackRequest(pdpvt); /* jrw */ +} + +static int +xxGpibWork(pdpvt, cmdType) +struct gpibDpvt *pdpvt; +int cmdType; +{ + int status; /* for GPIBREAD, contains ERROR or # of bytes read */ + struct gpibCmd *pCmd = &gpibCmds[pdpvt->parm]; + short ibnode = pdpvt->head.device; + short bbnode; /* In case is a bitbus->gpib type link */ + + /* If is a BBGPIB_IO link, the bug address is needed */ + if (pdpvt->linkType == BBGPIB_IO) + bbnode = pdpvt->head.bitBusDpvt->txMsg->node; + + /* + * check to see if this node has timed out within last 10 sec + */ + if(tickGet() < (pdpvt->phwpvt->tmoVal +TIME_WINDOW) ) + { + if (dg535Debug) + logMsg("dg535-xxGpibWork(): timeout flush\n"); + return(ERROR); + } + switch (cmdType) + { + case GPIBWRITE: /* write the message to the GPIB listen adrs */ + if(dg535Debug) + 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; + } + status = (*(drvGpib.readIb))(pdpvt->linkType, pdpvt->head.link, + bbnode, ibnode, pdpvt->rsp, pCmd->rspLen); +#endif + break; + + case GPIBREAD: /* write the command string */ + if(dg535Debug) + logMsg("xxGpibWork : processing GPIBREAD\n"); + status = (*(drvGpib.writeIb))(pdpvt->linkType, pdpvt->head.link, + bbnode, ibnode, pCmd->cmd, strlen(pCmd->cmd)); + if (status == ERROR) + { + break; + } + /* This falls thru to the raw read code below! */ + + case GPIBRAWREAD: /* for SRQs, read the data w/o a sending a command */ + + /* read the instrument */ + 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; + + case GPIBREADW: /* for SRQs, write the command first */ + 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; + case GPIBCNTL: /* send cmd with atn line active */ + status = (*(drvGpib.writeIbCmd))(pdpvt->linkType, pdpvt->head.link, + bbnode, pCmd->cmd, strlen(pCmd->cmd)); + break; + } + if(dg535Debug) + logMsg("xxGpibWork : done, status = %d\n",status); + + /* if error occurrs then mark it with time */ + if(status == ERROR) + { + (pdpvt->phwpvt->tmoCount)++; /* count number of timeouts */ + pdpvt->phwpvt->tmoVal = tickGet(); /* set last timeout time */ + } + return(status); +} + +/****************************************************************************** + * + * This is invoked by the linkTask when an SRQ is detected from a device + * operated by this module. + * + * It calls the work routine associated with the type of record expecting + * the SRQ response. + * + * No semaphore locks are needed around the references to anything in the + * hwpvt structure, because it is static unless modified by the linkTask. + * + ******************************************************************************/ + +#ifdef _SRQSUPPORT_ + +static int srqHandler(phwpvt, srqStatus) +struct hwpvt *phwpvt; +int srqStatus; /* The poll response from the device */ +{ + if (dg535Debug || ibSrqDebug) + logMsg("srqHandler(0x%08.8X, 0x%02.2X): called\n", phwpvt, srqStatus); + + /* Invoke the command-type specific SRQ handler */ + if (phwpvt->srqCallback != NULL) + return((*(phwpvt->srqCallback))(phwpvt->parm, srqStatus)); + + logMsg("Unsolicited SRQ rec'd from link %d, device %d, status = 0x%02.2X\n", + phwpvt->link, phwpvt->device, srqStatus); + + return(IDLE); +} + +#endif /* _SRQSUPPORT_ */ + +/****************************************************************************** + * + * 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) + * + ******************************************************************************/ + +static void +processCallback(pDpvt) +struct gpibDpvt *pDpvt; +{ + if(dg535Debug) + logMsg("processCallback: calling process\n"); + + dbScanLock(pDpvt->precord); + (*(struct rset *)(pDpvt->precord->rset)).process(pDpvt->precord->pdba); + dbScanUnlock(pDpvt->precord); +} + +/****************************************************************************** + * + * This function is used to set alarm status information. + * + ******************************************************************************/ +static long +setPvSevr(pPv, status, severity) +struct dbCommon *pPv; +short severity; +short status; +{ + if (severity > pPv->nsev ) + { + pPv->nsta = status; + pPv->nsev = severity; + } +} diff --git a/src/devOpt/devXxHvpsGpib.c b/src/devOpt/devXxHvpsGpib.c new file mode 100644 index 000000000..2472c895d --- /dev/null +++ b/src/devOpt/devXxHvpsGpib.c @@ -0,0 +1,1600 @@ +/* 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; + } +} diff --git a/src/vxWorks/devOpt/devXxDg535Gpib.c b/src/vxWorks/devOpt/devXxDg535Gpib.c new file mode 100644 index 000000000..eb43dc513 --- /dev/null +++ b/src/vxWorks/devOpt/devXxDg535Gpib.c @@ -0,0 +1,2405 @@ +/* devXxDg535Gpib.c */ +/* share/src/devOpt $Id$ */ +/* + * Author: Ned D. Arnold + * Date: 05-28-91 + * + * Experimental Physics and Industrial Control System (EPICS) + * + * Copyright 1988, 1989, 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 + * + * All rights reserved. No part of this publication may be reproduced, + * stored in a retrieval system, transmitted, in any form or by any + * means, electronic, mechanical, photocopying, recording, or otherwise + * without prior written permission of Los Alamos National Laboratory + * and Argonne National Laboratory. + * + * Modification Log: + * ----------------- + * .01 05-30-91 nda Initial Release + * .02 06-18-91 nda init_rec_mbbo must return(2) if no init value + * .03 07-02-91 nda renamed String/StringOut DSET's to Si/So + * .04 07-11-91 jrw added the callbackRequest to process() + * .05 07-15-91 jrw redesigned init processing... more generic + * .06 11-01-91 jrw major rework to fit into new GPIB driver + * .07 11-11-91 jrw added new version of SRQ support + * ... + */ + + +/* devDg535Gpib.c - Device Support Routines */ +/* includes support for the following device types : */ + +#define DSET_AI devAiDg535Gpib +#define DSET_AO devAoDg535Gpib +#define DSET_BI devBiDg535Gpib +#define DSET_BO devBoDg535Gpib +#define DSET_MBBO devMbbiDg535Gpib +#define DSET_MBBI devMbboDg535Gpib +#define DSET_SI devSiDg535Gpib +#define DSET_SO devSoDg535Gpib + +#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 { + long number; + DRVSUPFUN report; + DRVSUPFUN init; + int (*qGpibReq)(); + int (*registerSrqCallback)(); + int (*writeIb)(); + int (*readIb)(); + int (*writeIbCmd)(); + int (*ioctl)(); +} drvGpib; + +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_mbbi(); +long read_mbbi(); +long init_rec_mbbo(); +long write_mbbo(); +long init_rec_stringin(); +long read_stringin(); +long init_rec_stringout(); +long write_stringout(); +long init_rec_xx(); + +long report(); + +int aiGpibWork(), aiGpibSrq(), aiGpibFinish(); +int aoGpibWork(); +int biGpibWork(), biGpibSrq(), biGpibFinish(); +int boGpibWork(); +int mbbiGpibWork(), mbbiGpibSrq(), mbbiGpibFinish(); +int mbboGpibWork(); +int stringinGpibWork(), stringinGpibSrq(), stringinGpibFinish(); +int stringoutGpibWork(); +int xxGpibWork(); + +int srqHandler(); + +void processCallback(); +void callbackRequest(); + +/****************************************************************************** + * + * Define all the dset's. + * + * Note that the dset names are provided via the #define lines at the top of + * the file. + * + * Other than for the debugging flag, these DSETs are the only items that + * will appear in the global name space within the IOC. + * + ******************************************************************************/ +/* ai dset*/ +typedef struct { + long number; + DEVSUPFUN report; + DEVSUPFUN init; + DEVSUPFUN init_record; + DEVSUPFUN get_ioint_info; + DEVSUPFUN read_ai; + DEVSUPFUN special_linconv; +} gDset; + +gDset DSET_AI = { 6, report, init_dev_sup, init_rec_ai, NULL, read_ai, NULL }; +gDset DSET_AO = { 6, NULL, NULL, init_rec_ao, NULL, write_ao, NULL }; +gDset DSET_BI = { 5, NULL, NULL, init_rec_bi, NULL, read_bi }; +gDset DSET_BO = { 5, NULL, NULL, init_rec_bo, NULL, write_bo }; +gDset DSET_MBBI = { 5, NULL, NULL, init_rec_mbbi, NULL, read_mbbi }; +gDset DSET_MBBO = { 5, NULL, NULL, init_rec_mbbo, NULL, write_mbbo }; +gDset DSET_SI = { 5, NULL, NULL, init_rec_stringin, NULL, read_stringin }; +gDset DSET_SO = { 5, NULL, NULL, init_rec_stringout, NULL, write_stringout }; + +/****************************************************************************** + * + * This section defines any device-type specific data areas. + * + ******************************************************************************/ +/*#define RESPONDS_2_WRITES */ /* if GPIB machine responds to writes */ +#define _SRQSUPPORT_ /* for srq support */ + +#define TIME_WINDOW 600 /* 10 seconds on a getTick call */ + +int dg535Debug = 0; +extern int ibSrqDebug; + +static char UDF[10] = "Undefined"; +static char pOK[3] = "OK"; + +/* forward declarations of some custom convert routines */ + +int setDelay(); /* used to set delay */ +int rdDelay(); /* used to place string in .DESC field */ + +/****************************************************************************** + * + * This structure holds device-related data on a per-device basis and is + * referenced by the gpibDpvt structures. They are built using a linked + * list entered from hwpvtHead. This linked list is only for this specific + * device type (other gpib devices may have their own lists.) + * + ******************************************************************************/ +struct hwpvt { + struct hwpvt *next; /* to next structure for same type device */ + + int linkType; /* is a GPIB_IO, BBGPIB_IO... from link.h */ + int link; /* link number */ + int bug; /* used only on BBGPIB_IO links */ + int device; /* gpib device number */ + + unsigned long tmoVal; /* time last timeout occurred */ + unsigned long tmoCount; /* total number of timeouts since boot time */ + + /* No semaphore guards here because can inly be mod'd by the linkTask */ + int (*srqCallback)(); /* filled by cmds expecting SRQ callbacks */ + caddr_t parm; /* filled in by cmds expecting SRQ callbacks */ +}; +static struct hwpvt *hwpvtHead = NULL; /* pointer to first hwpvt in chain */ + +/****************************************************************************** + * + * This structure will be attached to each pv (via psub->dpvt) to store the + * appropriate head.workStart pointer, callback address to record support, + * gpib link #, device address, and command information. + * + ******************************************************************************/ + +struct gpibDpvt { + struct dpvtGpibHead head; /* fields used by the GPIB driver */ + + 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... */ + struct hwpvt *phwpvt; /* pointer to per-device private area */ +}; + +/****************************************************************************** + * + * This is used to define the strings that are used for button labels. + * These strings are put into the record's znam & onam foelds if the + * record is a BI or BO type and into the zrst, onst... fields of an + * MBBI or MBBO record. + * + * Before these strings are placed into the record, the record is + * check to see if there is already a string defined (could be user-entered + * with DCT.) If there is already a string present, it will be preserved. + * + * There MUST ALWAYS be 2 and only 2 entries in the names.item list + * for BI and BO records if a name list is being specified for them here. + * The names.count field is ignored for BI and BO record types, but + * should be properly specified as 2 for future compatibility. + * + * NOTE: + * If a name string is filled in an an MBBI/MBBO record, it's corresponding + * value will be filled in as well. For this reason, there MUST be + * a value array and a valid nobt value for every MBBI/MBBO record that + * contains an item array! + * + ******************************************************************************/ + +struct names { + int count; /* CURRENTLY only used for MBBI and MBBO */ + char **item; + unsigned long *value; /* CURRENTLY only used for MBBI and MBBO */ + short nobt; /* CURRENTLY only used for MBBI and MBBO */ +}; + +static char *offOnList[] = { "Off", "On" }; +static struct names offOn = { 2, offOnList, NULL, 1 }; + +static char *disableEnableList[] = { "Disable", "Enable" }; +static struct names disableEnable = { 2, disableEnableList, NULL, 1 }; + +static char *resetList[] = { "Reset", "Reset" }; +static struct names reset = { 2, resetList, NULL, 1 }; + +static char *lozHizList[] = { "50 OHM", "IB_Q_HIGH Z" }; +static struct names lozHiz = {2, lozHizList, NULL, 1}; + +static char *invertNormList[] = { "INVERT", "NORM" }; +static struct names invertNorm = { 2, invertNormList, NULL, 1 }; + +static char *fallingRisingList[] = { "FALLING", "RISING" }; +static struct names fallingRising = { 2, fallingRisingList, NULL, 1 }; + +static char *singleShotList[] = { "SINGLE", "SHOT" }; +static struct names singleShot = { 2, singleShotList, NULL, 1 }; + +static char *clearList[] = { "CLEAR", "CLEAR" }; +static struct names clear = { 2, clearList, NULL, 1 }; + +static char *tABCDList[] = { "T", "A", "B", "C", "D" }; +static unsigned long tABCDVal[] = { 1, 2, 3, 5, 6 }; +static struct names tABCD = { 5, tABCDList, tABCDVal, 3 }; + +static char *ttlNimEclVarList[] = { "TTL", "NIM", "ECL", "VAR" }; +static unsigned long ttlNimEclVarVal[] = { 0, 1, 2, 3 }; +static struct names ttlNimEclVar = { 4, ttlNimEclVarList, + ttlNimEclVarVal, 2 }; + +static char *intExtSsBmStopList[] = { "INTERNAL", "EXTERNAL", + "SINGLE SHOT", "BURST MODE", "STOP" }; +static unsigned long intExtSsBmStopVal[] = { 0, 1, 2, 3, 2 }; +static struct names intExtSsBm = { 4, intExtSsBmStopList, + intExtSsBmStopVal, 2 }; +static struct names intExtSsBmStop = { 5, intExtSsBmStopList, + intExtSsBmStopVal, 3 }; + +/* Channel Names, used to derive string representation of programmed delay */ + +char *pchanName[8] = {" ", "T + ", "A + ", "B + ", " ", "C + ", "D + ", " "}; + +/****************************************************************************** + * + * The following #define statements enumerate the record types that + * are supported by this device support module. These are used by the init + * routines when they to type checking against the records that have + * been defined for use with this type of GPIB device. + * + ******************************************************************************/ + +#define GPIB_AO 1 +#define GPIB_AI 2 +#define GPIB_BO 3 +#define GPIB_BI 4 +#define GPIB_MBBO 5 +#define GPIB_MBBI 6 +#define GPIB_SI 7 +#define GPIB_SO 8 + +/****************************************************************************** + * + * Enumeration of gpib command types supported by this device type. + * + ******************************************************************************/ + +#define GPIBREAD 1 +#define GPIBWRITE 2 +#define GPIBCMD 3 +#define GPIBCNTL 4 +#define GPIBSOFT 5 +#define GPIBREADW 6 +#define GPIBRAWREAD 7 + +/****************************************************************************** + * + * 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 (gpibDpvt.msg) + * (3) 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 gpibDpvt->dbAddr->precord->val + * (2) The ascii string is sent to the instrument + * + * GPIBCMD : (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 + * + * GPIBREADW : (1) The cmd string is sent to the instrument + * (2) Wait for SRQ + * (3) Data is read from the inst into a buffer (gpibDpvt.msg) + * (4) The important data is extracted from the buffer using the + * format string. + * + * GPIBRAWREAD: Used internally with GPIBREADW. Not useful from cmd table. + * + * 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 + * gpibCmd.convert field to use it rather than the above approaches. + * + ******************************************************************************/ + +struct gpibCmd { + int rec_typ; /* enum - GPIB_AO GPIB_AI GPIB_BO... */ + 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; /* pointer to button label strings */ +}; + +/****************************************************************************** + * + * Array of structures that define all GPIB messages + * supported for this type of instrument. + * + ******************************************************************************/ + +#define FILL {0,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 gpibCmd gpibCmds[] = +{ + /* Param 0, (model) */ +FILL, + + /* Channel A Delay and Output */ + /* Param 1, write A delay */ + {GPIB_AO, GPIBWRITE, IB_Q_HIGH, UDF, "DT 2\n", "DT 2,?,%.12lf\n", 0, 32, + setDelay, 0, 0, NULL, NULL}, + + /* Param 2, currently undefined */ + FILL, + + /* Param 3, read A Delay */ + {GPIB_AI, GPIBREAD, IB_Q_LOW, UDF, "DT 2\n", NULL, 0, 32, + rdDelay, 0, 0, NULL, NULL }, + + /* Param 4, not yet implemented */ + FILL, + + /* Param 5, set A delay reference channel */ + {GPIB_MBBO, GPIBWRITE, IB_Q_HIGH, UDF, "DT 2\n", "DT 2,%u,", 0, 32, + setDelay, 0, 0, NULL, &tABCD}, + + /* Param 6, read A delay reference */ + {GPIB_MBBI, GPIBREAD, IB_Q_LOW, UDF, "DT 2\n", NULL, 0, 32, + rdDelay, 0, 0, NULL, &tABCD}, + + /* Param 7, set A output mode */ + {GPIB_MBBO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "OM 2,%u\n", 0, 32, + NULL, 0, 0, NULL, &ttlNimEclVar}, + + /* Param 8, read A output mode */ + {GPIB_MBBI, GPIBREAD, IB_Q_LOW, UDF, "OM 2\n", "%lu", 0, 32, + NULL, 0, 0, NULL, &ttlNimEclVar}, + + /* Param 9, set A output amplitude */ + {GPIB_AO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "OA 2,%.1f\n", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 10, read A output amplitude */ + {GPIB_AI, GPIBREAD, IB_Q_LOW, UDF, "OA 2\n", "%lf", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 11, set A output offset */ + {GPIB_AO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "OO 2,%.1f\n", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 12, read A output offset */ + {GPIB_AI, GPIBREAD, IB_Q_LOW, UDF, "OO 2\n", "%lf", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 13, set A output Termination */ + {GPIB_BO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "TZ 2,%u\n", 0, 32, + NULL, 0, 0, NULL, &lozHiz}, + + /* Param 14, read A output Termination */ + {GPIB_BI, GPIBREAD, IB_Q_LOW, UDF, "TZ 2\n", "%lu", 0, 32, + NULL, 0, 0, NULL, &lozHiz}, + + /* Param 15, set A output Polarity */ + {GPIB_BO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "OP 2,%u\n", 0, 32, + NULL, 0, 0, NULL, &invertNorm}, + + /* Param 16, read A output Polarity */ + {GPIB_BI, GPIBREAD, IB_Q_LOW, UDF, "OP 2\n", "%lu", 0, 32, + NULL, 0, 0, NULL, NULL}, + +/* Channel B Delay and Output */ + /* Param 17, write B delay */ + {GPIB_AO, GPIBWRITE, IB_Q_HIGH, UDF, "DT 3\n", "DT 3,?,%.12lf\n", 0, 32, + setDelay, 0, 0, NULL, NULL}, + + /* Param 18, currently undefined */ + FILL, + + /* Param 19, read B Delay */ + {GPIB_AI, GPIBREAD, IB_Q_LOW, UDF, "DT 3\n", NULL, 0, 32, + rdDelay, 0, 0, NULL, NULL}, + + /* Param 20, not yet implemented */ + FILL, + + /* Param 21, set B delay reference channel */ + {GPIB_MBBO, GPIBWRITE, IB_Q_HIGH, UDF, "DT 3\n", "DT 3,%u,", 0, 32, + setDelay, 0, 0, NULL, &tABCD}, + + /* Param 22, read B delay reference */ + {GPIB_MBBI, GPIBREAD, IB_Q_LOW, UDF, "DT 3\n", NULL, 0, 32, + rdDelay, 0 ,0, NULL, &tABCD}, + + /* Param 23, set B output mode */ + {GPIB_MBBO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "OM 3,%u\n", 0, 32, + NULL, 0, 0, NULL, &ttlNimEclVar}, + + /* Param 24, read B output mode */ + {GPIB_MBBI, GPIBREAD, IB_Q_LOW, UDF, "OM 3\n", "%lu", 0 ,32, + NULL, 0, 0, NULL, &ttlNimEclVar}, + + /* Param 25, set B output amplitude */ + {GPIB_AO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "OA 3,%.1f\n", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 26, read B output amplitude */ + {GPIB_AI, GPIBREAD, IB_Q_LOW, UDF, "OA 3\n", "%lf", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 27, set B output offset */ + {GPIB_AO, GPIBWRITE, IB_Q_HIGH, NULL, "OO 3,%.1f\n", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 28, read B output offset */ + {GPIB_AI, GPIBREAD, IB_Q_LOW, UDF, "OO 3\n", "%lf", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 29, set B output Termination */ + {GPIB_BO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "TZ 3,%u\n", 0, 32, + NULL, 0, 0, NULL, &lozHiz}, + + /* Param 30, read B output Termination */ + {GPIB_BI, GPIBREAD, IB_Q_LOW, UDF, "TZ 3\n", "%lu", 0, 32, + NULL, 0, 0, NULL, &lozHiz}, + + /* Param 31, set B output Polarity */ + {GPIB_BO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "OP 3,%u\n", 0, 32, + NULL, 0, 0, NULL, &invertNorm}, + + /* Param 32, read B output Polarity */ + {GPIB_BI, GPIBREAD, IB_Q_LOW, UDF, "OP 3\n", "%lu", 0, 32, + NULL, 0, 0, NULL, NULL}, + +/* Channel AB Outputs */ + /* Param 33, set AB output mode */ + {GPIB_MBBO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "OM 4,%u\n", 0, 32, + NULL, 0, 0, NULL, &ttlNimEclVar}, + + /* Param 34, read AB output mode */ + {GPIB_MBBI, GPIBREAD, IB_Q_LOW, UDF, "OM 4\n", "%lu", 0, 32, + NULL, 0, 0, NULL, &ttlNimEclVar}, + + /* Param 35, set AB output amplitude */ + {GPIB_AO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "OA 4,%.1f\n", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 36, read AB output amplitude */ + {GPIB_AI, GPIBREAD, IB_Q_LOW, UDF, "OA 4\n", "%lf", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 37, set AB output offset */ + {GPIB_AO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "OO 4,%.1f\n", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 38, read AB output offset */ + {GPIB_AI, GPIBREAD, IB_Q_LOW, UDF, "OO 4\n", "%lf", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 39, set AB output Termination */ + {GPIB_BO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "TZ 4,%u\n", 0, 32, + NULL, 0, 0, NULL, &lozHiz}, + + /* Param 40, read AB output Termination */ + {GPIB_BI, GPIBREAD, IB_Q_LOW, UDF, "TZ 4\n", "%lu", 0, 32, + NULL, 0, 0, NULL, &lozHiz}, + + /* Param 41, set AB output Polarity */ + {GPIB_BO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "OP 4,%u\n", 0, 32, + NULL, 0, 0, NULL, &invertNorm}, + + /* Param 42, read AB output Polarity */ + {GPIB_BI, GPIBREAD, IB_Q_LOW, UDF, "OP 4\n", "%lu", 0, 32, + NULL, 0, 0, NULL, NULL}, + +/* Channel C Delay and Output */ + /* Param 43, write C delay */ + {GPIB_AO, GPIBWRITE, IB_Q_HIGH, UDF, "DT 5\n", "DT 5,?,%.12lf\n", 0, 32, + setDelay, 0, 0, NULL, NULL}, + + /* Param 44, currently undefined */ + FILL, + + /* Param 45, read C Delay */ + {GPIB_AI, GPIBREAD, IB_Q_LOW, UDF, "DT 5\n", NULL, 0, 32, + rdDelay, 0, 0, NULL, NULL}, + + /* Param 46, not yet implemented */ + FILL, + + /* Param 47, set C delay reference channel */ + {GPIB_MBBO, GPIBWRITE, IB_Q_HIGH, UDF, "DT 5\n", "DT 5,%u,", 0, 32, + setDelay, 0, 0, NULL, &tABCD}, + + /* Param 48, read C delay reference */ + {GPIB_MBBI, GPIBREAD, IB_Q_LOW, UDF, "DT 5\n", NULL, 0, 32, + rdDelay, 0, 0, NULL, &tABCD}, + + /* Param 49, set C output mode */ + {GPIB_MBBO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "OM 5,%u\n", 0, 32, + NULL, 0, 0, NULL, &ttlNimEclVar}, + + /* Param 50, read C output mode */ + {GPIB_MBBI, GPIBREAD, IB_Q_LOW, UDF, "OM 5\n", "%lu", 0, 32, + NULL, 0, 0, NULL, &ttlNimEclVar}, + + /* Param 51, set C output amplitude */ + {GPIB_AO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "OA 5,%.1f\n", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 52, read C output amplitude */ + {GPIB_AI, GPIBREAD, IB_Q_LOW, UDF, "OA 5\n", "%lf", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 53, set C output offset */ + {GPIB_AI, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "OO 5,%.1f\n", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 54, read C output offset */ + {GPIB_AI, GPIBREAD, IB_Q_LOW, UDF, "OO 5\n", "%lf", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 55, set C output Termination */ + {GPIB_BO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "TZ 5,%u\n", 0, 32, + NULL, 0, 0, NULL, &lozHiz}, + + /* Param 56, read C utput Termination */ + {GPIB_BI, GPIBREAD, IB_Q_LOW, UDF, "TZ 5\n", "%lu", 0, 32, + NULL, 0, 0, NULL, &lozHiz}, + + /* Param 57, set C output Polarity */ + {GPIB_BO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "OP 5,%u\n", 0, 32, + NULL, 0, 0, NULL, &invertNorm}, + + /* Param 58, read C output Polarity */ + {GPIB_BI, GPIBREAD, IB_Q_LOW, UDF, "OP 5\n", "%lu", 0, 32, + NULL, 0, 0, NULL, NULL}, + +/* Channel D Delay and Output */ + /* Param 59, write D delay */ + {GPIB_AO, GPIBWRITE, IB_Q_HIGH, UDF, "DT 6\n", "DT 6,?,%.12lf\n", 0, 32, + setDelay, 0, 0, NULL, NULL}, + + /* Param 60, currently undefined */ + FILL, + + /* Param 61, read D Delay */ + {GPIB_AI, GPIBREAD, IB_Q_LOW, UDF, "DT 6\n", NULL, 0, 32, + rdDelay, 0, 0, NULL, NULL}, + + /* Param 62, not yet implemented */ + FILL, + + /* Param 63, set D delay reference channel */ + {GPIB_MBBO, GPIBWRITE, IB_Q_HIGH, UDF, "DT 6\n", "DT 6,%u,", 0, 32, + setDelay, 0, 0, NULL, &tABCD}, + + /* Param 64, read D delay reference */ + {GPIB_MBBI, GPIBREAD, IB_Q_LOW, UDF, "DT 6\n", NULL, 0, 32, + rdDelay, 0 ,0, NULL, &tABCD}, + + /* Param 65, set D output mode */ + {GPIB_MBBI, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "OM 6,%u\n", 0, 32, + NULL, 0, 0, NULL, &ttlNimEclVar}, + + /* Param 66, read D output mode */ + {GPIB_MBBI, GPIBREAD, IB_Q_LOW, UDF, "OM 6\n", "%lu", 0, 32, + NULL, 0, 0, NULL, &ttlNimEclVar}, + + /* Param 67, set D output amplitude */ + {GPIB_AO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "OA 6,%.1f\n", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 68, read D output amplitude */ + {GPIB_AI, GPIBREAD, IB_Q_LOW, UDF, "OA 6\n", "%lf", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 69, set D output offset */ + {GPIB_AO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "OO 6,%.1f\n", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 70, read D output offset */ + {GPIB_AI, GPIBREAD, IB_Q_LOW, UDF, "OO 6\n", "%lf", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 71, set D output Termination */ + {GPIB_BO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "TZ 6,%u\n", 0, 32, + NULL, 0, 0, NULL, &lozHiz}, + + /* Param 72, read D output Termination */ + {GPIB_BI, GPIBREAD, IB_Q_LOW, UDF, "TZ 6\n", "%lu", 0, 32, + NULL, 0, 0, NULL, &lozHiz}, + + /* Param 73, set D output Polarity */ + {GPIB_BO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "OP 6,%u\n", 0, 32, + NULL, 0, 0, NULL, &invertNorm}, + + /* Param 74, read D output Polarity */ + {GPIB_BI, GPIBREAD, IB_Q_LOW, UDF, "OP 6\n", "%lu", 0, 32, + NULL, 0, 0, NULL, NULL}, + +/* Channel CD Outputs */ + /* Param 75, set CD output mode */ + {GPIB_MBBO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "OM 7,%u\n", 0, 32, + NULL, 0, 0, NULL, &ttlNimEclVar}, + + /* Param 76, read CD output mode */ + {GPIB_MBBI, GPIBREAD, IB_Q_LOW, UDF, "OM 7\n", "%lu", 0, 32, + NULL, 0, 0, NULL, &ttlNimEclVar}, + + /* Param 77, set CD output amplitude */ + {GPIB_AO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "OA 7,%.1f\n", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 78, read CD output amplitude */ + {GPIB_AI, GPIBREAD, IB_Q_LOW, UDF, "OA 7\n", "%lf", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 79, set CD output offset */ + {GPIB_AI, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "OO 7,%.1f\n", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 80, read CD output offset */ + {GPIB_AI, GPIBREAD, IB_Q_LOW, UDF, "OO 7\n", "%lf", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 81, set CD output Termination */ + {GPIB_BO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "TZ 7,%u\n", 0, 32, + NULL, 0, 0, NULL, &lozHiz}, + + /* Param 82, read CD output Termination */ + {GPIB_BI, GPIBREAD, IB_Q_LOW, UDF, "TZ 7\n", "%lu", 0, 32, + NULL, 0, 0, NULL, &lozHiz}, + + /* Param 83, set CD output Polarity */ + {GPIB_BO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "OP 7,%u\n", 0, 32, + NULL, 0, 0, NULL, &invertNorm}, + + /* Param 84, read CD output Polarity */ + {GPIB_BI, GPIBREAD, IB_Q_LOW, UDF, "OP 7\n", "%lu", 0, 32, + NULL, 0, 0, NULL, NULL}, + +/* Trigger Settings */ + /* Param 85, set Trig Mode */ + {GPIB_MBBO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "TM %u\n", 0, 32, + NULL, 0, 0, NULL, &intExtSsBmStop}, + + /* Param 86, read Trig Mode */ + {GPIB_MBBI, GPIBREAD, IB_Q_LOW, UDF, "TM \n", "%lu", 0, 32, + NULL, 0, 0, NULL, &intExtSsBm}, + + /* Param 87, set Trig Rate */ + {GPIB_AO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "TR 0,%.3lf\n", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 88, read Trig Rate */ + {GPIB_AI, GPIBREAD, IB_Q_LOW, UDF, "TR 0\n", "%lf", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 89, set Burst Rate */ + {GPIB_AO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "TR 1,%.3lf\n", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 90, read Burst Rate */ + {GPIB_AI, GPIBREAD, IB_Q_LOW, UDF, "TR 1\n", "%lf", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 91, set Burst Count */ + {GPIB_AO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "BC %01.0lf\n", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 92, read Burst Count */ + {GPIB_AI, GPIBREAD, IB_Q_LOW, UDF, "BC \n", "%lf", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 93, set Burst Period */ + {GPIB_AO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "BP %01.0lf\n", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 94, read Burst Period */ + {GPIB_AI, GPIBREAD, IB_Q_LOW, UDF, "BP \n", "%lf", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 95, set Trig Input Z */ + {GPIB_BO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "TZ 0,%u\n", 0, 32, + NULL, 0, 0, NULL, &lozHiz}, + + /* Param 96, read Trig Input Z */ + {GPIB_BI, GPIBREAD, IB_Q_LOW, UDF, "TZ 0\n", "%lu", 0, 32, + NULL, 0, 0, NULL, &lozHiz}, + + /* Param 97, set Trig Input slope */ + {GPIB_BO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "TS %u\n", 0, 32, + NULL, 0, 0, NULL, &fallingRising}, + + /* Param 98, read Trig Input slope */ + {GPIB_BI, GPIBREAD, IB_Q_LOW, UDF, "TS \n", "%lu", 0, 32, + NULL, 0, 0, NULL, &fallingRising}, + + /* Param 99, set Trig Input level */ + {GPIB_AO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "TL %.2lf\n", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 100, read Trig Input Level */ + {GPIB_AI, GPIBREAD, IB_Q_LOW, UDF, "TL \n", "%lf", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 101, generate Single Trig */ + {GPIB_BO, GPIBCMD, IB_Q_HIGH, UDF, "SS \n", NULL, 0, 32, + NULL, 0, 0, NULL, &singleShot}, + + /* Param 102, Store Setting # */ + {GPIB_AO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "ST %01.0lf\n", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 103, Recall Setting # */ + {GPIB_AO, GPIBWRITE, IB_Q_HIGH, UDF, NULL, "RC %01.0lf\n", 0, 32, + NULL, 0, 0, NULL, NULL}, + + /* Param 104, Recall Setting # */ + {GPIB_BO, GPIBCMD, IB_Q_HIGH, UDF, "CL \n", NULL, 0, 32, + NULL, 0, 0, NULL, &clear} +}; + + +/* The following is the number of elements in the command array above. */ +#define NUMPARAMS sizeof(gpibCmds)/sizeof(struct gpibCmd) + +#define GPIBMSGLENGTH 32 /* used by the delay routines only */ + +/****************************************************************************** + * + * Unique message interpretaion for reading Channel Delays : + * The command to read the delay setting returns a string with two arguments. + * This routine extracts both arguments and assigns them appropriately. Also, + * a string is generated with the format CHAN + xxx.xxxxxxxxxxxx and stored + * in the .DESC field of the ai record. (ex: T + .000000500000) If either + * parameter has changed, a db_post_event is issued for the .DESC field (ai + * record only). + * + ******************************************************************************/ + +static int rdDelay(pdpvt) +struct gpibDpvt *pdpvt; +{ + int status; + double delay; + unsigned long chan; + unsigned short monitor_mask = 0; + + struct aiRecord *pai= (struct aiRecord *)(pdpvt->precord); + struct mbbiRecord *pmbbi= (struct mbbiRecord *)(pdpvt->precord); + + if(dg535Debug) + logMsg("rdDelay : returned msg :%s\n",pdpvt->msg); + + /* Change the "," in returned string to a " " to separate fields */ + pdpvt->msg[1] = 0x20; + + /* scan response string for chan reference & delay value */ + status = sscanf(pdpvt->msg, "%ld%lf", &chan, &delay); + + if(dg535Debug) + logMsg("rdDelay :sscanf status = %d\n",status); + + switch (pdpvt->parm) + { + case 3: /* A Delay monitor, must be an ai record */ + case 19: /* B Delay monitor, must be an ai record */ + case 45: /* C Delay monitor, must be an ai record */ + case 61: /* D Delay monitor, must be an ai record */ + if (status == 2) /* make sure both parameters were assigned */ + { + /* check if delay or reference channel has changed */ + if ((pai->val != delay) || (pai->desc[0] != pchanName[chan][0])) + { + monitor_mask = DBE_VALUE; + } + /* assign new delay to value field*/ + pai->val = delay; + strcpy(pai->desc, pchanName[chan]); + strcat(pai->desc, &((pdpvt->msg)[3])); + if(dg535Debug) + logMsg("rdDelay : %s",pai->desc); + if (monitor_mask) + { + db_post_events(pai, pai->desc, monitor_mask); + } + } + else + { + if (pai->nsev < VALID_ALARM) + { + pai->nsev = VALID_ALARM; + pai->nsta = READ_ALARM; + } + } + break; + + case 6: /* A Delay Reference monitor, must be an mbbi record */ + case 22: /* B Delay Reference monitor, must be an mbbi record */ + case 48: /* C Delay Reference monitor, must be an mbbi record */ + case 64: /* D Delay Reference monitor, must be an mbbi record */ + if (status == 2) /* make sure both parameters were assigned */ + { + pmbbi->rval = chan; + } + else + { + if (pmbbi->nsev < VALID_ALARM) + { + pmbbi->nsev = VALID_ALARM; + pmbbi->nsta = READ_ALARM; + } + } + break; + } + return(OK); +} + +/****************************************************************************** + * + * Unique message generation for writing channel Delays : + * The command to set the channel delay requires two parameters: The channel + * # to reference from and the time delay. Since changing either of these + * parameters requires the command to be sent, the current state of other + * parameter must be determined. This is done by reading the delay (which + * returns both parameters), changing one of the paramaters, and sending + * the command back. + * + * WARNING!!!!! + * This function modifies the gpibCmds table!!! This is not a very nice + * thing to do! It is OK to do if only one dg535 is out there. But it will NOT + * work if there are more because modifying the gpibCmds table removes + * the re-entrant properties of this routine!!!! This should be + * re-designed to use a local temporary storage area. + * + ******************************************************************************/ + +static int setDelay(pdpvt) +struct gpibDpvt *pdpvt; +{ + int status; + char curChan; + char tempMsg[GPIBMSGLENGTH]; + + struct aoRecord *pao= (struct aoRecord *)(pdpvt->precord); + struct mbboRecord *pmbbo= (struct mbboRecord *)(pdpvt->precord); + + if(dg535Debug) + logMsg("setDelay : returned msg :%s\n",pdpvt->msg); + + /* adjust the gpibCmd to do a GPIBREAD of the current + * delay setting first. + */ + + gpibCmds[pdpvt->parm].type = GPIBREAD; + + /* go read the current delay setting */ + if(xxGpibWork(pdpvt, gpibCmds[pdpvt->parm].type) == ERROR) + { /* abort operation if read failed */ + gpibCmds[pdpvt->parm].type = GPIBWRITE; /* set back to write */ + return(ERROR); /* return, signalling an error */ + } + + /* Due to a fluke in the DG535, read again to insure accurate data */ + + if(xxGpibWork(pdpvt, gpibCmds[pdpvt->parm].type) == ERROR) /* go read the current delay setting */ + { /* abort operation if read failed */ + gpibCmds[pdpvt->parm].type = GPIBWRITE; /* set back to write */ + return(ERROR); /* return, signalling an error */ + } + + /* change one of the two parameters ... */ + + switch(pdpvt->parm) + { + case 1: /* changing time delay */ + case 17: + case 43: + case 59: + curChan = pdpvt->msg[0]; /* save current chan reference */ + /* generate new delay string (correct rounding error) */ + sprintf(pdpvt->msg,gpibCmds[pdpvt->parm].format, (pao->val + 1.0e-13)); + pdpvt->msg[5] = curChan; /* replace "?" with current chan */ + break; + + case 5: /* changing reference channel */ + case 21: + case 47: + case 63: + strcpy(tempMsg, &((pdpvt->msg)[3])); /* save current delay setting */ + /* generate new channel reference */ + sprintf(pdpvt->msg, gpibCmds[pdpvt->parm].format, (unsigned int)pmbbo->rval); + strcat(pdpvt->msg, tempMsg); /* append current delay setting */ + break; + } + + gpibCmds[pdpvt->parm].type = GPIBWRITE; /* set cmnd back to write */ + + return(OK); /* aoGpibWork or mbboGpibWork will call xxGpibWork */ +} +/************************************************************************** + * + * This should be the end of device specific modifications. + * + **************************************************************************/ + +/****************************************************************************** + * + * Print a report of operating statistics for all devices supported by this + * module. + * + ******************************************************************************/ +static long +report() +{ + struct hwpvt *phwpvt; + + printf("DG535 device support loaded:\n"); + + phwpvt = hwpvtHead; + + while (phwpvt != NULL) + { + if (phwpvt->linkType == GPIB_IO) + printf(" NI-link %d, node %d, timeouts %ld\n", phwpvt->link, phwpvt->device, phwpvt->tmoCount); + else if (phwpvt->linkType == BBGPIB_IO) + printf(" BB-link %d, bug %d, node %d, timeouts %ld\n", phwpvt->link, phwpvt->bug, phwpvt->device, phwpvt->tmoCount); + + phwpvt = phwpvt->next; + } + return(0); +} + + +/****************************************************************************** + * + * Initialization for device support + * This is called one time before any records are initialized with a parm + * value of 0. And then again AFTER all record-level init is complete + * with a param value of 1. + * + ******************************************************************************/ +static long +init_dev_sup() +{ + + static char firstTime = 1; + + if (!firstTime) + { + return(OK); + } + firstTime = 0; + logMsg("dg535 Device Support Initializing ...\n"); + + return(OK); +} + +/****************************************************************************** + * + * Initialization routines. + * + ******************************************************************************/ +/****************************************************************************** + * + * ai record init + * + ******************************************************************************/ + +static long +init_rec_ai(pai, process) +struct aiRecord *pai; +void (*process)(); +{ + long result; + + /* Do common initialization */ + if (result = init_rec_xx((caddr_t) pai, &pai->inp, GPIB_AI)) + { + return(result); + } + /* Do initialization of other fields in the record that are unique + * to this record type */ + + ((struct gpibDpvt *)pai->dpvt)->head.workStart = aiGpibWork; + + return(0); +} + +/****************************************************************************** + * + * ao record init + * + ******************************************************************************/ + +static long +init_rec_ao(pao, process) +struct aoRecord *pao; +void (*process)(); +{ + long result; + + /* do common initialization */ + if (result = init_rec_xx((caddr_t) pao, &pao->out, GPIB_AO)) + { + return(result); + } + /* do initialization of other fields in the record that are unique + * to this record type */ + + ((struct gpibDpvt *)pao->dpvt)->head.workStart = aoGpibWork; + + return(0); +} + +/****************************************************************************** + * + * bi record init + * + ******************************************************************************/ + +static long +init_rec_bi(pbi, process) +struct biRecord *pbi; +void (*process)(); +{ + long result; + + /* Do common initialization */ + if (result = init_rec_xx((caddr_t) pbi, &pbi->inp, GPIB_BI)) + { + return(result); + } + /* Do initialization of other fields in the record that are unique + * to this record type */ + + ((struct gpibDpvt *)pbi->dpvt)->head.workStart = biGpibWork; + + /* See if there are names asociated with the record that should */ + /* be filled in */ + if (gpibCmds[((struct gpibDpvt *)pbi->dpvt)->parm].namelist != NULL) + { + if (pbi->znam[0] == '\0') + { + strcpy(pbi->znam, gpibCmds[((struct gpibDpvt *)pbi->dpvt)->parm].namelist->item[0]); + } + if (pbi->onam[0] == '\0') + { + strcpy(pbi->onam, gpibCmds[((struct gpibDpvt *)pbi->dpvt)->parm].namelist->item[1]); + } + } + return(0); +} + +/****************************************************************************** + * + * bo record init + * + ******************************************************************************/ + +static long +init_rec_bo(pbo, process) +struct boRecord *pbo; +void (*process)(); +{ + long result; + + /* do common initialization */ + if (result = init_rec_xx((caddr_t) pbo, &pbo->out, GPIB_BO)) + { + return(result); + } + /* do initialization of other fields in the record that are unique + * to this record type */ + + ((struct gpibDpvt *)pbo->dpvt)->head.workStart = boGpibWork; + + /* see if there are names asociated with the record that should */ + /* be filled in */ + if (gpibCmds[((struct gpibDpvt *)pbo->dpvt)->parm].namelist != NULL) + { + if (pbo->znam[0] == '\0') + { + strcpy(pbo->znam, gpibCmds[((struct gpibDpvt *)pbo->dpvt)->parm].namelist->item[0]); + } + if (pbo->onam[0] == '\0') + { + strcpy(pbo->onam, gpibCmds[((struct gpibDpvt *)pbo->dpvt)->parm].namelist->item[1]); + } + } + return(0); +} + +/****************************************************************************** + * + * mbbi record init + * + ******************************************************************************/ + +static long +init_rec_mbbi(pmbbi, process) +struct mbbiRecord *pmbbi; +void (*process)(); +{ + long result; + char message[100]; + struct gpibDpvt *dpvt; /* pointer to gpibDpvt, not yet assigned */ + int name_ct; /* for filling in the name strings */ + char *name_ptr; /* index into name list array */ + unsigned long *val_ptr; /* indev into the value list array */ + + /* do common initialization */ + if (result = init_rec_xx((caddr_t)pmbbi, &pmbbi->inp, GPIB_MBBI)) + { + return(result); + } + + dpvt = (struct gpibDpvt *)pmbbi->dpvt; /* init pointer to gpibDpvt */ + + /* do initialization of other fields in the record that are unique + * to this record type */ + + dpvt->head.workStart = mbbiGpibWork; + + /* see if there are names asociated with the record that should */ + /* be filled in */ + if (gpibCmds[dpvt->parm].namelist != NULL) + { + if (gpibCmds[dpvt->parm].namelist->value == NULL) + { + sprintf(message, "devDg535Gpib: MBBI value list wrong for param #%d\n", dpvt->parm); + logMsg(message); + return(ERROR); + } + pmbbi->nobt = gpibCmds[dpvt->parm].namelist->nobt; + name_ct = 0; /* current name string element */ + name_ptr = pmbbi->zrst; /* first name string element */ + val_ptr = &(pmbbi->zrvl); /* first value element */ + while (name_ct < gpibCmds[dpvt->parm].namelist->count) + { + if (name_ptr[0] == '\0') + { + strcpy(name_ptr, gpibCmds[dpvt->parm].namelist->item[name_ct]); + *val_ptr = gpibCmds[dpvt->parm].namelist->value[name_ct]; + } + name_ct++; + name_ptr += sizeof(pmbbi->zrst); + val_ptr++; + } + } + return(0); +} + +/****************************************************************************** + * + * mbbo record init + * + ******************************************************************************/ + +static long +init_rec_mbbo(pmbbo, process) +struct mbboRecord *pmbbo; +void (*process)(); +{ + long result; + char message[100]; + struct gpibDpvt *dpvt; /* pointer to gpibDpvt, not yet assigned */ + int name_ct; /* for filling in the name strings */ + char *name_ptr; /* index into name list array */ + unsigned long *val_ptr; /* indev into the value list array */ + + /* do common initialization */ + if (result = init_rec_xx((caddr_t)pmbbo, &pmbbo->out, GPIB_MBBO)) + { + return(result); + } + + dpvt = (struct gpibDpvt *)pmbbo->dpvt; /* init pointer to gpibDpvt */ + + /* do initialization of other fields in the record that are unique + * to this record type */ + + dpvt->head.workStart = mbboGpibWork; + + /* see if there are names asociated with the record that should */ + /* be filled in */ + if (gpibCmds[dpvt->parm].namelist != NULL) + { + if (gpibCmds[dpvt->parm].namelist->value == NULL) + { + sprintf(message, "devDg535Gpib: MBBO value list wrong for param #%d\ +n", dpvt->parm); + logMsg(message); + return(ERROR); + } + + pmbbo->nobt = gpibCmds[dpvt->parm].namelist->nobt; + name_ct = 0; /* current name string element */ + name_ptr = pmbbo->zrst; /* first name string element */ + val_ptr = &(pmbbo->zrvl); /* first value element */ + while (name_ct < gpibCmds[dpvt->parm].namelist->count) + { + if (name_ptr[0] == '\0') + { + strcpy(name_ptr, gpibCmds[dpvt->parm].namelist->item[name_ct]); + *val_ptr = gpibCmds[dpvt->parm].namelist->value[name_ct]; + } + name_ct++; + name_ptr += sizeof(pmbbo->zrst); + val_ptr++; + } + } + return(2); +} + +/****************************************************************************** + * + * stringin record init + * + ******************************************************************************/ + +static long +init_rec_stringin(pstringin, process) +struct stringinRecord *pstringin; +void (*process)(); +{ + long result; + struct gpibDpvt *dpvt; /* pointer to gpibDpvt, not yet assigned */ + + /* do common initialization */ + if (result = init_rec_xx((caddr_t) pstringin, &pstringin->inp, GPIB_SI)) + { + return(result); + } + dpvt = (struct gpibDpvt *)pstringin->dpvt; /* init pointer to gpibDpvt */ + + /* do initialization of other fields in the record that are unique + * to this record type */ + + dpvt->head.workStart = stringinGpibWork; + + return(0); +} + +/****************************************************************************** + * + * stringout record init + * + ******************************************************************************/ + +static long +init_rec_stringout(pstringout, process) +struct stringoutRecord *pstringout; +void (*process)(); +{ + long result; + struct gpibDpvt *dpvt; /* pointer to gpibDpvt, not yet assigned */ + + /* do common initialization */ + if (result = init_rec_xx((caddr_t) pstringout, &pstringout->out, GPIB_SO)) + { + return(result); + } + + dpvt = (struct gpibDpvt *)pstringout->dpvt; /* init pointer to gpibDpvt */ + + /* do initialization of other fields in the record that are unique + * to this record type */ + + dpvt->head.workStart = stringoutGpibWork; + + return(0); +} + +/****************************************************************************** + * + * This init routine is common to all record types + * + ******************************************************************************/ +static long +init_rec_xx(prec, plink, rec_typ) +struct dbCommon *prec; +struct link *plink; +int rec_typ; +{ + struct gpibDpvt *pdpvt; + struct dbCommon *pdbCommon = (struct dbCommon *)prec; + char message[100]; + struct gpibCmd *pCmd; + char foundIt; + int bbnode; + + /* allocate space for the private structure */ + pdpvt = (struct gpibDpvt *) malloc(sizeof(struct gpibDpvt)); + prec->dpvt = (void *) pdpvt; + + pdpvt->precord = prec; + pdpvt->parm = -1; /* In case the sscanf fails */ + pdpvt->linkType = plink->type; + + switch (plink->type) { + case GPIB_IO: /* Is a straight Network Instruments link */ + 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 */ + bbnode = -1; + break; + + case BBGPIB_IO: /* Is a bitbus -> gpib link */ + pdpvt->head.device = plink->value.bbgpibio.gpibaddr; /* 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 */ + bbnode = plink->value.bbgpibio.bbaddr; + 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; + } + /* Try to find the hardware private structure */ + foundIt = 0; + pdpvt->phwpvt = hwpvtHead; + while ((pdpvt->phwpvt != NULL) && !foundIt) + { + if (pdpvt->phwpvt->linkType == plink->type && + pdpvt->phwpvt->link == pdpvt->head.link && + pdpvt->phwpvt->device == pdpvt->head.device) + if (plink->type == BBGPIB_IO) + { + if (pdpvt->phwpvt->bug == pdpvt->head.bitBusDpvt->txMsg->node) + foundIt = 1; + } + else + foundIt = 1; + else + pdpvt->phwpvt = pdpvt->phwpvt->next; /* check the next one */ + } + if (!foundIt) + { /* I couldn't find it. Allocate a new one */ + pdpvt->phwpvt = (struct hwpvt *) malloc(sizeof (struct hwpvt)); + pdpvt->phwpvt->next = hwpvtHead; /* put at the top of the list */ + hwpvtHead = pdpvt->phwpvt; + + pdpvt->phwpvt->linkType = plink->type; + pdpvt->phwpvt->link = pdpvt->head.link; + pdpvt->phwpvt->device = pdpvt->head.device; + + if (pdpvt->phwpvt->linkType == BBGPIB_IO) + pdpvt->phwpvt->bug = pdpvt->head.bitBusDpvt->txMsg->node; + + pdpvt->phwpvt->tmoVal = 0; + pdpvt->phwpvt->tmoCount = 0; + pdpvt->phwpvt->srqCallback = NULL; + pdpvt->phwpvt->parm = (caddr_t)NULL; + } + + /* Check for valid GPIB address */ + 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 > NUMPARAMS)) + { + strcpy(message, pdbCommon->name); + strcat(message,": init_record : Parameter # out of range"); + errMessage(S_db_badField,message); + return(S_db_badField); + } + + /* make sure that the record type matches the GPIB port type (jrw) */ + if (gpibCmds[pdpvt->parm].rec_typ != rec_typ ) + { + strcpy(message, pdbCommon->name); + strcat(message,": init_record: record type invalid for spec'd param #"); + errMessage(S_db_badField,message); + return(S_db_badField); + } + + pCmd = &gpibCmds[pdpvt->parm]; + if(pCmd->msgLen > 0) + pdpvt->msg = (char *)(malloc(pCmd->msgLen)); + if(pCmd->rspLen > 0) + pdpvt->rsp = (char *)(malloc(pCmd->rspLen)); + +#ifdef _SRQSUPPORT_ +/* + * Ok to re-register a handler for the same device, just don't do it after + * init time is over! + */ + (*(drvGpib.registerSrqCallback))(pdpvt->linkType, pdpvt->head.link, + bbnode, pdpvt->head.device, srqHandler, pdpvt->phwpvt); +#endif + + /* fill in the required stuff for the callcack task (jrw) */ + pdpvt->process = processCallback; + pdpvt->processPri = priorityLow; + + return(0); +} + +/****************************************************************************** + * + * These are the functions that are called to actually communicate with + * the GPIB device. + * + ******************************************************************************/ +static long +read_ai(pai) +struct aiRecord *pai; +{ + struct gpibDpvt *pdpvt = (struct gpibDpvt *)(pai->dpvt); + struct gpibCmd *pCmd; + + pCmd = &gpibCmds[pdpvt->parm]; + if (pai->pact) + { + if (dg535Debug) + 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(0); + } + else + { /* put pointer to dpvt field on ring buffer */ + if (dg535Debug) + 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 gpibDpvt *pdpvt = (struct gpibDpvt *)(pao->dpvt); + struct gpibCmd *pCmd; + + pCmd = &gpibCmds[pdpvt->parm]; + + if (pao->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(pao,WRITE_ALARM,VALID_ALARM); + return(0); + } + return(1); + } +} + +static long +read_bi(pbi) +struct biRecord *pbi; +{ + struct gpibDpvt *pdpvt = (struct gpibDpvt *)(pbi->dpvt); + struct gpibCmd *pCmd; + + pCmd = &gpibCmds[pdpvt->parm]; + + if (pbi->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(pbi,READ_ALARM,VALID_ALARM); + return(0); + } + return(1); + } +} + + +static long +write_bo(pbo) +struct boRecord *pbo; +{ + struct gpibDpvt *pdpvt = (struct gpibDpvt *)(pbo->dpvt); + struct gpibCmd *pCmd; + + pCmd = &gpibCmds[pdpvt->parm]; + + if (pbo->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(pbo,WRITE_ALARM,VALID_ALARM); + return(0); + } + return(1); + } +} + +static long +read_mbbi(pmbbi) +struct mbbiRecord *pmbbi; +{ + struct gpibDpvt *pdpvt = (struct gpibDpvt *)(pmbbi->dpvt); + struct gpibCmd *pCmd; + + pCmd = &gpibCmds[pdpvt->parm]; + + if (pmbbi->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(pmbbi,READ_ALARM,VALID_ALARM); + return(0); + } + return(1); + } +} + + +static long +write_mbbo(pmbbo) +struct mbboRecord *pmbbo; +{ + struct gpibDpvt *pdpvt = (struct gpibDpvt *)(pmbbo->dpvt); + struct gpibCmd *pCmd; + + pCmd = &gpibCmds[pdpvt->parm]; + + if (pmbbo->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(pmbbo,WRITE_ALARM,VALID_ALARM); + return(0); + } + return(1); + } +} + +static long +read_stringin(pstringin) +struct stringinRecord *pstringin; +{ + struct gpibDpvt *pdpvt = (struct gpibDpvt *)(pstringin->dpvt); + struct gpibCmd *pCmd; + + pCmd = &gpibCmds[pdpvt->parm]; + if (pstringin->pact) + { + if (dg535Debug) + 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 (dg535Debug) + 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 gpibDpvt *pdpvt = (struct gpibDpvt *)(pstringout->dpvt); + struct gpibCmd *pCmd; + + pCmd = &gpibCmds[pdpvt->parm]; + + 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); + } +} + +/****************************************************************************** + * + * Routines that do the actual GPIB work. They are called by the linkTask. + * + ******************************************************************************/ + +static int +aiGpibWork(pdpvt) +struct gpibDpvt *pdpvt; +{ + struct aiRecord *pai= ((struct aiRecord *)(pdpvt->precord)); + struct gpibCmd *pCmd = &gpibCmds[pdpvt->parm]; + + /* go send predefined cmd msg and read response into msg[] */ + + if(dg535Debug) + logMsg("aiGpibWork: starting ...\n"); + + if (xxGpibWork(pdpvt, pCmd->type) == ERROR) + { + setPvSevr(pai,READ_ALARM,VALID_ALARM); + + if(dg535Debug) + logMsg("aiGpibWork: calling process ...\n"); + + pdpvt->head.header.callback.finishProc = pdpvt->process; + pdpvt->head.header.callback.priority = pdpvt->processPri; + callbackRequest(pdpvt); + } + else + { + if (pCmd->type != GPIBREADW) + aiGpibFinish(pdpvt); /* If not waiting on SRQ, finish */ + else + { + pdpvt->phwpvt->srqCallback = aiGpibSrq; /* mark the handler */ + pdpvt->phwpvt->parm = (caddr_t)pdpvt; /* mark the handler */ + return(BUSY); /* indicate device still in use */ + } + } + return(IDLE); /* indicate device is now idle */ +} + +static int +aiGpibSrq(pdpvt, srqStatus) +struct gpibDpvt *pdpvt; +int srqStatus; +{ + if (dg535Debug || ibSrqDebug) + logMsg("aiGpibSrq(0x%08.8X, 0x%02.2X): processing srq\n", pdpvt, srqStatus); + + /* do actual SRQ processing in here */ + + pdpvt->phwpvt->srqCallback = NULL; /* unmark the handler */ + pdpvt->phwpvt->parm = (caddr_t)NULL; + + aiGpibFinish(pdpvt); /* and finish the processing */ + return(IDLE); /* indicate device now idle */ +} + +static int +aiGpibFinish(pdpvt) +struct gpibDpvt *pdpvt; +{ + double value; + struct aiRecord *pai = ((struct aiRecord *)(pdpvt->precord)); + struct gpibCmd *pCmd = &gpibCmds[pdpvt->parm]; + + if (pCmd->convert != NULL) + { + if(dg535Debug) + logMsg("aiGpibWork: calling convert ...\n"); + (*(pCmd->convert))(pdpvt,pCmd->P1,pCmd->P2, pCmd->P3); + if(dg535Debug) + 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(dg535Debug) + logMsg("aiGpibWork: calling process ...\n"); + + pdpvt->head.header.callback.finishProc = pdpvt->process; + pdpvt->head.header.callback.priority = pdpvt->processPri; + callbackRequest(pdpvt); + + return(0); +} + +static int +aoGpibWork(pdpvt) +struct gpibDpvt *pdpvt; +{ + int cnvrtStat = OK; + struct aoRecord *pao= ((struct aoRecord *)(pdpvt->precord)); + struct gpibCmd *pCmd = &gpibCmds[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, pCmd->type) == ERROR)) + { + setPvSevr(pao,WRITE_ALARM,VALID_ALARM); + } + + pdpvt->head.header.callback.finishProc = pdpvt->process; + pdpvt->head.header.callback.priority = pdpvt->processPri; + callbackRequest(pdpvt); /* jrw */ +} + +static int +biGpibWork(pdpvt) +struct gpibDpvt *pdpvt; +{ + struct biRecord *pbi= ((struct biRecord *)(pdpvt->precord)); + struct gpibCmd *pCmd = &gpibCmds[pdpvt->parm]; + + /* go send predefined cmd msg and read response into msg[] */ + + if (xxGpibWork(pdpvt, pCmd->type) == ERROR) + { + setPvSevr(pbi,READ_ALARM,VALID_ALARM); + + if(dg535Debug) + logMsg("aiGpibWork: calling process ...\n"); + + pdpvt->head.header.callback.finishProc = pdpvt->process; + pdpvt->head.header.callback.priority = pdpvt->processPri; + callbackRequest(pdpvt); + } + else /* interpret response that came back */ + { + if (pCmd->type != GPIBREADW) + biGpibFinish(pdpvt); /* If not waiting on SRQ, finish */ + else + { + pdpvt->phwpvt->srqCallback = biGpibSrq; /* mark the handler */ + pdpvt->phwpvt->parm = (caddr_t)pdpvt; /* mark the handler */ + return(BUSY); /* indicate device still in use */ + } + } + return(IDLE); +} + +static int +biGpibSrq(pdpvt, srqStatus) +struct gpibDpvt *pdpvt; +int srqStatus; +{ + if (dg535Debug || ibSrqDebug) + logMsg("biGpibSrq(0x%08.8X, 0x%02.2X): processing srq\n", pdpvt, srqStatus); + + /* do actual SRQ processing in here */ + + pdpvt->phwpvt->srqCallback = NULL; /* unmark the handler */ + pdpvt->phwpvt->parm = (caddr_t)NULL; /* unmark the handler */ + + biGpibFinish(pdpvt); /* and finish the processing */ + return(IDLE); /* indicate device now idle */ +} + +static int +biGpibFinish(pdpvt) +struct gpibDpvt *pdpvt; +{ + unsigned long value; + struct biRecord *pbi= ((struct biRecord *)(pdpvt->precord)); + struct gpibCmd *pCmd = &gpibCmds[pdpvt->parm]; + + if (pCmd->convert != NULL) + { + (*(pCmd->convert))(pdpvt,pCmd->P1,pCmd->P2, pCmd->P3); + } + 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); + } + } + + pdpvt->head.header.callback.finishProc = pdpvt->process; + pdpvt->head.header.callback.priority = pdpvt->processPri; + callbackRequest(pdpvt); /* jrw */ + + return(0); +} + + +static int +boGpibWork(pdpvt) +struct gpibDpvt *pdpvt; +{ + int cnvrtStat = OK; + int strStat = OK; + struct boRecord *pbo= ((struct boRecord *)(pdpvt->precord)); + struct gpibCmd *pCmd = &gpibCmds[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, (unsigned int)pbo->val); + } + + /* go access board with this message, unless convert was unsuccessful */ + if ((cnvrtStat == ERROR) || (xxGpibWork(pdpvt, pCmd->type) == ERROR)) + { + setPvSevr(pbo,WRITE_ALARM,VALID_ALARM); + } + + pdpvt->head.header.callback.finishProc = pdpvt->process; + pdpvt->head.header.callback.priority = pdpvt->processPri; + callbackRequest(pdpvt); +} + +static int +mbbiGpibWork(pdpvt) +struct gpibDpvt *pdpvt; +{ + struct mbbiRecord *pmbbi= ((struct mbbiRecord *)(pdpvt->precord)); + struct gpibCmd *pCmd = &gpibCmds[pdpvt->parm]; + + /* go send predefined cmd msg and read string response into msg[] */ + + if (xxGpibWork(pdpvt, pCmd->type) == ERROR) + { + setPvSevr(pmbbi,WRITE_ALARM,VALID_ALARM); + + if(dg535Debug) + logMsg("mbbiGpibWork: calling process ...\n"); + + pdpvt->head.header.callback.finishProc = pdpvt->process; + pdpvt->head.header.callback.priority = pdpvt->processPri; + callbackRequest(pdpvt); + } + else + { + if (pCmd->type != GPIBREADW) + mbbiGpibFinish(pdpvt); /* If not waiting on SRQ, finish */ + else + { + pdpvt->phwpvt->srqCallback = mbbiGpibSrq; /* mark the handler */ + pdpvt->phwpvt->parm = (caddr_t)pdpvt; /* mark the handler */ + return(BUSY); /* indicate device still in use */ + } + } + return(IDLE); +} + +static int +mbbiGpibSrq(pdpvt, srqStatus) +struct gpibDpvt *pdpvt; +int srqStatus; +{ + if (dg535Debug || ibSrqDebug) + logMsg("mbbiGpibSrq(0x%08.8X, 0x%02.2X): processing srq\n", pdpvt, srqStatus); + + /* do actual SRQ processing in here */ + + pdpvt->phwpvt->srqCallback = NULL; /* unmark the handler */ + pdpvt->phwpvt->parm = (caddr_t)NULL; /* unmark the handler */ + + mbbiGpibFinish(pdpvt); /* and finish the processing */ + return(IDLE); /* indicate device now idle */ +} + +static int +mbbiGpibFinish(pdpvt) +struct gpibDpvt *pdpvt; +{ + unsigned long value; + struct mbbiRecord *pmbbi= ((struct mbbiRecord *)(pdpvt->precord)); + struct gpibCmd *pCmd = &gpibCmds[pdpvt->parm]; + + if (pCmd->convert != NULL) + { + (*(pCmd->convert))(pdpvt,pCmd->P1,pCmd->P2, pCmd->P3); + } + 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)) + { + pmbbi->rval = value; + } + else /* sscanf did not find or assign the parameter */ + { + setPvSevr(pmbbi,READ_ALARM,VALID_ALARM); + } + } + pdpvt->head.header.callback.finishProc = pdpvt->process; + pdpvt->head.header.callback.priority = pdpvt->processPri; + callbackRequest(pdpvt); + + return(0); +} + +static int +mbboGpibWork(pdpvt) +struct gpibDpvt *pdpvt; +{ + int cnvrtStat = OK; + int strStat = OK; + struct mbboRecord *pmbbo= ((struct mbboRecord *)(pdpvt->precord)); + struct gpibCmd *pCmd = &gpibCmds[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, (unsigned int)pmbbo->rval); + } + + /* go access board with this message, unless convert was unsuccessful */ + if ((cnvrtStat == ERROR) || (xxGpibWork(pdpvt, pCmd->type) == ERROR)) + { + setPvSevr(pmbbo,WRITE_ALARM,VALID_ALARM); + } + + pdpvt->head.header.callback.finishProc = pdpvt->process; + pdpvt->head.header.callback.priority = pdpvt->processPri; + callbackRequest(pdpvt); /* jrw */ +} + +static int +stringinGpibWork(pdpvt) +struct gpibDpvt *pdpvt; +{ + struct stringinRecord *pstringin=((struct stringinRecord*)(pdpvt->precord)); + struct gpibCmd *pCmd = &gpibCmds[pdpvt->parm]; + + /* go send predefined cmd msg and read response into msg[] */ + + if(dg535Debug) + logMsg("stringinGpibWork: starting ...\n"); + + if (xxGpibWork(pdpvt, pCmd->type) == ERROR) + { + if(dg535Debug) + logMsg("stringinGpibWork: error in xxGpibWork ...\n"); + setPvSevr(pstringin,READ_ALARM,VALID_ALARM); + + pdpvt->head.header.callback.finishProc = pdpvt->process; + pdpvt->head.header.callback.priority = pdpvt->processPri; + callbackRequest(pdpvt); /* jrw */ + } + else + { + if (pCmd->type != GPIBREADW) + stringinGpibFinish(pdpvt); /* If not waiting on SRQ, finish */ + else + { + pdpvt->phwpvt->srqCallback = stringinGpibSrq; /* mark the handler */ + pdpvt->phwpvt->parm = (caddr_t)pdpvt; /* mark the handler */ + return(BUSY); /* indicate device still in use */ + } + } + return(IDLE); +} + +static int +stringinGpibSrq(pdpvt, srqStatus) +struct gpibDpvt *pdpvt; +int srqStatus; +{ + if (dg535Debug || ibSrqDebug) + logMsg("stringinGpibSrq(0x%08.8X, 0x%02.2X): processing srq\n", pdpvt, srqStatus); + + /* do actual SRQ processing in here */ + + pdpvt->phwpvt->srqCallback = NULL; /* unmark the handler */ + pdpvt->phwpvt->parm = (caddr_t)NULL; /* unmark the handler */ + + stringinGpibFinish(pdpvt); /* and finish the processing */ + return(IDLE); /* indicate device now idle */ +} + +static int +stringinGpibFinish(pdpvt) +struct gpibDpvt *pdpvt; +{ + struct stringinRecord *pstringin=((struct stringinRecord*)(pdpvt->precord)); + struct gpibCmd *pCmd = &gpibCmds[pdpvt->parm]; + + if (pCmd->convert != NULL) + { + if(dg535Debug) + logMsg("stringinGpibWork: calling convert ...\n"); + (*(pCmd->convert))(pdpvt,pCmd->P1,pCmd->P2, pCmd->P3); + if(dg535Debug) + logMsg("stringinGpibWork: returned from convert ...\n"); + } + else /* interpret msg with predefined format and write into .val */ + { + /* scan response string, return value will be 1 if successful */ + strncpy(pstringin->val,pdpvt->msg,39); + pstringin->val[40] = '\0'; + } + pdpvt->head.header.callback.finishProc = pdpvt->process; + pdpvt->head.header.callback.priority = pdpvt->processPri; + callbackRequest(pdpvt); /* jrw */ + + return(0); +} + +static int +stringoutGpibWork(pdpvt) +struct gpibDpvt *pdpvt; +{ + int cnvrtStat = OK; + struct stringoutRecord *pstringout= ((struct stringoutRecord *)(pdpvt->precord)); + struct gpibCmd *pCmd = &gpibCmds[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 */ + { + strncpy(pdpvt->msg, pstringout->val, 40); + } + + /* go access board with this message, unless convert was unsuccessful */ + if ((cnvrtStat == ERROR) || (xxGpibWork(pdpvt, pCmd->type) == ERROR)) + { + setPvSevr(pstringout,WRITE_ALARM,VALID_ALARM); + } + + pdpvt->head.header.callback.finishProc = pdpvt->process; + pdpvt->head.header.callback.priority = pdpvt->processPri; + callbackRequest(pdpvt); /* jrw */ +} + +static int +xxGpibWork(pdpvt, cmdType) +struct gpibDpvt *pdpvt; +int cmdType; +{ + int status; /* for GPIBREAD, contains ERROR or # of bytes read */ + struct gpibCmd *pCmd = &gpibCmds[pdpvt->parm]; + short ibnode = pdpvt->head.device; + short bbnode; /* In case is a bitbus->gpib type link */ + + /* If is a BBGPIB_IO link, the bug address is needed */ + if (pdpvt->linkType == BBGPIB_IO) + bbnode = pdpvt->head.bitBusDpvt->txMsg->node; + + /* + * check to see if this node has timed out within last 10 sec + */ + if(tickGet() < (pdpvt->phwpvt->tmoVal +TIME_WINDOW) ) + { + if (dg535Debug) + logMsg("dg535-xxGpibWork(): timeout flush\n"); + return(ERROR); + } + switch (cmdType) + { + case GPIBWRITE: /* write the message to the GPIB listen adrs */ + if(dg535Debug) + 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; + } + status = (*(drvGpib.readIb))(pdpvt->linkType, pdpvt->head.link, + bbnode, ibnode, pdpvt->rsp, pCmd->rspLen); +#endif + break; + + case GPIBREAD: /* write the command string */ + if(dg535Debug) + logMsg("xxGpibWork : processing GPIBREAD\n"); + status = (*(drvGpib.writeIb))(pdpvt->linkType, pdpvt->head.link, + bbnode, ibnode, pCmd->cmd, strlen(pCmd->cmd)); + if (status == ERROR) + { + break; + } + /* This falls thru to the raw read code below! */ + + case GPIBRAWREAD: /* for SRQs, read the data w/o a sending a command */ + + /* read the instrument */ + 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; + + case GPIBREADW: /* for SRQs, write the command first */ + 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; + case GPIBCNTL: /* send cmd with atn line active */ + status = (*(drvGpib.writeIbCmd))(pdpvt->linkType, pdpvt->head.link, + bbnode, pCmd->cmd, strlen(pCmd->cmd)); + break; + } + if(dg535Debug) + logMsg("xxGpibWork : done, status = %d\n",status); + + /* if error occurrs then mark it with time */ + if(status == ERROR) + { + (pdpvt->phwpvt->tmoCount)++; /* count number of timeouts */ + pdpvt->phwpvt->tmoVal = tickGet(); /* set last timeout time */ + } + return(status); +} + +/****************************************************************************** + * + * This is invoked by the linkTask when an SRQ is detected from a device + * operated by this module. + * + * It calls the work routine associated with the type of record expecting + * the SRQ response. + * + * No semaphore locks are needed around the references to anything in the + * hwpvt structure, because it is static unless modified by the linkTask. + * + ******************************************************************************/ + +#ifdef _SRQSUPPORT_ + +static int srqHandler(phwpvt, srqStatus) +struct hwpvt *phwpvt; +int srqStatus; /* The poll response from the device */ +{ + if (dg535Debug || ibSrqDebug) + logMsg("srqHandler(0x%08.8X, 0x%02.2X): called\n", phwpvt, srqStatus); + + /* Invoke the command-type specific SRQ handler */ + if (phwpvt->srqCallback != NULL) + return((*(phwpvt->srqCallback))(phwpvt->parm, srqStatus)); + + logMsg("Unsolicited SRQ rec'd from link %d, device %d, status = 0x%02.2X\n", + phwpvt->link, phwpvt->device, srqStatus); + + return(IDLE); +} + +#endif /* _SRQSUPPORT_ */ + +/****************************************************************************** + * + * 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) + * + ******************************************************************************/ + +static void +processCallback(pDpvt) +struct gpibDpvt *pDpvt; +{ + if(dg535Debug) + logMsg("processCallback: calling process\n"); + + dbScanLock(pDpvt->precord); + (*(struct rset *)(pDpvt->precord->rset)).process(pDpvt->precord->pdba); + dbScanUnlock(pDpvt->precord); +} + +/****************************************************************************** + * + * This function is used to set alarm status information. + * + ******************************************************************************/ +static long +setPvSevr(pPv, status, severity) +struct dbCommon *pPv; +short severity; +short status; +{ + if (severity > pPv->nsev ) + { + pPv->nsta = status; + pPv->nsev = severity; + } +} diff --git a/src/vxWorks/devOpt/devXxHvpsGpib.c b/src/vxWorks/devOpt/devXxHvpsGpib.c new file mode 100644 index 000000000..2472c895d --- /dev/null +++ b/src/vxWorks/devOpt/devXxHvpsGpib.c @@ -0,0 +1,1600 @@ +/* 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; + } +}