/* devVme18k07.c */
/* devVme18k07.c - Device Support Routines for VME adc board */
/*
 *      Original Author: Makoto Tobiyama
 *      Current Author:
 *      Date:            29/Jun/2010
 *      Modified         
 *
 *      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	<devCamac.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>

struct D18k07 {
  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];
};

#define	Status	Enable

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 vme18k07_isr();

static int  checkLink();

/* Create the dset for devBo18k07 */
struct {
        long            number;
        DEVSUPFUN       report;         
        DEVSUPFUN       init;   
        DEVSUPFUN       init_record;
        DEVSUPFUN       get_ioint_info;
        DEVSUPFUN       write_bo;       
}devBo18k07={
        5,
        NULL,
        NULL,
        init_bo_record,
        NULL,
        write_bo
};
/* For devMbbi18k07  */
struct{
        long            number;
        DEVSUPFUN       report;
        DEVSUPFUN       init;
        DEVSUPFUN       init_mi_record;
        DEVSUPFUN       get_ioint_info;
        DEVSUPFUN       read_mbbiDirect;
}devMbbi18k07={
        5,
        NULL,
        NULL,
        init_mi_record,
        get_mbbi_int_info,
        read_mbbiDirect
};

struct {
    long        number;
    DEVSUPFUN   report;
    DEVSUPFUN   init;
    DEVSUPFUN   init_record;
    DEVSUPFUN   get_ioint_info;
    DEVSUPFUN   read_write;
    DEVSUPFUN   conv;
}devWf18k07 ={
  6,
  NULL,
  NULL,
  init_wf_record,
  NULL,
  read_wf_record,
  NULL
};

struct {
        long            number;
        DEVSUPFUN       report;
        DEVSUPFUN       init;
        DEVSUPFUN       init_record;
        DEVSUPFUN       get_ioint_info;
        DEVSUPFUN       write_longout;
        DEVSUPFUN       special_linconv;
}devLo18k07={
        6,
        NULL,
        NULL,
        NULL,
        NULL,
        write_longout,
        NULL
};

struct {
        long            number;
        DEVSUPFUN       report;
        DEVSUPFUN       init;
        DEVSUPFUN       init_record;
        DEVSUPFUN       get_ioint_info;
        DEVSUPFUN       read_longin;
        DEVSUPFUN       special_linconv;
}devLi18k07={
        6,
        NULL,
        NULL,
        init_li_record,
        NULL,
        read_longin,
        NULL};


struct ioCard {
  volatile struct D18k07     *card; /* address of this card */
  FAST_LOCK                    lock; /* semaphore */
  IOSCANPVT                  ioscanpvt; 
      };

#define CONST_NUM_LINKS 10
/* #define STATIC  */
#define DEBUG_ON

static int            debug_flag = 5;
static unsigned long  Base_IO;
static int            D18k07_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;



int dev18k07Config(ncards,a32base,irq,intvecbase)
int ncards;
long a32base;
int irq;
int intvecbase;
{
  D18k07_num_links = ncards;
  Base_IO = a32base;
  int_level= irq;
  INT_VEC_BASE=intvecbase;
  logMsg("dev18k07 NumLink= %d BaseIO= %x IRQ = %d INTVECBASE =%x\n",D18k07_num_links,Base_IO,int_level,INT_VEC_BASE);
  init_all(0);
}

static long init_all(after)
int after;
{
  int                          cardNum, chanNum;
  unsigned char                probeVal[4];
  volatile  struct D18k07     *p;
  unsigned short               mem_pat;

  if (init_flag != 0 ) 
   return(OK);

  init_flag = 1;

  if (sysBusToLocalAdrs(VME_AM_EXT_SUP_DATA,(char *)Base_IO,(char **)&p) == ERROR)
	{
		logMsg("18k07: cannot find extended address space\n");
		return(ERROR);
	}
  for (cardNum=0; cardNum< D18k07_num_links; cardNum++)
   {
     if (vxMemProbe((char*) &(p->ad_status), READ, 4, &probeVal[0])!= OK)
       {
	 if (debug_flag >0 ) 
         logMsg("No 18k07 with cardNum= %d\n probe= %x\n",cardNum,p);
	 cards[cardNum].card = NULL;
       }
     else
       {
	 if (debug_flag >0)
           logMsg("Found 18k07 with cardNum= %d\n address= %x\n",cardNum,p);
	   cards[cardNum].card = p;  /* Remember address of the board */
	   scanIoInit(&(cards[cardNum].ioscanpvt));
       }
     p->irq_enb = 0x00;
     FASTLOCKINIT(&(cards[cardNum].lock));
     FASTUNLOCK(&(cards[cardNum].lock)); /* Init the board lock */
     p++;
   }
  return(OK);
}
/******************************************************************
*
* Interrupt service routine
*
*******************************************************************/
static void vme18k07_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("18k07 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 18k07 for card %d\n    if (pbo->rval == 0x0) /* trigger off */ 
      cardstatusA[cardN] = (cardstatusA[cardN] & 0xfffffffe);
    else          /* trigger on */
      cardstatusA[cardN] = (cardstatusA[cardN] | 0x1);
",cardN);
      return(ERROR);
    }

  if (debug_flag>5) logMsg("BO\n");
  FASTLOCK(&(cards[cardN].lock));
    /* ADC start */
    cards[cardN].card->ad_start = 0x1;
    FASTUNLOCK(&(cards[cardN].lock));
  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);

  if (checkLink(cardN) == ERROR)
    return(ERROR);

  FASTLOCK(&(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;
  }
  FASTUNLOCK(&(cards[cardN].lock));
  return(CONVERT);
}

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");

  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(CONVERT);
}


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)vme18k07_isr, 
		 (int)pmbbi) != OK)
    logMsg("devVme18k07: Interrupt connect failed for card %d\n",pmbbi->inp.value.vmeio.card);
  logMsg("intConnect 0x%x\n",pmbbi);
	 
  sysIntEnable(int_level);
  logMsg("devVme18k07 int set for int 0x%x\n",int_level);
  }
  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: /* 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");

        return(CONVERT);
}

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");
  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)vme18k07_isr, 
		 (int)pwf) != OK)
    logMsg("devVme18k07: Interrupt connect failed for card %d\n",pwf->inp.value.vmeio.card);
  logMsg("intConnect 0x%x\n",pwf);
	 
  sysIntEnable(int_level);
  logMsg("devVme18k07 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;

  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);

  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 */

    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); */
      }
    pwf->nord = 1048576;
    cards[cardN].card->ad_start = 0x1;
    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");
  

  }
  /*  cards[cardN].card->status = 0x1; */

  if (debug_flag >5) logMsg("18k07 card %d end of read\n",cardN); 
  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 >= D18k07_num_links)
    return(ERROR);
  if (cards[cardN].card == NULL)
    {
      logMsg("No 18K07 with this number = %d\n",cardN);
      return(ERROR);
    }

  if (debug_flag >10)
    logMsg("Yes you have 18k07 with card No= %d\n",cardN);
  return(OK);
}


mailto: makoto.tobiyama@kek.jp
Last update: 9/Jul/2010