/********************************************************************\
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