/********************************************************************\
 
 
 
  Name:         drsread.cpp
 
  Created by:   Rok Pestotnik
 
 
 
  Contents:     Simple example application to read out a DRS4
 
                evaluation board and save into the data file
 
                                Interface dll for LabWindows CVI
 
 
 
\********************************************************************/
 
#ifdef DLLMAIN
 
#define DLLEXPORT  __declspec(dllexport)
 
#else 
 
#define DLLEXPORT  
 
#endif
 
 
 
 
 
#include <stdio.h>
 
#include <string.h>
 
#include <stdlib.h>
 
 
 
#include <math.h>
 
#include <time.h>
 
#include <signal.h>
 
 
 
#include <TFile.h>
 
#include <TH2F.h>
 
#include <TCanvas.h>
 
//#include <TApplication.h>
 
 
 
#ifdef _MSC_VER
 
 
 
#include "gettimeofday.h"
 
#include "timer.h"
 
 
 
#define DIR_SEPARATOR '\\'
 
 
 
#elif defined(OS_LINUX) || defined(OS_DARWIN)
 
 
 
#define O_BINARY 0
 
#include <unistd.h>
 
#include <ctype.h>
 
#include <sys/ioctl.h>
 
#include <errno.h>
 
#define DIR_SEPARATOR '/'
 
#endif
 
 
 
#include "DRS.h"
 
#include "drsread.h"
 
 
 
 
 
/*------------------------------------------------------------------*/
 
class drssettings  {
 
    static drssettings *s_instance;
 
public:
 
   drssettings(){
 
       mask     = 0xF;
 
       range = 0;
 
       trigger_type = 1;
 
       sampling_frequency = 5;
 
       trigger_delay = 0;
 
       trigger_channel=0;
 
       trigger_polarity=false;
 
       trigger_level=0.05;
 
           
 
   };
 
   ~drssettings(){};
 
   static drssettings *instance()
 
    {
 
        if (!s_instance)
 
          s_instance = new drssettings;
 
        return s_instance;
 
    };
 
 
 
   
 
   unsigned char mask;
 
   double        range;
 
   int           trigger_type; // 0 software, 1 fast hardware, 2 slow hardware
 
   int           trigger_channel;
 
   int           sampling_frequency;
 
   double        trigger_delay;
 
   double        trigger_level;
 
   bool          trigger_polarity;
 
};
 
drssettings *drssettings::s_instance = 0;
 
drssettings *DRSParameters;
 
DLLEXPORT void DRSSetMask(int mask){ drssettings::instance()->mask;};
 
DLLEXPORT void DRSSetTriggerType(int type){ drssettings::instance()->trigger_type = type;};
 
DLLEXPORT void DRSSetFrequency(int freq){ drssettings::instance()->sampling_frequency = freq;};
 
DLLEXPORT void DRSSetRange(double range){ drssettings::instance()->range = range;};
 
DLLEXPORT void DRSSetTriggerChannel(int channel){ drssettings::instance()->trigger_channel = channel;};
 
DLLEXPORT void DRSSetTriggerDelay(double delay){ drssettings::instance()->trigger_delay = delay;};
 
DLLEXPORT void DRSSetTriggerLevel(double level){ drssettings::instance()->trigger_level = level;};
 
DLLEXPORT void DRSSetTriggerPolarity(int polarity){ drssettings::instance()->trigger_polarity = (polarity==1);};
 
 
 
 
 
static int DRSTimeout;
 
 
 
DLLEXPORT int DRSIsTimeout()
 
{
 
        return DRSTimeout;
 
}
 
 
 
DLLEXPORT void DRSSetTimeout ( void )
 
{
 
    DRSTimeout=1;
 
    printf("->>> Timer Out !!!\n");
 
}
 
 
 
static DRS *drs=NULL;
 
 
 
DLLEXPORT int DRSInit()
 
{
 
 
 
   DRSBoard *b;
 
   /* do drsinitial scan */
 
   drs = new DRS();
 
   if (!drs) return -1;
 
   DRSParameters = drssettings::instance();
 
   
 
   /* show any found board(s) */
 
   for (int i=0 ; i<drs->GetNumberOfBoards() ; i++) {
 
      b = drs->GetBoard(i);
 
      printf("Found DRS4 evaluation board, serial #%d, firmware revision %d\n", 
 
         b->GetBoardSerialNumber(), b->GetFirmwareVersion());
 
   }
 
 
 
   /* exit if no board found */
 
   int nBoards = drs->GetNumberOfBoards();
 
   if (nBoards == 0) {
 
      printf("No DRS4 evaluation board found\n");
 
      return -2;
 
   }
 
 
 
   /* continue working with first board only */
 
   b = drs->GetBoard(0);
 
 
 
   /* drsinitialize board */
 
   b->Init();
 
 
 
   /* set sampling frequency default 5 */
 
   b->SetFrequency(DRSParameters->sampling_frequency, true);
 
 
 
   /* enable transparent mode needed for analog trigger */
 
   b->SetTranspMode(1);
 
 
 
   /* set input range to -0.5V ... +0.5V -> range=0 */
 
   b->SetInputRange(DRSParameters->range);
 
 
 
   /* use following line to set range to 0..1V */
 
   //b->SetInputRange(0.5);
 
   
 
   /* use following line to turn on the internal 100 MHz clock connected to all channels  */
 
   //b->EnableTcal(1);
 
 
 
   /* kaj je to ....
 
    // Set domino mode
 
   // mode == 0: single sweep 
 
   // mode == 1: run continously -- default
 
   b->SetDominoMode(1);
 
    // Set domino activity
 
   // mode == 0: stop during readout  
 
   // mode == 1: keep domino wave running -- default
 
   //   
 
   b->SetDominoActive(1);
 
   
 
   // Set readout mode
 
   // mode == 0: start from first bin  -- default
 
   // mode == 1: start from domino stop
 
   //
 
   b->SetReadoutMode(1);
 
   */
 
   
 
   /* use following lines to enable hardware trigger on CH1 at 50 mV positive edge */
 
   printf("Board Type:%d\n",b->GetBoardType() );
 
   if (b->GetBoardType() >= 8) {        // Evaluaiton Board V4&5
 
      
 
      b->EnableTrigger(DRSParameters->trigger_type, 0);           // enable hardware trigger - 1 fast trigger, 2 slow trigger, 0 disable hw trigger
 
      b->SetTriggerSource(1<<DRSParameters->trigger_channel);        // set CH1 as source // simple or of single channel
 
   } else if (b->GetBoardType() == 7) { // Evaluation Board V3
 
      b->EnableTrigger(0, 1);           // lemo off, analog trigger on
 
      b->SetTriggerSource(0);           // use CH1 as source
 
   }
 
   b->SetTriggerLevel(DRSParameters->trigger_level);            // 0.05 V
 
   b->SetTriggerPolarity(DRSParameters->trigger_polarity);        // positive edge
 
   
 
   /* use following lines to set individual trigger elvels */
 
   //b->SetIndividualTriggerLevel(1, 0.1);
 
   //b->SetIndividualTriggerLevel(2, 0.2);
 
   //b->SetIndividualTriggerLevel(3, 0.3);
 
   //b->SetIndividualTriggerLevel(4, 0.4);
 
   //b->SetTriggerSource(15);
 
   
 
   b->SetTriggerDelayNs( DRSParameters->trigger_delay);             // zero ns trigger delay
 
   
 
   /* use following lines to enable the external trigger */
 
   //if (b->GetBoardType() == 8) {     // Evaluaiton Board V4
 
   //   b->EnableTrigger(1, 0);           // enable hardware trigger
 
   //   b->SetTriggerSource(1<<4);        // set external trigger as source
 
   //} else {                          // Evaluation Board V3
 
   //   b->EnableTrigger(1, 0);           // lemo on, analog trigger off
 
   // }
 
 
 
   return 0;
 
 
 
 
 
}
 
 
 
static float DRSTimeArray[8][1024];
 
static float DRSWaveArray[8][1024];
 
 
 
DLLEXPORT float * DRSGetTime(int ch){ return DRSTimeArray[ch];}
 
DLLEXPORT float * DRSGetWave(int ch){ return DRSWaveArray[ch];}
 
 
 
DLLEXPORT int DRSRead( int DRStimer)
 
{
 
  
 
   DRSBoard *b = drs->GetBoard(0);
 
 
 
      
 
 
 
      /* wait for trigger */
 
         
 
 
 
      int tout=1000; /* timeout in mili seconds */
 
      DRSTimeout=0;
 
 
 
      if (DRStimer) start_timer(tout, &DRSSetTimeout);
 
        
 
          /* start board (activate domino wave) */
 
      b->StartDomino();
 
           
 
      if (!DRSParameters->trigger_type) b->SoftTrigger();
 
          
 
      while (b->IsBusy()){
 
                        
 
        if (DRSTimeout) {
 
          printf("Waiting for Trigger.. at line %d\n",  __LINE__);
 
 
 
          if (DRStimer) stop_timer();
 
          
 
          return -1;
 
        }
 
          }; 
 
      
 
 
 
      if (DRStimer) stop_timer();
 
 
 
    
 
        
 
      /* read all waveforms */
 
      b->TransferWaves(0, 8);
 
 
 
 
 
      for (int k=0;k<4;k++){
 
        if (! (DRSParameters->mask & ( 0x1<<k ))  ) continue;
 
      /* Note: On the evaluation board input #1 is connected to channel 0 and 1 of
 
       the DRS chip, input #2 is connected to channel 2 and 3 and so on. So to
 
       get the input #2 we have to read DRS channel #2, not #1. */
 
 
 
      /* read time (X) array of k-th channel in ns and waveform (Y) array of k-th channel in mV */
 
        b->GetTime(0, 2*k, b->GetTriggerCell(DRSParameters->trigger_channel), DRSTimeArray[k]);
 
        b->GetWave(0, 2*k, DRSWaveArray[k]);
 
        
 
         
 
      }
 
 
 
  return 0;    
 
}
 
 
 
DLLEXPORT int DRSEnd(){
 
   
 
   /* delete DRS object -> close USB connection */
 
   if (drs) delete drs;
 
   drs = NULL;
 
   return 0;
 
}
 
 
 
 
 
 
 
DLLEXPORT int DRSToBuffer( unsigned char *p, int m_evSerial  )
 
{
 
  
 
   unsigned short d;
 
   float t;
 
   unsigned char *p0 = p;
 
 
 
   int m_nBoards    = drs->GetNumberOfBoards();
 
   int m_waveDepth  = 1024 ;// 2048
 
   int m_inputRange = drs->GetBoard(0)->GetInputRange();  
 
   time_t rawtime;
 
   time ( &rawtime );
 
   struct tm m_evTimestamp;
 
   m_evTimestamp = *(localtime ( &rawtime ));
 
   struct timeval mtime;
 
   gettimeofday(&mtime, NULL);
 
      
 
      if (m_evSerial == 0) {
 
         // time calibration header
 
         memcpy(p, "TIME", 4);
 
         p += 4;
 
 
 
         for (int b=0 ; b<m_nBoards ; b++) {
 
            // store board serial number
 
            sprintf((char *)p, "B#");
 
            p += 2;
 
            *(unsigned short *)p = drs->GetBoard(b)->GetBoardSerialNumber();
 
            p += sizeof(unsigned short);
 
 
 
            for (int i=0 ; i<4 ; i++) {
 
               if (DRSParameters->mask & (0x1<<i)) {
 
                  sprintf((char *)p, "C%03d", i+1);
 
                  p += 4;
 
                  float tcal[2048];
 
                  drs->GetBoard(b)->GetTimeCalibration(0, i*2, 0, tcal, 0);
 
                  for (int j=0 ; j<m_waveDepth ; j++) {
 
                     // save binary time as 32-bit float value
 
                     if (m_waveDepth == 2048) {
 
                        t = (tcal[j]+tcal[j+1])/2;
 
                        j++;
 
                     } else
 
                        t = tcal[j];
 
                     *(float *)p = t;
 
                     p += sizeof(float);
 
                  }
 
               }
 
            }
 
         }
 
      }
 
 
 
 
 
 
 
      memcpy(p, "EHDR", 4);
 
      p += 4;
 
      *(int *)p = m_evSerial;
 
      p += sizeof(int);
 
      *(unsigned short *)p = m_evTimestamp.tm_year;
 
      p += sizeof(unsigned short);
 
      *(unsigned short *)p = m_evTimestamp.tm_mon;
 
      p += sizeof(unsigned short);
 
      *(unsigned short *)p = m_evTimestamp.tm_mday;
 
      p += sizeof(unsigned short);
 
      *(unsigned short *)p = m_evTimestamp.tm_hour;
 
      p += sizeof(unsigned short);
 
      *(unsigned short *)p = m_evTimestamp.tm_min;
 
      p += sizeof(unsigned short);
 
      *(unsigned short *)p = m_evTimestamp.tm_sec;
 
      p += sizeof(unsigned short);
 
      *(unsigned short *)p = mtime.tv_usec/1000;
 
      p += sizeof(unsigned short);
 
      *(unsigned short *)p = (unsigned short)(m_inputRange * 1000); // range
 
      p += sizeof(unsigned short);
 
      
 
      int b=0; // only for board 0
 
 
 
         // store board serial number
 
         sprintf((char *)p, "B#");
 
         p += 2;
 
         *(unsigned short *)p = drs->GetBoard(b)->GetBoardSerialNumber();
 
         p += sizeof(unsigned short);
 
         
 
         // store trigger cell
 
         sprintf((char *)p, "T#");
 
         p += 2;
 
         *(unsigned short *)p = drs->GetBoard(b)->GetTriggerCell(DRSParameters->trigger_channel);
 
         p += sizeof(unsigned short);
 
         
 
         for (int i=0 ; i<4 ; i++) {
 
            if (DRSParameters->mask & (0x1<<i)) {
 
               sprintf((char *)p, "C%03d", i+1);
 
               p += 4;
 
               for (int j=0 ; j<m_waveDepth ; j++) {
 
                  // save binary date as 16-bit value:
 
                  // 0 = -0.5V,  65535 = +0.5V    for range 0
 
                  // 0 = -0.05V, 65535 = +0.95V   for range 0.45
 
                  if (m_waveDepth == 2048) {
 
                     // in cascaded mode, save 1024 values as averages of the 2048 values
 
                     d = (unsigned short)(((DRSWaveArray[i][j]+DRSWaveArray[i][j+1])/2000.0 - m_inputRange + 0.5) * 65535);
 
                     *(unsigned short *)p = d;
 
                     p += sizeof(unsigned short);
 
                     j++;
 
                  } else {
 
                     d = (unsigned short)((DRSWaveArray[i][j]/1000.0 - m_inputRange + 0.5) * 65535);
 
                     *(unsigned short *)p = d;
 
                     p += sizeof(unsigned short);
 
                  }
 
               }
 
            }
 
         }
 
   
 
   return (p-p0); // return number of bytes
 
}
 
 
 
 
 
 
 
#ifdef MAIN
 
 
 
 
 
 
 
#include "XGetopt.h"
 
#include "getopt.h"
 
 
 
TH2F *h[4];
 
 
 
typedef struct {
 
   char           recid[4];
 
   unsigned int posx, posy, posz;
 
   unsigned int iposx, iposy, iposz;
 
} POSREC;
 
 
 
 
 
int help() {
 
    printf ("*********************************************************************************:\n");
 
    printf ("Usage: Read of the DRS4 PSI board and dump of the waveforms in the file:\n\n");
 
    printf ("Arguments: \n");
 
    printf ("-v verbosity \n");
 
    printf ("-a output rootfile \n");
 
    printf ("-o output filename \n");
 
    printf ("-r range \n");
 
    printf ("-n number of events\n");
 
    printf ("-m channel bit mask\n");
 
    printf ("-h trigger type (0 software, 1 fast hardware, 2 slow hardware)\n");
 
    printf ("-d trigger delay in ns\n");
 
    printf ("-f sampling frequency\n");
 
    printf ("-t trigger channel\n");
 
        printf ("-l trigger level\n");
 
        printf ("-p trigger polarity (0 positive\n");
 
    printf ("*********************************************************************************:\n");
 
    printf ("Examples:\n\n");
 
   
 
    return 0;
 
}
 
 
 
 
 
 
 
char filename[0xFF]="";
 
char rootfile[0xFF]="";
 
int  neve          =  0;
 
int  verbose       =  0;
 
 
 
void Init(int argc, char **argv){
 
   DRSParameters = drssettings::instance();
 
   char c;
 
   
 
   extern char *optarg;
 
   extern int optind;
 
   extern int optopt;
 
   while ((c = getopt (argc, argv, "a:o:v:m:n:f:d:r:h:t:p:l:")) != -1){
 
 
 
        switch (c)
 
        {
 
 
 
        case 'a':
 
            sprintf(rootfile,"%s", optarg );
 
            break;       // root output
 
 
 
        case 'o':
 
            sprintf(filename,"%s", optarg );
 
            break;       // output
 
 
 
        case 'v':
 
             verbose = atoi(optarg);
 
            break;                       // verbosity
 
        case 'm':{
 
            unsigned long ul = strtoul (optarg,NULL,0); 
 
            DRSSetMask( (unsigned char)( ul & 0xF ) ) ;
 
            break;
 
        }                               // channel mask
 
        case 'n':
 
            neve =  atoi (optarg);
 
            break;                          // number of events or number of scan points
 
 
 
        case 'f':
 
            DRSSetFrequency( atoi (optarg) );
 
            break;                          // sampling frequency
 
 
 
        case 'd':
 
            DRSSetTriggerDelay(  atof (optarg) );
 
            break;                          // trigger delay
 
        case 'p':
 
            DRSSetTriggerPolarity( atoi (optarg));
 
            break;                          // trigger polarity
 
        case 'l':
 
            DRSSetTriggerLevel(atoi (optarg));
 
            break;                          // trigger level
 
 
 
 
 
        case 'r':
 
            DRSSetRange (  atof (optarg) );
 
            break;                          // range 
 
        case 'h':
 
            DRSSetTriggerType( atoi (optarg) );
 
            break;         // send sotware trigger before reading out the dat
 
        case 't':
 
            DRSSetTriggerChannel( atoi(optarg) );
 
            break;         // trigger channel
 
 
 
 
 
        case '?':
 
            if (optopt == 'c')
 
                fprintf (stderr, "Option -%c requires an argument.\n", optopt);
 
            else if (isprint (optopt))
 
                fprintf (stderr, "Unknown option `-%c'.\n", optopt);
 
            else
 
                fprintf (stderr,
 
                         "Unknown option character `\\x%x'.\n",
 
                         optopt);
 
            abort ();
 
        default:
 
            abort ();
 
        }
 
    }
 
    //for (int i=optind; i<argc; i++) data = strtoul (argv[i],NULL,0);
 
 
 
}
 
 
 
int ctrl_c=0;
 
DLLEXPORT void DRSSigInt ( int )
 
{
 
    ctrl_c = 1;
 
    printf("->>> CTRL+c !!!\n");
 
}
 
 
 
//#ifdef __CINT__
 
int main(int argc, char **argv){
 
//#else
 
//int drsread(int argc, char **argv){   
 
//#endif
 
 
 
 if (signal (SIGINT, DRSSigInt) == SIG_ERR) {
 
   perror ("sigignore");
 
 }
 
 
 
 
 
Init(argc, argv); 
 
if (argc==1) { help(); return 0; } 
 
 
 
FILE *fp=NULL;
 
if (strlen(filename)>0) {
 
  if (verbose) printf("Data in the file:%s\n", filename);
 
  fp=fopen(filename,"wb");
 
}
 
 
 
TFile *rfile= NULL; 
 
if (strlen(rootfile)>0) {
 
  if (verbose) printf("Data in the file:%s\n", rootfile);   
 
  rfile = new TFile(rootfile,"RECREATE");
 
}
 
 
 
 
 
TCanvas *c = new TCanvas(); c->Divide(2,2);
 
c->Draw();
 
for (int i=0;i<4;i++){
 
   if (! (DRSParameters->mask & ( 0x1<<i ))  ) continue;        
 
   char name[0xff];
 
   sprintf(name,"h%d",i);
 
   h[i]=new TH2F(name,name,1024,0,204,1024,-0.6+DRSParameters->range,0.6+DRSParameters->range);
 
   c->cd(i+1); h[i]->Draw("colz");
 
   
 
}
 
 
 
 
 
 
 
//---------------------------------------
 
static unsigned char *buffer;
 
static int buffer_size = 0;
 
const int nBoards=1;
 
const int waveDepth=1024;
 
if (buffer_size == 0) {
 
         buffer_size =  4 +  nBoards * (4 + 4*(4+waveDepth*4));
 
         buffer_size += 24 + nBoards * (8 + 4*(4+waveDepth*2));
 
         buffer = (unsigned char *)malloc(buffer_size);
 
}
 
   
 
time_t t,told, tstart;
 
if (!DRSInit()){
 
  time(&tstart);
 
  told=tstart;
 
  int i=0;
 
  for (i=0; i<neve; i++) {
 
    int nb =  (DRSRead(1) == 0 && fp ) ? DRSToBuffer( buffer , i ) : 0;
 
        
 
        if (DRSTimeout) i--;
 
    if (ctrl_c) break;
 
    time(&t);
 
    if (t!=told ) {
 
                printf("%d events in %2.2f min (%d s) %s",i+1, (double)(t-tstart)/60.,int(t-tstart), ctime(&t));
 
                c->Modified(); c->Update();
 
        }       
 
    told=t;
 
// Save data    
 
        if (nb>0 && fp) fwrite(buffer, 1,nb ,fp); 
 
// Plot Data
 
        for (int k=0;k<4;k++){
 
        if (! (DRSParameters->mask & ( 0x1<<k ))  ) continue;
 
        float *t=DRSGetTime(k);
 
        float *x=DRSGetWave(k);         
 
            for (int i=0 ; i<1024 ; i++) {
 
           if (verbose) printf("[%d] %d. x= %3.2f  y=%3.2f\n", k, i, t[i], x[i] );
 
           h[k]->Fill( t[i], x[i]*1e-3);
 
        } 
 
        }
 
  }
 
  time(&t);
 
  printf("%d events in %2.2f min (%d s) %s",i+1, (double)(t-tstart)/60.,int(t-tstart), ctime(&t));
 
 
 
  DRSEnd();
 
}
 
//---------------------------------------
 
if (rfile !=NULL) rfile->Write();
 
if (fp) fclose(fp);
 
if (c) c->SaveAs("drsread.pdf");
 
// TApplication* theApp = new TApplication("App", NULL, NULL);
 
// theApp->Run();
 
 
 
 
 
   
 
}
 
 
 
#endif