/* devVme17k82.c */
/* devVme17k82.c - Device Support Routines for VME adc board */
/*
 *      Original Author: Makoto Tobiyama
 *      Current Author:
 *      Date:            18/Aug/2003
 *      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 D17k82 {
  unsigned long  ch1ch3[262144];
  unsigned long  ch2ch4[262144];
  unsigned long  status;
  unsigned long  dum1[262143];
  unsigned long  trigger;
  unsigned long  dummy[262143];
};

#define	Status	Enable

static long init_all();
static long init_mi_record();
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 int  checkLink();

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

struct {
    long        number;
    DEVSUPFUN   report;
    DEVSUPFUN   init;
    DEVSUPFUN   init_record;
    DEVSUPFUN   get_ioint_info;
    DEVSUPFUN   read_write;
    DEVSUPFUN   conv;
}devWf17k82 ={
  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;
}devLo17k82={
        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;
}devLi17k82={
        6,
        NULL,
        NULL,
        init_li_record,
        NULL,
        read_longin,
        NULL};


struct ioCard {
  volatile struct D17k82     *card; /* address of this card */
  FAST_LOCK                    lock; /* semaphore */
      };

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

static int            debug_flag = 5;
static unsigned long  Base_IO;
static int            D17k82_num_links;

static struct ioCard  cards[CONST_NUM_LINKS];
static int            init_flag = 0;
static int            mem_size[CONST_NUM_LINKS];
static int            ad_ready[CONST_NUM_LINKS];
static long           cardstatusA[CONST_NUM_LINKS];

int dev17k82Config(ncards,a32base)
int ncards;
long a32base;
{
  D17k82_num_links = ncards;
  Base_IO = a32base;
  logMsg("dev17k82 NumLink= %d BaseIO= %x\n",D17k82_num_links,Base_IO);
  init_all(0);
}

static long init_all(after)
int after;
{
  int                          cardNum, chanNum;
  unsigned char                probeVal[4];
  volatile  struct D17k82     *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("17k82: cannot find extended address space\n");
		return(ERROR);
	}
  for (cardNum=0; cardNum< D17k82_num_links; cardNum++)
   {
     if (vxMemProbe((char*) &(p->status), READ, 4, &probeVal[0])!= OK)
       {
	 if (debug_flag >0 ) 
         logMsg("No 17k82 with cardNum= %d\n probe= %x\n",cardNum,p);
	 cards[cardNum].card = NULL;
       }
     else
       {
	 if (debug_flag >0)
           logMsg("Found 17k82 with cardNum= %d\n address= %x\n",cardNum,p);
	cards[cardNum].card = p;  /* Remember address of the board */
           
       }
     cardstatusA[cardNum] = 0x0;
     p->status = cardstatusA[cardNum];
     FASTLOCKINIT(&(cards[cardNum].lock));
     FASTUNLOCK(&(cards[cardNum].lock)); /* Init the board lock */
     p++;
   }
  return(OK);
}

/**************************************************************************
 *
 * 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 17k82 for card %d\n",cardN);
      return(ERROR);
    }

  if (debug_flag>5) logMsg("BO\n");
  FASTLOCK(&(cards[cardN].lock));

  switch(pbo->out.value.vmeio.signal){
  case 0 :{        /* trigger on_off */
    if (pbo->rval == 0x0) /* trigger off */ 
      cardstatusA[cardN] = (cardstatusA[cardN] & 0xfffffffe);
    else          /* trigger on */
      cardstatusA[cardN] = (cardstatusA[cardN] | 0x1);
    cards[cardN].card->status = cardstatusA[cardN];
    break;
  }
  case 1:{ /* sample internal / external */
    if (pbo->rval == 0x1) /* sample internal */
      cardstatusA[cardN] = (cardstatusA[cardN] | 0x100);
    else  /* external */
      cardstatusA[cardN] = (cardstatusA[cardN] & 0xfffffeff);


    cards[cardN].card->status = cardstatusA[cardN];
    break;
  }
  }
  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 :{        /* trigger point */
    switch(plongout->val){
    case 0 : {  /* 0 -100% */ 
                cardstatusA[cardN] = (cardstatusA[cardN] & 0xfffff1ff);
		cards[cardN].card->status = cardstatusA[cardN];

		break;
    }
    case 1 : { /* 12.5% */
                cardstatusA[cardN] = ((cardstatusA[cardN] & 0xfffff1ff) | 0x200) ;
		cards[cardN].card->status = cardstatusA[cardN];

	     	break;
    }
    case 2 : { /* 25% */
                cardstatusA[cardN] = ((cardstatusA[cardN] & 0xfffff1ff) | 0x400) ;
		cards[cardN].card->status = cardstatusA[cardN];

	     	break;
    }
    case 3 : { /* 37.5% */
                cardstatusA[cardN] = ((cardstatusA[cardN] & 0xfffff1ff) | 0x600) ;
		cards[cardN].card->status = cardstatusA[cardN];

	     	break;
    }
    case 4 : { /* 50% */
                cardstatusA[cardN] = ((cardstatusA[cardN] & 0xfffff1ff) | 0x800) ;
		cards[cardN].card->status = cardstatusA[cardN];
	     	break;
    }
    case 5 : { /* 62.5% */
                cardstatusA[cardN] = ((cardstatusA[cardN] & 0xfffff1ff) | 0xA00) ;
		cards[cardN].card->status = cardstatusA[cardN];
	     	break;
    }
    case 6 : { /* 75% */
                cardstatusA[cardN] = ((cardstatusA[cardN] & 0xfffff1ff) | 0xC00) ;
		cards[cardN].card->status = cardstatusA[cardN];
	     	break;
    }
    case 7 : { /* 87.5% */
                cardstatusA[cardN] = ((cardstatusA[cardN] & 0xfffff1ff) | 0xE00) ;
		cards[cardN].card->status = cardstatusA[cardN];
	     	break;
    }
    default:{ break;}
    break;
  }
  break;}
  case 1: { /* memory capacity */
  switch(plongout->val){
    case 0 : {  /* 2048 */ 
                cardstatusA[cardN] = (cardstatusA[cardN] & 0xffff0fff);
		cards[cardN].card->status = cardstatusA[cardN];
		mem_size[cardN] = 2048;

		break;
    }
    case 1 : {  /* 4096 */ 
                cardstatusA[cardN] = ((cardstatusA[cardN] & 0xffff0fff) | 0x1000);
		cards[cardN].card->status = cardstatusA[cardN];
		mem_size[cardN] = 4096;

		break;
    }
    case 2 : {  /* 8192 */ 
                cardstatusA[cardN] = ((cardstatusA[cardN] & 0xffff0fff) | 0x2000);
		cards[cardN].card->status = cardstatusA[cardN];
		mem_size[cardN] = 8192;

		break;
    }
    case 3 : {  /* 16384 */ 
                cardstatusA[cardN] = ((cardstatusA[cardN] & 0xffff0fff) | 0x3000);
		cards[cardN].card->status = cardstatusA[cardN];
		mem_size[cardN] = 16384;

		break;
    }
    case 4 : {  /* 32768 */ 
                cardstatusA[cardN] = ((cardstatusA[cardN] & 0xffff0fff) | 0x4000);
		cards[cardN].card->status = cardstatusA[cardN];
		mem_size[cardN] = 32768;
		break;
    }
    case 5 : {  /* 65536 */ 
                cardstatusA[cardN] = ((cardstatusA[cardN] & 0xffff0fff) | 0x5000);
		cards[cardN].card->status = cardstatusA[cardN];
		mem_size[cardN] = 65536;
		break;
    }
    case 6 : {  /* 131072 */ 
                cardstatusA[cardN] = ((cardstatusA[cardN] & 0xffff0fff) | 0x6000);
		cards[cardN].card->status = cardstatusA[cardN];
		mem_size[cardN] = 131072;
		break;
    }
    case 7 : {  /* 262144 */ 
                cardstatusA[cardN] = ((cardstatusA[cardN] & 0xffff0fff) | 0x7000);
		cards[cardN].card->status = cardstatusA[cardN];
		mem_size[cardN] = 262144;
		break;
    }
  default : { /* 262144 */ 
                cardstatusA[cardN] = ((cardstatusA[cardN] & 0xffff0fff) | 0x7000);
		cards[cardN].card->status = cardstatusA[cardN];
		mem_size[cardN] = 262144;
		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 (debug_flag >10)
    logMsg("read_longin called with card number of %d\n",cardN);

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

  plongin->val = (cards[cardN].card->trigger) & 0x3ffff;
  return(CONVERT);
}


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);
   
    pmbbi->rval = (cards[cardN].card->status) & 0x7fff;

  if (debug_flag >5)
   logMsg("mbbi read complete \n");

        return(CONVERT);
}


static long init_wf_record(pwf)
struct waveformRecord	*pwf;
{
  return(0);
}

static long read_wf_record(pwf)
struct waveformRecord	*pwf;
{
  short cardN;
  unsigned long a1;
  long ii;
  long taddress,sta,t_set,mems,mem_start,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);
  if (((((cards[cardN].card->status)>>2) & 0x01) == 0 ) &&
         ((((cards[cardN].card->status)>>1) & 0x01) ==1)){
    logMsg("17k82 card %d Memory not ready\n",cardN);
    return(ERROR);
  }
   cardstatusA[cardN] = (cardstatusA[cardN] & 0xfffffffe);
    cards[cardN].card->status = cardstatusA[cardN]; /* disable trigger */

  taddress = (cards[cardN].card->trigger) & 0x3ffff;
    
  sta = (cards[cardN].card->status) & 0x7fff;
  t_set = ((sta & 0xf00) >>9);
  mems = 2048 << ((sta & 0xf000)>>12);

  mem_start = mems *t_set/8;
  start = taddress - mem_start;
  if (start  < 0) start = start + mems; 
    
  switch(pwf->inp.value.vmeio.signal){
  case 0: { /* ch1ch3 */

    for (ii=0;ii<mems;ii++)
      {
	is = (ii-start);
        if (is <0) is += mems;
	(unsigned long)a1 = (unsigned long)(cards[cardN].card->ch1ch3[ii]);
	us_thing[is] = (unsigned short)(a1 & 0xfff);
	us_thing[is+262144] = (unsigned short)((a1>>16) & 0xfff);
	/* if (is<10) logMsg("ch1ch3 %d %x\n",is,a1); */ 
      }
    pwf->nord = 524288;
    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;
    /* cardstatusA[cardN] = (cardstatusA[cardN] | 0x1); *//* enable trigger */
    /* cards[cardN].card->status = cardstatusA[cardN]; */    
    break;
  }
  default : logMsg("Invalid Signal\n");
  

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

  if (debug_flag >5) logMsg("17k82 card %d end of read\n",cardN); 
  return(0);
}


/**************************************************************************
 *
 * Make sure card number is valid
 *
 **************************************************************************/



static int checkLink(cardN)
short   cardN;
{
  if (cardN >= D17k82_num_links)
    return(ERROR);
  if (cards[cardN].card == NULL)
    {
      logMsg("No 17K82 with this number = %d\n",cardN);
      return(ERROR);
    }

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