Subversion Repositories f9daq

Rev

Rev 326 | Blame | Compare with Previous | Last modification | View Log | RSS feed

#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;
  if (strcmp(optarg,"TP")==0) {
    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;
  }
  if (strcmp(optarg,"ID")==0) {
    *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;
    }
    asic =   strtoul (sasic,NULL,0);
    ch   =   strtoul (v0,NULL,0);
    gval =   strtoul (v0,NULL,0);
    cval =   strtoul (v1,NULL,0);
    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;
        }
        if (strcmp(cmd,"init")==0) {
          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;
        }
        if (strcmp(cmd,"csr1")==0) {
          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;
        }
        if (strcmp(cmd,"gain")     ==0) {
          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;
        }
        if (strcmp(cmd,"tpenb")==0) {
          creg->tpenb = cval;
          break;
        }
        if (strcmp(cmd,"kill")==0) {
          creg->kill  = cval;
          break;
        }
        break;
      }
    }

  }
  fclose(fp);
  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;
}