/* devPVME332.c */
/* devPVME332.c - Device Support Routines for VME PVME-332 */
/* 16 bit low cost A/D board (64ch) */
/*
* Original Author: M. Tobiyama
* Current Author: M. Tobiyama
* Date:
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1997, KEKB.
*
*
* Modification Log:
* -----------------
* ver0.0 28/Aug/98 M.Tobiyama
*/
#include <vxWorks.h>
#include <types.h>
#include <stdioLib.h>
#include <string.h>
#include <iv.h>
#include <vme.h>
#include <dbDefs.h>
#include <dbAccess.h>
#include <recSup.h>
#include <devSup.h>
#include <devCamac.h>
#include <link.h>
#include <module_types.h>
#include <fast_lock.h>
#include <longinRecord.h>
#include <longoutRecord.h>
#include <boRecord.h>
#include <biRecord.h>
#include <mbbiDirectRecord.h>
#include <mbboDirectRecord.h>
#include <waveformRecord.h>
/* #include <callback.h> */
#include <dbScan.h>
/* #define Base_IO 0x20000 */ /* Std. I/O Address */
#define TG_EXT_GO 0x81
#define TG_EXT_NO 0x80
#define TG_INT_NO 0x00
#define SINGLE 0x00
#define DIFFER 0x01
#define B10_16 0x00
#define B05_16 0x01
#define U10_16 0x04
#define U05_16 0x05
#define FIFORESET 0x04
#define INT_TIMER 0xffff
struct DPvme332 {
unsigned char dummy0;
unsigned char trg_cntrl_reg;
unsigned char dummy1;
unsigned char trg_strt_reg;
unsigned char dummy2;
unsigned char sts_reg;
unsigned char dummy3;
unsigned char scn_cnt_reg;
unsigned char dummy4;
unsigned char mode_reg;
unsigned char dummy5;
unsigned char ana_con_reg;
unsigned char dummy6;
unsigned char rst_reg;
unsigned char dummy7;
unsigned char int_cntrl_reg;
unsigned char dummy8;
unsigned char int_vct_reg;
unsigned char dummy9;
unsigned char int_sts_reg;
unsigned short intvl_tm_reg;
unsigned short data_reg;
unsigned short dummys[116];
};
#define Status Enable
int devPvme332Config();
static long init_all();
static long init_wf_record();
static long init_mi_record();
static long init_bo_record();
static long read_wf_record();
static long get_wf_int_info();
static long read_mbbiDirect();
static long write_bo_record();
static void pvme332_isr();
static int checkLink();
struct {
long number;
DEVSUPFUN report;
DEVSUPFUN init;
DEVSUPFUN init_record;
DEVSUPFUN get_ioint_info;
DEVSUPFUN read_write;
DEVSUPFUN conv;
}devWfPvme332 ={
6,
NULL,
NULL,
init_wf_record,
get_wf_int_info,
read_wf_record,
NULL
};
/* Create the dset for devBoPvme332 */
struct {
long number;
DEVSUPFUN report;
DEVSUPFUN init;
DEVSUPFUN init_record;
DEVSUPFUN get_ioint_info;
DEVSUPFUN write_bo;
}devBoPvme332={
5,
NULL,
NULL,
init_bo_record,
NULL,
write_bo_record
};
/* For devMbbiPvme332 */
struct{
long number;
DEVSUPFUN report;
DEVSUPFUN init;
DEVSUPFUN init_mi_record;
DEVSUPFUN get_ioint_info;
DEVSUPFUN read_mbbiDirect;
}devMbbiPvme332={
5,
NULL,
NULL,
init_mi_record,
NULL,
read_mbbiDirect};
struct ioCard {
volatile struct DPvme332 *card; /* address of this card */
FAST_LOCK lock; /* semaphore */
IOSCANPVT ioscanpvt;/* list or records processed upon interrupt */
};
#define CONST_NUM_LINKS 10
/* #define STATIC */
#define DEBUG_ON
static int debug_flag = 1;
static unsigned long Base_IO;
static int pvme332_num_links, pvme_adc;
static unsigned short INT_VEC_BASE;
static struct ioCard cards_332[CONST_NUM_LINKS];
static int init_flag = 0;
static unsigned char int_level;
static unsigned char tg_mode;
int devPvme332Config(ncards,a24base,irq,intvecbase,Nchannel)
int ncards;
long a24base;
int irq;
int intvecbase;
int Nchannel;
{
pvme332_num_links = ncards;
Base_IO = a24base;
int_level = irq;
INT_VEC_BASE = intvecbase;
pvme_adc = Nchannel;
logMsg("Pvme332 NumLink= %d BaseIO= %x INTVECBASE= %x ADC= %d Ch\n",pvme332_num_links,Base_IO,INT_VEC_BASE,pvme_adc);
init_all(0);
}
static long init_all(after)
int after;
{
short cardNum, chanNum;
int i,j;
unsigned char probeVal;
unsigned short p1;
volatile struct DPvme332 *p;
char temp;
if (init_flag != 0 )
return(OK);
init_flag = 1;
if (sysBusToLocalAdrs(VME_AM_STD_SUP_DATA,(char *)Base_IO,(char **)&p) == ERROR)
{
logMsg("VmeP332: cannot find A24 address space\n");
return(ERROR);
}
for (cardNum=0; cardNum< pvme332_num_links; cardNum++)
{
tg_mode = 0x81; /*external trigger enable afterwards*/
probeVal = TG_INT_NO; /* INT trigger -- trigger disable */
if (vxMemProbe((char*) &(p->trg_cntrl_reg), WRITE, 1, &probeVal)!=OK)
{
if (debug_flag >0 )
logMsg("No PVME332 with cardNum= %d\n probe= %x\n",cardNum,p);
cards_332[cardNum].card = NULL;
}
else
{
probeVal=0x06; /* adc calib */
if ((vxMemProbe((char*) &(p->rst_reg), WRITE,1,&probeVal)==OK)&&(debug_flag >5))
logMsg("ADC calibration for card %d\n",cardNum);
nanosleep(4000000);
probeVal=SINGLE; /* single ended input */
if ((vxMemProbe((char*) &(p->mode_reg), WRITE,1,&probeVal)==OK)&&(debug_flag >5))
logMsg("Mode for cardNum = %d Single\n",cardNum);
probeVal=B10_16; /* 16 bit +-10V */
if ((vxMemProbe((char*) &(p->ana_con_reg), WRITE,1,&probeVal)==OK)&&(debug_flag >5))
logMsg("Analog input for cardNum = %d BIP10\n",cardNum);
probeVal= pvme_adc - 1;
if ((vxMemProbe((char*) &(p->scn_cnt_reg), WRITE,1,&probeVal)==OK)&&(debug_flag >5))
logMsg("Scan count for cardNum = %d is %d\n",cardNum,pvme_adc);
probeVal=0x00 & (unsigned char)(int_level);/* Int disable */
if ((vxMemProbe((char*) &(p->int_cntrl_reg), WRITE,1,&probeVal)==OK)&&(debug_flag >5))
logMsg("Int number %d = %x\n",cardNum,int_level);
probeVal = INT_VEC_BASE+cardNum;
if ((vxMemProbe((char*) &(p->int_vct_reg), WRITE,1,&probeVal)==OK)&&(debug_flag >5))
logMsg("Int vector %x = %x\n",cardNum,probeVal);
/* p->int_sts_reg = 0x01; */
if (debug_flag >0)
logMsg("Found PVME332 with cardNum= %d address= %x\n",cardNum,p);
cards_332[cardNum].card = p; /* Remember address of the board */
scanIoInit(&(cards_332[cardNum].ioscanpvt));
/* if (intConnect(INUM_TO_IVEC(INT_VEC_BASE + cardNum),(VOIDFUNCPTR)pvme332_isr, (int)&cards[cardNum]) != OK)
logMsg("devPVME332: Interrupt connect failed for card %d\n",cardNum);
logMsg("intConnect 0x%X\n",&cards[cardNum]);
*/
cards_332[cardNum].card->int_cntrl_reg = (0x10) | (unsigned char)(int_level);
FASTLOCKINIT(&(cards_332[cardNum].lock));
FASTUNLOCK(&(cards_332[cardNum].lock)); /* Init the board lock */
}
p++;
}
return(OK);
}
/******************************************************************
*
* Interrupt service routine
*
*******************************************************************/
/*
static long pvme332_isr(struct ioCard *pc)
{
volatile struct DPvme332 *p = pc->card;
unsigned char mode;
logMsg("pvme332 int called \n");
mode=p->int_sts_reg;
logMsg("pvme332 interrupt handler is called. 0x%X\n",pc->ioscanpvt);
scanIoRequest(pc->ioscanpvt);
logMsg("pvme332 interrupt called\n");
}
*/
static void pvme332_isr(pwf)
struct waveformRecord *pwf;
{
unsigned char mode;
short cardN;
cardN = pwf->inp.value.vmeio.card;
/* logMsg("pvme332_isr int called \n");*/
mode = cards_332[cardN].card->int_sts_reg;
scanIoRequest(cards_332[cardN].ioscanpvt);
/* logMsg("pvme332 int called \n");*/
return;
}
/**************************************************************************
*
* BO Initialization (Called one time for each BO PowerUT card record)
*
**************************************************************************/
static long init_bo_record(pbo)
struct boRecord *pbo;
{
pbo->mask = 1;
return(0);
}
/**************************************************************************
*
* Perform a write operation from a BO record
*
**************************************************************************/
static long write_bo_record(pbo)
struct boRecord *pbo;
{
short cardN;
cardN = pbo->out.value.vmeio.card;
if (checkLink(cardN) == ERROR)
{
logMsg("Error--- No PVME332 for card %d\n",cardN);
return(ERROR);
}
FASTLOCK(&(cards_332[cardN].lock));
switch(pbo->out.value.vmeio.signal){
case 0:
cards_332[cardN].card->trg_strt_reg = 0x01; /* trigger start */
break;
case 1:
if ((pbo->rval) & 0x01)
{
tg_mode = 0x01;
cards_332[cardN].card->trg_cntrl_reg = 0x01;
}
else
{
tg_mode = 0x81;
cards_332[cardN].card->trg_cntrl_reg = 0x81;
}
break;
case 2:
cards_332[cardN].card->rst_reg = ((pbo->rval))<<1 & 0x02; /* ADC calib */
nanosleep(1400000);
break;
}
FASTUNLOCK(&(cards_332[cardN].lock));
return(0);
}
static long init_mi_record(pmbbi)
struct MbbiDirectRecord *pmbbi;
{
return(0);
}
static long read_mbbiDirect(pmbbi)
struct mbbiDirectRecord *pmbbi;
{
short cardN;
cardN = pmbbi->inp.value.vmeio.card;
if (debug_flag >5)
logMsg("read_mbbiDirect called with card %d\n",cardN);
if (checkLink(cardN) == ERROR)
return(ERROR);
switch(pmbbi->inp.value.vmeio.signal){
case 0:
pmbbi->rval = (unsigned char)(cards_332[cardN].card->sts_reg);
break;
case 1:
pmbbi->rval = cards_332[cardN].card->trg_cntrl_reg;
break;
case 2:
pmbbi->rval = cards_332[cardN].card->scn_cnt_reg;
break;
case 3:
pmbbi->rval = cards_332[cardN].card->mode_reg;
break;
case 4:
pmbbi->rval = cards_332[cardN].card->ana_con_reg;
break;
case 5:
pmbbi->rval = cards_332[cardN].card->int_cntrl_reg;
break;
case 6:
pmbbi->rval = cards_332[cardN].card->int_vct_reg;
break;
case 7:
pmbbi->rval = cards_332[cardN].card->int_sts_reg;
break;
case 8:
pmbbi->rval = cards_332[cardN].card->intvl_tm_reg;
break;
default:
return(-1);
}
if (debug_flag >5)
logMsg("read complete \n");
return(CONVERT);
}
static long init_wf_record(pwf)
struct waveformRecord *pwf;
{
short cardNum;
cardNum = pwf->inp.value.vmeio.card;
if (intConnect(INUM_TO_IVEC(INT_VEC_BASE + cardNum),
(VOIDFUNCPTR)pvme332_isr,
(int)pwf) != OK)
logMsg("devPVME332: Interrupt connect failed for card %d\n",pwf->inp.value.vmeio.card);
logMsg("intConnect 0x%X\n",pwf);
sysIntEnable(int_level);
logMsg("pvme332 int set for int 0x%x\n",int_level);
cards_332[cardNum].card->trg_cntrl_reg = 0x81;
return(0);
}
static long read_wf_record(pwf)
struct waveformRecord *pwf;
{
short cardN;
int i;
unsigned short samples;
unsigned short* us_thing = (unsigned short*)pwf->bptr;
short* s_thing = (short*)pwf->bptr;
if (debug_flag >5)
logMsg("read_wf_record called...\n");
cardN = pwf->inp.value.vmeio.card;
if (debug_flag >5)
logMsg("read_wf_record called with card number of %d\n",cardN);
if (checkLink(cardN) == ERROR)
return(ERROR);
cards_332[cardN].card->trg_cntrl_reg = 0x80 ; /* disable trigger */
switch(pwf->ftvl)
{
case DBF_USHORT:
/* unsigned short* us_thing = (unsigned short*)pwf->bptr; */
for (i=0; i<pwf->nelm;i++)
{
samples=cards_332[cardN].card->data_reg;
us_thing[i]=(unsigned short)(samples);
}
pwf->nord=i;
cards_332[cardN].card->trg_cntrl_reg = tg_mode | 0x01;
break;
case DBF_SHORT:
/* short* s_thing = (short*)pwf->bptr; */
/* logMsg("short called \n"); */
for (i=0; i<pwf->nelm;i++)
{
samples=cards_332[cardN].card->data_reg;
s_thing[i]=(short)(samples-32767);
/* logMsg("FIFO status = %x\n",cards_332[cardN].card->sts_reg);*/
}
pwf->nord=i;
cards_332[cardN].card->trg_cntrl_reg = tg_mode |0x01;
break;
default:
logMsg("devPVME332: Invalid data type\n");
}
cards_332[cardN].card->rst_reg = 0x04;
cards_332[cardN].card->trg_cntrl_reg = (unsigned char)((tg_mode)|( 0x01));
return(0);
}
#define ADDING 0
#define DELETING 1
static long get_wf_int_info(cmd,pwf,ppvt)
int cmd;
struct waveformRecord *pwf;
IOSCANPVT *ppvt;
{
short cardN;
unsigned char stat;
cardN = pwf->inp.value.vmeio.card;
/*logMsg("pvme332 intInfo. 0x%X\n",*ppvt); */
/* if (cmd == ADDING)
{
sysIntEnable(int_level);
logMsg("pvme332 int set for int 0x%x\n",int_level);
}
*/
*ppvt = cards_332[cardN].ioscanpvt;
/* logMsg("pvme332 intInfo. 0x%X\n",*ppvt); */
/* cards_332[cardN].card->int_cntrl_reg = (0x10) | (unsigned char)(int_level);*/
cards_332[cardN].card->trg_cntrl_reg = (unsigned char)((tg_mode)|(0x01));
if (debug_flag >5) logMsg("wf_INT CALLED\n");
return(0);
}
/**************************************************************************
*
* Make sure card number is valid
*
**************************************************************************/
static int checkLink(cardN)
short cardN;
{
if (cardN >= pvme332_num_links)
return(ERROR);
if (cards_332[cardN].card == NULL)
{
logMsg("No PVME332 with this number = %d\n",cardN);
return(ERROR);
}
if (debug_flag >10)
logMsg("Yes you have PVME332 with card No= %d\n",cardN);
return(OK);
}