/* devPVME632.c */
/* devPVME632.c - Device Support Routines for  VME PVME-632 */
/*     16 bit D/A 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 7/Jun/2000	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 */

struct DPvme632 {
  unsigned short dac_0;
  unsigned short dac_1;
  unsigned short dac_2;
  unsigned short dac_3;
  unsigned short dac_4;
  unsigned short dac_5;
  unsigned short dac_6;
  unsigned short dac_7;
  unsigned short dac_8;
  unsigned short dac_9;
  unsigned short dac_10;
  unsigned short dac_11;
  unsigned short dac_12;
  unsigned short dac_13;
  unsigned short dac_14;
  unsigned short dac_15;
  unsigned short load_reg;
  unsigned short sts_reg;
  unsigned short zero_reg;
  unsigned short dummy[109]
};


/* #define	Status	Enable */

static long init_all();

static long init_bo_record();
static long init_bi_record();
static long write_bo();
static long read_bi();
static long init_lo_record();
static long write_longout_record();

static unsigned short inpconv();
static int  checkLink();

struct {
	long		number;
	DEVSUPFUN	report;
	DEVSUPFUN	init;
	DEVSUPFUN	init_lo_record;
	DEVSUPFUN	get_ioint_info;
	DEVSUPFUN	write_longout_record;
	DEVSUPFUN	special_linconv;
}devLoPvme632={
	6,
	NULL,
	NULL,
	init_lo_record,
	NULL,
	write_longout_record,
        NULL};

struct {
        long            number;
        DEVSUPFUN       report;         
        DEVSUPFUN       init;           
        DEVSUPFUN       init_bo_record;    
        DEVSUPFUN       get_ioint_info; 
        DEVSUPFUN       write_bo;      
}devBoPvme632={
        5,
        NULL,
        NULL,
        init_bo_record,
        NULL,
        write_bo
};
struct {
        long            number;
        DEVSUPFUN       report; 
        DEVSUPFUN       init;    
        DEVSUPFUN       init_bi_record;   
        DEVSUPFUN       get_ioint_info;
        DEVSUPFUN       read_bi; 
}devBiPvme632={
        5,
        NULL,
        NULL,
        init_bi_record,
        NULL,
        read_bi
};

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

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

static int   debug_flag = 1;
static unsigned long Base_IO;
static int     pvme632_num_links;

static struct ioCard cards[CONST_NUM_LINKS];
static int           init_flag = 0;


int devPvme632Config(ncards,a24base)
int ncards;
long a24base;
{
  pvme632_num_links = ncards;
  Base_IO = a24base;
  logMsg("Pvme632 NumLink= %d BaseIO= %x\n",pvme632_num_links,Base_IO);
  init_all(0);
}


static long init_all(after)
int after;
{
  int                          cardNum, chanNum;
  unsigned char                probeVal[2];
  volatile  struct DPvme632    *p;

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

  init_flag = 1;

  if (sysBusToLocalAdrs(VME_AM_STD_SUP_DATA,(char *)Base_IO,(char **)&p) == ERROR)
	{
		logMsg("VmeP632: cannot find A24 address space\n");
		return(ERROR);
	}
#ifdef DEBUG_ON  
    if ( CDEBUG)logMsg("PVME632 (init) Called. pass = %d\n", after);
#endif
  for (cardNum=0; cardNum< pvme632_num_links; cardNum++)
   {
     if (vxMemProbe((char*) &(p->sts_reg), READ, 2, &probeVal)< OK)
       {
	 if (debug_flag >0 ) 
         logMsg("No PVME632 with cardNum= %d\n probe= %x\n",cardNum,p);
	 cards[cardNum].card = NULL;
       }
     else
       { 
	 if (debug_flag >0)
         logMsg("Found PVME632 with cardNum= %d\n address= %x\n",cardNum,p);
	 cards[cardNum].card = p;  /* Remember address of the board */
	 FASTLOCKINIT(&(cards[cardNum].lock));
	 FASTUNLOCK(&(cards[cardNum].lock)); /* Init the board lock */
	 p->zero_reg = 0x0001; /* enable output */ 
       }
     p++;
   }
  return(OK);
}

static long init_bi_record(pbi)
struct biRecord *pbi;
{

        pbi->mask = 1;
		return(0);
}

static long read_bi(pbi)
struct biRecord *pbi;
{
  short cardN;

  cardN = pbi->inp.value.vmeio.card;
  if (checkLink(cardN) == ERROR)
    return(ERROR);
  switch (pbi->inp.value.vmeio.signal){
  case 0: /* enable D/A write -- not used */
          pbi->rval = cards[cardN].card->sts_reg &pbi->mask;
          break;
  case 1: /* zero-reset 1: output enable */
          pbi->rval = cards[cardN].card->zero_reg & pbi->mask;
          break;
  }
  return(0);
}

static long init_bo_record(pbo)
struct boRecord *pbo;
{

        pbo->mask = 1;
		return(0);
}


static long write_bo(pbo)
struct boRecord *pbo;
{

  short cardN;

  cardN = pbo->out.value.vmeio.card;
  if (checkLink(cardN) == ERROR)
    {
      logMsg("Error--- No PVME632 for card %d\n",cardN);
      return(ERROR);
    }

  FASTLOCK(&(cards[cardN].lock));
  switch (pbo->out.value.vmeio.signal){
 
  case 0 : /* synchronus output trigger -- not used */
          cards[cardN].card->load_reg = pbo->rval & pbo->mask;
          break;
  case 1: /* enable output = 1 */
          cards[cardN].card->zero_reg =pbo ->rval & pbo->mask;
          break;
  }
  FASTUNLOCK(&(cards[cardN].lock));
	return(0);
}





static long init_lo_record(plongin)
struct longinRecord	*plongin;
{
  return(0);
}

static long write_longout_record(plongout)
struct longoutRecord	*plongout;
{

  short cardN;
  
  cardN = plongout->out.value.vmeio.card;

  if (debug_flag >4) 
   logMsg("write_longout called with card %d\n",cardN);

  if (checkLink(cardN) == ERROR)
    return(ERROR);
  FASTLOCK(&(cards[cardN].lock));
  if (debug_flag >4)   logMsg("card locked...\n");
		
  switch(plongout->out.value.vmeio.signal){
  case 0: /* DAC 0 */
          cards[cardN].card->dac_0 = inpconv(plongout->val);
	  if (debug_flag >4)
		    logMsg("write_longout signal 0 DAC0\n");
	  break;
  case 1: /* DAC 1 */
          cards[cardN].card->dac_1 = inpconv(plongout->val);
	  if (debug_flag >4)
		    logMsg("write_longout signal 1 DAC1\n");
	  break;
  case 2: /* DAC 2 */
          cards[cardN].card->dac_2 = inpconv(plongout->val);
	  if (debug_flag >4)
		    logMsg("write_longout signal 2 DAC2\n");
	  break;
  case 3: /* DAC 3 */
          cards[cardN].card->dac_3 = inpconv(plongout->val);
	  if (debug_flag >4)
		    logMsg("write_longout signal 3 DAC3\n");
	  break;
  case 4: /* DAC 4 */
          cards[cardN].card->dac_4 = inpconv(plongout->val);
	  if (debug_flag >4)
		    logMsg("write_longout signal 4 DAC4\n");
	  break;
  case 5: /* DAC 5 */
          cards[cardN].card->dac_5 = inpconv(plongout->val);
	  if (debug_flag >4)
		    logMsg("write_longout signal 5 DAC5\n");
	  break;
  case 6: /* DAC 6 */
          cards[cardN].card->dac_6 = inpconv(plongout->val);
	  if (debug_flag >4)
		    logMsg("write_longout signal 6 DAC6\n");
	  break;
  case 7: /* DAC 7 */
          cards[cardN].card->dac_7 = inpconv(plongout->val);
	  if (debug_flag >4)
		    logMsg("write_longout signal 7 DAC7\n");
	  break;
  case 8: /* DAC 8 */
          cards[cardN].card->dac_8 = inpconv(plongout->val);
	  if (debug_flag >4)
		    logMsg("write_longout signal 8 DAC8\n");
	  break;
  case 9: /* DAC 9 */
          cards[cardN].card->dac_9 = inpconv(plongout->val);
	  if (debug_flag >4)
		    logMsg("write_longout signal 9 DAC9\n");
	  break;
  case 10: /* DAC 10 */
          cards[cardN].card->dac_10 = inpconv(plongout->val);
	  if (debug_flag >4)
		    logMsg("write_longout signal 10 DAC10\n");
	  break;
  case 11: /* DAC 11 */
          cards[cardN].card->dac_11 = inpconv(plongout->val);
	  if (debug_flag >4)
		    logMsg("write_longout signal 11 DAC11\n");
	  break;
  case 12: /* DAC 12 */
          cards[cardN].card->dac_12 = inpconv(plongout->val);
	  if (debug_flag >4)
		    logMsg("write_longout signal 12 DAC12\n");
	  break;
  case 13: /* DAC 13 */
          cards[cardN].card->dac_13 = inpconv(plongout->val);
	  if (debug_flag >4)
		    logMsg("write_longout signal 13 DAC13\n");
	  break;
  case 14: /* DAC 14 */
          cards[cardN].card->dac_14 = inpconv(plongout->val);
	  if (debug_flag >4)
		    logMsg("write_longout signal 14 DAC14\n");
	  break;
  case 15: /* DAC 15 */
          cards[cardN].card->dac_15 = inpconv(plongout->val);
	  if (debug_flag >4)
		    logMsg("write_longout signal 15 DAC15\n");
	  break;
  default:
          return(-1);
		}
  FASTUNLOCK(&(cards[cardN].lock));
  if (debug_flag >4)
   logMsg("unlock card ...\n");

        return(CONVERT);
}

static unsigned short inpconv(indata)
     long indata;
{
  if (indata>32767)
    return(65535);
  else if (indata <-32768)
    return(0);
  else 
    {
      return(indata + 32768);
    }
}
    


/**************************************************************************
 *
 * Make sure card number is valid
 *
 **************************************************************************/
static int checkLink(cardN)
short   cardN;
{
  if (cardN >= pvme632_num_links)
    return(ERROR);
  if (cards[cardN].card == NULL)
    {
      logMsg("No PVME632 with this number = %d\n",cardN);
      return(ERROR);
    }

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