/* devVme18k11.c */
/* devVme18k11.c - Device Support Routines for VME adc board */
/*
*
* Original Author: Makoto Tobiyama
* Current Author:
* Date: 29/Jun/2010
* Modified for MVME5500 11/Jun/2011
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1997, KEKB.
*
*
* Modification Log:
* -----------------
*/
#include <vxWorks.h>
#include <types.h>
#include <stdioLib.h>
#include <string.h>
/* #include <sys/time.h> */
#include <vme.h>
#include <dbDefs.h>
#include <dbAccess.h>
#include <recSup.h>
#include <devSup.h>
#include <link.h>
#include <iv.h>
#include <module_types.h>
#include <longinRecord.h>
#include <longoutRecord.h>
#include <boRecord.h>
#include <biRecord.h>
#include <mbbiDirectRecord.h>
#include <mbboDirectRecord.h>
#include <waveformRecord.h>
#include <stringoutRecord.h>
#include <dbScan.h>
#include <epicsMutex.h>
#include <epicsExport.h>
#if 1
#include </space/wind221/target/config/mv5500/sysDma.h>
#include </space/wind221/target/config/mv5500/universe.h>
#include <vxLib.h>
#include <time.h>
#endif
void dmaCallBackCh0( void );
void dmaCallBackCh1( void );
struct D18k11 {
unsigned long call[524288];
unsigned long ad_start;
unsigned long ad_memory;
unsigned long trg_pos;
unsigned long irq_enb;
unsigned long reserve_io;
unsigned long ad_status;
unsigned long irq_no;
unsigned long irq_id;
unsigned long dum1[262136];
unsigned long trigger;
unsigned long dummy[262143];
};
#defineStatusEnable
static long init_all();
static long init_mi_record();
static long get_mbbi_int_info();
static long init_bo_record();
static long write_bo();
static long read_mbbiDirect();
static long init_wf_record();
static long read_wf_record();
static long init_lo_record();
static long write_longout();
static long init_li_record();
static long read_longin();
static void vme18k11_isr();
static int checkLink();
/* Create the dset for devBo18k11 */
struct {
long number;
DEVSUPFUN report;
DEVSUPFUN init;
DEVSUPFUN init_record;
DEVSUPFUN get_ioint_info;
DEVSUPFUN write_bo;
}devBo18k11={
5,
NULL,
NULL,
init_bo_record,
NULL,
write_bo
};
epicsExportAddress(dset,devBo18k11);
/* For devMbbi18k11 */
struct{
long number;
DEVSUPFUN report;
DEVSUPFUN init;
DEVSUPFUN init_mi_record;
DEVSUPFUN get_ioint_info;
DEVSUPFUN read_mbbiDirect;
}devMbbi18k11={
5,
NULL,
NULL,
init_mi_record,
get_mbbi_int_info,
read_mbbiDirect
};
epicsExportAddress(dset,devMbbi18k11);
struct {
long number;
DEVSUPFUN report;
DEVSUPFUN init;
DEVSUPFUN init_record;
DEVSUPFUN get_ioint_info;
DEVSUPFUN read_write;
DEVSUPFUN conv;
}devWf18k11 ={
6,
NULL,
NULL,
init_wf_record,
NULL,
read_wf_record,
NULL
};
epicsExportAddress(dset,devWf18k11);
struct {
long number;
DEVSUPFUN report;
DEVSUPFUN init;
DEVSUPFUN init_record;
DEVSUPFUN get_ioint_info;
DEVSUPFUN write_longout;
DEVSUPFUN special_linconv;
}devLo18k11={
6,
NULL,
NULL,
NULL,
NULL,
write_longout,
NULL
};
epicsExportAddress(dset,devLo18k11);
struct {
long number;
DEVSUPFUN report;
DEVSUPFUN init;
DEVSUPFUN init_record;
DEVSUPFUN get_ioint_info;
DEVSUPFUN read_longin;
DEVSUPFUN special_linconv;
}devLi18k11={
6,
NULL,
NULL,
init_li_record,
NULL,
read_longin,
NULL};
epicsExportAddress(dset,devLi18k11);
struct ioCard {
volatile struct D18k11 *card; /* address of this card */
epicsMutexId lock; /* semaphore */
IOSCANPVT ioscanpvt;
};
#define CONST_NUM_LINKS 10
/* #define STATIC */
#define DEBUG_ON
static int debug_flag = 0;
static unsigned long Base_IO;
static int D18k11_num_links;
static struct ioCard cards[CONST_NUM_LINKS];
static int init_flag = 0;
static unsigned short INT_VEC_BASE;
static unsigned char int_level;
#if 1
static unsigned long *gplTmpData; /* 256K Word * 4ch(256*1024*2*4/4) */
#endif
int dev18k11Config(ncards,a32base,irq,intvecbase)
int ncards;
long a32base;
int irq;
int intvecbase;
{
D18k11_num_links = ncards;
Base_IO = a32base;
int_level= irq;
INT_VEC_BASE=intvecbase;
logMsg("dev18k11 NumLink= %d BaseIO= %x IRQ = %d INTVECBASE =%x\n",D18k11_num_links,Base_IO,int_level,INT_VEC_BASE,0,0);
init_all(0);
}
static long init_all(after)
int after;
{
int cardNum, chanNum;
unsigned char probeVal[4];
volatile struct D18k11 *p;
unsigned short mem_pat;
if (init_flag != 0 )
return(OK);
init_flag = 1;
#if 1
if ( sysVmeDmaInit() != OK ) {
logMsg("sysVmeDmaInit() Error!!\n",0,0,0,0,0,0);
return(ERROR);
}
logMsg("sysVmeDmaInit() OK!!\n",0,0,0,0,0,0);
#endif
if (sysBusToLocalAdrs(VME_AM_EXT_SUP_DATA,(char *)Base_IO,(char **)&p) == ERROR)
{
logMsg("18k11: cannot find extended address space\n",0,0,0,0,0,0);
return(ERROR);
}
for (cardNum=0; cardNum< D18k11_num_links; cardNum++) {
if (vxMemProbe((char*) &(p->ad_status), READ, 4, &probeVal[0])!= OK)
{
if (debug_flag >0 )
logMsg("No 18k11 with cardNum= %d\n probe= %x\n",cardNum,p,0,0,0,0);
cards[cardNum].card = NULL;
} else
{
if (debug_flag >0)
logMsg("Found 18k11 with cardNum= %d\n address= %x\n",cardNum,p,0,0,0,0);
cards[cardNum].card = p; /* Remember address of the board */
scanIoInit(&(cards[cardNum].ioscanpvt));
} p->irq_enb = 0x00;
cards[cardNum].lock = epicsMutexMustCreate();
epicsMutexUnlock((cards[cardNum].lock)); /* Init the board lock */
p++;
}
gplTmpData = memalign( 256, 524288*4 ); /* 256K Word x 4ch */
if (sysVmeDmaCnfgSet(DCTL_VDW_64 | DCTL_VCT_BLK,
DCTL_VAS_A32,
DCTL_PGM_DATA,
DCTL_SUPER_SUP) != OK){
logMsg("devVme18k11 error DMA setting\n",0,0,0,0,0,0);}
return(OK);
}
/******************************************************************
*
* Interrupt service routine
*
*******************************************************************/
static void vme18k11_isr(pmbbi)
struct mbbiDirectRecord*pmbbi;
{ unsigned char mode;
short cardN;
unsigned long ad;
unsigned char intreg;
cardN = pmbbi->inp.value.vmeio.card;
ad = (cards[cardN].card->ad_status) & 0xff;
scanIoRequest(cards[cardN].ioscanpvt);
/* logMsg("18k11 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(pbo)
struct boRecord *pbo;
{
short cardN;
cardN = pbo->out.value.vmeio.card;
if (checkLink(cardN) == ERROR)
{
logMsg("Error--- No 18k11 for card %d\n",cardN,0,0,0,0,0);
return(ERROR);
}
if (debug_flag>5) logMsg("BO\n",0,0,0,0,0,0);
epicsMutexMustLock((cards[cardN].lock));
/* ADC start */
cards[cardN].card->ad_start = 0x1;
epicsMutexUnlock((cards[cardN].lock));
return(0);
}
static long init_lo_record(plongout)
struct longoutRecord *plongout;
{
return(0);
}
static long write_longout(plongout)
struct longoutRecord *plongout;
{
short cardN;
cardN = plongout->out.value.vmeio.card;
if (debug_flag >10)
logMsg("write_lo called with card %d\n",cardN,0,0,0,0,0);
if (checkLink(cardN) == ERROR)
return(ERROR);
epicsMutexMustLock((cards[cardN].lock));
switch(plongout->out.value.vmeio.signal){
case 0 : /* adc_memory_size */
cards[cardN].card->ad_memory = 0x3 & (plongout->val);
break;
case 1 : /* trigger position */ cards[cardN].card->trg_pos = 0x7 & (plongout ->val);
break;
case 2 : /* interrupt enable */
cards[cardN].card->irq_enb = 0x3 & (plongout -> val);
break;
default: break; }
epicsMutexUnlock((cards[cardN].lock));
return(OK);
}
static long init_li_record(plongin)
struct longinRecord *plongin;
{
return(0);
}
static long read_longin(plongin)
struct longinRecord *plongin;
{
short cardN;
if (debug_flag >10)
logMsg("read_longin called...\n",0,0,0,0,0,0);
cardN = plongin->inp.value.vmeio.card;
if (checkLink(cardN) == ERROR)
return(ERROR);
switch(plongin->inp.value.vmeio.signal){
case 0: /* AD_MEMORY */
plongin->val = (cards[cardN].card->ad_memory) & 0x3;
break;
case 1: /* TRG_POS */
plongin->val = (cards[cardN].card->trg_pos) & 0x7;
break;
case 2: /* IRQ_ENB */
plongin->val = (cards[cardN].card->irq_enb) & 0x3;
break;
case 3 : /* AD_status */
plongin->val = (cards[cardN].card->ad_status) & 0xff;
break;
case 4: /* IRQ_NO */
plongin->val = (cards[cardN].card->irq_no) & 0xf;
break;
case 5: /* IRQ_VECTOR */ plongin->val = (cards[cardN].card->irq_id) &0xff;
break;
default: break;
}
return(OK);
}
static long init_mi_record(pmbbi)
struct mbbiDirectRecord*pmbbi;
{ short cardNum;
short signal;
cardNum = pmbbi->inp.value.vmeio.card;
signal = pmbbi->inp.value.vmeio.signal;
if (signal == 1) {
if (intConnect(INUM_TO_IVEC(INT_VEC_BASE + cardNum),
(VOIDFUNCPTR)vme18k11_isr,
(int)pmbbi) != OK)
logMsg("devVme18k11: Interrupt connect failed for card %d\n",pmbbi->inp.value.vmeio.card,0,0,0,0,0); logMsg("intConnect 0x%x\n",pmbbi);
sysIntEnable(int_level); logMsg("devVme18k11 int set for int 0x%x\n",int_level,0,0,0,0,0);
}
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,0,0,0,0,0);
if (checkLink(cardN) == ERROR)
return(ERROR);
switch(pmbbi->inp.value.vmeio.signal){
case 0: /* IRQ_ENB */
pmbbi->rval = (cards[cardN].card->irq_enb) & 0x3;
break;
case 1: /* AD_STATUS */
pmbbi->rval = (cards[cardN].card->ad_status) & 0xff;
break;
default: break;
}
if (debug_flag >5)
logMsg("mbbi read complete \n",0,0,0,0,0,0);
return(OK);
}
static long get_mbbi_int_info(cmd,pmbbi,ppvt)
int cmd;
struct mbbiDirectRecord *pmbbi;
IOSCANPVT *ppvt;
{
short cardN;
unsigned char stat;
cardN = pmbbi->inp.value.vmeio.card;
*ppvt = cards[cardN].ioscanpvt;
if (debug_flag >5) logMsg("mbbi_INT CALLED\n",0,0,0,0,0,0);
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)vme18k11_isr,
(int)pwf) != OK)
logMsg("devVme18k11: Interrupt connect failed for card %d\n",pwf->inp.value.vmeio.card); logMsg("intConnect 0x%x\n",pwf);
sysIntEnable(int_level); logMsg("devVme18k11 int set for int 0x%x\n",int_level);
*/
return(0);
}
static long read_wf_record(pwf)
struct waveformRecord*pwf;
{ short cardN;
unsigned long a1,a2;
unsigned long taddress,sta,t_set,mems,mem_start;
long ii,start,is;
unsigned short* us_thing = (unsigned short*)pwf->bptr;
#if 1
STATUS iDmaStartRc;
unsigned int p1=0,p2=0,p3=0,p4=0,pSta=0;
#endif
#if 1
struct timespec oTimeSpec1;
struct timespec oTimeSpec2;
struct timespec oTimeSpec3;
struct timespec oTimeSpec4;
struct timespec oTimeSpec5;
/*
clock_gettime( CLOCK_REALTIME, &oTimeSpec1 );
*/
#endif
cardN = pwf->inp.value.vmeio.card;
if (debug_flag >5)
logMsg("read_wf_record called with card number of %d\n",cardN,0,0,0,0,0);
if (checkLink(cardN) == ERROR)
return(ERROR);
taddress = (cards[cardN].card->trigger) & 0x3ffff;
t_set = (cards[cardN].card->trg_pos) & 0x7; /* 0 for -100% */
mems = 0x8000 << ((cards[cardN].card->ad_memory) & 0x3 );
/* logMsg("MEMS %x TADDRESS %x\n",mems, taddress); */
mem_start = mems *(t_set)/4;
start = taddress - mem_start;
if (start < 0) start = start + mems;
switch(pwf->inp.value.vmeio.signal){
case 0: { /* all channel */
#if 0
logMsg("card[%d] address[%x] mems[%x]\n",cardN,&cards[cardN].card->call[0],mems);
#endif
#if 0
/* clock_gettime( CLOCK_REALTIME, &oTimeSpec1 ); */
for (ii=0;ii<mems;ii++)
{
is = (ii-start);
if (is <0) is += mems;
(unsigned long)a1 = (unsigned long)(cards[cardN].card->call[ii]);
us_thing[is] = (unsigned short)(a1 & 0x3fff);
us_thing[is+262144] = (unsigned short)((a1>>16) & 0x3fff);
(unsigned long)a2 = (unsigned long)(cards[cardN].card->call[ii+262144]);
us_thing[is+524288] = (unsigned short)(a2 & 0x3fff);
us_thing[is+786432] = (unsigned short)((a2>>16) & 0x3fff);
/* logMsg("A1 =%x\n",a1); */
/* if (ii<10) logMsg("call %d A1=%x\n",ii,a1); */
} /* clock_gettime( CLOCK_REALTIME, &oTimeSpec2 ); */
#else
sysUnivVERRClr();
if(sysVmeDmaStatusGet(&pSta) != OK )
{
logMsg("sysVmeDmaStatusGet() Error!!\n", 0, 0, 0, 0, 0);
}
#if 0
logMsg("VmeDmaStatus[%x]\n",pSta,0,0,0,0,0);
#endif
if(sysVmeDmaCnfgGet(&p1,&p2,&p3,&p4) != OK )
{
logMsg("sysVmeDmaCnfgGet() Error!!\n", 0, 0, 0, 0, 0);
}
#if 0
logMsg("xferType[%x] addrSpace[%x] dataType[%x] userType[%x]\n",p1,p2,p3,p4,0,0);
#endif
/* clock_gettime( CLOCK_REALTIME, &oTimeSpec1 ); */
/* iDmaStartRc = sysVmeDmaV2LCopy( &cards[cardN].card->call[0], gplTmpData+0, mems * 4 ); */
iDmaStartRc = sysVmeDmaV2LCopy( &cards[cardN].card->call[0], gplTmpData+0, mems * 8 );
/* clock_gettime( CLOCK_REALTIME, &oTimeSpec2 ); */
if(iDmaStartRc != 0)
{
logMsg("-->sysVmeDmaV2LCopy() error!! Rc[%d] card[%d] ch1ch3\n", iDmaStartRc, cardN, 0, 0 ,0, 0 );
}
/* clock_gettime( CLOCK_REALTIME, &oTimeSpec3 ); */
/* iDmaStartRc = sysVmeDmaV2LCopy( &cards[cardN].card->call[262144], gplTmpData+262144, mems * 4 ); */
/* clock_gettime( CLOCK_REALTIME, &oTimeSpec4 ); */
if(iDmaStartRc != 0)
{
logMsg("-->sysVmeDmaV2LCopy() error!! Rc[%d] card[%d] ch2ch4\n", iDmaStartRc, cardN, 0, 0 ,0, 0 );
}
/* logMsg("--gplTmpData[0,1] %x %x\n",gplTmpData[0],gplTmpData[1],0,0,0,0);
logMsg("--gplTmpData[2,3] %x %x\n",gplTmpData[2],gplTmpData[3],0,0,0,0); */
/* for ( ii = 0; ii < mems; ii++ )
{
us_thing[ii + 0] = (unsigned short)( gplTmpData[ii + 0] & 0x3fff );
us_thing[ii + 262144] = (unsigned short)( ( gplTmpData[ii + 0] >> 16 ) & 0x3fff );
us_thing[ii + 524288] = (unsigned short)( gplTmpData[ii + 262144] & 0x3fff );
us_thing[ii + 786432] = (unsigned short)( ( gplTmpData[ii + 262144] >> 16 ) & 0x3fff );
}*/
for ( ii = 0; ii < mems ; ii++ )
{
us_thing[ii+ 0] = (unsigned short)( gplTmpData[ii*2+1] & 0x3fff );
us_thing[ii + 262144] = (unsigned short)( ( gplTmpData[ii*2+1] >> 16 ) & 0x3fff );
us_thing[ii + 524288] = (unsigned short)( gplTmpData[ii*2] & 0x3fff );
us_thing[ii + 786432] = (unsigned short)( ( gplTmpData[ii*2] >> 16 ) & 0x3fff );
}
/* logMsg("--us_thing[0,1] %x %x\n",us_thing[0],us_thing[1],0,0,0,0); */
/* clock_gettime( CLOCK_REALTIME, &oTimeSpec5 ); */
#endif
pwf->nord = 1048576;
cards[cardN].card->ad_start = 0x1;
#if 0
logMsg("ad_start[%d]\n",cardN,0,0,0,0,0);
#endif
break;
}
case 1: { /* ch2ch4 */
/*
for (ii=0;ii<mems;ii++)
{
is = (ii-start);
if (is <0) is += mems;
(unsigned long)a1 = (unsigned long)(cards[cardN].card->ch2ch4[ii]);
us_thing[is] = (unsigned short)(a1 & 0xfff);
us_thing[is+262144] = (unsigned short)((a1>>16) & 0xfff);
if ((debug_flag >10 ) && (ii<40)){
logMsg("ii= %d down %d up %d\n",ii,us_thing[ii],us_thing[ii+262144]);
}
} pwf->nord = 524288;
cards[cardN].card->ad_start = 0x1; */
break;
}
default : logMsg("Invalid Signal\n",0,0,0,0,0,0);
}
/* cards[cardN].card->status = 0x1; */
if (debug_flag >5) logMsg("18k11 card %d end of read\n",cardN,0,0,0,0,0);
#if 0
/*
logMsg( "card[%d] ch1ch3 DMA Info. vmeaddr[0x%x]->memaddr[0x%x] readlen[0x%x]", &cards[cardN].card->call[0], gplTmpData+0, mems*4,0,0,0 );
*/
logMsg( "card[%d] ch1ch3 DMA stime[%ld.%09ld] etime[%ld.%09ld]\n",
cardN, oTimeSpec1.tv_sec, oTimeSpec1.tv_nsec, oTimeSpec2.tv_sec, oTimeSpec2.tv_nsec, 0 );
/*
logMsg( "card[%d] ch2ch4 DMA Info. vmeaddr[0x%x]->memaddr[0x%x] readlen[0x%x]", &cards[cardN].card->call[262144], gplTmpData+262144, mems*4,0,0,0 );
*/
logMsg( "card[%d] ch2ch4 DMA stime[%ld.%09ld] etime[%ld.%09ld]\n",
cardN, oTimeSpec3.tv_sec, oTimeSpec3.tv_nsec, oTimeSpec4.tv_sec, oTimeSpec4.tv_nsec, 0 );
logMsg( "card[%d] Move&Shift eTime[%ld.%09ld] \n",cardN,oTimeSpec5.tv_sec,oTimeSpec5.tv_nsec,0,0,0 );
#endif
return(0);
}
/*
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;
*ppvt = cards[cardN].ioscanpvt;
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 >= D18k11_num_links)
return(ERROR);
if (cards[cardN].card == NULL)
{
logMsg("No 18K11 with this number = %d\n",cardN,0,0,0,0,0);
return(ERROR);
}
if (debug_flag >10)
logMsg("Yes you have 18k11 with card No= %d\n",cardN,0,0,0,0,0);
return(OK);
}
void dmaCallBackCh0( void )
{
logMsg( "call dmaCallBackCh0\n",0,0,0,0,0,0 );
}
void dmaCallBackCh1( void )
{
logMsg( "call dmaCallBackCh1\n", 0,0,0,0,0,0 );
}