/******************************************************************************
 *
 * devCommonGpib.h,v
 *
 ******************************************************************************/
/***********************************************************************
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory, and the Regents of the University of
* California, as Operator of Los Alamos National Laboratory, and
* Berliner Elektronenspeicherring-Gesellschaft m.b.H. (BESSY).
* gpibCore is distributed subject to a Software License Agreement
* found in file LICENSE that is included with this distribution.
***********************************************************************/
/*
 * Interface for GPIB device support library
 *
 * Current Author: Benjamin Franksen
 * Original Author: John Winans
 */
#ifndef INCdevCommonGpibh
#define INCdevCommonGpibh

#include <callback.h>
#include <dbScan.h>	/* IOSCANPVT */
#include <devSup.h>	/* DEVSUPFUN */

/* supported record types */
#include <aiRecord.h>
#include <aoRecord.h>
#include <biRecord.h>
#include <boRecord.h>
#include <mbbiRecord.h>
#include <mbboRecord.h>
#include <mbbiDirectRecord.h>
#include <mbboDirectRecord.h>
#include <longinRecord.h>
#include <longoutRecord.h>
#include <stringinRecord.h>
#include <stringoutRecord.h>
#include <eventRecord.h>
#include <waveformRecord.h>

/* driver interface */

#include "drvGpibInterface.h"
typedef struct gDset {
    long number;
    DEVSUPFUN funPtr[20];
}gDset;

/******************************************************************************
 *
 * 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.)
 *
 * The srqCallback() and parm fields are used for GPIBREADW type calls.  They
 * should place the address of the appropriate function (aiGpibSrq if an AI
 * record is being processed) into the srqCallback() field and the pdpvt
 * field for the device into the parm field.  This allows the SrqHandler()
 * function to locate the proper function and work areas to complete the
 * GPIBREADW operation.
 *
 * The srqPollStatus and ioscanpvt are used for unsollicited SRQs
 * The lingin records has support for GPIBSRQHANDLER
 *
 ******************************************************************************/
typedef struct hwpvt {
    struct hwpvt *next;	        /* to next structure for same type device */
    int link;
    short device;	        /* gpib primary address */
    short secondary;	        /* gpib secondary address */
    unsigned long tmoFlag;	/* previous operation timed out */
    epicsTimeStamp tmoVal;	/* when previous operation timed out */
    unsigned long tmoCount;	/* total number of timeouts since boot time */
    /* No semaphore guards here because can only be mod'd by the linkTask */
    srqHandlerFunc srqCallback;	/* filled by cmds expecting SRQ callbacks */
    void *parm;	                /* filled in by cmds expecting SRQ callbacks */
    void *pupvt;	        /* user defined pointer */
    /*The following fields are for GPIBSRQHANDLER records*/
    int srqPollStatus;          /* status retuned by serialPoll */
    IOSCANPVT ioscanpvt;	/* For GPIBSRQHANDLER records */
}hwpvt;

/******************************************************************************
 * gpibDpvt 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.
 ******************************************************************************/
typedef struct gpibDpvt {
    struct dpvtGpibHead head; /* fields used by the GPIB driver */
    CALLBACK callback;	      /* for record process completion */
    int timeout;	      /* io time allowed for transaction */
    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 */
    struct hwpvt *phwpvt;     /* pointer to per-device private area */
    void *pupvt;	      /* user defined pointer */
}gpibDpvt;
#define GET_GPIB_HW_PVT(pGpibDpvt) \
    (((struct gpibDpvt*)(pGpibDpvt))->phwpvt->pupvt)
#define SET_GPIB_HW_PVT(pGpibDpvt,value)\
    (((struct gpibDpvt*)(pGpibDpvt))->phwpvt->pupvt = value)

/******************************************************************************
 * devGpibNames used to define the strings that are used for button labels.
 * These strings are put into the record's znam & onam fields 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
 * checked 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!
 ******************************************************************************/
typedef struct devGpibNames {
    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 */
}devGpibNames;

/******************************************************************************
 *
 * Enumeration of gpib command types supported.
 *
 * 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
 *
 * GPIBACMD: (1) The cmd 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:(1) Data is read from the inst into a buffer (gpibDpvt.msg)
 *             (2) The important data is extracted from the buffer using the
 *                 format string.
 *
 * The following is only supported on mbbo and bo record types.
 *
 * GPIBEFASTO: (1) Sends out the string pointed to by p3[VAL] w/o formating
 *
 * The following are only supported on mbbi and bi record types.
 *
 * GPIBEFASTI: (1) Send out the cmd string
 *             (2) Data is read from the inst into a buffer (gpibDpvt.msg)
 *             (3) Check the response against P3[0..?]
 *             (4) Set the value field to index when response = P3[index]
 *
 * GPIBEFASTIW:(1) Send out the cmd string
 *             (2) Wait for SRQ
 *             (3) Data is read from the inst into a buffer (gpibDpvt.msg)
 *             (4) Check the response against P3[0..?]
 *             (5) Set the value field to index when response = P3[index]
 *
 * Commands for Bus Management Lines
 * GPIBIFC:     bo only. (0,1) => (do nothing, pulse Interface Clear)
 * GPIBREN:     bo only. (0,1) => (drop,assert) Remote Enable
 * Universial Commands
 * GPIBDCL:     bo only. (0,1) => (do nothing, send Device Clear)
 * GPIBLLO:     bo only. (0,1) => (do nothing, Send Local Lockout)
 * Addressed Commands
 * GPIBSDC:     bo only. (0,1) => (do nothing, send Selective Device Clear)
 * GPIBGTL:     bo only. (0,1) => (do nothing, send Go To Local)
 *
 * GPIBRESETLNK:bo only. (0,1) => (do nothing, Reset Link Thread)
 * GPIBSRQHANDLER: longin only. Register SRQ handler. val is status byte
 *
 *
 * 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.
 *
 ******************************************************************************/

#define GPIBREAD        1
#define GPIBWRITE       2
#define GPIBCMD         3
#define GPIBACMD        4
#define GPIBSOFT        5
#define GPIBREADW       6
#define GPIBRAWREAD     7
#define	GPIBEFASTO      8
#define	GPIBEFASTI      9
#define	GPIBEFASTIW    10
#define GPIBIFC        11
#define GPIBREN        12
#define GPIBDCL        13
#define GPIBLLO        14
#define GPIBSDC        15
#define GPIBGTL        16
#define GPIBRESETLNK   17
#define GPIBSRQHANDLER 18

#define GPIBEOS	       32  /*GPIBEOS MUST BE 32!!!! */

/*
 * Added GPIBEOS to support readIbEos. Last item of parameter table entry
 * (companion, normally unused) serves as EOS character.
 * Add (or 'or') GPIBEOS to cmd type to use readIbEos instead of readIb.
 */

typedef struct gpibCmd {
    gDset *rec_typ;	/* used to indicate record type supported */
    int type;	/* enum - GPIBREAD...GPIBEFASTIW */
    short pri;	/* request priority--IB_Q_HIGH or IB_Q_LOW */
    char *cmd;	/* CONSTANT STRING to send to instrument */
    char *format;	/* string used to generate or interpret msg */
    long rspLen;	/* room for response error message */
    long msgLen;	/* room for return data message length */
    int (*convert) ();	/* custom routine for conversions */
    int P1;	/* user defined parameter used in convert() */
    int P2;	/* user defined parameter used in convert() */
    /* P3 plays dual role. For EFAST address of EFAST table   */
    /* For convert it is passed to convert */
    char **P3;
    struct devGpibNames *pdevGpibNames;	/* pointer to name strings */
    int companion;	/* companion command (used at init time) */
}gpibCmd;
#define FILL	{NULL,0,0,NULL,NULL,0,0,NULL,0,0,NULL,NULL,-1}
#define FILL10	FILL,FILL,FILL,FILL,FILL,FILL,FILL,FILL,FILL,FILL

/******************************************************************************
 *
 * debugFlag:
 *   Must point to a flag used to request debugging traces for the device
 *   while executing library code.
 *
 * respond2Writes:
 *   Set to TRUE if the device responds to write operations.  This causes
 *   a read operation to follow each write operation.  (See also wrConversion)
 *
 * timeWindow:
 *   Set to the number of milliseconds that should be skipped after a timeout
 *   is detected on a device.  All commands issued within this time window
 *   will be aborted and returned as errors.
 *
 * hwpvtHead:
 *   This is the root pointer for the per-hardware device private structure
 *   list.  It should ALWAYS be initialized to NULL.
 *
 * gpibCmds:
 *   Pointer to the gpibCmds array.
 *
 * numparams:
 *   The number of parameters described in the gpibCmds array.
 *
 * magicSrq:
 *   Set to the parameter number that should be processed if an unsolicited
 *   SRQ is detected.
 *
 * name:
 *   Must point to a string containing the device name (used for
 *   debug messages.)
 *
 * srqHandler:
 *   Must point to the SRQ handler for the device support module if SRQs are
 *   supported or NULL if not.
 *
 * wrConversion:
 *   If not set to NULL and respond2Writes is true and a GPIBWRITE or GPIBCMD
 *   operation has completed it's read portion, this secondary conversion
 *   routine is called.
 *
 ******************************************************************************/
typedef struct devGpibParmBlock {
    int *debugFlag;	/* pointer to debug flag */
    int respond2Writes;	/* set to true if a device responds to writes */
    int timeWindow;	/* milliseconds to skip after a timeout */
    struct hwpvt *hwpvtHead;	/* pointer to the hwpvt list for device type */
    struct gpibCmd *gpibCmds;	/* pointer to gpib command list */
    int numparams;	/* number of elements in the command list */
    int magicSrq;	/* obsolete: magic parm to handle unsolicited SRQs */
    char *name;	/* pointer to a string containing device type */
    int timeout;	/* milliseconds to wait for DMA to complete */
    srqHandlerFunc srqHandler;	/* user SRQ handler or NULL if not supported */
    int (*wrConversion) ();	/* secondary conversion routine */
}devGpibParmBlock;

/******************************************************************************
 * function prototypes
 ******************************************************************************/
long devGpibLib_report(gDset * dset);
long devGpibLib_initDevSup(int parm, gDset * dset);
long devGpibLib_initAi(struct aiRecord * pai);
long devGpibLib_initAo(struct aoRecord * pao);
long devGpibLib_initLi(struct longinRecord * pli);
long devGpibLib_initLo(struct longoutRecord * plo);
long devGpibLib_initBi(struct biRecord * pbi);
long devGpibLib_initBo(struct boRecord * pbo);
long devGpibLib_initMbbi(struct mbbiRecord * pmbbi);
long devGpibLib_initMbbo(struct mbboRecord * pmbbo);
long devGpibLib_initMbbiDirect(struct mbbiDirectRecord * pmbbiDirect);
long devGpibLib_initMbboDirect(struct mbboDirectRecord * pmbboDirect);
long devGpibLib_initSi(struct stringinRecord * psi);
long devGpibLib_initSo(struct stringoutRecord * pso);
long devGpibLib_initEv(struct eventRecord * pev);
long devGpibLib_initWf(struct waveformRecord * pwf);
long devGpibLib_initXx(struct dbCommon * prec, struct link * plink);
long devGpibLib_readAi(struct aiRecord * pai);
long devGpibLib_writeAo(struct aoRecord * pao);
long devGpibLib_readLi(struct longinRecord * pli);
long devGpibLib_writeLo(struct longoutRecord * plo);
long devGpibLib_readBi(struct biRecord * pbi);
long devGpibLib_writeBo(struct boRecord * pbo);
long devGpibLib_readMbbi(struct mbbiRecord * pmbbi);
long devGpibLib_writeMbbo(struct mbboRecord * pmbbo);
long devGpibLib_readMbbiDirect(struct mbbiDirectRecord * pmbbiDirect);
long devGpibLib_writeMbboDirect(struct mbboDirectRecord * pmbboDirect);
long devGpibLib_readSi(struct stringinRecord * psi);
long devGpibLib_writeSo(struct stringoutRecord * pso);
long devGpibLib_readEv(struct eventRecord * pev);
long devGpibLib_readWf(struct waveformRecord * pwf);
long devGpibLib_readXx(struct dbCommon * prec, long success_ret);
long devGpibLib_writeXx(struct dbCommon * prec);
int devGpibLib_aiGpibWork(struct gpibDpvt * pdpvt);
int devGpibLib_aiGpibSrq(struct gpibDpvt * pdpvt, int statusByte);
void devGpibLib_aiGpibFinish(struct gpibDpvt * pdpvt);
int devGpibLib_aoGpibWork(struct gpibDpvt * pdpvt);
int devGpibLib_liGpibWork(struct gpibDpvt * pdpvt);
int devGpibLib_liGpibSrq(struct gpibDpvt * pdpvt, int statusByte);
void devGpibLib_liGpibFinish(struct gpibDpvt * pdpvt);
int devGpibLib_loGpibWork(struct gpibDpvt * pdpvt);
int devGpibLib_biGpibWork(struct gpibDpvt * pdpvt);
int devGpibLib_biGpibSrq(struct gpibDpvt * pdpvt, int statusByte);
void devGpibLib_biGpibFinish(struct gpibDpvt * pdpvt);
int devGpibLib_boGpibWork(struct gpibDpvt * pdpvt);
int devGpibLib_mbbiGpibWork(struct gpibDpvt * pdpvt);
int devGpibLib_mbbiGpibSrq(struct gpibDpvt * pdpvt, int statusByte);
void devGpibLib_mbbiGpibFinish(struct gpibDpvt * pdpvt);
int devGpibLib_mbboGpibWork(struct gpibDpvt * pdpvt);
int devGpibLib_mbbiDirectGpibWork(struct gpibDpvt * pdpvt);
int devGpibLib_mbbiDirectGpibSrq(struct gpibDpvt * pdpvt, int statusByte);
void devGpibLib_mbbiDirectGpibFinish(struct gpibDpvt * pdpvt);
int devGpibLib_mbboDirectGpibWork(struct gpibDpvt * pdpvt);
int devGpibLib_stringinGpibWork(struct gpibDpvt * pdpvt);
int devGpibLib_stringinGpibSrq(struct gpibDpvt * pdpvt, int statusByte);
void devGpibLib_stringinGpibFinish(struct gpibDpvt * pdpvt);
int devGpibLib_stringoutGpibWork(struct gpibDpvt * pdpvt);
int devGpibLib_evGpibWork(struct gpibDpvt * pdpvt);
int devGpibLib_evGpibSrq(struct gpibDpvt * pdpvt, int statusByte);
void devGpibLib_evGpibFinish(struct gpibDpvt * pdpvt);
int devGpibLib_wfGpibWork(struct gpibDpvt * pdpvt);
int devGpibLib_wfGpibSrq(struct gpibDpvt * pdpvt, int statusByte);
void devGpibLib_wfGpibFinish(struct gpibDpvt * pdpvt);
int devGpibLib_xxinGpibWork(struct gpibDpvt * pdpvt,
     void (*finish) (struct gpibDpvt * pdpvt));
int devGpibLib_xxGpibSrq(struct gpibDpvt * pdpvt, int statusByte,
     void (*finish) (struct gpibDpvt * pdpvt));
int devGpibLib_xxGpibWork(struct gpibDpvt * pdpvt, int cmdType,
     unsigned short val);
long devGpibLib_get_ioint_info(int cmd,struct dbCommon * prec,IOSCANPVT * ppvt);
long devGpibLib_srqHandler(void *parm, int statusByte);

/*
 * devCommonGpib.h,v
 * Revision 1.5  2003/04/10 15:17:02  mrk
 * open source license
 *
 * Revision 1.4  2003/03/14 16:46:16  mrk
 * Changes for March 2003 version
 *
 * Revision 1.3  2002/11/04 20:30:02  mrk
 * fix comment
 *
 * Revision 1.2  2002/11/01 19:29:22  mrk
 * More changes for ioctl replacement
 *
 * Revision 1.1  2002/10/18 17:21:03  mrk
 * moved to here
 *
 * Revision 1.4  2001/04/17 18:40:06  mrk
 * Changes to get ready for bitBus support which will be implemented with bitBus
 *
 * Revision 1.3  2001/02/27 15:06:27  norume
 * Clean up handling of dead time after timeout.  There is no longer any
 * chance of wrap-around (well, not for around 3 million years) and the
 * code is faster in the most common case than the old version.
 *
 * Revision 1.2  2001/02/22 19:57:21  norume
 * Many, many R3.14 changes.  Driver tested on RTEMS-gen68360 and Linux.
 *
 * Revision 1.1.1.1  2001/02/15 14:52:50  mrk
 * Import sources
 *
 * Revision 1.3  2000/05/19 20:37:35  franksen
 * fixed debug messages; overhauled report functions; fixed bug in HiDEOSGpibInit;
 * adapted everything to upper/lower interface seperation
 *
 * Revision 1.2  2000/05/19 12:57:41  franksen
 * use errlogPrintf; fixed bug in drvGpibGetLink;
 * changed type of link/gpibAddr from short to int
 *
 * Revision 1.1.1.1  2000/03/21 18:06:35  franksen
 * unbundled gpib first version
 */
#endif	/* INCdevCommonGpibh */
