#ifdef _CVI_
 
#include <utility.h>
 
#else
 
#include <unistd.h>
 
 
 
void Delay(double x) {
 
  usleep(int(1e6*x));
 
}
 
#endif
 
 
 
#include <stdlib.h>
 
#include <stdint.h>
 
#include <string.h>
 
#include <stdio.h>
 
#include "sa02lib.h"
 
 
 
//uint32_t  sa02BoardNumber = 0;
 
uint32_t  sa02BoardType   = 0;
 
int       sa02Verbose = 0;
 
int       sa02TimerOut;
 
int       sa02BltReadout = 0;
 
uint32_t  sa02Address    = 0;
 
 
 
 
 
int sa02SetAddress(uint32_t address) {
 
  sa02Address    =  address;
 
  return 0;
 
}
 
 
 
int sa02Help( void ) {
 
  sa02Printf ("*********************************************************************************:\n");
 
  sa02Printf ("Usage: Performs single/multiple read or write access to SA02 via CAEN V1495 multipurpose IO board:\n\n");
 
  sa02Printf ("Arguments: \n");
 
  sa02Printf ("-i input parameter filename // can be specified multiple times  \n");
 
  sa02Printf ("-v verbosity \n");
 
  sa02Printf ("-g bltreadout \n");
 
  sa02Printf ("-o output filename \n");
 
  sa02Printf ("-f output filename - append data to file\n");
 
  sa02Printf ("-w write command (FE TP DLY0 MUX MUXASIC VTH1 VTH2 TPLVL0 TPLVL1 GREG CREG CMON TMON0 TMON1 DMON) \n");
 
  sa02Printf ("-a vme base address 0x32100000 \n");
 
  sa02Printf ("-c asic chip number (0..3) \n");
 
  sa02Printf ("-x asic channel number (0..36) \n");
 
  sa02Printf ("-t sleep time bewteen events (sec) \n");
 
  sa02Printf ("-d data\n");
 
  sa02Printf ("-b dataoff - scan over the asic channels instead of the parameter, data step is the channel step, chip and channel are initial chip and  channel. Should apper after -p or-w\n");
 
  sa02Printf ("-s data step or in case of -b the channel step \n");
 
  sa02Printf ("-r number of readouts for each event\n");
 
  sa02Printf ("-n number of events\n");
 
  sa02Printf ("-h <command> at each event execute external command after readouts are done");
 
  sa02Printf ("-q enable test pulse\n");
 
  sa02Printf ("-e send software trigger before reading the data\n");
 
  sa02Printf ("-p asicparameter ( PHASECMPS GAIN SHAPINGTIME COMPARATOR VRDRIVE MONITOR ID)\n");
 
  sa02Printf ("-p asicparameter ( DECAYTIME OFFSET FINEADJ_UNIPOL FINEADJ_DIFF TPENB KILL)\n\n");
 
  sa02Printf ("-u value ... send test SEU software trigger \n");
 
  sa02Printf ("-z value ... finish the execution of the program in <value> s \n");
 
  sa02Printf ("-m fixeddata : test fixed data, if error occurs, abort \n");
 
  sa02Printf ("-l board mask   \n");
 
  sa02Printf ("*********************************************************************************:\n");
 
  sa02Printf ("Examples:\n\n");
 
  sa02Printf ("Threshold scan:\n");
 
 
 
  sa02Printf ("100 events TMON0 reading and 10 readings of the data for each event:\n");
 
  sa02Printf ("./sa02_ctrl  -a 0x32100000  -w TMON0 -n 100 -r 10 -t 10000 -v 1\n\n");
 
  sa02Printf ("scan 9 points TPLVL0 inital data 111 stepsize 11, send 1 test pulse, read data :\n");
 
  sa02Printf ("./sa02_ctrl  -a 0x32100000  -w TPLVL0 -d 111 -s 11 -n 9 -e 1 -r 1 -v 1\n\n");
 
  sa02Printf ("Initialize the board from input.param, Read 10000 events of data. the result is saved in the output.dat\n");
 
  sa02Printf ("./sa02_ctrl  -a 0x32100000  -i input.param -n 10000 -r 1 -o output.dat \n\n");
 
  sa02Printf ("Initialize the board from input.param, Read 10000 events of data. scan TPENB from 0 to 144 channels, send test pulse before the data acquisition,\n ");
 
  sa02Printf ("set TPENB to b after the acquisition, the result is saved in the output.dat\n");
 
  sa02Printf ("./sa02_ctrl  -a 0x32100000  -i input.param -p TPENB -d 1 -b 0 -s 1 -n 144 -c 0 -x 0 -e 1 -r 10000 -o output.dat \n\n");
 
  return 0;
 
}
 
 
 
void sa02PrintGREG(uint32_t *data, const char *txt) {
 
  sa02AsicGlobalRegister *a=(sa02AsicGlobalRegister *) data;
 
  sa02Printf("sa02PrintGREG %s 0x%08x\n",txt, *data);
 
  sa02Printf("phasecmps   =%d\n",a->phasecmps);
 
  sa02Printf("gain        =%d\n",a->gain);
 
  sa02Printf("shapingtime =%d\n",a->shapingtime);
 
  sa02Printf("comparator  =%d\n",a->comparator);
 
  sa02Printf("vrdrive     =%d\n",a->vrdrive);
 
  sa02Printf("monitor     =%d\n",a->monitor);
 
  sa02Printf("id          =%d\n",a->id);
 
  sa02Printf("unused      =0x%0x\n",a->unused);
 
};
 
 
 
void sa02PrintCREG(uint32_t *data, const char *txt) {
 
  sa02AsicChannelRegister *a=(sa02AsicChannelRegister *) data;
 
  sa02Printf("sa02PrintCREG %s 0x%08x\n",txt, *data);
 
  sa02Printf("decaytime     =%d\n",a->decaytime);
 
  sa02Printf("offset        =%d\n",a->offset);
 
  sa02Printf("fineadj_unipol=%d\n",a->fineadj_unipol);
 
  sa02Printf("fineadj_diff  =%d\n",a->fineadj_diff);
 
  sa02Printf("reserved      =%d\n",a->reserved);
 
  sa02Printf("tpenb         =%d\n",a->tpenb);
 
  sa02Printf("kill          =%d\n",a->kill);
 
  sa02Printf("unused      =0x%0x\n",a->unused);
 
};
 
 
 
int sa02MuxMap(int i ) {
 
 
 
  if (sa02BoardType > 1) return i;
 
  switch ( i ) {
 
    case 0:
 
      return 2;
 
    case 1:
 
      return 0;
 
    case 2:
 
      return 3;
 
    case 3:
 
      return 1;
 
  }
 
  return i;
 
};
 
 
 
#define ADC_VCC 3.3
 
#define AMP_IB_min -1.15e-6
 
#define ADC_IB_min 2355
 
#define AMP_IB_max 0.2e-6
 
#define ADC_IB_max 2665
 
 
 
double sa02ampIb(int adc) {
 
  if (adc <= ADC_IB_min) return AMP_IB_min;
 
  if (adc > ADC_IB_max) return AMP_IB_max;
 
  return AMP_IB_min + ((AMP_IB_max-AMP_IB_min)/(ADC_IB_max-ADC_IB_min)) * (adc - ADC_IB_min);
 
}
 
             
 
double sa02adc2V(int adc) {
 
  adc &=0xFFF;
 
  return ADC_VCC * (double)adc/4096;
 
}
 
 
 
double sa02adc2Vp(int adc) {
 
  adc &=0xFFF;
 
  return ADC_VCC * (double)adc/4096 + 1.0e+4 * sa02ampIb(adc);
 
}
 
 
 
double sa02adc2Vm(int adc) {
 
  adc &=0xFFF;
 
  return ADC_VCC * (2. * (double)adc/4096. - 1.) + 5.1e+4 * sa02ampIb(adc);
 
}
 
 
 
double sa02adc2V38(int adc) {
 
  adc &=0xFFF;
 
  return ADC_VCC * (2. * (double)adc/4096.) + 5.1e+4 * sa02ampIb(adc);
 
}
 
 
 
double sa02adc2Va(int adc) {
 
  adc &=0xFFF;
 
  return ADC_VCC * (double)adc/4096. - (ADC_VCC/2. + 0.06);
 
}
 
 
 
//-------------------------------------------------------------------------
 
 
 
uint32_t  sa02Write(uint32_t sa02BoardNumber, uint32_t regh, uint32_t regl, uint32_t *response)
 
 
 
{
 
  VME_A32D32_W(sa02Address+FEB_DATAOUT0+FEB_DATA_INC*sa02BoardNumber,regl);
 
  VME_A32D32_W(sa02Address+FEB_DATAOUT1+FEB_DATA_INC*sa02BoardNumber,regh);
 
  Delay(0.001);
 
  VME_A32D32_R(sa02Address+FEB_DATAIN0+FEB_DATA_INC*sa02BoardNumber,response);
 
  VME_A32D32_R(sa02Address+FEB_DATAIN1+FEB_DATA_INC*sa02BoardNumber,response+1);
 
 
 
  if (sa02Verbose>1) {
 
    sa02Printf("sa02Write board= %d 0x%08x  0x%08x  retval =0x%08X_%08X\n",  sa02BoardNumber, regh, regl, response[1], response[0]);
 
  }
 
 
 
 
 
  return response[0];
 
 
 
}
 
 
 
//-------------------------------------------------------------------------
 
int Sa02DaqMode (uint32_t mode) {
 
  VME_A32D32_W(sa02Address+FEB_DAQMODE,mode);
 
  return 0;
 
}
 
 
 
int Sa02SetPtsOutput(uint32_t mask) {
 
  VME_A32D32_W(sa02Address+FEB_DEBUGMON,mask);
 
  return 0;
 
}
 
 
 
int Sa02SetNeve (uint32_t neve) {
 
 
 
  VME_A32D32_W(sa02Address+FEB_SETNEVE,neve);
 
  return 0;
 
}
 
 
 
uint32_t Sa02GetNeve (uint32_t*inputtriggers) {
 
  uint32_t neve=0;
 
  VME_A32D32_R(sa02Address+FEB_GETNEVE,&neve);
 
  *inputtriggers = (neve >> 16)  &0xFFFF;
 
  return neve &0xFFFF;   // output triggers
 
}
 
 
 
uint32_t Sa02GetCounter (uint32_t board, uint32_t *errors) {
 
  uint32_t neve=0;
 
  VME_A32D32_R(sa02Address+FEB_CNTR+FEB_DATA_INC*board,&neve);
 
  *errors = (neve >> 16)  &0xFFFF;
 
  return neve &0xFFFF;
 
}
 
 
 
uint32_t Sa02GetChAddr (uint32_t board) {
 
  uint32_t neve=0;
 
  VME_A32D32_R(sa02Address+FEB_CHADDR+FEB_DATA_INC*board,&neve);
 
  return neve;
 
}
 
 
 
int sa02Reset1( void ) {
 
  uint32_t rdy=1;
 
 
 
  VME_A32D32_W(sa02Address+FEB_DATA_RST,rdy);
 
 
 
  return 0;
 
}
 
 
 
int Sa02SEUTrigger (void) {
 
  uint32_t rdy;
 
  rdy=1;
 
  VME_MWRST();
 
  VME_MW(VME_A32, VME_D32, sa02Address+FEB_SEUTRG,rdy);
 
  rdy=0;
 
  VME_MW(VME_A32, VME_D32, sa02Address+FEB_SEUTRG,rdy);
 
  VME_MWEXEC();
 
  return 0;
 
}
 
 
 
int Sa02SelectTrigger (uint32_t trg) {
 
  VME_A32D32_W(sa02Address+FEB_SELTRG,trg);
 
  return 0;
 
}
 
 
 
int Sa02SelectTriggerWithMaskAndLength (uint32_t trg, uint32_t mask, uint32_t len) {
 
  VME_A32D32_W(sa02Address+FEB_SELTRG, trg | (mask << 4) | (len << 16) );
 
  return 0;
 
}
 
 
 
int Sa02SoftwareTrigger (void ) {
 
  uint32_t rdy =1;
 
  VME_MWRST();
 
  VME_MW(VME_A32, VME_D32,sa02Address+FEB_SWTRG,rdy);
 
  VME_MWEXEC();
 
  return 0;
 
}
 
 
 
int Sa02TestPulseEnable (uint32_t board, uint32_t enable ) {
 
 
 
  uint32_t response[2]= {0,0};
 
  return sa02Cmd(board,FEB_TP, enable, 0, 0 ,1,response);
 
}
 
 
 
int sa02Reset( void ) {
 
  uint32_t rdy;
 
  rdy=1;
 
  VME_MWRST();
 
  VME_MW(VME_A32, VME_D32, sa02Address+FEB_DATA_RST,rdy);
 
  VME_MWEXEC();
 
  return 0;
 
}
 
 
 
 
 
int chaddr[1024];
 
int sa02Read(uint32_t mask,  uint32_t * data) {
 
  uint32_t rdy = 0, ready=0;
 
  int tout=1000; /* 1/100 of a second */
 
  int count=0;
 
  int k=0, j=0;
 
  int nb=0;
 
  int board;
 
  uint32_t neve;
 
  uint32_t c[4]= { 0,0,0,0} ,e[4]= { 0,0,0,0};
 
 
 
 
 
  sa02Tmlnk (tout);
 
  while (1) {
 
    VME_A32D32_R(  sa02Address+FEB_DATA_RDY,&rdy);
 
    if (rdy & (1<<12) )  break;
 
    count++;
 
 
 
    if (sa02TimerOut) {
 
      uint32_t trgin=0;
 
      uint32_t value=0;
 
      VME_A32D32_R(sa02Address+FEB_DEADBEEF, &value);
 
      sa02Printf("READ at FEB_DEADBEEF 0x%08x\n",  value);
 
      sa02Printf("[%d] rdy 0x%0x 0x%08x Waiting for DATA READY bit... at line %d\n",count, ready & 0x1, rdy ,  __LINE__);
 
      for (k=0; k<4; k++)  c[k] = Sa02GetCounter ( k ,&e[k]);
 
      for (k=0; k<4; k++)  sa02Printf("CNTR%d=%d (ERR=%d)\t",k,c[k],e[k]);
 
      nb = Sa02GetNeve (&trgin);
 
      sa02Printf("\tNeve=%d Input triggers %d\n", nb , trgin );
 
      sa02Tmulk();
 
      sa02Reset();
 
      return 0;
 
    }
 
  }
 
  sa02Tmulk();
 
 
 
 
 
 
 
  for (j=0; j<144*4; j++) data[j]=0;
 
  if (sa02BltReadout) {
 
    //int size=sizeof(uint32_t)*FEB_BLTDATA_STOP - FEB_BLTDATA_START ;
 
    //VME_A32D32BLT_READ(addr, data ,size ,&nb); // BLT RANGE 0x0-0xffc
 
    //nb = VME_A32D32BLT_R(addr+FEB_BLTDATA_START, data ,size);
 
    sa02Printf("VME_A32D32BLT_READ not implemented\n %s at line %d\n",__FILE__ ,  __LINE__);
 
 
 
  } else {
 
 
 
    
 
    for (board=0; board<4; board++) {
 
      VME_MRRST(); // MultiReadReset 
 
      for (j=0; j<144; j++) {
 
        if (mask & (1<<board)) {
 
          VME_MR(VME_A32, VME_D32,sa02Address+FEB_DATA  +FEB_DATA_INC*board,&data[j+144*board]);
 
        } else data[j+144*board]=0;
 
      }
 
      if ( (mask & (1<<board)) && VME_GetInterface()!= WIENER_VMEMM ) j = VME_MREXEC(&data[144*board]); // MultiReadExecute
 
 
 
    }
 
 
 
    
 
    /*
 
    for (i=0; i<j; i++)
 
 
 
      data[i]=((data[i]>>28)&0xF) |
 
              ((data[i]>>20)&0xF0) |
 
              ((data[i]>>12)&0xF00) |
 
              ((data[i]>>4)&0xF000) |
 
              ((data[i]&0xF000)<<4) |
 
              ((data[i]&0xF00)<<12) |
 
              ((data[i]&0xF0)<<20) |
 
              (data[i]&0xF)<<28;
 
    */
 
    /*
 
      for (i=0; i<j; i++)
 
        data[i]=(data[i]>>24)&0xFF |
 
                (data[i]>>8)&0xFF00 |
 
                (data[i]&0xFF00)<<8 |
 
                (data[i]&0xFF)<<24;
 
    */
 
    nb=j*board*sizeof(uint32_t);
 
 
 
  }
 
  if (sa02Verbose>0) sa02Printf("\tNeve=%d\tCNTR0=%d\tCNTR1=%d\tCNTR2=%d\tCNTR3=%d\n", Sa02GetNeve (&neve), Sa02GetCounter ( 0,&neve ),Sa02GetCounter ( 1 ,&neve),Sa02GetCounter ( 2 ,&neve),Sa02GetCounter ( 3,&neve ));
 
 
 
  if (sa02Verbose>1) {
 
    sa02Printf("sa02Read nb=%d\n",nb);
 
    for (j
=0; j
<144*4; j
++) printf("%d addr %d data=%d  data=0x%x\n", j
, chaddr
[j
], data
[j
],data
[j
] ) ;  
  }
 
  return nb;
 
}
 
 
 
//-------------------------------------------------------------------------
 
uint32_t  sa02Cmd(uint32_t board, uint32_t cmd, uint32_t data, int chip, int ch, int nload, uint32_t *response) {
 
  uint32_t datal=0, datah=0, datam, datac;
 
  uint32_t retval=0,val;
 
  int i;
 
 
 
  if (sa02Verbose>2) {
 
    sa02Printf("sa02Cmd board=%d cmd=0x%0x data=0x%0x asic=%d ch=%d \n", board, cmd, data, chip, ch);
 
  }
 
  switch (cmd & (~ FEB_RO)) {
 
    case FEB_VTH2:
 
    case FEB_VTH1:
 
    case FEB_TPLVL0:
 
    case FEB_TPLVL1:
 
      datah = cmd&0xFFFF0000;
 
      datal = ((cmd<<16)&0xFF0000)|(data&0x0FFF) ;
 
      for (i=0; i<nload; i++) retval = sa02Write(board,datah,datal,response);
 
      return retval;
 
      break;
 
    case FEB_DLY0:
 
    case FEB_TP:
 
    case FEB_ADC_RESET:
 
    case FEB_SEL_DATA:
 
    case FEB_SHFT_CLK:
 
    case FEB_SEND_CLK:
 
    case FEB_MUX:
 
      datah = cmd;
 
      datal = data&0xFFF ;
 
      for (i=0; i<2; i++) retval = sa02Write(board,datah,datal,response);
 
      return retval;
 
      break;
 
    case FEB_SERIAL:
 
    case FEB_TMON1:
 
    case FEB_TMON0:
 
      datah = cmd;
 
      datal = data&0xFFF ;
 
      for (i=0; i<nload; i++) retval = sa02Write(board,datah,datal,response);
 
      return retval;
 
      break;
 
    case FEB_ADC_READ:
 
      datah = cmd;
 
      datal = data&0xFFF ;
 
      val = sa02Write(board,datah,datal,response);
 
      for (i=0; i<10; i++) {
 
        retval=sa02Write(board,datah,datal,response);
 
        if (abs((val
&0xFFF)-(retval
&0xFFF))<3)  
          break;
 
        else
 
          val=retval;
 
      }
 
      return retval;
 
      break;
 
    case SA0x_ASIC0_CMON:
 
      data  = 36*chip+ch;
 
    case SA0x_ASIC0_CREG:
 
      if (sa02Verbose>4) {
 
        sa02PrintCREG(&data,"Loading creg data->");
 
      }
 
      datah = cmd + FEB_SUBA_INC*chip;
 
      datam = 0x3FFFF;
 
      datal = ((ch &0x3F )<< 18) | (data & datam );
 
      datac = datam;
 
      break;
 
    case SA0x_ASIC0_GREG:
 
      if (sa02Verbose>4) {
 
        sa02PrintGREG(&data,"Loading greg data->");
 
      }
 
      datah = cmd + FEB_SUBA_INC*chip;
 
      datam = 0x3FFFFFF;
 
      datal = data & datam;
 
      datac = 0x1FFFF; // greg->id (chip sn ,last 9 bits) is read only
 
      break;
 
    default:
 
      sa02Printf("sa02Cmd: Unknown command 0x%0x\n",cmd);
 
      return 0;
 
      break;
 
  }
 
  if ((sa02BoardType == 0) && (cmd & FEB_RO)) {
 
    sa02Printf("sa02Cmd: Readback-only with SA02 NOT possible! 0x%0X\n",cmd);
 
    return 0;
 
  }
 
  if (cmd == SA0x_ASIC0_CMON) {
 
    for (i=0; i<nload; i++) retval = sa02Write(board,datah,datal,response);
 
    return 0;
 
  }
 
  retval = sa02Write(board,datah,datal,response);
 
  if (cmd & FEB_RO) return retval;
 
  if (sa02BoardType) {
 
    datah |= FEB_RO;
 
    if (sa02Verbose>4)
 
          sa02Printf("SA03 read from 0x%x\n", datah );
 
  } else {
 
    if (sa02Verbose>4)
 
          sa02Printf("SA02 reload from 0x%x\n",datah);
 
  }
 
  for (i=0; i<5; i++) {
 
    response[0]=0;
 
    val = sa02Write(board,datah,datal,response);
 
    val = sa02Write(board,datah,datal,response);
 
    retval = sa02Write(board,datah,datal,response);
 
    if (val==retval) {
 
      retval &= datam;
 
      if ((retval & datac) == (data & datac)) return retval;
 
    }
 
    sa02Printf("SA0x parameter load attampt %d failed: %d\n",i,144*board+36*chip+ch);
 
    retval = sa02Write(board,datah&(~FEB_RO),datal,response);
 
  }
 
//  if (sa02Verbose>2) {
 
    switch (cmd) {
 
      case SA0x_ASIC0_GREG:
 
        sa02Printf("-----------------------------\n");
 
        sa02Printf("SA0x_ASIC0_GREG %d  %d 0x%04x 0x%04x chip,ch,read,write\n", chip ,0, retval & 0x1FFFF ,data & 0x3FFFFFF);
 
        sa02PrintGREG(&data,"Loaded GREG data->");
 
        sa02PrintGREG(&retval,"Returned GREG data->");
 
        break;
 
      case SA0x_ASIC0_CREG:
 
        sa02Printf("-----------------------------\n");
 
        sa02Printf("SA0x_ASIC0_CREG %d  %d 0x%04x 0x%04x chip,ch,read,write\n", chip ,ch,retval,data & 0x3FFFF);
 
        sa02PrintCREG(&data,"Loaded CREG data->");
 
        sa02PrintCREG(&retval,"Returned CREG data->");
 
        break;
 
    }
 
//  }
 
  return retval;
 
}
 
 
 
// 1 .read the content of the registers
 
// 2. modify the registers and
 
// 3. upload new values
 
int sa02AsicWrite(uint32_t board, uint32_t reg, uint32_t data, int chip, int ch, uint32_t mask,  uint32_t shft ) {
 
  uint32_t datar, datal;
 
  uint32_t response[2]= {0,0};
 
 
 
  if (sa02Verbose>3) {
 
    sa02Printf("-------------------------------------------------------\n");
 
    sa02Printf("sa02AsicWrite chip %d channel %d data %d mask 0x%0x\n", chip, ch,data,mask);
 
  }
 
  // read asic register
 
  datar = sa02Cmd(board,reg, data, chip, ch, 1 ,response); // load registers one time to get the previous value
 
  // modify asic register
 
  datar &= (~mask);
 
  datal = mask & (data << shft);
 
  datar |= datal;
 
  // write asic register
 
  return sa02Cmd(board,reg, datar, chip, ch ,2,response); // registers are loaded 2 times to get back the value
 
}
 
//-------------------------------------------------------------------------
 
uint32_t sa02GetCmdCode(char *optarg) {
 
  uint32_t cmd=0;
 
//    if (strcmp(optarg,"FE")==0)     cmd = FEB_FE;
 
    cmd = FEB_TP;
 
  }
 
  if (strcmp(optarg
,"SERIAL")==0) {  
    cmd = FEB_SERIAL;
 
  }
 
  if (strcmp(optarg
,"DLY0")==0) {  
    cmd = FEB_DLY0;
 
  }
 
  if (strcmp(optarg
,"MUX")==0) {  
    cmd = FEB_MUX;
 
  }
 
  if (strcmp(optarg
,"SELDATA")==0) {  
    cmd = FEB_SEL_DATA;
 
  }
 
  if (strcmp(optarg
,"SELMON")==0) {  
    cmd = FEB_SEL_MON;
 
  }
 
  if (strcmp(optarg
,"SHFTCLK")==0) {  
    cmd = FEB_SHFT_CLK;
 
  }
 
  if (strcmp(optarg
,"SENDCLK")==0) {  
    cmd = FEB_SEND_CLK;
 
  }
 
  if (strcmp(optarg
,"MUXASIC")==0) {  
    cmd = FEB_MUX;
 
  }
 
  if (strcmp(optarg
,"VTH2")==0) {  
    cmd = FEB_VTH2;
 
  }
 
  if (strcmp(optarg
,"VTH1")==0) {  
    cmd = FEB_VTH1;
 
  }
 
  if (strcmp(optarg
,"TPLVL0")==0) {  
    cmd = FEB_TPLVL0;
 
  }
 
  if (strcmp(optarg
,"TPLVL1")==0) {  
    cmd = FEB_TPLVL1;
 
  }
 
  if (strcmp(optarg
,"RGREG")==0) {  
    cmd = SA0x_ASIC0_GREG | FEB_RO;
 
  }
 
  if (strcmp(optarg
,"RCREG")==0) {  
    cmd = SA0x_ASIC0_CREG | FEB_RO;
 
  }
 
  if (strcmp(optarg
,"GREG")==0) {  
    cmd = SA0x_ASIC0_GREG;
 
  }
 
  if (strcmp(optarg
,"CREG")==0) {  
    cmd = SA0x_ASIC0_CREG;
 
  }
 
  if (strcmp(optarg
,"CMON")==0) {  
    cmd = SA0x_ASIC0_CMON;
 
  }
 
  if (strcmp(optarg
,"TMON0")==0) {  
    cmd = FEB_TMON0;
 
  }
 
  if (strcmp(optarg
,"TMON1")==0) {  
    cmd = FEB_TMON1;
 
  }
 
  if (strcmp(optarg
,"ADC_READ")==0) {  
    cmd = FEB_ADC_READ;
 
  }
 
  if (strcmp(optarg
,"ADC_RESET")==0) {  
    cmd = FEB_ADC_RESET;
 
  }
 
// if (strcmp(optarg,"DMON")==0)   cmd = FEB_DMON;
 
  return cmd;
 
}
 
//-------------------------------------------------------------------------
 
 
 
uint32_t sa02GetAsicCode(char *optarg, uint32_t *asicpar, uint32_t *asicshft) {
 
  uint32_t cmd=0;
 
  if (strcmp(optarg
,"PHASECMPS")==0) {  
    *asicpar  = ASIC_PHASECMPS;
 
    *asicshft = ASIC_PHASECMPS_SHFT;
 
    cmd  = SA0x_ASIC0_GREG;
 
  }
 
  if (strcmp(optarg
,"GAIN")==0) {  
    *asicpar  = ASIC_GAIN;
 
    *asicshft = ASIC_GAIN;
 
    cmd  = SA0x_ASIC0_GREG;
 
  }
 
  if (strcmp(optarg
,"SHAPINGTIME")==0) {  
    *asicpar  = ASIC_SHAPINGTIME;
 
    *asicshft = ASIC_SHAPINGTIME_SHFT;
 
    cmd  = SA0x_ASIC0_GREG;
 
  }
 
  if (strcmp(optarg
,"COMPARATOR")==0) {  
    *asicpar  = ASIC_COMPARATOR;
 
    *asicshft = ASIC_COMPARATOR_SHFT;
 
    cmd  = SA0x_ASIC0_GREG;
 
  }
 
  if (strcmp(optarg
,"VRDRIVE")==0) {  
    *asicpar  = ASIC_VRDRIVE;
 
    *asicshft = ASIC_VRDRIVE_SHFT;
 
    cmd  = SA0x_ASIC0_GREG;
 
  }
 
  if (strcmp(optarg
,"MONITOR")==0) {  
    *asicpar  = ASIC_MONITOR;
 
    *asicshft = ASIC_MONITOR_SHFT;
 
    cmd  = SA0x_ASIC0_GREG;
 
  }
 
    *asicpar = ASIC_ID;
 
    *asicshft =ASIC_ID_SHFT;
 
    cmd  = SA0x_ASIC0_GREG;
 
  }
 
  if (strcmp(optarg
,"DECAYTIME")==0) {  
    *asicpar = ASIC_DECAYTIME;
 
    *asicshft =ASIC_DECAYTIME_SHFT;
 
    cmd  = SA0x_ASIC0_CREG;
 
  }
 
  if (strcmp(optarg
,"OFFSET")==0) {  
    *asicpar = ASIC_OFFSET;
 
    *asicshft =ASIC_OFFSET_SHFT;
 
    cmd  = SA0x_ASIC0_CREG;
 
  }
 
  if (strcmp(optarg
,"FINEADJ_UNIPOL")==0) {  
    *asicpar = ASIC_FINEADJ_UNIPOL;
 
    *asicshft =ASIC_FINEADJ_UNIPOL_SHFT;
 
    cmd  = SA0x_ASIC0_CREG;
 
  }
 
  if (strcmp(optarg
,"FINEADJ_DIFF")==0) {  
    *asicpar = ASIC_FINEADJ_DIFF;
 
    *asicshft =ASIC_FINEADJ_DIFF_SHFT;
 
    cmd  = SA0x_ASIC0_CREG;
 
  }
 
  if (strcmp(optarg
,"TPENB")==0) {  
    *asicpar = ASIC_TPENDB;
 
    *asicshft =ASIC_TPENDB_SHFT;
 
    cmd  = SA0x_ASIC0_CREG;
 
  }
 
  if (strcmp(optarg
,"KILL")==0) {  
    *asicpar  = ASIC_KILL;
 
    *asicshft =ASIC_KILL_SHFT;
 
    cmd  = SA0x_ASIC0_CREG;
 
  }
 
  return cmd;
 
}
 
 
 
//-------------------------------------------------------------------------
 
int sa02Init( void ) {
 
  sa02Printf ("sa02Init not implemeted yet\n");
 
  return 0;
 
}
 
 
 
//-------------------------------------------------------------------------
 
int sa02LoadParametersFromFile( const char *fname, uint16_t mask) {
 
  uint32_t gdata;
 
  uint32_t cdata;
 
  uint32_t board=0;
 
 
 
  sa02AsicGlobalRegister  *greg = (sa02AsicGlobalRegister  *) &gdata ;
 
  sa02AsicChannelRegister *creg = (sa02AsicChannelRegister *) &cdata ;
 
#define NDIM 400
 
  int ndim=NDIM;
 
  char line[NDIM];
 
  char cmd[NDIM];
 
  char sasic[NDIM];
 
  char v0[NDIM];
 
  char v1[NDIM];
 
  int asic=0, ch=0;
 
  int gval=0, cval=0;
 
  int dum=0;
 
  int b=0;
 
  uint32_t sa02code;
 
  uint32_t response[2]= {0,0};
 
 
 
  FILE 
*fp 
= fopen(fname
,"r"); 
  if (!fp) {
 
    sa02Printf("Error! Cannot open file %s\n",fname);
 
    return -1;
 
  }
 
  gdata=0;
 
  cdata=0;
 
 
 
  while (fgets(line
,ndim
,fp
)!=NULL
) {  
    int nb 
= sscanf(line
,"%s%s%s%s",cmd
,sasic
,v0
,v1
);  
    if (nb<1 || cmd[0]=='#') {
 
      continue;
 
    }
 
    if (sa02Verbose>2) {
 
      sa02Printf("%d %s",nb,line);
 
    }
 
    sa02code = sa02GetCmdCode(cmd);
 
    if (strcmp(cmd
,"MUXASIC")==0) {  
      asic = sa02MuxMap(asic);
 
    }
 
        
 
        
 
        
 
    
 
    switch (nb) {
 
      case 1: {
 
        if ( sa02code ) {
 
          for (b=0;b<4;b++) if (mask &(1<<b)) {
 
              sa02Cmd(b,sa02code, dum, dum, dum ,2,response);
 
            }    
 
          break;
 
        }
 
          sa02Init();
 
          break;
 
        }
 
        break;
 
      }
 
      case 2: {
 
        if ( sa02code ) {
 
          for (b=0;b<4;b++) if (mask &(1<<b)) {
 
              sa02Cmd(b,sa02code, asic, dum, dum, 2,response);
 
            }    
 
          break;
 
        }
 
        if (strcmp(cmd
,"param_board")==0) {  
          if (asic != board){
 
            if ( mask &(1<<asic)) sa02Printf("Parameters for board=%d (mask=0x%x) will be loaded\n",asic,mask );
 
            else sa02Printf("Parameters for board=%d (mask=0x%x) will not be loaded\n",asic,mask ); 
 
          }  
 
          board = asic;
 
          
 
                  
 
          break;
 
        }
 
        if (strcmp(cmd
,"load_global")==0) {  
          if (mask &(1<<board)) sa02Cmd(board,SA0x_ASIC0_GREG, gdata, asic, ch,1,response);
 
          break;
 
        }
 
          sa02Printf ("%s not implemeted yet\n",cmd);
 
          break;
 
        }
 
        if (strcmp(cmd
,"hdcycle")==0) {  
          sa02Printf ("%s not implemeted yet\n",cmd);
 
          break;
 
        }
 
        if (strcmp(cmd
,"trgdelay")==0) {  
          sa02Printf ("%s not implemeted yet\n",cmd);
 
          break;
 
        }
 
        break;
 
      }
 
      case 3: {
 
        if ( sa02code) {
 
          sa02Cmd(board,sa02code, gval, asic, dum, 2,response);
 
          break;
 
        }
 
        if (strcmp(cmd
,"param_global")==0) {  
          gdata = 0;
 
          break;
 
        }
 
        if (strcmp(cmd
,"phasecmps")==0) {  
          greg->phasecmps = gval;
 
          break;
 
        }
 
          greg->gain = gval;
 
          break;
 
        }
 
        if (strcmp(cmd
,"shapingtime")==0) {  
          greg->shapingtime = gval;
 
          break;
 
        }
 
        if (strcmp(cmd
,"comparator")==0) {  
          greg->comparator = gval;
 
          break;
 
        }
 
        if (strcmp(cmd
,"vrdrive")==0) {  
          greg->vrdrive = gval;
 
          break;
 
        }
 
        if (strcmp(cmd
,"monitor")==0) {  
          greg->monitor = gval;
 
          break;
 
        }
 
        if (strcmp(cmd
,"load_ch")==0) {  
          //        if (sa02Verbose>2) sa02PrintCREG((uint32_t *)creg);
 
          if (mask &(1<<board)) sa02Cmd(board,SA0x_ASIC0_CREG, cdata, asic, ch,1,response);
 
          cdata=0;
 
          break;
 
        }
 
        if (strcmp(cmd
,"select")==0) {  
          sa02Printf ("%s not implemeted yet\n", cmd);
 
          break;
 
        }
 
        break;
 
      }
 
      case 4: {
 
        if (strcmp(cmd
,"param_ch")==0) {  
          cdata = 0;
 
          break;
 
        }
 
        if (strcmp(cmd
,"decaytime")==0) {  
          creg->decaytime = cval;
 
          break;
 
        }
 
        if (strcmp(cmd
,"offset")==0) {  
          creg->offset = cval;
 
          break;
 
        }
 
        if (strcmp(cmd
,"fineadj_unipol")==0) {  
          creg->fineadj_unipol = cval;
 
          break;
 
        }
 
        if (strcmp(cmd
,"fineadj_diff")==0) {  
          creg->fineadj_diff   = cval;
 
          break;
 
        }
 
          creg->tpenb = cval;
 
          break;
 
        }
 
          creg->kill  = cval;
 
          break;
 
        }
 
        break;
 
      }
 
    }
 
 
 
  }
 
  sa02Printf("Parameters loaded from file %s to FEBs\n", fname);
 
  return 0;
 
}
 
 
 
//-------------------------------------------------------------------------
 
 
 
int sa02GetSerial( uint32_t board, char * serial) {
 
  uint32_t cmd,response[2]= {0,0};
 
 
 
  cmd=FEB_SERIAL;
 
  sa02Cmd(board,cmd,0,0,0,1,response);
 
  sprintf(serial
,"0x%07X%08X",0x1FFFFFF & response
[1],response
[0]);  
  return 0;
 
}
 
 
 
//-------------------------------------------------------------------------
 
 
 
int sa02Status( uint32_t board, char * serial, double *sdata) {
 
  uint32_t val,data,cmd,response[2]= {0,0};
 
  int chip,channel,i=0;
 
  double doubleval;
 
 
 
 
 
  chip=0;
 
  channel=0;
 
  data=0;
 
 
 
  sa02Printf("FEB SlowControl data:\n");
 
 
 
  VME_A32D32_R(sa02Address+FEB_DEADBEEF, &val);
 
  sa02Printf("READ at FEB_DEADBEEF 0x%08x\n",  val);
 
 
 
  sa02GetSerial(board, serial);
 
  sa02Printf("SERIAL FPGA = %s \n", serial);
 
 
 
  cmd=FEB_TMON0;
 
  val=sa02Cmd(board, cmd, data, chip, channel ,1,response);
 
  doubleval = ( (val >>2 ) & 0xFFF ) * 0.0625;
 
  sa02Printf("TMON0 = %5.1f C\n",doubleval);
 
  sdata[i++]=doubleval;
 
 
 
  cmd=FEB_TMON1;
 
  val=sa02Cmd(board, cmd, data, chip, channel ,1,response);
 
  doubleval = ( (val >>2 ) & 0xFFF ) * 0.0625;
 
  sa02Printf("TMON1 = %5.1f C\n",doubleval);
 
  sdata[i++]=doubleval;
 
 
 
  if (sa02BoardType<2) return 0;
 
 
 
  cmd=FEB_MUX;
 
  data=0x10;
 
  val=sa02Cmd(board, cmd, data, chip, channel ,1,response);
 
  Delay(0.01);
 
  cmd=FEB_ADC_READ;
 
  val=sa02Cmd(board, cmd, data, chip, channel ,1,response);
 
  doubleval = sa02adc2Vp(val);
 
  sa02Printf("VDD   = %6.3f V\n",doubleval);
 
  sdata[i++]=doubleval;
 
 
 
  cmd=FEB_MUX;
 
  data=0x11;
 
  val=sa02Cmd(board, cmd, data, chip, channel ,1,response);
 
  Delay(0.01);
 
  cmd=FEB_ADC_READ;
 
  val=sa02Cmd(board, cmd, data, chip, channel ,1,response);
 
  doubleval = sa02adc2Vp(val);
 
  sa02Printf("V+2   = %6.3f V\n",doubleval);
 
  sdata[i++]=doubleval;
 
 
 
  cmd=FEB_MUX;
 
  data=0x12;
 
  val=sa02Cmd(board, cmd, data, chip, channel ,1,response);
 
  Delay(0.01);
 
  cmd=FEB_ADC_READ;
 
  val=sa02Cmd(board, cmd, data, chip, channel ,1,response);
 
  doubleval = sa02adc2Vm(val);
 
  sa02Printf("V-2   = %6.3f V\n",doubleval);
 
  sdata[i++]=doubleval;
 
 
 
 
 
  cmd=FEB_MUX;
 
  data=0x13;
 
  val=sa02Cmd(board, cmd, data, chip, channel ,1,response);
 
  Delay(0.01);
 
  cmd=FEB_ADC_READ;
 
  val=sa02Cmd(board, cmd, data, chip, channel ,1,response);
 
  doubleval = sa02adc2Vm(val);
 
  sa02Printf("VSS   = %6.3f V\n",doubleval);
 
  sdata[i++]=doubleval;
 
 
 
  cmd=FEB_MUX;
 
  data=0x20;
 
  val=sa02Cmd(board, cmd, data, chip, channel ,1,response);
 
  Delay(0.01);
 
  cmd=FEB_ADC_READ;
 
  val=sa02Cmd(board, cmd, data, chip, channel ,1,response);
 
  if (sa02BoardType>2)
 
    doubleval = sa02adc2Vm(val);
 
  else
 
    doubleval = sa02adc2V(val);
 
  sa02Printf("VTH1  = %6.3f V\n",doubleval);
 
  sdata[i++]=doubleval;
 
 
 
  cmd=FEB_MUX;
 
  data=0x30;
 
  val=sa02Cmd(board, cmd, data, chip, channel ,1,response);
 
  Delay(0.01);
 
  cmd=FEB_ADC_READ;
 
  val=sa02Cmd(board, cmd, data, chip, channel ,1,response);
 
  if (sa02BoardType>2)
 
    doubleval = sa02adc2Vm(val);
 
  else
 
    doubleval = sa02adc2V(val);
 
  sa02Printf("VTH2  = %6.3f V\n",doubleval);
 
  sdata[i++]=doubleval;
 
 
 
  cmd=FEB_MUX;
 
  data=0x40;
 
  val=sa02Cmd(board, cmd, data, chip, channel ,1,response);
 
  Delay(0.01);
 
  cmd=FEB_ADC_READ;
 
  val=sa02Cmd(board, cmd, data, chip, channel ,1,response);
 
  doubleval = sa02adc2Vp(val);
 
  sa02Printf("VCC12 = %6.3f V\n",doubleval);
 
  sdata[i++]=doubleval;
 
 
 
  cmd=FEB_MUX;
 
  data=0x50;
 
  val=sa02Cmd(board, cmd, data, chip, channel ,1,response);
 
  Delay(0.01);
 
  cmd=FEB_ADC_READ;
 
  val=sa02Cmd(board, cmd, data, chip, channel ,1,response);
 
  doubleval = sa02adc2Vp(val);
 
  sa02Printf("VCC15 = %6.3f V\n",doubleval);
 
  sdata[i++]=doubleval;
 
 
 
  cmd=FEB_MUX;
 
  data=0x60;
 
  val=sa02Cmd(board, cmd, data, chip, channel ,1,response);
 
  Delay(0.01);
 
  cmd=FEB_ADC_READ;
 
  val=sa02Cmd(board, cmd, data, chip, channel ,1,response);
 
  doubleval = sa02adc2Vp(val);
 
  sa02Printf("VCC25 = %6.3f V\n",doubleval);
 
  sdata[i++]=doubleval;
 
 
 
  cmd=FEB_MUX;
 
  data=0x70;
 
  val=sa02Cmd(board, cmd, data, chip, channel ,1,response);
 
  Delay(0.01);
 
  cmd=FEB_ADC_READ;
 
  val=sa02Cmd(board, cmd, data, chip, channel ,1,response);
 
  doubleval = sa02adc2V38(val);
 
  sa02Printf("V+3.8 = %6.3f V\n",doubleval);
 
  sdata[i++]=doubleval;
 
 
 
  cmd=FEB_MUX;
 
  data=0x00;
 
  val=sa02Cmd(board, cmd, data, chip, channel ,1,response);
 
 
 
  return 0;
 
}