//
 
//  test.c
 
//  
 
//  Description : test program for V729
 
//
 
//  Author : S. Korpar
 
//  Date   : 2005/07/15
 
// adapted to CAEN V1719 by R. Pestotnik  2012/09/07
 
 
 
#include <stdlib.h>
 
#include <stdio.h>
 
#include <string.h>
 
#include <unistd.h>
 
#include <ctype.h>
 
 
 
#include <vector>
 
#include <sys/time.h>
 
#include <sys/stat.h>
 
#include <signal.h>
 
#include <string>
 
#include "vme.h"
 
#include "CAEN_V729_DEF.h"
 
 
 
#define V729_OFFSET 0x880000
 
#define IREG_OFFSET 0x2000
 
#define V729_WAIT 1
 
 
 
 
 
#define TRUE 1
 
#define FALSE 0
 
 
 
uint32_t V729_module=0;
 
 
 
 
 
int timer_out;
 
struct sigaction oact;
 
 
 
//---------------------------------------------------------
 
void SigInt (int sig)
 
{
 
 
 
    timer_out=1;
 
}
 
 
 
//---------------------------------------------------------
 
void timerast (int signumber)
 
{
 
    timer_out = TRUE;
 
}
 
 
 
//---------------------------------------------------------
 
void tmlnk (int tout)
 
{
 
    timer_out = FALSE;
 
    struct sigaction act;
 
    struct itimerval tdelay;
 
 
 
    act.sa_handler = timerast;
 
    sigemptyset (&act.sa_mask);
 
    act.sa_flags = 0;
 
 
 
    tdelay.it_value.tv_sec = tout / 100;
 
    tdelay.it_value.tv_usec = 10000 * (tout % 100);
 
    tdelay.it_interval.tv_sec = 0;
 
    tdelay.it_interval.tv_usec = 0;
 
 
 
    if (sigaction (SIGALRM, &act, &oact) < 0)
 
    {
 
    }
 
    if (setitimer (ITIMER_REAL, &tdelay, NULL) < 0)
 
    {
 
    }
 
}
 
 
 
//---------------------------------------------------------
 
void tmulk ()
 
{
 
    struct itimerval tdelay;
 
 
 
    tdelay.it_value.tv_sec = 0;
 
    tdelay.it_value.tv_usec = 0;
 
    tdelay.it_interval.tv_sec = 0;
 
    tdelay.it_interval.tv_usec = 0;
 
 
 
    if (setitimer (ITIMER_REAL, &tdelay, NULL) < 0)
 
    {
 
    }
 
    if (sigaction (SIGALRM, &oact, NULL) < 0)
 
    {
 
    }
 
}
 
 
 
//---------------------------------------------------------
 
int wait_while(int num){
 
  int i, tmp;
 
 
 
  for ( i =0; i <num; i++ ) tmp = 0;
 
  return tmp;
 
}
 
 
 
//---------------------------------------------------------
 
void V729_map( uint32_t addr)
 
{
 
  V729_module = addr;
 
  return;
 
}
 
 
 
//---------------------------------------------------------
 
void V729_info(FILE *kam)
 
{
 
  unsigned short code, mid, ver;
 
 
 
  
 
  VME_A24D16_R(V729_module+0xFA,&code);
 
  VME_A24D16_R(V729_module+0xFC,&mid);
 
  VME_A24D16_R(V729_module+0xFE,&ver);
 
  fprintf(kam
, "code/mid/ver = 0x%04X/0x%04X/0x%04X\n", code
, mid
, ver
);   
  fprintf(kam
, "Fixed code (0xFAF5) = 0x%04X\n", code
);   
  fprintf(kam
, "Manufacturer/Type = 0x%02X/0x%03X\n",  
         (mid & 0xFC00)>>10, mid & 0x3FF); 
 
  fprintf(kam
, "Version/Serial = %d/%d\n",  
         (ver & 0xF000)>>12, ver & 0xFFF); 
 
  return;
 
}
 
 
 
 
 
//---------------------------------------------------------
 
void V729_reg( uint32_t val){
 
 uint32_t push=0; 
 
 
 
 VME_A24D16_W(V729_module+V729_FSR, &val);
 
 VME_A24D16_W(V729_module+V729_UFSR, &push); //push
 
 usleep(V729_WAIT);
 
 
 
}
 
 
 
 
 
//---------------------------------------------------------
 
void V729_reset(int nall,int nbefore,int obae,int obaf)
 
{
 
  uint32_t cbl;
 
 
 
//  cbl=4096+12-100;
 
  cbl=4096+12-nbefore;
 
  uint32_t val=0;
 
  VME_A24D16_W(V729_module+V729_RR, &val); // reset
 
  printf("nbefore=%d\t", nbefore
);  
  
 
// set AE
 
  V729_reg( (obae & 0xFF)<<8 ) ; //
 
  V729_reg( (obae & 0xF00) ) ; //
 
 
 
  
 
// set AF and CBL
 
  V729_reg( ((obaf & 0xFF)<<8) + (cbl & 0xFF)   ); 
 
  V729_reg( (obaf & 0xF00) + ((cbl & 0xF00)>>8) ); 
 
  
 
 
 
 
 
 VME_A24D16_W(V729_module+V729_SR,&nall); //total number of samples
 
 
 
  return;
 
}
 
//---------------------------------------------------------
 
 
 
void V729_set_bias(int range, int bias1, int bias2)
 
{
 
    int i;
 
    uint32_t bias;
 
 
 
    switch (range) {
 
        case 0: //User
 
            for (i=0x18;i<0x27;i+=4){
 
                VME_A24D16_W(V729_module+i, &bias1); //bias
 
                usleep(V729_WAIT);
 
                VME_A24D16_W(V729_module+i+2, &bias2); //bias
 
                usleep(V729_WAIT);
 
            }
 
            printf("Bias + %x  - %x\n", bias1
, bias2
);  
            break;
 
        case 1: //Single Ended +
 
            for (i=0x18;i<0x27;i+=4){
 
                bias = 0xCC; VME_A24D16_W(V729_module+i, &bias); //bias
 
                usleep(V729_WAIT);
 
                bias =0x733; VME_A24D16_W(V729_module+i+2, &bias); //bias
 
                usleep(V729_WAIT);
 
            }
 
            break;
 
        case 2: //Single Ended -
 
            for (i=0x18;i<0x27;i+=4){
 
                bias =0x733; VME_A24D16_W(V729_module+i, &bias); //bias
 
                usleep(V729_WAIT);
 
                bias= 0xD99 ; VME_A24D16_W(V729_module+i+2, &bias); //bias
 
                usleep(V729_WAIT);
 
            }
 
            break;
 
        case 4: //Differential Unipolar
 
            for (i=0x18;i<0x27;i+=4){
 
                bias = 0x400; VME_A24D16_W(V729_module+i,&bias); //bias
 
                usleep(V729_WAIT);
 
                bias = 0xA66; VME_A24D16_W(V729_module+i+2, &bias); //bias
 
                usleep(V729_WAIT);
 
            }
 
            break;
 
        case 3: //Single Ended Bipolar
 
        case 5: //Differential Bipolar
 
        default:
 
            for (i=0x18;i<0x27;i+=2){
 
                bias=0x733; VME_A24D16_W(V729_module+i, &bias); //bias
 
                usleep(V729_WAIT);
 
            }
 
            break;
 
    }
 
    return;
 
}
 
 
 
//---------------------------------------------------------
 
void V729_aquisition_mode(uint32_t mode) // mode 0 aqusition mode, 0x30 buffers programming
 
{
 
#ifdef V729_DEBUG
 
  int status;
 
  VME_A24D16_R(V729_module+V729_CSR, &status);
 
  usleep(V729_WAIT);
 
  fprintf(stderr
, "0x0E = 0x%04X\n", status
);  
#endif
 
  
 
  VME_A24D16_W(V729_module+V729_CSR, &mode); //aquisition mode
 
  usleep(V729_WAIT);
 
#ifdef V729_DEBUG
 
  VME_A24D16_W(V729_module+V729_CSR, &status);
 
  usleep(V729_WAIT);
 
  fprintf(stderr
, "0x0E = 0x%04X\n", status
);  
#endif
 
  return;
 
}
 
 
 
//---------------------------------------------------------
 
void V729_soft_stop()
 
{
 
  uint32_t sw=1;
 
  VME_A24D16_W(V729_module+0x16,&sw);
 
//  usleep(V729_WAIT);
 
  sw =0;
 
  VME_A24D16_W(V729_module+0x16,&sw);
 
//  usleep(V729_WAIT);
 
  return;
 
}
 
 
 
//---------------------------------------------------------
 
void V729_clear_buffer()
 
{
 
    const int tout=100; /* 1/100 of a second */
 
    tmlnk (tout);
 
    uint32_t data1,data2;
 
    do {
 
        VME_A24D32_R(V729_module+V729_OBR1, &data1);
 
        if (timer_out) break;
 
    } while (data1 & (0x3<<29));
 
 
 
    do {
 
        VME_A24D32_R(V729_module+V729_OBR2, &data2);
 
        if (timer_out) break;
 
    } while (data2 & (0x3<<29));
 
 
 
    tmulk();
 
    return;
 
}
 
 
 
void V729_get_buffer(uint32_t *data1, uint32_t *data2)
 
{
 
    VME_A24D32_R(V729_module+V729_OBR1, data1);
 
//    usleep(V729_WAIT);
 
    VME_A24D32_R(V729_module+V729_OBR2, data2);
 
//    usleep(V729_WAIT);
 
    return;
 
}
 
int V729_status()
 
{
 
  uint32_t status;
 
  VME_A24D16_R(V729_module+V729_CSR, &status);
 
  return status;
 
}
 
 
 
 
 
//---------------------------------------------------------
 
void V729_init(uint32_t addr, int nall, int cbl, uint32_t bias1, uint32_t bias2){
 
  V729_map(addr);
 
  V729_info(stderr);
 
  V729_reset(nall,cbl,nall,0xC00);
 
  V729_set_bias(0,bias1,bias2);
 
  V729_aquisition_mode(0);
 
CAENVME_SetFIFOMode(udev,1);
 
  sleep(1);
 
}
 
 
 
 
 
//---------------------------------------------------------
 
int V729_event(int mask, int nall, uint32_t *data,uint32_t *data1,uint32_t *data2){
 
  uint32_t status;
 
  const int tout=100; /* 1/100 of a second */
 
  tmlnk (tout);
 
  int count=0;
 
 
 
  //status= 0x80 ; VME_A16D16_W(IREG_OFFSET+0x8,&status); // pulse ch 8
 
  
 
  status = 0x1a ; VME_A16D16_W(IREG_OFFSET+0xC,&status); // clr1 enable1  .... clear busy1 flag 
 
  do {
 
      //usleep(1);
 
      VME_A24D16_R(V729_module+V729_CSR, &status);
 
//    fprintf(stderr,"0x%X, 0x%X\n",status,(status & 0x5) ^ 0x5);
 
    count++;
 
    if (timer_out) {
 
       tmulk ();
 
       printf("[%d] daq=%x status AE01=%d AE23=%d Waiting for DATA TRG bit... at line %d\n",count 
, (status
>>4)&0x3, status
&0x1,(status
>>2)&0x1 , __LINE__
);  
       
 
       V729_clear_buffer();
 
       
 
       return -1;
 
    }
 
  } while ((status & 0x5) ^ 0x5);
 
  tmulk ();
 
 
 
  
 
  int nb;
 
  const int blt=1;
 
  if (blt){
 
  
 
  VME_A24D32_FIFOBLTR(V729_module+V729_OBR1,data1,(nall+5)*sizeof(uint32_t),&nb);
 
  VME_A24D32_FIFOBLTR(V729_module+V729_OBR2,data2,(nall+5)*sizeof(uint32_t),&nb);
 
  for (int i=0;i<nall+5;i++){
 
    data[2*i]   = data1[i];
 
    data[2*i+1] = data2[i];
 
  }
 
  nb*=2;
 
  } else {
 
 
 
 
 
  VME_MRRST(); // MultiReadReset
 
  int nc=0;
 
  for (int i=0;i<nall+5;i++){
 
    //if (mask & 0x3)
 
    VME_A24D32_MR(V729_module+V729_OBR1, &data[nc++]);
 
    //if (mask & 0xc) 
 
    VME_A24D32_MR(V729_module+V729_OBR2, &data[nc++]);
 
  }
 
  int j = VME_MREXEC(data); // MultiReadExecute
 
  nb=j*sizeof(uint32_t);
 
 
 
  }
 
 
 
  return nb;
 
}
 
 
 
//---------------------------------------------------------
 
int V729_decode(uint32_t mask, int nall, uint32_t *data,  uint16_t *dadc, int debug){
 
  uint16_t *adc[4];
 
  for (int i=0;i<4;i++) adc[i] = &dadc[4+i*(nall+2)];
 
  
 
  int nc=0;
 
  int narrays=0;
 
  if (mask & 0x3) narrays++;
 
  if (mask & 0xc) narrays++;
 
 
 
  int indx[4] ={0,0,0,0};
 
  int shft[4] ={0,0,0,0};
 
  int ashft[4]={0,0,0,0};
 
  int nmask=0;
 
 
 
  for (int i=0;i<4;i++) if (mask & (1<<i) ) {
 
    indx[nmask] = i;
 
    shft[nmask] = (i%2)*12;
 
    if (( (mask & 0x3) > 0 ) && (i>1))  ashft[nmask]=1  ;
 
    else ashft[nmask]=0;
 
    nmask++;
 
  }
 
  for (int j=0;j<nmask;j++){ 
 
    nc=0;
 
    for (int i=0;i<nall+5;i++){
 
      int ii=narrays*i+ashft[j];
 
      
 
      uint32_t data1 = data[ii];
 
      
 
      if (data1 & (1<<31)) {
 
        if (debug
) fprintf(stdout
,"data1: empty flags: 0x%X, time tag: 0x%06X\n", (data1
>>29) & 0x3, data1 
& 0xFFFFFF);  
      } else if ((data1>>29) & 0x3){
 
        if (nc<nall){ 
 
          adc[j][nc] = (data1>>shft[j]) & 0xFFF;
 
          if (debug
) printf("[%d/%d] ADC%d adc0=%d\n", i
,nc
,indx
[j
], adc
[j
][nc
]);  
          nc++;
 
        }
 
 
 
      } else {
 
        if (debug
) fprintf(stdout
,"Data(%4d) %d indx=%d %d nc=%d(%d) %d 0x%08X\n", i
, indx
[j
],narrays
*i
+ashft
[j
],j
,nc
,nmask
,narrays
, data1
);  
      }
 
    }
 
  }
 
  return nc;
 
}
 
//---------------------------------------------------------
 
 
 
// test program
 
#ifdef V729_MAIN
 
int ctrlc=0;
 
 
 
void CatchSig (int i){
 
    ctrlc = 1;
 
}
 
 
 
 
 
int main(int argc,char **argv){
 
 
 
   if (argc == 1) {
 
    
 
    printf ("*********************************************************************************:\n");  
    printf ("Usage: %s <arguments> .........   CAEN V729A data aquisition:\n\n", argv
[0]);  
    printf ("-d <debuglevel>  \n");  
    printf ("-a <VME address>  \n");  
    printf ("-c <n samples before stop>  \n");  
    printf ("-n <number of events> \n");  
    printf ("-l <nall> number of samples \n");  
    printf ("-m <channel mask: 4bits (1 bit/ch)> \n");  
    printf ("-o <output file name> \n");  
 
 
    printf ("*********************************************************************************:\n");  
  }
 
 
 
  uint32_t mask=0xF;
 
  int  cbl=13; 
 
  int nall=1330;
 
  char filename[0xFF]="";
 
  int verbose = 0;
 
  int neve    = 1;
 
  uint32_t addr= V729_OFFSET;
 
  uint32_t bias1 = 0x600; // vecje vrednosti povzročajo težave in zacno kanali oscilirat ....
 
  uint32_t bias2 = 0x200;
 
  int append=0;
 
  int c=0;
 
  while ((c = getopt (argc, argv, "b:e:a:d:c:l:n:o:m:f:")) != -1)
 
    switch (c){
 
      case 'd':
 
        break;
 
      case 'c':
 
        break;
 
      case 'l':
 
       
 
        if (nall%16) {
 
          printf ("buffer length should be multiple of 16 , modulo = %d\n",nall
%16);  
         // exit(-1);
 
        }
 
        break;     
 
      case 'n':
 
        break;   
 
      case 'a':
 
        break;             // address
 
      case 'b':
 
        break;             // bias
 
      case 'e':
 
        break;             // bias
 
 
 
      case 'm':
 
        break;             // mask 
 
      case 'o':
 
        append=0;
 
        break;       // output
 
      case 'f':
 
        append=1;
 
        break;       // output
 
    }
 
 
 
// intercept routine
 
  if (signal 
(SIGINT
, CatchSig
) == SIG_ERR
)  perror ("sigignore");  
 
 
  
 
  // reset timers
 
  time_t t,told=0, tstart;
 
  tstart=t;
 
 
 
  // open file
 
  FILE *fp=NULL;
 
  int output=0;
 
    if (verbose
) printf("Data in the file:%s\n", filename
);  
    if (append
) fp
=fopen(filename
,"a");  
    else        fp
=fopen(filename
,"w");  
    output=1;
 
  }
 
 
 
  // alloocate storage
 
  uint32_t *data = new uint32_t[2*(nall+5)];
 
  uint32_t *data1 = new uint32_t[2*(nall+5)];
 
  uint32_t *data2 = new uint32_t[2*(nall+5)];
 
  int nmask=0;
 
  for (int i=0;i<4;i++) if (mask & (1<<i)) nmask++;
 
  int adclen = nall+2;
 
  int len    = nmask* adclen+2;
 
  uint16_t *adc = new uint16_t[len]; // 4 channels + 4 ch header + 1 event hdr
 
  
 
  // write headers
 
  uint16_t *evhdr  = &adc[0];
 
  evhdr[0] = 0;
 
  evhdr[1] = len  *sizeof(uint16_t);
 
  int imask=0;
 
  for (int ch=0;ch<4;ch++){
 
    if (  mask & (1<<ch) ) {
 
      uint16_t *chhdr= &adc[2+imask*adclen];
 
      chhdr[0] = ch+1;
 
      chhdr[1] = adclen *sizeof(uint16_t);
 
      imask++;
 
    }
 
  }
 
 
 
  // start
 
  int ncount =0;
 
  int nerrors=0;
 
  int nball  =0;
 
 
 
  // open VME and initialize board
 
  char *serial = new char[100];
 
 
 
 
 
  VME_START(serial);
 
  printf("CAEN V1718 BoardFWRelease %s\n", serial
);  
 
 
  V729_init(addr, nall, cbl, bias1,bias2);
 
 
 
  // event loop
 
  for (int j=0; j<neve; j++) {
 
     if (ctrlc) break;
 
     int nb= V729_event(mask,nall,data, data1,data2);
 
     if (nb<0) {  // timeout
 
       j--;
 
       nerrors++;
 
     } else {
 
 
 
       V729_decode(mask,nall,data,adc, verbose);
 
 
 
       // V729_clear_buffer();
 
       if (output
) nball 
+= fwrite(adc  
,   1, sizeof(uint16_t)*len
, fp
);   
 
 
       ncount++;
 
     }
 
     if (t
/4!=told 
) printf("%d events in %2.2f min (%d s) USBerr=%d TIMEOUTS=%d %s",ncount
, (double)(t
-tstart
)/60.
,int(t
-tstart
), VMEerrors
, nerrors
, ctime(&t
));  
     told=t/4;   
 
  }
 
 
 
  // end
 
  VME_STOP();
 
  printf("%d events in %2.2f min  (%d s) USBerr=%d TIMEOUTS=%d  %s\n",ncount
, (double)(t
-tstart
)/60.
,int(t
-tstart
),VMEerrors
, nerrors
, ctime(&t
));  
  return 0;
 
}
 
 
 
#endif //V729_MAIN