/* devPVME331.c */
/* devPVME331.c - Device Support Routines for VME PVME-331 */
/* 16 bit low cost A/D board (16ch) */
/*
* Original Author: M. Tobiyama
* Current Author: M. Tobiyama
* Date:
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1997, KEKB.
*
*
* Modification Log:
* -----------------
* ver0.0 19/Aug/98 M.Tobiyama
* ver0.1 7/Sep/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 <dbScan.h>
/* #define Base_IO 0x20000 */ /* Std. I/O Address */
#define UNI10 0x30
#define UNI05 0x20
#define BIP10 0x40
#define BIP05 0x10
#define EXTRIG 0x81
#define SINGLE 0x00
#define DIFFER 0x01
#define FIFORESET 0x04
#define INTTIMER 0xffff
#define INT_LEVEL 0x05
struct DPvme331 {
unsigned char dummy0;
unsigned char scan_file0;
unsigned char dummy1;
unsigned char scan_file1;
unsigned char dummy2;
unsigned char scan_file2;
unsigned char dummy3;
unsigned char scan_file3;
unsigned char dummy4;
unsigned char scan_file4;
unsigned char dummy5;
unsigned char scan_file5;
unsigned char dummy6;
unsigned char scan_file6;
unsigned char dummy7;
unsigned char scan_file7;
unsigned char dummy8;
unsigned char scan_file8;
unsigned char dummy9;
unsigned char scan_file9;
unsigned char dummy10;
unsigned char scan_file10;
unsigned char dummy11;
unsigned char scan_file11;
unsigned char dummy12;
unsigned char scan_file12;
unsigned char dummy13;
unsigned char scan_file13;
unsigned char dummy14;
unsigned char scan_file14;
unsigned char dummy15;
unsigned char scan_file15;
unsigned char dummy16;
unsigned char trg_cntrl_reg;
unsigned char dummy17;
unsigned char trg_strt_reg;
unsigned char dummy18;
unsigned char sts_reg;
unsigned char dummy19;
unsigned char scn_cnt_reg;
unsigned char dummy20;
unsigned char mode_reg;
unsigned char dummy21;
unsigned char rst_reg;
unsigned char dummy22;
unsigned char int_cntrl_reg;
unsigned char dummy23;
unsigned char int_vct_reg;
unsigned char dummy24;
unsigned char int_sts_reg;
unsigned short dummy25;
unsigned short intvl_tm_reg;
unsigned short data_reg;
unsigned short dummys[100];
};
#define Status Enable
int devPvme331Config();
static long init_all();
static long init_wf_record();
static long init_bi_record();
static long init_bo_record();
static long read_wf_record();
static long get_wf_int_info();
static long read_bi_record();
static long write_bo_record();
static void pvme331_isr();
static int checkLink();
struct {
long number;
DEVSUPFUN report;
DEVSUPFUN init;
DEVSUPFUN init_record;
DEVSUPFUN get_ioint_info;
DEVSUPFUN read_write;
DEVSUPFUN conv;
}devWfPvme331 ={
6,
NULL,
NULL,
init_wf_record,
get_wf_int_info,
read_wf_record,
NULL
};
/* Create the dset for devBiPvme331 */
struct {
long number;
DEVSUPFUN report; /* used by dbior */
DEVSUPFUN init; /* called 1 time before & after all reco
rds */
DEVSUPFUN init_record; /* called 1 time for each record */
DEVSUPFUN get_ioint_info; /* used for COS processing */
DEVSUPFUN read_bi; /* input command goes here */
}devBiPvme331={
5,
NULL,
NULL,
init_bi_record,
NULL,
read_bi_record
};
/* Create the dset for devBoPvme331 */
struct {
long number;
DEVSUPFUN report; /* used by dbior */
DEVSUPFUN init; /* called 1 time before & after all reco
rds */
DEVSUPFUN init_record; /* called 1 time for each record */
DEVSUPFUN get_ioint_info; /* used for COS processing (not used for
outputs)*/
DEVSUPFUN write_bo; /* output command goes here */
}devBoPvme331={
5,
NULL,
NULL,
init_bo_record,
NULL,
write_bo_record
};
struct ioCard {
volatile struct DPvme331 *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 pvme331_num_links, pvme_adc;
static unsigned short INT_VEC_BASE;
static struct ioCard cards[CONST_NUM_LINKS];
static int init_flag = 0;
static int int_level;
static unsigned char tg_mode = 0x80, tg_enable=0x01;
int devPvme331Config(ncards,a24base,intvecbase,Nchannel)
int ncards;
long a24base;
int intvecbase;
int Nchannel;
{
pvme331_num_links = ncards;
Base_IO = a24base;
INT_VEC_BASE = intvecbase;
pvme_adc = Nchannel;
logMsg("Pvme331 NumLink= %d BaseIO= %x INTVECBASE= %x ADC= %d Ch\n",pvme331_num_links,Base_IO,INT_VEC_BASE,pvme_adc);
init_all(0);
}
static long init_all(after)
int after;
{
int cardNum, chanNum;
int i,j;
unsigned char probeVal;
unsigned short p1;
volatile struct DPvme331 *p;
if (init_flag != 0 )
return(OK);
init_flag = 1;
if (sysBusToLocalAdrs(VME_AM_STD_SUP_DATA,(char *)Base_IO,(char **)&p) == ERROR)
{
logMsg("VmeP331: cannot find A24 address space\n");
return(ERROR);
}
for (cardNum=0; cardNum< pvme331_num_links; cardNum++)
{
if (vxMemProbe((char*) &(p->rst_reg), READ, 1, &probeVal)!=OK)
{
if (debug_flag >0 )
logMsg("No PVME331 with cardNum= %d\n probe= %x\n",cardNum,p);
cards[cardNum].card = NULL;
}
else
{
probeVal=0x0f;
if ((vxMemProbe((char*) &(p->rst_reg), WRITE,1,&probeVal)==OK)&&(debug_flag >5))
logMsg("System Reset for card %d\n",cardNum);
nanosleep(4000000);
probeVal=BIP10 | 0x00;
if ((vxMemProbe((char*) &(p->scan_file0), WRITE,1,&probeVal)==OK)&&(debug_flag >5))
logMsg("Scan file 0 set %d\n",cardNum);
probeVal=BIP10 | 0x01;
if ((vxMemProbe((char*) &(p->scan_file1), WRITE,1,&probeVal)==OK)&&(debug_flag >5))
logMsg("Scan file 1 set %d\n",cardNum);
probeVal=BIP10 | 0x02;
if ((vxMemProbe((char*) &(p->scan_file2), WRITE,1,&probeVal)==OK)&&(debug_flag >5))
logMsg("Scan file 2 set %d\n",cardNum);
probeVal=BIP10 | 0x03;
if ((vxMemProbe((char*) &(p->scan_file3), WRITE,1,&probeVal)==OK)&&(debug_flag >5))
logMsg("Scan file 3 set %d\n",cardNum);
probeVal=BIP10 | 0x04;
if ((vxMemProbe((char*) &(p->scan_file4), WRITE,1,&probeVal)==OK)&&(debug_flag >5))
logMsg("Scan file 4 set %d\n",cardNum);
probeVal=BIP10 | 0x05;
if ((vxMemProbe((char*) &(p->scan_file5), WRITE,1,&probeVal)==OK)&&(debug_flag >5))
logMsg("Scan file 5 set %d\n",cardNum);
probeVal=BIP10 | 0x06;
if ((vxMemProbe((char*) &(p->scan_file6), WRITE,1,&probeVal)==OK)&&(debug_flag >5))
logMsg("Scan file 6 set %d\n",cardNum);
probeVal=BIP10 | 0x07;
if ((vxMemProbe((char*) &(p->scan_file7), WRITE,1,&probeVal)==OK)&&(debug_flag >5))
logMsg("Scan file 7 set %d\n",cardNum);
probeVal=BIP10 | 0x08;
if ((vxMemProbe((char*) &(p->scan_file8), WRITE,1,&probeVal)==OK)&&(debug_flag >5))
logMsg("Scan file 8 set %d\n",cardNum);
probeVal=BIP10 | 0x09;
if ((vxMemProbe((char*) &(p->scan_file9), WRITE,1,&probeVal)==OK)&&(debug_flag >5))
logMsg("Scan file 9 set %d\n",cardNum);
probeVal=BIP10 | 0x0A;
if ((vxMemProbe((char*) &(p->scan_file10), WRITE,1,&probeVal)==OK)&&(debug_flag >5))
logMsg("Scan file 10 set %d\n",cardNum);
probeVal=BIP10 | 0x0B;
if ((vxMemProbe((char*) &(p->scan_file11), WRITE,1,&probeVal)==OK)&&(debug_flag >5))
logMsg("Scan file 11 set %d\n",cardNum);
probeVal=BIP10 | 0x0C;
if ((vxMemProbe((char*) &(p->scan_file12), WRITE,1,&probeVal)==OK)&&(debug_flag >5))
logMsg("Scan file 12 set %d\n",cardNum);
probeVal=BIP10 | 0x0D;
if ((vxMemProbe((char*) &(p->scan_file13), WRITE,1,&probeVal)==OK)&&(debug_flag >5))
logMsg("Scan file 13 set %d\n",cardNum);
probeVal=BIP10 | 0x0E;
if ((vxMemProbe((char*) &(p->scan_file14), WRITE,1,&probeVal)==OK)&&(debug_flag >5))
logMsg("Scan file 14 set %d\n",cardNum);
probeVal=BIP10 | 0x0F;
if ((vxMemProbe((char*) &(p->scan_file15), WRITE,1,&probeVal)==OK)&&(debug_flag >5))
logMsg("Scan file 15 set %d\n",cardNum);
probeVal=pvme_adc-1;
if ((vxMemProbe((char*) &(p->scn_cnt_reg), WRITE,1,&probeVal)==OK)&&(debug_flag >5))
logMsg("Number of ADC channel for %d = %d\n",cardNum,probeVal);
probeVal=0x00;
if ((vxMemProbe((char*) &(p->mode_reg), WRITE,1,&probeVal)==OK)&&(debug_flag >5))
logMsg("ADC mode for %d = Single\n",cardNum);
/* probeVal=FIFORESET;
if ((vxMemProbe((char*) &(p->rst_reg), WRITE,1,&probeVal)==OK)&&(debug_flag >5))
logMsg("FIFO counter reset for card %d\n",cardNum);
*/
p->intvl_tm_reg = INTTIMER;
probeVal=INT_VEC_BASE + cardNum;
if ((vxMemProbe((char*) &(p->int_vct_reg), WRITE,1,&probeVal)==OK)&&(debug_flag >5))
logMsg("Int vec base for card %d = %x\n",cardNum,probeVal);
probeVal=0x08 | INT_LEVEL;/* Int enable , IRQ=3 */
int_level = INT_LEVEL;
if ((vxMemProbe((char*) &(p->int_cntrl_reg), WRITE,1,&probeVal)==OK)&&(debug_flag >5))
logMsg("Int number %d = %x\n",cardNum,int_level);
if (debug_flag >0)
logMsg("Found PVME331 with cardNum= %d address= %x\n",cardNum,p);
cards[cardNum].card = p; /* Remember address of the board */
scanIoInit(&cards[cardNum].ioscanpvt);
logMsg("pvme331 ioInit. 0x%X\n",cards[cardNum].ioscanpvt);
FASTLOCKINIT(&(cards[cardNum].lock));
FASTUNLOCK(&(cards[cardNum].lock)); /* Init the board lock */
}
p++;
}
return(OK);
}
/******************************************************************
*
* Interrupt service routine
*
*******************************************************************/
static void pvme331_isr(pwf)
struct waveformRecord *pwf;
{
unsigned char mode;
short cardN;
cardN = pwf->inp.value.vmeio.card;
/* logMsg("pvme331_isr int called \n");*/
mode = cards[cardN].card->int_sts_reg;
scanIoRequest(cards[cardN].ioscanpvt);
/* logMsg("pvme331 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;
unsigned char tgreg;
cardN = pbo->out.value.vmeio.card;
if (checkLink(cardN) == ERROR)
{
logMsg("Error--- No PVME331 for card %d\n",cardN);
return(ERROR);
}
FASTLOCK(&(cards[cardN].lock));
switch(pbo->out.value.vmeio.signal){
case 0:
cards[cardN].card->trg_strt_reg = 0x01;
break;
case 1:
if (((pbo->rval)&(pbo->mask)) == 0x01)
tg_mode = 0x00;
else
tg_mode = 0x80;
cards[cardN].card->trg_cntrl_reg = (tg_mode) | (tg_enable);
break;
case 2:
if (((pbo->rval)&(pbo->mask)) == 0x01)
tg_enable = 0x00;
else
tg_enable = 0x01;
cards[cardN].card->trg_cntrl_reg =(tg_mode) |(tg_enable);
break;
case 3:
cards[cardN].card->rst_reg = ((pbo->rval))<<1 & 0x02; /* ADC calib */
nanosleep(4000000);
break;
}
FASTUNLOCK(&(cards[cardN].lock));
return(0);
}
/**************************************************************************
*
* BI Initialization (Called one time for each BI PowerUT card record)
*
**************************************************************************/
static long
init_bi_record(pbi)
struct biRecord *pbi;
{
pbi->mask = 1;
return(0);
}
/**************************************************************************
*
* Perform a read operation from a BI record
*
**************************************************************************/
static long
read_bi_record(pbi)
struct biRecord *pbi;
{
short cardN;
cardN = pbi->inp.value.vmeio.card;
if (checkLink(cardN) == ERROR)
return(ERROR);
pbi->rval = cards[cardN].card->sts_reg & pbi->mask;
if (debug_flag >0)
logMsg("read_bi signal 0 status %d\n",pbi->rval);
return(0);
}
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)pvme331_isr,
(int)pwf) != OK)
logMsg("devPVME331: Interrupt connect failed for card %d\n",pwf->inp.value.vmeio.card);
logMsg("intConnect 0x%X\n",pwf);
sysIntEnable(int_level);
logMsg("pvme331 int set for int 0x%x\n",int_level);
/* cards[cardNum].card->trg_cntrl_reg = 0x81;*/
tg_mode = 0x80;
tg_enable = 0x01;
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[cardN].card->trg_cntrl_reg = 0x80;
switch(pwf->ftvl)
{
case DBF_USHORT:
/* unsigned short* us_thing = (unsigned short*)pwf->bptr; */
for (i=0; i<pwf->nelm;i++)
{
samples=cards[cardN].card->data_reg;
us_thing[i]=(unsigned short)(samples);
}
pwf->nord=i;
cards[cardN].card->trg_cntrl_reg = (tg_mode | tg_enable);
break;
case DBF_SHORT:
/* short* s_thing = (short*)pwf->bptr; */
for (i=0; i<pwf->nelm;i++)
{
samples=cards[cardN].card->data_reg;
s_thing[i]=(short)(samples);
}
pwf->nord=i;
cards[cardN].card->trg_cntrl_reg = (tg_mode|tg_enable);
break;
default:
logMsg("devPVME331: Invalid data type\n");
}
cards[cardN].card->rst_reg=0x04;
cards[cardN].card->trg_cntrl_reg = (tg_mode|tg_enable);
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;
cardN = pwf->inp.value.vmeio.card;
*ppvt = cards[cardN].ioscanpvt;
logMsg("pvme331 intInfo. 0x%X\n",*ppvt);
cards[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 >= pvme331_num_links)
return(ERROR);
if (cards[cardN].card == NULL)
{
logMsg("No PVME331 with this number = %d\n",cardN);
return(ERROR);
}
if (debug_flag >10)
logMsg("Yes you have PVME331 with card No= %d\n",cardN);
return(OK);
}