/* devRPV100.c */
/* devRPV100.c - Device Support Routines for  VME RPV-100 */
/*     Octal 100MHz visual scaler
/*
 *      Original Author: M. Tobiyama
 *      Current Author:  M. Tobiyama
 *      Date:            
 *
 *      Experimental Physics and Industrial Control System (EPICS)
 *
 *      Copyright 1997, KEKB.
 *
 *
 * Modification Log:
 * -----------------
 *	ver0.0 06/Jul/2005	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        <dbScan.h>



struct DRPV100 {
  unsigned short  ch0up;
  unsigned short  ch0dn;
  unsigned short  ch1up;
  unsigned short  ch1dn;
  unsigned short  ch2up;
  unsigned short  ch2dn;
  unsigned short  ch3up;
  unsigned short  ch3dn;
  unsigned short  ch4up;
  unsigned short  ch4dn;
  unsigned short  ch5up;
  unsigned short  ch5dn;
  unsigned short  ch6up;
  unsigned short  ch6dn;
  unsigned short  ch7up;
  unsigned short  ch7dn;
  unsigned short  dum1[111];
  unsigned short  reset;
  unsigned short  dum2[128];
};


#define	Status	Enable 

int devRPV100Config();

static long init_all();
static long init_mo_record();
static long write_mbboDirect();
static long init_li_record();
static long read_longin();

static int  checkLink();

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

struct{
        long            number;
        DEVSUPFUN       report;
        DEVSUPFUN       init;
        DEVSUPFUN       init_mo_record;
        DEVSUPFUN       get_ioint_info;
        DEVSUPFUN       write_mbboDirect;
}devMbboRPV100={
        5,
        NULL,
        NULL,
        init_mo_record,
        NULL,
        write_mbboDirect};

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

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

static int   debug_flag = 0;
static unsigned long Base_IO;
static int     rpv100_num_links;

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

int devRPV100Config(ncards,a16base)
int ncards;
long a16base;
{
  rpv100_num_links = ncards;
  Base_IO = a16base;
  logMsg("RPV100 NumLink= %d BaseIO= %x\n",rpv100_num_links,Base_IO);
  init_all(0);
}

static long init_all(after)
int after;
{
  int                          cardNum, chanNum;
  int                          i,j;
  unsigned char                probeVal[2];
  unsigned short               p1;
  volatile  struct DRPV100    *p;

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

  init_flag = 1;

  if (sysBusToLocalAdrs(VME_AM_SUP_SHORT_IO,(char *)Base_IO,(char **)&p) == ERROR)
	{
		logMsg("VME RPV100: cannot find A16 address space\n");
		return(ERROR);
	}

  for (cardNum=0; cardNum< rpv100_num_links; cardNum++)
   {
     if (vxMemProbe((char*) &(p->ch0up), READ, 2, &probeVal)!=OK)
       {
         logMsg("No RPV100 with cardNum= %d\n probe= %x\n",cardNum,p);
	 cards[cardNum].card = NULL;
       } 
     else
       {
         p->reset = 0xff;  /* reset all */ 
	
         if (debug_flag >0)
	   logMsg("Found RPV100 with cardNum= %d 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++;
   }
  return(OK);
}

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

static unsigned long bcdtodec(unsigned short a)
{
  unsigned long result;

  result =
    (a >>15)*8000 +
    ((a >>14)& 0x1) * 4000 +
    ((a >>13)& 0x1) * 2000 +
    ((a >>12)& 0x1) * 1000 +
    ((a >>11)& 0x1) * 800 +
    ((a >>10)& 0x1) * 400 +
    ((a >> 9)& 0x1) * 200 +
    ((a >> 8)& 0x1) * 100 +
    ((a >> 7)& 0x1) * 80 +
    ((a >> 6)& 0x1) * 40 +
    ((a >> 5)& 0x1) * 20 +
    ((a >> 4)& 0x1) * 10 +
    ((a >> 3)& 0x1) *  8 +
    ((a >> 2)& 0x1) *  4 +
    ((a >> 1)& 0x1) *  2 +
    ((a & 0x1));

  return result;
}

static long read_longin(plongin)
struct longinRecord	*plongin;
{
  short cardN;

  if (debug_flag >5)
    logMsg("read_longin called...\n");

  cardN = plongin->inp.value.vmeio.card;
  if (debug_flag >5)
    logMsg("read_longin called with card number of %d\n",cardN);

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

  switch(plongin->inp.value.vmeio.signal){
  case 0: /* ch 0*/
    plongin->val = bcdtodec(cards[cardN].card->ch0up)*10000+bcdtodec(cards[cardN].card->ch0dn);
    break;
  case 1: /* ch 1*/
    plongin->val = bcdtodec(cards[cardN].card->ch1up)*10000+bcdtodec(cards[cardN].card->ch1dn);
    break;
  case 2: /* ch 2*/
    plongin->val = bcdtodec(cards[cardN].card->ch2up)*10000+bcdtodec(cards[cardN].card->ch2dn);
    break;
  case 3: /* ch 3*/
    plongin->val = bcdtodec(cards[cardN].card->ch3up)*10000+bcdtodec(cards[cardN].card->ch3dn);
    break;
  case 4: /* ch 4*/
    plongin->val = bcdtodec(cards[cardN].card->ch4up)*10000+bcdtodec(cards[cardN].card->ch4dn);
    break;
  case 5: /* ch 5*/
    plongin->val = bcdtodec(cards[cardN].card->ch5up)*10000+bcdtodec(cards[cardN].card->ch5dn);
    break;
  case 6: /* ch 6*/
    plongin->val = bcdtodec(cards[cardN].card->ch6up)*10000+bcdtodec(cards[cardN].card->ch6dn);
    break;
  case 7: /* ch 7*/
    plongin->val = bcdtodec(cards[cardN].card->ch7up)*10000+bcdtodec(cards[cardN].card->ch7dn);
    break;
  default:
    return(-1);
  }
        return(CONVERT);
}



static long init_mo_record(pmbbo)
struct mbboDirectRecord	*pmbbo;
{
  return(0);
}

static long write_mbboDirect(pmbbo)
struct mbboDirectRecord *pmbbo;
{
  short cardN;
  
  cardN = pmbbo->out.value.vmeio.card;
  if (debug_flag >5) 
   logMsg("write_mbboDirect called with card %d\n",cardN);

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

  FASTLOCK(&(cards[cardN].lock));
  if (debug_flag >5)
   logMsg("card locked...\n");
  
  cards[cardN].card->reset = pmbbo->rval;
  pmbbo->rbv=pmbbo->rval;
  
  if (debug_flag >5)
   logMsg("write complete \n");
  FASTUNLOCK(&(cards[cardN].lock));
  if (debug_flag >5)
   logMsg("unlock card ...\n");

        return(CONVERT);
}




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

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