#include <stdio.h>
 
#include <stdlib.h>
 
#include <string.h>
 
#include <unistd.h>
 
#include <sys/mman.h>
 
#include <errno.h>
 
#include <ctype.h>
 
#include <time.h>
 
#include <sys/time.h>
 
#include <sys/stat.h>
 
#include <signal.h>
 
#include <zlib.h>
 
 
 
#include "CAENV965_DEF.h"
 
#include "VmUsbStack.h"
 
 
 
#include "vme.h"
 
 
 
#include "daq.h"
 
 
 
#define VERSION 1.0
 
#define TIMEOUT 3
 
 
 
 
 
/* VME modules */
 
 
 
#define CAEN_V792      0x340000  // IJS V792
 
#define CAEN_V792_1    0x530000  // FMF1 V792
 
#define CAEN_V792_2    0x630000  // FMF2 V792
 
#define CAEN_V965      0x350000  // IJS  V965
 
int addr[3]={CAEN_V792,CAEN_V792_1,CAEN_V965  };
 
int nadc=3;
 
 
 
int gPedestal = 255;
 
 
 
#define BUFF_L 2048
 
static  int stackwrite[10000];
 
static  int stackdata[10000],stackdump[27000];
 
 
 
 
 
/************************************************/
 
int weight_while(int num)
 
{
 
  int i, tmp;
 
 
 
  for ( i =0; i <num; i++ ) tmp = 0;
 
  return 0;
 
}
 
#define WWHILE weight_while(0)
 
 
 
#define TRUE 1
 
#define FALSE 0
 
 
 
int timer_out;
 
struct sigaction oact;
 
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 fexist( char * path){
 
   struct stat sbuf;
 
   int res;
 
   if(!path || !*path) return 0;
 
   res=stat(path,&sbuf);
 
   if (res){
 
       if (errno==ENOENT) {
 
           return 0;
 
       } else {
 
           return -1;
 
       }
 
   }
 
   return 1;
 
}
 
 
 
 
 
 
 
 
 
int daq::init(){
 
 
 
  xxusb_register_write(udev,1,0x0); // Stop DAQ mode
 
  while (xxusb_usbfifo_read(udev,(int *) stackdump,BUFF_L,100)>0); 
 
 
 
 
 
  int rate=1000;
 
  int i=80000000/rate-40; // 80 MHz
 
  if (i<72) i=72; 
 
        // Set DGG channel A as a pulser, output on O1,
 
        //     with delay =500 x 12.5ns,
 
        //     and width =  500 x 12.5ns,
 
        //     not latching or inverting
 
  //  VME_DGG(udev,0,6,0,24000,6000,0,0);
 
  VME_DGG(udev,0,6,0,i,40,0,0);
 
        // Set DGG channel B to trigger on NIM1, output on O2,
 
        //     with delay =200 x 12.5ns,
 
        //     and width =  200 x 12.5ns,
 
        //     not latching or inverting
 
        VME_DGG(udev,1,1,1,0,10,0,1);
 
 
 
 
 
// INIT stackdata
 
        int fPedestal=gPedestal;
 
         printf("CAEN V965 Pedestal set to %d\n", fPedestal
);  
        if (fInit != NULL ) delete fInit;
 
        fInit=new VmUsbStack();
 
 
 
        for (int i=0;i<nadc;i++){
 
                fInit->WriteA24D16( addr[i] + CAENV965_CRN , 0x0);
 
                fInit->WriteA24D16( addr[i] + CAENV965_GEO , i);
 
                fInit->ReadA24D16(addr[i] + CAENV965_GEO);
 
    for (int j=0;j<32;j++){
 
                   fInit->WriteA24D16(addr[i] + CAENV965_THM + 0x02*j, fThreshold[j+i*32]); // threshold/kill for 32 channels
 
    }
 
                fInit->WriteA24D16( addr[i] + CAENV965_BS1, 0x80 ); // soft reset
 
                fInit->WriteA24D16( addr[i] + CAENV965_BC1, 0x80 ); // soft reset
 
                fInit->WriteA24D16( addr[i] + CAENV965_PED, fPedestal ); // pedestal
 
                fInit->WriteA24D16( addr[i] + CAENV965_BS2,0x5000); 
 
                fInit->WriteA24D16( addr[i] + CAENV965_BS2,0x4);  // clear module
 
                fInit->WriteA24D16( addr[i] + CAENV965_BC2,0x4);
 
        }
 
        fInit->Marker(0xFAFC);
 
        
 
//      fInit->Print(); 
 
        
 
        
 
        // READOUT stackdata
 
        if (fStack != NULL ) delete fStack; 
 
        fStack=new VmUsbStack();
 
        fStack->Marker(0xFFAB); 
 
        //fStack->ConditionalRead(addr[i] + CAENV965_SR1,0x1);        // TRG wait : loop until bit 0 is on
 
        // fStack->RepeatRead( CMD_A24, CMD_D32, addr[i] + CAENV965_OB,34,0);  // repead read
 
        //fStack->ConditionalRead(addr[i] + CAENV965_OB ,0x4000000) ; // loop until bit 26 is on, read data 
 
  for (int j=0;j<36;j++) fStack->ReadA24D32(addr[0] + CAENV965_OB); 
 
  for (int j=0;j<36;j++) fStack->ReadA24D32(addr[1] + CAENV965_OB);
 
  for (int j=0;j<8;j++) fStack->ReadA24D32(addr[2] + CAENV965_OB);// 4 channels connected
 
        fStack->Marker(0xFAFB); 
 
 
 
        for (int i=0;i<nadc;i++){
 
                fStack->WriteA24D16(addr[i] + CAENV965_BS2,0x4);  // clear module
 
                fStack->WriteA24D16(addr[i] + CAENV965_BC2,0x4);  
 
        }
 
 
 
        //fStack->Print();
 
 
 
 VME_LED_settings(udev, 0,0,0,0); // Set Yellow LED to light with with USB out buffer not empty
 
 VME_LED_settings(udev, 1,1,0,0); // Set Red LED to light with NIM1
 
 VME_LED_settings(udev,2,0,0,0); // Set Green LED to light when stack is not empty
 
 
 
 Uint32_t  vmereg;
 
 VME_register_read(udev,0x00,&vmereg);
 
 printf("VMUSB Firmware ID -> 0x%08X\n",vmereg
);  
 
 
 VME_register_read(udev,0x04,&vmereg);
 
 printf("VMUSB Global Mode -> 0x%08X\n",vmereg
);  
 
 
 vmereg=(vmereg&0xF000)|0x0004;
 
 VME_register_write(udev,0x04,vmereg);
 
 VME_register_write(udev,0x08,0x00000080);
 
 VME_register_write(udev,0x28,0x0);
 
 VME_register_write(udev,0x2C,0x0);
 
 VME_register_write(udev,0x30,0x0);
 
 VME_register_write(udev,0x34,0x0);
 
 VME_register_write(udev,0x3C,0x000);
 
 
 
 int nb = fInit->Get(10000,stackdata);
 
 int ret= xxusb_stack_execute(udev,(Uint32_t *)stackdata);
 
 printf("Init::%d ret=%d\n",nb
,ret
);  
 if (ret
>0) for (int i
=0;i
<ret
/2;i
++) printf ("stackdata=0x%08X\n",stackdata
[i
]);   
 
 
 int nb0= fStack->Get(10000,&stackwrite[0]);
 
 if (nb0>768) {
 
   fprintf(stderr
,"nb0=%d > 768 error xxusb_stack_write\n", nb0
);  
 }
 
 nb =xxusb_stack_write(udev,0x2,(Uint32_t *) stackwrite);
 
 nb0=xxusb_stack_read(udev,0x2,(Uint32_t *) stackdata);
 
 for (int i=0;i<stackwrite[0]+1;i++){
 
   if (stackdata
[i
]!=stackwrite
[i
]) printf("%d %d init err %x %x\n",nb
,nb0
,stackwrite
[i
], stackdata
[i
]);  
 }
 
 
 
 if (fMode==2) xxusb_register_write(udev,1,0x1); // Start DAQ mode
 
 
 
 return 0;
 
}
 
 
 
int daq::connect(){
 
    VME_START(NULL);
 
    return 0;
 
}
 
  
 
int daq::disconnect(){ 
 
  /* zakljuci */
 
  VME_STOP();
 
  printf("daq::disconnect()\n");  
  return 0;
 
}
 
 
 
int daq:: clear(){    
 
   return 0;
 
}
 
 
 
inline int module_header(int recid,Uint32_t *data,int len){
 
   data[0] = recid;
 
   data[1] = (len >0)? len : 0 ;
 
   return data[1]+2;
 
}
 
 
 
 
 
int daq::event(unsigned int *data, int maxn, int *ctr, int print){
 
   int tout=200; /* 1/100 of a second */
 
   const int lsize=sizeof(unsigned Uint32_t);  
 
 
 
 
 
   ctr[0]++;
 
   ctr[1]++; 
 
   
 
   int count=0;
 
 
 
         switch (fMode){
 
         case 0:// normal calls
 
                 {
 
                         unsigned short clr= 0x4;
 
                         unsigned int status=0; 
 
                         Uint32_t mdata;
 
                         
 
                         for (int i=0;i<2;i++){
 
                                 // wait for trg
 
                                 tmlnk (tout);
 
                                 do VME_A24D16_R( addr[i] + CAENV965_SR1, &status); while ( (status&0x1)==0 && timer_out==0 );
 
                                 tmulk();
 
                                 // readout data
 
                                 if (timer_out) return 0;
 
                                 int len=0; 
 
                                 
 
                                 do {
 
                                         VME_A24D32_R(addr[i]  + CAENV965_OB, &mdata);
 
                                         mdata=data[count++];
 
                                         len++;
 
                                 } while  ( (mdata & 0x4000000)==0 && timer_out==0) ; // bit 26 EOB or not valid datum
 
                                 // clear
 
                                 VME_A24D16_W( addr[i] + CAENV965_BS2, &clr);
 
                                 VME_A24D16_W( addr[i] + CAENV965_BC2, &clr); 
 
                                 
 
                                 if (count+2<maxn) {
 
                                         if (print
)  printf("V965 %3d\n",len
);   
                                         count+=module_header(0x130+i,&data[count],len); 
 
                                         ctr[2]++;
 
                                         ctr[3]+=len;
 
                                 }
 
                         
 
                                 timer_out=0; 
 
                         } 
 
                 }
 
                 break;
 
         case 1:// stack execute
 
                 {
 
                         fStack->Get(10000,(int *)data);
 
                         int ret=xxusb_stack_execute(udev,(Uint32_t *) data); //The first element of the array is the number of bytes.
 
       if (ret< 0 ) {
 
                                 printf ("xxusb_stack_execute error err=%d\n",ret
);     \
  
                                 count = 0;
 
                         } else count= ret/lsize; 
 
 
 
                 }
 
                 break;
 
         case 2:// stack load
 
                 {
 
                         int ret=xxusb_usbfifo_read(udev,(int *) data,BUFF_L,100);
 
                         if (ret< 0 ) {
 
                                 if (ret!=-110) {
 
                                    printf ("xxusb_usbfifo_read error err=%d\n",ret
);  
                                    end();
 
                                    init();
 
                                 }      
 
                                 count = 0;
 
                         } else {
 
                                 if (0 && print && ret>0) {
 
                                         for (int i=0;i<100;i++) {
 
                                                 printf ("%4d fifodata=0x%08X\n",i
, data
[i
]);  
             if (data[i]==0xFAFB) break;
 
                                         } 
 
                                         /*
 
   
 
   0 fifodata=0x0000000D
 
   1 fifodata=0x00000049
 
   2 fifodata=0x0000FFAB
 
   3 fifodata=0x00002000
 
   4 fifodata=0x00000200
 
   5 fifodata=0x00004141
 
   6 fifodata=0x00000000
 
   7 fifodata=0x00004057
 
   8 fifodata=0x00000010
 
   9 fifodata=0x00004052
 
  10 fifodata=0x00000001
 
  11 fifodata=0x0000405C
 
  12 fifodata=0x00000011
 
  13 fifodata=0x0000405D
 
  14 fifodata=0x00000002
 
  15 fifodata=0x0000405E
 
  16 fifodata=0x00000012
 
  17 fifodata=0x0000401C
 
  18 fifodata=0x00000003
 
  19 fifodata=0x0000402F
 
  20 fifodata=0x00000013
 
  21 fifodata=0x00004024
 
  22 fifodata=0x00000004
 
  23 fifodata=0x00004076
 
  24 fifodata=0x00000014
 
  25 fifodata=0x0000412F
 
  26 fifodata=0x00000005
 
  27 fifodata=0x0000404C
 
  28 fifodata=0x00000015
 
  29 fifodata=0x00004132
 
  30 fifodata=0x00000006
 
  31 fifodata=0x00004044
 
  32 fifodata=0x00000016
 
  33 fifodata=0x0000404A
 
  34 fifodata=0x00000007
 
  35 fifodata=0x0000409B
 
  36 fifodata=0x00000017
 
  37 fifodata=0x000040F1
 
  38 fifodata=0x00000008
 
  39 fifodata=0x00004087
 
  40 fifodata=0x00000018
 
  41 fifodata=0x00004173
 
  42 fifodata=0x00000009
 
  43 fifodata=0x0000404C
 
  44 fifodata=0x00000019
 
  45 fifodata=0x0000406C
 
  46 fifodata=0x0000000A
 
  47 fifodata=0x00004070
 
  48 fifodata=0x0000001A
 
  49 fifodata=0x0000406E
 
  50 fifodata=0x0000000B
 
  51 fifodata=0x00004014
 
  52 fifodata=0x0000001B
 
  53 fifodata=0x000040B7
 
  54 fifodata=0x0000000C
 
  55 fifodata=0x000040A9
 
  56 fifodata=0x0000001C
 
  57 fifodata=0x00004048
 
  58 fifodata=0x0000000D
 
  59 fifodata=0x00004118
 
  60 fifodata=0x0000001D
 
  61 fifodata=0x0000409D
 
  62 fifodata=0x0000000E
 
  63 fifodata=0x0000405B
 
  64 fifodata=0x0000001E
 
  65 fifodata=0x00004285
 
  66 fifodata=0x0000000F
 
  67 fifodata=0x00004159
 
  68 fifodata=0x0000001F
 
  69 fifodata=0x00000035
 
  70 fifodata=0x00000400
 
  71 fifodata=0x00000035
 
  72 fifodata=0x00000600
 
  73 fifodata=0x00000035
 
  74 fifodata=0x0000FAFB
 
 
 
 
 
                                         */
 
                                 }
 
                                 if (print
) printf("------------------ret=%d data[0]=%d\n",ret
,(int)data
[0]);  
                                 count= ret/lsize;
 
                                 ctr[2]+=data[0];
 
                                 ctr[3]+=count;
 
                         }
 
                 } 
 
                 break;
 
         }
 
   return count*lsize;
 
}
 
 
 
int daq::end(){
 
 
 
         xxusb_register_write(udev,1,0x0); // Stop DAQ mode
 
         while (xxusb_usbfifo_read(udev,(int *) stackdata,BUFF_L,30)>0);  
 
  return 0;
 
}
 
 
 
daq::daq(){
 
  fMode = 2;
 
  fPedestal=255;
 
  for (int i=0;i<128;i++){ 
 
     if (i<72) fThreshold.push_back(0);       
 
     else      fThreshold.push_back(0x1<<8); // samo 4 kanali na zadnjem modulu so enablani
 
  }
 
  fThresholdEnable=0;
 
  fStop=0;
 
  fInit=NULL;
 
  fStack=NULL;
 
  connect();
 
}
 
 
 
daq::~daq(){
 
disconnect();
 
}
 
 
 
#ifdef MAIN
 
/* ------------------- CatchSig ----------------- */
 
int ctrlcflag=0;
 
 
 
void SigInt (int sig)
 
{
 
    ctrlcflag = 1;
 
    timer_out=1;
 
}
 
 
 
int main (int argc, char **argv){
 
   // intercept routine
 
   if (signal (SIGINT, SigInt) == SIG_ERR) {
 
   }
 
 
 
   // print welcome message
 
  time_t t,told, tstart, tstop;
 
  fprintf(stdout
,"#############################################\n");  
  fprintf(stdout
,"Program %s version %2.1f\n",argv
[0], VERSION
);  
  fprintf(stdout
,"Compiled on %s %s\n",__DATE__
, __TIME__
);  
  fprintf(stdout
,"#############################################\n");  
 
 
 
 
  int neve=-1;
 
  char cfname[100]="test.dat";
 
  char *fname=cfname;
 
  char *fpedname=NULL;
 
 
 
#define BSIZE 10000
 
  Uint32_t data[10000];
 
 
 
 
 
  daq *d= new daq();
 
  int c;
 
 
 
  while ((c = getopt (argc, argv, "p:n:t:o:")) != -1)
 
    switch (c)
 
      {
 
      case 'o':
 
        if (fexist(fname)==1){
 
          fprintf(stdout
,"File %s already exist. Appending ....\n",fname
);  
          //fprintf(stdout,"Remove the file and restart !!!\n");
 
          //exit(0);
 
        } 
 
        break;       // input file
 
      case 'n':
 
        neve  
= atoi(optarg
); // negative argument time ( in s )limited event loop 
        break;
 
      case 't':
 
        {
 
          
 
          FILE 
*fped
=fopen(fpedname
,"r"); 
          int j=0;   
 
          int ndim=400;
 
          char line[ndim];   
 
          int val=0;
 
          while (fgets(line
,ndim
,fped
)!=NULL
){   
            d->fThreshold[j++]=val;
 
          }
 
          d->fThresholdEnable=1;
 
          //fclose(fped);
 
          break;
 
        }
 
      case 'p':
 
        gPedestal  
= atoi(optarg
); // injected charge to the qdc 
        break;
 
      }
 
  
 
  if (argc==1) {
 
    fprintf(stdout
,"Usage: %s -o [filename] -n [number of events] -t [thresholdfile] -p <qdc inject charge>\n negative number of events = acq time in seconds\n",argv
[0]);  
  }
 
  //FILE *fp=fopen(fname,"a");
 
  gzFile fp=gzopen(fname,"a");
 
  
 
  d->init();
 
  d->clear();
 
  
 
  int hdr[4]={2}; // recid od run 11 naprej
 
  int i=0;
 
  int ntotal=0;
 
  int counters[30]={0,0,0,0,0, 0,0,0,0,0,0,0};
 
  char names[10][20]={"TRG","CAEN V965"};
 
  tstart=t;
 
  tstop=tstart+360000;
 
  if (neve<-1) {
 
    tstop=tstart-neve;
 
    neve=-1;
 
  }
 
  for (i=0;i!=neve && !ctrlcflag && t<tstop;i++){ 
 
     if (t
!=told 
) printf("%d in %2.2f min daq::event() %s\n",i
, (double)(t
-tstart
)/60.
, ctime(&t
));   
     int nb=d->event(data,BSIZE, counters,t!=told);
 
     if (nb>0){
 
      // zapis v datoteko   
 
      hdr[1]=nb+4*sizeof(int);
 
      hdr[3]=i;
 
   
 
      //fwrite(hdr,   sizeof(int),4 , fp); 
 
      gzwrite(fp, hdr,   sizeof(int)*4); //gzip
 
     // recid=1 do runa 10.  ntotal += fwrite(data,   sizeof(int),nb, fp);
 
      //ntotal += fwrite(data, 1,nb, fp);
 
      ntotal += gzwrite(fp, data, nb);
 
      told=t;
 
     } else i--;
 
  } 
 
 
 
  d->end();
 
  delete d;
 
  printf("Number of Events: %d\n",i
);  
  if (ctrlcflag
) printf("User Program termination CTRL-C\n");  
  if (t
>tstop  
) printf("Timeout termination tstart# t>tstop: %d# %d >%d\n",(int)t
, (int)tstart
, (int) tstop
);  
  
 
 
 
  //fclose(fp);  
 
  gzclose(fp);  
 
  fprintf(stdout
,"%d bytes written to %s\nCounts:\n", (int) (ntotal
*sizeof(int)),fname
);  
  for (i
=0;i
<2;i
++) fprintf(stdout
,"%s\t%d\t%d\n",names
[i
],counters
[2*i
],counters
[2*i
+1]) ;  
 
 
 
 
  return 0;
 
}
 
#endif