537 lines
12 KiB
C
537 lines
12 KiB
C
/* devXxBugRac.c */
|
|
|
|
/* Device Support Routines for BUF RAC commands */
|
|
/*
|
|
* Original Author: Ned Arnold (based on work by Jim Kowalkowski)
|
|
* Date: 02/01/93
|
|
*
|
|
* 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 02-01093 nda initialized
|
|
* .02 06-03-94 nda removed automatic retry on a TIMEOUT
|
|
* .03 06-03-94 nda removed drvBitBus.qReq at init time
|
|
* ...
|
|
*/
|
|
|
|
|
|
|
|
#include <vxWorks.h>
|
|
#include <vme.h>
|
|
#include <types.h>
|
|
#include <stdioLib.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
#include <iv.h>
|
|
|
|
#include <alarm.h>
|
|
#include <callback.h>
|
|
#include <dbRecType.h>
|
|
#include <dbDefs.h>
|
|
#include <dbAccess.h>
|
|
#include <dbCommon.h>
|
|
#include <fast_lock.h>
|
|
#include <recSup.h>
|
|
#include <devSup.h>
|
|
#include <drvSup.h>
|
|
#include <dbScan.h>
|
|
#include <special.h>
|
|
#include <module_types.h>
|
|
#include <eventRecord.h>
|
|
#include <drvBitBusInterface.h>
|
|
#include <aiRecord.h>
|
|
#include <aoRecord.h>
|
|
#include <choiceAo.h>
|
|
#include <biRecord.h>
|
|
#include <boRecord.h>
|
|
#include <longinRecord.h>
|
|
#include <longoutRecord.h>
|
|
#include <mbboRecord.h>
|
|
#include <mbbiRecord.h>
|
|
|
|
/* types */
|
|
#define AI 0x01
|
|
#define AO 0x02
|
|
#define BI 0x03
|
|
#define BO 0x04
|
|
#define LI 0x05
|
|
#define LO 0x06
|
|
#define MBBI 0x07
|
|
#define MBBO 0x08
|
|
|
|
|
|
/* Define forward references */
|
|
long report();
|
|
long init();
|
|
static long init_ai();
|
|
static long init_ao();
|
|
static long init_bo();
|
|
static long init_bi();
|
|
static long init_li();
|
|
long init_lo();
|
|
static long init_mbbi();
|
|
static long init_mbbo();
|
|
long get_ioint_info();
|
|
static long bug_rac();
|
|
|
|
/* Create the dsets for devXxBugRac */
|
|
typedef struct {
|
|
long number;
|
|
DEVSUPFUN report;
|
|
DEVSUPFUN init;
|
|
DEVSUPFUN init_record;
|
|
DEVSUPFUN get_ioint_info;
|
|
DEVSUPFUN read_write;
|
|
DEVSUPFUN special_linconv;
|
|
} IODSET;
|
|
|
|
/* DEFINE SUPPORTED RAC COMMANDS
|
|
#define RESET_STATION 0x00 /* BO record */
|
|
#define GET_FUNCTION_ID 0x03 /* LI record */
|
|
|
|
/* xxDSET devXxxx={ 5,report,init,init_rec,get_ioint_info,bug_rac}; */
|
|
|
|
IODSET devBoBugRac = { 5, NULL, NULL, init_bo, NULL, bug_rac };
|
|
IODSET devLiBugRac = { 5, NULL, NULL, init_li, NULL, bug_rac };
|
|
|
|
/* forward references */
|
|
|
|
static void get_data();
|
|
static void send_cntl_trans();
|
|
extern struct drvBitBusEt drvBitBus;
|
|
|
|
volatile int bugRacDebug=0;
|
|
|
|
#define OFF 0
|
|
#define ON 1
|
|
|
|
#ifdef NODEBUG
|
|
#define Debug(FMT,V) ;
|
|
#else
|
|
#define Debug(FMT,V) { if(bugRacDebug) \
|
|
{\
|
|
printf("%s(%d):",__FILE__,__LINE__); \
|
|
printf(FMT,V); \
|
|
} \
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
struct dprivate {
|
|
struct dpvtBitBusHead bitbus;
|
|
char type;
|
|
unsigned char cmd;
|
|
struct dbCommon *precord; /* at end for callback to get it */
|
|
};
|
|
|
|
static int io_callback(struct dprivate *pcallback)
|
|
{
|
|
struct dbCommon *precord;
|
|
struct rset *prset;
|
|
|
|
precord=pcallback->precord;
|
|
prset=(struct rset *)(precord->rset);
|
|
|
|
dbScanLock(precord);
|
|
(*prset->process)(precord);
|
|
dbScanUnlock(precord);
|
|
}
|
|
|
|
static struct dprivate * set_bitbus(int prio,unsigned char cmd,struct bitbusio *pbitbusio)
|
|
{
|
|
struct dprivate *my_dpvt;
|
|
|
|
my_dpvt=(struct dprivate *)(malloc(sizeof(struct dprivate)));
|
|
|
|
my_dpvt->bitbus.finishProc=io_callback;
|
|
my_dpvt->bitbus.psyncSem=(SEM_ID *)NULL;
|
|
my_dpvt->bitbus.priority=prio;
|
|
my_dpvt->bitbus.link=pbitbusio->link;
|
|
my_dpvt->bitbus.rxMaxLen=9;
|
|
my_dpvt->bitbus.ageLimit=240;
|
|
|
|
my_dpvt->bitbus.txMsg.length=9;
|
|
my_dpvt->bitbus.txMsg.route=0x40;
|
|
my_dpvt->bitbus.txMsg.node=pbitbusio->node;
|
|
my_dpvt->bitbus.txMsg.tasks=0;
|
|
my_dpvt->bitbus.txMsg.cmd=cmd;
|
|
my_dpvt->bitbus.txMsg.data=(unsigned char *)malloc(2);
|
|
my_dpvt->bitbus.rxMsg.data=(unsigned char *)malloc(BB_MAX_DAT_LEN);
|
|
|
|
my_dpvt->bitbus.txMsg.data[0]='\0';
|
|
my_dpvt->bitbus.txMsg.data[1]='\0';
|
|
|
|
Debug("command sent:(%02.2x)\n", my_dpvt->bitbus.txMsg.cmd);
|
|
|
|
return(my_dpvt);
|
|
}
|
|
|
|
|
|
static long init_ai(struct aiRecord *ai)
|
|
{
|
|
struct bitbusio *pbitbusio = (struct bitbusio *)(&ai->inp.value);
|
|
struct dprivate *my_dpvt;
|
|
int ret;
|
|
|
|
Debug("init ai invoked\n",0);
|
|
|
|
/* type must be an BITBUS_IO */
|
|
if(ai->inp.type!=BITBUS_IO)
|
|
{
|
|
recGblRecordError(S_dev_badBus,(void *)ai,
|
|
"devXxBugRac (init_record) Illegal IN Bus Type");
|
|
return(S_dev_badBus);
|
|
}
|
|
|
|
|
|
my_dpvt=set_bitbus(ai->prio,pbitbusio->signal,pbitbusio);
|
|
my_dpvt->precord = (struct dbCommon *)ai;
|
|
my_dpvt->type = AI;
|
|
|
|
ai->dpvt=(void *)my_dpvt;
|
|
return(0);
|
|
}
|
|
|
|
|
|
static long init_ao(struct aoRecord *ao)
|
|
{
|
|
struct bitbusio *pbitbusio = (struct bitbusio *)(&ao->out.value);
|
|
struct dprivate *my_dpvt;
|
|
|
|
Debug("init ao invoked\n",0);
|
|
|
|
/* out must be an BITBUS_IO */
|
|
if(ao->out.type!=BITBUS_IO)
|
|
{
|
|
recGblRecordError(S_dev_badBus,(void *)ao,
|
|
"devXxBugRac (init_record) Illegal OUT Bus Type");
|
|
return(S_dev_badBus);
|
|
}
|
|
|
|
my_dpvt=set_bitbus(ao->prio,pbitbusio->signal,pbitbusio);
|
|
my_dpvt->precord = (struct dbCommon *)ao;
|
|
my_dpvt->type = AO;
|
|
|
|
ao->dpvt=(void *)my_dpvt;
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
static long init_bi(struct biRecord *bi)
|
|
{
|
|
struct bitbusio *pbitbusio = (struct bitbusio *)(&bi->inp.value);
|
|
struct dprivate *my_dpvt;
|
|
unsigned char cmd = 0;
|
|
|
|
Debug("init bi invoked\n",0);
|
|
|
|
/* out must be an BITBUS_IO */
|
|
if(bi->inp.type!=BITBUS_IO)
|
|
{
|
|
recGblRecordError(S_dev_badBus,(void *)bi,
|
|
"devXxBugRac (init_record) Illegal IN Bus Type");
|
|
return(S_dev_badBus);
|
|
}
|
|
|
|
|
|
my_dpvt=set_bitbus(bi->prio,pbitbusio->signal,pbitbusio);
|
|
my_dpvt->precord = (struct dbCommon *)bi;
|
|
my_dpvt->type = BI;
|
|
my_dpvt->cmd = cmd;
|
|
bi->dpvt=(void *)my_dpvt;
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
static long init_bo(struct boRecord *bo)
|
|
{
|
|
struct bitbusio *pbitbusio = (struct bitbusio *)(&bo->out.value);
|
|
struct dprivate *my_dpvt;
|
|
|
|
Debug("init bo invoked\n",0);
|
|
|
|
/* out must be an BITBUS_IO */
|
|
if(bo->out.type!=BITBUS_IO)
|
|
{
|
|
recGblRecordError(S_dev_badBus,(void *)bo,
|
|
"devXxBugRac (init_record) Illegal IN Bus Type");
|
|
return(S_dev_badBus);
|
|
}
|
|
|
|
switch(pbitbusio->signal)
|
|
{
|
|
default:
|
|
recGblRecordError(S_dev_badBus,(void *)bo,
|
|
"devXxBugRac (init_record) Illegal IN signal number");
|
|
return(S_dev_badBus);
|
|
case 0: /* signal 0 is a bo record */
|
|
break;
|
|
}
|
|
|
|
my_dpvt=set_bitbus(bo->prio,pbitbusio->signal,pbitbusio);
|
|
my_dpvt->precord = (struct dbCommon *)bo;
|
|
my_dpvt->type = BO;
|
|
my_dpvt->cmd = pbitbusio->signal;
|
|
|
|
bo->dpvt=(void *)my_dpvt;
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
static long init_li(struct longinRecord *li)
|
|
{
|
|
struct bitbusio *pbitbusio = (struct bitbusio *)(&li->inp.value);
|
|
struct dprivate *my_dpvt;
|
|
unsigned char cmd = 0;
|
|
|
|
Debug("init li invoked\n",0);
|
|
|
|
/* out must be an BITBUS_IO */
|
|
if(li->inp.type!=BITBUS_IO)
|
|
{
|
|
recGblRecordError(S_dev_badBus,(void *)li,
|
|
"devXxBugRac (init_record) Illegal IN Bus Type");
|
|
return(S_dev_badBus);
|
|
}
|
|
|
|
switch(pbitbusio->signal)
|
|
{
|
|
default:
|
|
recGblRecordError(S_dev_badBus,(void *)li,
|
|
"devXxBugRac (init_record) Illegal IN signal number");
|
|
return(S_dev_badBus);
|
|
case 3: /* signal 3 is a li record */
|
|
break;
|
|
}
|
|
|
|
my_dpvt=set_bitbus(li->prio,pbitbusio->signal,pbitbusio);
|
|
my_dpvt->precord = (struct dbCommon *)li;
|
|
my_dpvt->type = LI;
|
|
my_dpvt->cmd = pbitbusio->signal;
|
|
li->dpvt=(void *)my_dpvt;
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
static long init_mbbi(struct mbbiRecord *mbbi)
|
|
{
|
|
struct bitbusio *pbitbusio = (struct bitbusio *)(&mbbi->inp.value);
|
|
struct dprivate *my_dpvt;
|
|
unsigned char cmd = 0;
|
|
|
|
Debug("init mbbi invoked\n",0);
|
|
|
|
/* out must be an BITBUS_IO */
|
|
if(mbbi->inp.type!=BITBUS_IO)
|
|
{
|
|
recGblRecordError(S_dev_badBus,(void *)mbbi,
|
|
"devXxBugRac (init_record) Illegal IN Bus Type");
|
|
return(S_dev_badBus);
|
|
}
|
|
|
|
my_dpvt=set_bitbus(mbbi->prio,pbitbusio->signal,pbitbusio);
|
|
my_dpvt->precord = (struct dbCommon *)mbbi;
|
|
my_dpvt->type = MBBI;
|
|
my_dpvt->cmd = cmd;
|
|
mbbi->dpvt=(void *)my_dpvt;
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
static long init_mbbo(struct mbboRecord *mbbo)
|
|
{
|
|
struct bitbusio *pbitbusio = (struct bitbusio *)(&mbbo->out.value);
|
|
struct dprivate *my_dpvt;
|
|
unsigned char cmd = 0;
|
|
|
|
Debug("init mbbo invoked\n",0);
|
|
|
|
/* out must be an BITBUS_IO */
|
|
if(mbbo->out.type!=BITBUS_IO)
|
|
{
|
|
recGblRecordError(S_dev_badBus,(void *)mbbo,
|
|
"devXxBugRac (init_record) Illegal OUT Bus Type");
|
|
return(S_dev_badBus);
|
|
}
|
|
|
|
if(pbitbusio->signal >= 8 )
|
|
{
|
|
recGblRecordError(S_dev_badBus,(void *)mbbo,
|
|
"devXxBugRac (init_record) Illegal OUT signal number");
|
|
return(S_dev_badBus);
|
|
}
|
|
|
|
my_dpvt=set_bitbus(mbbo->prio,pbitbusio->signal,pbitbusio);
|
|
my_dpvt->precord = (struct dbCommon *)mbbo;
|
|
my_dpvt->type = MBBO;
|
|
my_dpvt->cmd = cmd;
|
|
|
|
mbbo->dpvt=(void *)my_dpvt;
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
static long bug_rac(struct dbCommon *io)
|
|
{
|
|
struct dprivate *my_dpvt=(struct dprivate *)io->dpvt;
|
|
struct dpvtBitBusHead *pbitbus;
|
|
|
|
if(!io->dpvt) return(S_dev_NoInit);
|
|
|
|
pbitbus=&(my_dpvt->bitbus);
|
|
|
|
if(io->pact==TRUE)
|
|
{
|
|
Debug("Bitbus message completed \n",0);
|
|
|
|
/* a transaction to bitbus has completed */
|
|
switch(pbitbus->status)
|
|
{
|
|
case BB_OK:
|
|
Debug("Getting data \n",0);
|
|
get_data(io);
|
|
return(0);
|
|
default:
|
|
recGblSetSevr(io,WRITE_ALARM,MAJOR_ALARM);
|
|
recGblRecordError(S_dev_badBus,(void *)io,
|
|
"devXxBugRac (iobug_rdwr) BitBus Error!");
|
|
return(S_dev_badBus);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* data needs to be sent to bitbus */
|
|
Debug("Sending transaction \n",0);
|
|
send_cntl_trans(io);
|
|
}
|
|
|
|
io->pact=TRUE;
|
|
|
|
/* queue the command */
|
|
if((*drvBitBus.qReq)(pbitbus,BB_Q_LOW)<0)
|
|
{
|
|
recGblSetSevr(io,WRITE_ALARM,MAJOR_ALARM);
|
|
recGblRecordError(S_dev_badBus,(void *)io,
|
|
"devXxBugRac (init_record) Initial BitBus message failed");
|
|
return(S_dev_badBus);
|
|
}
|
|
Debug("Queued transaction \n",0);
|
|
|
|
return(0);
|
|
}
|
|
|
|
static void get_data(struct dbCommon *io)
|
|
{
|
|
struct dprivate *my_dpvt=(struct dprivate *)io->dpvt;
|
|
struct dpvtBitBusHead *pbitbus;
|
|
struct boRecord *bo;
|
|
struct biRecord *bi;
|
|
struct aoRecord *ao;
|
|
struct aiRecord *ai;
|
|
struct longoutRecord *lo;
|
|
struct longinRecord *li;
|
|
struct mbboRecord *mbbo;
|
|
struct mbbiRecord *mbbi;
|
|
long value;
|
|
unsigned long uvalue;
|
|
|
|
pbitbus=&(my_dpvt->bitbus);
|
|
|
|
Debug("Command return: 0x%04.4X\n",pbitbus->rxMsg.cmd);
|
|
Debug("byte 1 of return: 0x%04.4X\n",pbitbus->rxMsg.data[0]);
|
|
Debug("byte 2 of return: 0x%04.4X\n",pbitbus->rxMsg.data[1]);
|
|
|
|
switch(my_dpvt->type)
|
|
{
|
|
case LI:
|
|
li=(struct longinRecord *)io;
|
|
switch(my_dpvt->bitbus.txMsg.cmd)
|
|
{
|
|
case GET_FUNCTION_ID:
|
|
/* extract the second ID code (task 1) */
|
|
li->val = pbitbus->rxMsg.data[1];
|
|
li->udf = 0;
|
|
if ((pbitbus->rxMsg.cmd) != 0)
|
|
{
|
|
recGblSetSevr(li, READ_ALARM, INVALID_ALARM);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static void send_cntl_trans(struct dbCommon *io)
|
|
{
|
|
struct dprivate *my_dpvt=(struct dprivate *)io->dpvt;
|
|
struct dpvtBitBusHead *pbitbus;
|
|
struct boRecord *bo;
|
|
struct aoRecord *ao;
|
|
struct mbboRecord *mbbo;
|
|
short lsb,msb;
|
|
|
|
pbitbus=&(my_dpvt->bitbus);
|
|
|
|
pbitbus->finishProc=io_callback;
|
|
pbitbus->psyncSem=(SEM_ID *)NULL;
|
|
pbitbus->priority=io->prio;
|
|
pbitbus->txMsg.cmd=my_dpvt->cmd;
|
|
|
|
switch(my_dpvt->type)
|
|
{
|
|
case BO:
|
|
bo=(struct boRecord *)io;
|
|
break;
|
|
case MBBO:
|
|
mbbo=(struct mbboRecord *)io;
|
|
break;
|
|
case AO:
|
|
ao=(struct aoRecord *)io;
|
|
pbitbus->txMsg.data[0]=0;
|
|
pbitbus->txMsg.data[1]=0;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
my_dpvt->precord=(struct dbCommon *)io;
|
|
|
|
Debug("Command send: 0x%02.2X\n",pbitbus->txMsg.cmd);
|
|
Debug("byte 1 sent: 0x%02.2X\n",(unsigned char)pbitbus->txMsg.data[0]);
|
|
Debug("byte 2 sent: 0x%02.2X\n",(unsigned char)pbitbus->txMsg.data[1]);
|
|
|
|
return;
|
|
}
|