1601 lines
48 KiB
C
1601 lines
48 KiB
C
/* 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 <vxWorks.h>
|
||
#include <taskLib.h>
|
||
#include <rngLib.h>
|
||
#include <types.h>
|
||
#include <stdioLib.h>
|
||
#include <symLib.h>
|
||
|
||
#include <alarm.h>
|
||
#include <cvtTable.h>
|
||
#include <dbDefs.h>
|
||
#include <dbAccess.h>
|
||
#include <recSup.h>
|
||
#include <devSup.h>
|
||
#include <drvSup.h>
|
||
#include <link.h>
|
||
#include <module_types.h>
|
||
#include <dbCommon.h>
|
||
#include <aiRecord.h>
|
||
#include <aoRecord.h>
|
||
#include <biRecord.h>
|
||
#include <boRecord.h>
|
||
#include <mbbiRecord.h>
|
||
#include <stringinRecord.h>
|
||
#include <stringoutRecord.h>
|
||
|
||
#include <drvGpibInterface.h>
|
||
|
||
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;
|
||
}
|
||
}
|