/* 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);
}