Subversion Repositories f9daq

Rev

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

/********************************************************************\

  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 DRSCalibrateTiming( )
{
   DRSBoard *b;
   if (drs == NULL) drs = new DRS();
   if (!drs) return -1;
   DRSParameters = drssettings::instance();
   
   //fCalMode = 2;
   if (drs->GetNumberOfBoards() ) {
        /* continue working with first board only */
     b = drs->GetBoard(0);
     
      if (b->GetFirmwareVersion() < 13279)
         printf("Firmware revision 13279 or later\nrequired for timing calibration\n");
      else if (b->GetInputRange() != 0)
         printf("Timing calibration can only be done\nat the -0.5V to +0.5V input range\n");

      else {


         /* remember current settings */
         double acalVolt   = b->GetAcalVolt();
         int    acalMode   = b->GetAcalMode();
         int    tcalFreq   = b->GetTcalFreq();
         int    tcalLevel  = b->GetTcalLevel();
         int    tcalSource = b->GetTcalSource();
         int    flag1      = b->GetTriggerEnable(0);
         int    flag2      = b->GetTriggerEnable(1);
         int    trgSource  = b->GetTriggerSource();
         int    trgDelay   = b->GetTriggerDelay();
         double range      = b->GetInputRange();
         int    config     = b->GetReadoutChannelConfig();

     
         int status = b->CalibrateTiming(NULL);

         if (!status)
            printf("Error performing timing calibration, please check waveforms and redo voltage calibration.\n");
         else
           printf("Timing calibration successfully finished.\n");
                     

         /* restore old values */
         b->EnableAcal(acalMode, acalVolt);
         b->EnableTcal(tcalFreq, tcalLevel);
         b->SelectClockSource(tcalSource);
         b->EnableTrigger(flag1, flag2);
         b->SetTriggerSource(trgSource);
         b->SetTriggerDelayPercent(trgDelay);
         b->SetInputRange(range);
         b->SetChannelConfig(config, 8, 8);

         if (b->GetBoardType() == 5)
            b->SetTranspMode(1); // Evaluation board with build-in trigger
         else
            b->SetTranspMode(1); // VPC Mezzanine board

         return status;
      }
     
   }
   return -1;
}


DLLEXPORT int DRSInit()
{

   DRSBoard *b;
   /* do drsinitial scan */
   if (drs == NULL) 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) {
                 memcpy(p, "DRS2", 4); // File identifier and version
         p += 4;
         // 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;
                           unsigned int s = drs->GetBoard(b)->GetScaler(i);
               memcpy(p, &s, sizeof(int));
               p += sizeof(int);
               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