source: drsdaq/DAQReadout.cc@ 177

Last change on this file since 177 was 176, checked in by ogrimm, 15 years ago
Migrated to DRS4. DRS class does not run with DRS2 FPGA firmware anymore.
File size: 50.7 KB
Line 
1/********************************************************************\
2
3 DAQReadout.cc
4
5 Main DAQ routines.
6
7 Sebastian Commichau, Oliver Grimm
8
9\********************************************************************/
10
11#include "DAQReadout.h"
12#include "SlowData.h"
13
14#define TMPNAME "/tmp/__tmp__drsdaq__" // ..for log file truncation
15
16static const char* daq_state_str[] = {"active", "stopped"};
17static const char* daq_runtype_str[] = {"data", "pedestal", "reserved", "test"};
18
19static const struct CL_Struct { const char *Name;
20 void (DAQReadout::*CommandPointer)();
21 bool NeedNotBusy;
22 const char *Parameters;
23 const char *Help;
24 } CommandList[] =
25 {{"board", &DAQReadout::cmd_board, true, "<i> [j] | <all>" ,"Address board i, boards i-j, all boards"},
26 {"status", &DAQReadout::cmd_status, false, "[daq|drs]", "Show DAQ/DRS status information"},
27 {"frequency", &DAQReadout::cmd_freq, true, "<GHz> [reg]", "Set DRS sampling frequency (regulated)"},
28 {"acalib", &DAQReadout::cmd_acalib, true, "<trig rate> ", "Amplitude calibration"},
29 {"tcalib", &DAQReadout::cmd_tcalib, true, "<trig rate> ", "Amplitude calibration"},
30 {"trigger", &DAQReadout::cmd_trigger, true, "<on|off>", "Hardware trigger on or off"},
31 {"wmode", &DAQReadout::cmd_wmode, true, "<run|stop>", "Domino wave running or stopped during read out"},
32 {"rmode", &DAQReadout::cmd_rmode, true, "<first|stop>", "Readout start at first bin or stop position (DRS4)"},
33 {"dmode", &DAQReadout::cmd_dmode, true, "<single|continuous>", "Domino wave single shot or continuous"},
34 {"centre", &DAQReadout::cmd_centre, true, "<V>", "Set centre of input range (DRS4)"},
35 {"refclk", &DAQReadout::cmd_refclk, true, "<FPGA|extern>", "Set reference clock to FPGA or external (DRS4)"},
36 {"read", &DAQReadout::cmd_read, false, "<brd chip chan> [res]", "Read current data (and restart if DAQ not active)"},
37 {"take", &DAQReadout::cmd_take, false, "<d|p|t> [n] [source]", "Start run (data, pedestal or test) with n events"},
38 {"events", &DAQReadout::cmd_events, false, "", "Number of events in current run"},
39 {"start", &DAQReadout::cmd_start, true, "", "Start DRS and DAQ without disk writing (feedback will be called)"},
40 {"stop", &DAQReadout::cmd_stop, false, "", "Issue soft trigger and stop DAQ"},
41 {"regtest", &DAQReadout::cmd_regtest, true, "", "DRS register test"},
42 {"ramtest", &DAQReadout::cmd_ramtest, true, "", "DRS RAM integrity and speed test"},
43 {"chiptest", &DAQReadout::cmd_chiptest, true, "", "Chip test"},
44 {"eepromtest", &DAQReadout::cmd_eepromtest, true, "", "EEPROM test"},
45 {"led", &DAQReadout::cmd_led, true, "<on|off>", "Turn LED on or off"},
46 {"config", &DAQReadout::cmd_config, false, "", "Print drsdaq configuration"},
47 {"serial", &DAQReadout::cmd_serial, true, "<i> <n>", "Set serial# of board <i> to <n> (experts only)"},
48 {"disk", &DAQReadout::cmd_disk, false, "" ,"Remaining disk space"},
49 {"uptime", &DAQReadout::cmd_uptime, false, "", "Get DAQ uptime"},
50 {"exit", &DAQReadout::cmd_exit, false, "", "Exit program"},
51 {"fmode", &DAQReadout::cmd_fmode, false, "[off|active|targ]", "Set or get feedback mode"},
52 {"faverage", &DAQReadout::cmd_faverage, false, "[n]", "Set ot get number of averages for feedback"},
53 {"fgain", &DAQReadout::cmd_fgain, false, "[gain]", "Set ot get feedback gain"},
54 {"ftarget", &DAQReadout::cmd_ftarget, false, "[brd chip chan]", "Set or get target value (also 'all' supported)"},
55 {"fresponse", &DAQReadout::cmd_fresponse, false, "[voltage]", "Start response measurement with given voltage difference"},
56 {"fconfig", &DAQReadout::cmd_fconfig, false, "", "Print feedback configuration"},
57 {"help", &DAQReadout::cmd_help, false, "", "Print help"}};
58
59
60// -----------------------------------------------
61// ***** Constructor: Class initialisation *****
62// -----------------------------------------------
63//
64
65DAQReadout::DAQReadout(const char *Configfile) {
66
67 time(&StartTime); // Start time of DAQ
68
69 // Initialize status structure
70 daq_state = stopped;
71 daq_runtype = data;
72 Socket = -1;
73 Exit = false;
74 NumEvents = 0;
75 NumEventsRequested = 0;
76 NumBoards = 0;
77 FirstBoard = 0;
78 LastBoard = -1;
79 CmdFromSocket = false;
80 ConfigOK = true;
81
82 // Read configuration file (if any item missing, program will be terminated in main() routine)
83 FILE *File;
84 if ((File = fopen(Configfile,"r")) == NULL) {
85 printf("Error: Could not open drsdaq configuration file '%s'\n", Configfile);
86 ConfigOK = false;
87 return;
88 }
89 else {
90 printf("Reading drsdaq configuration file %s\n", Configfile);
91 ConfigOK &= ReadCard("LogFile", fLogFile, 's', File);
92 ConfigOK &= ReadCard("SlowDataPath", fSlowDataPath, 's', File);
93 ConfigOK &= ReadCard("MaxLogLines", &fMaxLogLines, 'U', File);
94 ConfigOK &= ReadCard("RawDataPath", fRawDataPath, 's', File);
95 ConfigOK &= ReadCard("CalibDataPath", fCalibDataPath, 's', File);
96 ConfigOK &= ReadCard("FirstSample", &fFirstSample, 'I', File);
97 ConfigOK &= ReadCard("Samples", &fSamples, 'U', File);
98 ConfigOK &= ReadCard("MinDiskSpaceMB", &fMinDiskSpaceMB, 'U', File);
99 ConfigOK &= ReadCard("MaxFileSizeMB", &fMaxFileSizeMB, 'I', File);
100 ConfigOK &= ReadCard("CCPort", &fCCPort, 'I', File);
101 ConfigOK &= ReadCard("HVFeedbackConfig", fHVFeedbackConfig, 's', File);
102 ConfigOK &= ReadCard("DefaultFrequency", &fDefaultFrequency , 'd', File);
103 fclose(File);
104 if (!ConfigOK) return;
105 }
106 if (fFirstSample < 0 || fFirstSample > kNumberOfBins || fSamples > kNumberOfBins) {
107 PrintMessage("Warning: Sample range in configuration beyond limits, setting to full range\n");
108 fFirstSample = kNumberOfBins;
109 fSamples = kNumberOfBins;
110 }
111
112 // Open log file and log configuration
113 if ((Logfile = fopen(fLogFile, "a")) == NULL) printf("Warning: Could not open log file '%s'\n", fLogFile);
114 PrintMessage(MsgToLog,"********** Logging started **********\n");
115 PrintConfig(MsgToLog);
116
117 // Allocate headers and initialise to zero
118 RHeader = new RunHeader;
119 memset(RHeader, 0, sizeof(RunHeader));
120 EHeader = new EventHeader;
121 memset(EHeader, 0, sizeof(EventHeader));
122
123 // Scan for DRS boards
124 DRSFreq = new float [GetNumberOfBoards()];
125 ACalib = new bool [GetNumberOfBoards()];
126 ACalibTemp = new double [GetNumberOfBoards()];
127 TCalib = new bool [GetNumberOfBoards()];
128
129 if (GetNumberOfBoards() == 0) PrintMessage("No DRS boards found - check VME crate and configuration file!\n");
130
131 for (int i=0; i<GetNumberOfBoards(); i++) {
132 NumBoards++;
133 LastBoard++;
134 GetBoard(i)->Init();
135 DRSFreq[i] = 0;
136 ACalib[i] = false;
137 ACalibTemp[i] = -999;
138 TCalib[i] = false;
139 }
140 BStruct = new BoardStructure [NumBoards == 0 ? 1:GetNumberOfBoards()];
141 memset(BStruct, 0, sizeof(BoardStructure)*(NumBoards == 0 ? 1:GetNumberOfBoards()));
142
143 WaveForm = new short [NumBoards == 0 ? 1:NumBoards][kNumberOfChipsMax][kNumberOfChannelsMax][kNumberOfBins];
144 TriggerCell = new int [NumBoards == 0 ? 1:NumBoards][kNumberOfChipsMax] (); // Zero initialised
145
146 // Create instance of HV feedback (must be called after CMC board detection)
147 HVFB = new HVFeedback(this, fHVFeedbackConfig);
148
149 // Create instance of slow data class for DAQ
150 SlowDataClass = new SlowData("DAQ", fSlowDataPath);
151 if(SlowDataClass->ErrorCode != 0) {
152 PrintMessage("Warning: Could not open DAQ slowdata file (%s)\n", strerror(SlowDataClass->ErrorCode));
153 }
154 SlowDataClass->NewEntry("Runinfo-Info", "Run information written after completion or termination of run (Status can be OK or Error): Runnumber Status Runtype Events Files Description ");
155}
156
157// ------------------------
158// ***** Destructor *****
159// ------------------------
160
161DAQReadout::~DAQReadout() {
162 delete SlowDataClass;
163 delete RHeader; delete EHeader;
164 delete HVFB; delete[] ACalibTemp;
165 delete[] ACalib; delete[] TCalib;
166 delete[] DRSFreq; delete[] BStruct;
167 delete[] WaveForm; delete[] TriggerCell;
168
169 if(Logfile) {
170 if(!fclose(Logfile)) printf("Closing logfile\n");
171 else perror("Error closing logfile");
172 }
173}
174
175// --------------------------------
176// ***** Command evaluation *****
177// --------------------------------
178
179void DAQReadout::CommandControl(char *Command) {
180
181 if (strlen(Command)==0) return; // Ignore empty commands
182
183 if(Command[0]=='.') { // Shell command
184 system(&(Command[1]));
185 return;
186 }
187
188 for(int i=0; i<MAX_NUM_TOKEN; i++) Param[i] = ""; // All pointers point initially to empty string
189 NParam = ParseInput(Command, Param);
190
191 for(CmdNumber=0; CmdNumber<sizeof(CommandList)/sizeof(CL_Struct); CmdNumber++)
192 if (Match(Param[0], CommandList[CmdNumber].Name)) {
193 if(CommandList[CmdNumber].NeedNotBusy && daq_state==active) PrintMessage("DAQ is busy\n");
194 else if(CommandList[CmdNumber].NeedNotBusy && NumBoards==0) PrintMessage("No mezzanine boards available\n");
195 else (this->*CommandList[CmdNumber].CommandPointer)();
196 return;
197 }
198 PrintMessage("Unknown command '%s'\n",Param[0]);
199 return;
200}
201
202// Get uptime
203void DAQReadout::cmd_uptime() {
204 time_t ActualT;
205 time (&ActualT);
206 PrintMessage("%d:%02d:%02d\n", (int) difftime(ActualT, StartTime)/3600, ((int) difftime(ActualT, StartTime)/60)%60, (int) difftime(ActualT, StartTime)%60);
207}
208
209// Print disk space
210void DAQReadout::cmd_disk() {
211 PrintMessage("Free disk space (%s) [MB]: %lu\n", fRawDataPath, CheckDisk(fRawDataPath));
212}
213
214// Print current number of events
215void DAQReadout::cmd_events() {
216 if(daq_state != active) PrintMessage("DAQ not active\n");
217 else PrintMessage("Current number of events: %d (of %d requested)\n", NumEvents, NumEventsRequested);
218}
219
220// Print DAQ configuration
221void DAQReadout::cmd_config() {
222 PrintConfig(CmdFromSocket ? MsgToSocket : MsgToConsole);
223}
224
225// Start DAQ
226void DAQReadout::cmd_take() {
227
228 // Check conditions if this is not a test run
229 if(!Match(Param[1],"test")) {
230 if (daq_state==active || NumBoards==0) {
231 PrintMessage("DAQ is busy or no boards available\n");
232 return;
233 }
234 // Check if all boards have the same number of DRS chips and channels
235 // (restriction of current data format)
236 for (int i=FirstBoard; i<=LastBoard-1; i++) {
237 if ((GetBoard(i)->GetNumberOfChannels() != GetBoard(i+1)->GetNumberOfChannels()) || (GetBoard(i)->GetNumberOfChips() != GetBoard(i+1)->GetNumberOfChips())) {
238 PrintMessage("Cannot take data is not all boards have the same number of DRS chips and channels due to data format restriction\n");
239 return;
240 }
241 }
242 if (!IsDRSFreqSet()) {
243 PrintMessage("Setting default frequency\n");
244 SetDRSFrequency(fDefaultFrequency, true);
245 }
246 if (!ReadCalibration()) {
247 PrintMessage("Cannot start run if response calibration not read\n");
248 //return;
249 }
250 // Readout from domino wave stop position (ignored if not DRS4)
251 SetDOMINOReadMode(1);
252 }
253
254 if (Match(Param[1],"data")) {
255 HWTrigger(1);
256 daq_runtype = data;
257 }
258 else if (Match(Param[1],"pedestal")) {
259 HWTrigger(0);
260 daq_runtype = pedestal;
261 }
262 else if (Match(Param[1],"test")) {
263 daq_runtype = test;
264 }
265 else {
266 PrintUsage();
267 return;
268 }
269
270 if (NParam==3) NumEventsRequested = atoi(Param[2]);
271 if (NParam==4) {
272 NumEventsRequested = atoi(Param[2]);
273 strncpy(RHeader->Description, Param[3], sizeof(RHeader->Description));
274 }
275 else snprintf(RHeader->Description,sizeof(RHeader->Description),"DUMMY");
276
277 // Determine new run number using the file given by RUN_NUM_FILE
278 FILE *RunNumFile = fopen(RUN_NUM_FILE,"r+");
279 if(RunNumFile == NULL) {
280 PrintMessage("Error: Could not open file '%s' that contains the last run number (%s)\n",RUN_NUM_FILE,strerror(errno));
281 return;
282 }
283 if(fscanf(RunNumFile,"%u", &RunNumber) != 1 ) {
284 PrintMessage("Error: Could not read run number from file '%s'\n",RUN_NUM_FILE);
285 fclose(RunNumFile);
286 return;
287 }
288 RunNumber++;
289 rewind(RunNumFile);
290 if((fprintf(RunNumFile,"%.8u ",RunNumber) < 0) || (fclose(RunNumFile)!=0)) {
291 PrintMessage("Error: Could not write to or close run number file '%s'\n",RUN_NUM_FILE);
292 PrintMessage("*** This is a serious error because run numbers will get mixed. Fix it. DAQ will terminate.\n");
293 throw;
294 }
295
296 // Create DAQ thread
297 if ((pthread_create(&thread_DAQ, NULL, (void * (*)(void *)) DAQ,(void *) this)) != 0)
298 PrintMessage("pthread_create failed with DAQ thread (%s)\n",strerror(errno));
299 else {
300 daq_state = active;
301 Stop = false;
302 pthread_detach(thread_DAQ);
303 }
304}
305
306// Start DRS
307void DAQReadout::cmd_start() {
308 if (IsDRSFreqSet()) {
309 StartDRS();
310 PrintMessage("Domino wave started\n");
311
312 // Create DAQ thread
313 if ((pthread_create(&thread_DAQ_Silent, NULL, (void * (*)(void *)) DAQ_Silent,(void *) this)) != 0)
314 PrintMessage("pthread_create failed with DAQ_Silent thread (%s)\n",strerror(errno));
315 else {
316 daq_state = active;
317 Stop = false;
318 pthread_detach(thread_DAQ_Silent);
319 }
320 }
321}
322
323// EEPROM test
324void DAQReadout::cmd_eepromtest() {
325
326 unsigned short buf[16384],rbuf[16384];
327 int n = 0;
328
329 for (int i=FirstBoard; i<=LastBoard; i++) {
330 PrintMessage("EEPROM test of board #%d:\n\r",i);
331 for (int j=0; j<16384; j++) buf[j] = rand();
332 GetBoard(i)->WriteEEPROM(1, buf, sizeof(buf));
333 memset(rbuf, 0, sizeof(rbuf));
334 GetBoard(i)->Write(T_RAM, 0, rbuf, sizeof(rbuf));
335 GetBoard(i)->ReadEEPROM(1, rbuf, sizeof(rbuf));
336
337 for (int j=0; j<16384; j++) if (buf[j] != rbuf[j]) n++;
338 printf("32 kByte written, %d errors\n", n);
339 }
340}
341
342// RAM test
343void DAQReadout::cmd_ramtest() {
344 for (int i=FirstBoard; i<=LastBoard; i++) {
345 PrintMessage("RAM integrity and speed test of board #%d:\n",i);
346 GetBoard(i)->RAMTest(3);
347 }
348}
349
350// Register test
351void DAQReadout::cmd_regtest() {
352 for (int i=FirstBoard; i<=LastBoard; i++) {
353 PrintMessage("Register test of board #%d:\n\r",i);
354 GetBoard(i)->RegisterTest();
355 }
356}
357
358// Chip test
359void DAQReadout::cmd_chiptest() {
360 for (int i=FirstBoard; i<=LastBoard; i++) {
361 if (GetBoard(i)->ChipTest()) PrintMessage("Chip test of board %i successful\n", i);
362 else PrintMessage("Chip test of board %i failed\n", i);
363 }
364}
365
366// Stop DAQ
367void DAQReadout::cmd_stop() {
368 if(!daq_state==active && !IsDRSBusy()) PrintMessage("Nothing to stop\n");
369 if (daq_state==active) StopRun();
370 if (IsDRSBusy()) {
371 StopDRS();
372 PrintMessage("Domino wave stopped\n");
373 }
374}
375
376// Read current data
377// For socket transmission: all numbers must be separated by exactly one
378// whitespace; the first number is the number of numbers that follow, the
379// second number the sampling frequency in GHz, the third the conversion factor
380
381void DAQReadout::cmd_read() {
382 if(NumBoards==0) {
383 PrintMessage("No mezzanine boards available\n");
384 return;
385 }
386 if (NParam<4) {
387 PrintUsage();
388 return;
389 }
390 int Board = atoi(Param[1]), Chip = atoi(Param[2]), Channel = atoi(Param[3]);
391
392 if (Board>LastBoard || Board<FirstBoard) {
393 PrintMessage("Error: Board number out of range\n");
394 return;
395 }
396 if (Channel<0 || Channel>=GetBoard(Board)->GetNumberOfChannels()) {
397 PrintMessage("Error: Channel number out of range\n");
398 return;
399 }
400 if (Chip<0 || Chip>=GetBoard(Board)->GetNumberOfChips()) {
401 PrintMessage("Error: Chip number out of range\n");
402 return;
403 }
404
405 if (daq_state != active) {
406 ReadCalibration();
407 if(NParam==5) StopDRS();
408 ReadCalibratedDRSData();
409 if(NParam==5) StartDRS();
410 }
411
412 PrintMessage(CmdFromSocket ? MsgToSocket:MsgToConsole|MsgToLog, "==START== %d %.2f %.2f ",kNumberOfBins+2,DRSFreq[Board],GetBoard(Board)->GetPrecision());
413 double mean=0,square=0.0;
414 for (int k=0; k<kNumberOfBins; k++) {
415// PrintMessage(CmdFromSocket ? MsgToSocket:MsgToConsole|MsgToLog, "%.1f ", (float) WaveForm[Board][Chip][Channel][(k+TriggerCell[Board][Chip])%kNumberOfBins]);
416 PrintMessage(CmdFromSocket ? MsgToSocket:MsgToConsole|MsgToLog, "%.1f ", (float) WaveForm[Board][Chip][Channel][k]);
417
418 mean += (float) WaveForm[atoi(Param[1])][atoi(Param[2])][atoi(Param[3])][(k+TriggerCell[atoi(Param[1])][atoi(Param[2])])%kNumberOfBins];
419 square += pow((float) WaveForm[atoi(Param[1])][atoi(Param[2])][atoi(Param[3])][(k+TriggerCell[atoi(Param[1])][atoi(Param[2])])%kNumberOfBins],2);
420
421
422 }
423 PrintMessage(CmdFromSocket ? MsgToSocket:MsgToConsole|MsgToLog, "==END==");
424 PrintMessage(CmdFromSocket ? MsgToSocket:MsgToConsole|MsgToLog, "\n");
425 PrintMessage(MsgToConsole, "Trigger cell: %d\n", TriggerCell[Board][Chip]);
426 printf("rms: %f\n",sqrt(square/kNumberOfBins - pow(mean/kNumberOfBins,2)));
427}
428
429// Set Domino mode
430void DAQReadout::cmd_dmode() {
431 if (Match(Param[1],"continuous")) SetDOMINOMode(1);
432 else if (Match(Param[1],"single")) SetDOMINOMode(0);
433 else PrintUsage();
434}
435
436// Set Domino readout mode
437void DAQReadout::cmd_rmode() {
438 if (Match(Param[1],"first")) SetDOMINOReadMode(0);
439 else if (Match(Param[1],"stop")) SetDOMINOReadMode(1);
440 else PrintUsage();
441}
442
443// Set Domino wave mode
444void DAQReadout::cmd_wmode() {
445 if (Match(Param[1],"run")) SetDOMINOWaveMode(1);
446 else if (Match(Param[1],"stop")) SetDOMINOWaveMode(0);
447 else PrintUsage();
448}
449
450// Set input range
451void DAQReadout::cmd_centre() {
452
453 if (NParam!=2) {
454 PrintUsage();
455 return;
456 }
457
458 for (int i=FirstBoard; i<=LastBoard; i++) {
459 if (GetBoard(i)->SetInputRange(atof(Param[1])) == 1) {
460 PrintMessage("Range of board %d: %.2f to %.2f Volt (centre %.2f V)\n",i,atof(Param[1])-0.5, atof(Param[1])+0.5, atof(Param[1]));
461 }
462 else PrintMessage("Centre voltage of board %d out of range\n", i);
463 }
464}
465
466// Set refclock source
467void DAQReadout::cmd_refclk() {
468
469 if (NParam!=2) {
470 PrintUsage();
471 return;
472 }
473
474 for (int i=FirstBoard; i<=LastBoard; i++) {
475 if (Match(Param[1], "extern")) GetBoard(i)->SetRefclk(1);
476 else GetBoard(i)->SetRefclk(0);
477 }
478}
479
480// Set trigger mode
481void DAQReadout::cmd_trigger() {
482 if (Match(Param[1],"on")) HWTrigger(1);
483 else if (Match(Param[1],"off")) HWTrigger(0);
484 else PrintUsage();
485}
486
487// Set serial number of board
488void DAQReadout::cmd_serial() {
489 if (NParam==4 && Match(Param[3], "expert")) {
490 if ((atoi(Param[1]) < FirstBoard) || (atoi(Param[1]) > LastBoard))
491 PrintMessage("Board number out of range (%d...%d)!\n",FirstBoard,LastBoard);
492 else if (atoi(Param[2]) < 100 || atoi(Param[2]) >= 1000)
493 PrintMessage("Serial number out of range (100...999)!\n");
494 else {
495 PrintMessage("Flashing EEPROM of board %d...\n", atoi(Param[1]));
496 (GetBoard(atoi(Param[1])))->SetBoardSerialNumber(atoi(Param[2]));
497 }
498 }
499 else PrintMessage("You are not allowed to change the serial number!\n");
500}
501
502// Do amplitude calibration
503void DAQReadout::cmd_acalib() {
504
505 if (!IsDRSFreqSet()) {
506 PrintMessage("Set sampling frequency for all boards first\n");
507 return;
508 }
509
510 for (int i=FirstBoard; i<=LastBoard; i++) {
511 if (GetBoard(i)->GetDRSType()==2 && (NParam!=2 || !atof(Param[1]))) {
512 PrintUsage();
513 return;
514 }
515
516 PrintMessage("Creating amplitude calibration of board %d (serial #%04d)\n", i, GetBoard(i)->GetBoardSerialNumber());
517
518 GetBoard(i)->EnableTcal(0);
519 GetBoard(i)->SelectClockSource(0);
520 if (GetBoard(i)->GetDRSType() == 4) {
521 GetBoard(i)->SetFrequency(DRSFreq[i], true);
522 GetBoard(i)->CalibrateVolt(this);
523 } else {
524 GetBoard(i)->Init();
525 GetBoard(i)->SetFrequency(DRSFreq[i], true);
526 GetBoard(i)->SoftTrigger();
527
528 if (GetBoard(i)->GetDRSType() == 3) {
529 GetBoard(i)->GetResponseCalibration()->SetCalibrationParameters(1,11,0,20,0,0,0,0,0);
530 }
531 else GetBoard(i)->GetResponseCalibration()->SetCalibrationParameters(1,36,110,20,19,40,15,atof(Param[1]),0);
532
533 GetBoard(i)->SetCalibrationDirectory(fCalibDataPath);
534 for (int j=0; j<2; j++) {
535 GetBoard(i)->GetResponseCalibration()->ResetCalibration();
536 while (!GetBoard(i)->GetResponseCalibration()->RecordCalibrationPoints(j)) {}
537 PrintMessage("Calibration points recorded.\n");
538 while (!GetBoard(i)->GetResponseCalibration()->FitCalibrationPoints(j)) {}
539 PrintMessage("Calibration points fitted.\n");
540 while (!GetBoard(i)->GetResponseCalibration()->OffsetCalibration(j)) {}
541 PrintMessage("Offset calibration done.\n");
542 if (!GetBoard(i)->GetResponseCalibration()->WriteCalibration(j)) break;
543 }
544 } // else for DRS2/3
545 ACalib[i] = true;
546 ACalibTemp[i] = GetBoard(i)->GetTemperature();
547 } // Loop over boards
548 PrintMessage("Amplitude calibration finished\n");
549}
550
551// Do time calibration
552void DAQReadout::cmd_tcalib() {
553
554 if (!IsDRSFreqSet()) {
555 PrintMessage("Set sampling frequency for all boards first\n");
556 return;
557 }
558
559 for (int i=FirstBoard; i<=LastBoard; i++) {
560 if (GetBoard(i)->GetDRSType() != 4 || GetBoard(i)->GetFirmwareVersion() < 13279) {
561 PrintMessage("Time calibration needs DRS4 and minimum firmware version 13279, skipping board %d\n", i);
562 continue;
563 }
564 if (!ACalib[i]) {
565 PrintMessage("Amplitude calibration of board %d has to be done first, skipping this board\n", i);
566 continue;
567 }
568 PrintMessage("Creating time calibration of board %d (serial #%04d)\n", i, GetBoard(i)->GetBoardSerialNumber());
569
570 GetBoard(i)->SetFrequency(DRSFreq[i], true);
571 if (GetBoard(i)->CalibrateTiming(this) != 1) {
572 PrintMessage("Time calibration method returned error status, stopping calibration\n");
573 return;
574 }
575
576 TCalib[i] = true;
577
578 // Write calibration data to file
579 float Time[kNumberOfChipsMax][kNumberOfBins];
580 char *Filename;
581 FILE *Calibfile;
582 bool WriteOK = true;
583
584 // Copy calibration data into array
585 for (int Chip=0; Chip<GetBoard(i)->GetNumberOfChips(); Chip++) {
586 GetBoard(i)->GetTime(Chip, Time[Chip], true, false);
587 }
588
589 if (asprintf(&Filename, "TCalib_%d_%.2fGHz.txt", GetBoard(i)->GetBoardSerialNumber(), DRSFreq[i]) == -1) {
590 PrintMessage("Error: asprintf() failed, cannot generate filename (%s)\n", strerror(errno));
591 return;
592 }
593 if ((Calibfile=fopen(Filename,"w")) == NULL) {
594 PrintMessage("Error: Could not open file '%s' \n", Filename);
595 }
596 else {
597 if(fprintf(Calibfile, "# DRS time calibration\n") == -1) WriteOK = false;
598
599 for (int Bin=0; Bin<kNumberOfBins; Bin++) {
600 for (int Chip=0; Chip<GetBoard(i)->GetNumberOfChips(); Chip++) {
601 if(fprintf(Calibfile, "%.2f ", Time[Chip][Bin]) == -1) WriteOK = false;
602 }
603 if(fprintf(Calibfile, "\n") == -1) WriteOK = false;
604 }
605 if (fclose(Calibfile) != 0) PrintMessage("Error closing file '%s'\n", Filename);
606 }
607 if (!WriteOK) PrintMessage("Error writing to file '%s'\n", Filename);
608 else PrintMessage("Calibration written to file '%s'\n", Filename);
609
610 free(Filename);
611 }
612 PrintMessage("Time calibration finished\n");
613}
614
615// Set DRS sampling frequency
616void DAQReadout::cmd_freq() {
617 if (NParam>=2 && atof(Param[1])) {
618 SetDRSFrequency(atof(Param[1]), NParam==2 ? false : true);
619 }
620 else PrintUsage();
621}
622
623// Set LED
624void DAQReadout::cmd_led() {
625 if (Match(Param[1], "on") || Match(Param[1], "off"))
626 for (int i=FirstBoard; i<=LastBoard; i++)
627 (GetBoard(i))->SetLED(Match(Param[1], "on") ? 1 : 0);
628 else PrintUsage();
629}
630
631// Print status
632void DAQReadout::cmd_status() {
633
634 double freq;
635
636 if(NParam==1 || Match(Param[1],"daq")) {
637 PrintMessage("********** DAQ STATUS **********\n"
638 " DAQ: %s\n"
639 " Run number: %d\n"
640 " Run type: %s\n"
641 " Event: %d\n"
642 " Requested events per run: %d\n"
643 " Storage directory: %s\n"
644 " Disk space: %lu MByte\n"
645 " Socket state: %s\n"
646 " Total number of DRS boards: %d\n"
647 " Active DRS boards: %d\n",
648 daq_state_str[daq_state], daq_state==active ? (int) RunNumber:-1,
649 daq_state==active ? daq_runtype_str[daq_runtype]:"n/a", NumEvents,
650 NumEventsRequested, fRawDataPath,
651 CheckDisk(fRawDataPath), Socket==-1 ? "disconnected":"connected",
652 NumBoards, LastBoard - FirstBoard + 1);
653
654 for (int i=FirstBoard;i<=LastBoard;i++)
655 PrintMessage(" Frequency of board %d set: %s\n",i,(DRSFreq[i]!=0 ? "yes":"no"));
656 }
657
658 if(NParam==1 || Match(Param[1],"drs")) {
659 PrintMessage("\n********** DRS STATUS **********\n");
660 if (NumBoards) {
661 for (int i=FirstBoard; i<=LastBoard; i++) {
662
663 PrintMessage("Board #%d in slot %d %s\n",i,((GetBoard(i))->GetSlotNumber() >> 1)+2,((GetBoard(i))->GetSlotNumber() & 1)==0 ? "upper":"lower");
664 PrintMessage(" DRS%d serial %d, firmware %d\n"
665 " Actual temperature: %1.1lf C\n"
666 " Calibration temp.: %1.1lf C\n"
667 " Status reg.: 0x%08X\n",
668 GetBoard(i)->GetDRSType(),
669 GetBoard(i)->GetBoardSerialNumber(),
670 GetBoard(i)->GetFirmwareVersion(),
671 GetBoard(i)->GetTemperature(),
672 ACalibTemp[i],
673 GetBoard(i)->GetStatusReg());
674
675
676 if (GetBoard(i)->GetStatusReg() & BIT_RUNNING)
677 PrintMessage(" Domino wave running\n");
678 if (GetBoard(i)->GetStatusReg() & BIT_NEW_FREQ1)
679 PrintMessage(" New Freq1 ready\n");
680 if (GetBoard(i)->GetStatusReg() & BIT_NEW_FREQ2)
681 PrintMessage(" New Freq2 ready\n");
682
683 PrintMessage(" Control reg.: 0x%08X\n", (GetBoard(i))->GetCtrlReg());
684 if (GetBoard(i)->GetCtrlReg() & BIT_AUTOSTART)
685 PrintMessage(" AUTOSTART enabled\n");
686 if (GetBoard(i)->GetCtrlReg() & BIT_DMODE)
687 PrintMessage(" DMODE circular\n");
688 else
689 PrintMessage(" DMODE single shot\n");
690 if (GetBoard(i)->GetCtrlReg() & BIT_LED)
691 PrintMessage(" LED\n");
692 if (GetBoard(i)->GetCtrlReg() & BIT_TCAL_EN)
693 PrintMessage(" TCAL enabled\n");
694 if (GetBoard(i)->GetCtrlReg() & BIT_TCAL_SOURCE)
695 PrintMessage(" TCAL_SOURCE enabled\n");
696 if (GetBoard(i)->GetCtrlReg() & BIT_FREQ_AUTO_ADJ)
697 PrintMessage(" FREQ_AUTO_ADJ enabled\n");
698 if (GetBoard(i)->GetCtrlReg() & BIT_ENABLE_TRIGGER1)
699 PrintMessage(" ENABLE_TRIGGER\n");
700 if (GetBoard(i)->GetCtrlReg() & BIT_LONG_START_PULSE)
701 PrintMessage(" LONG_START_PULSE\n");
702 if (GetBoard(i)->GetCtrlReg() & BIT_ACAL_EN)
703 PrintMessage(" ACAL enabled\n");
704 PrintMessage(" Trigger bus: 0x%08X\n", GetBoard(i)->GetTriggerBus());
705 if (GetBoard(i)->IsBusy()) {
706 GetBoard(i)->ReadFrequency(0, &freq);
707 PrintMessage(" Frequency0: %1.4lf GHz\n", freq);
708 GetBoard(i)->ReadFrequency(1, &freq);
709 PrintMessage(" Frequency1: %1.4lf GHz\n", freq);
710 }
711 else PrintMessage(" Domino wave stopped\n");
712 }
713 }
714 else PrintMessage("No DRS boards available!\n\n");
715 }
716}
717
718// Adress DRS boards
719void DAQReadout::cmd_board() {
720 if (Match(Param[1],"all")) {
721 FirstBoard = 0;
722 LastBoard = GetNumberOfBoards()-1;
723 }
724 else if (NParam==2 && atoi(Param[1])>=0 && atoi(Param[1])<NumBoards) {
725 FirstBoard = atoi(Param[1]);
726 LastBoard = FirstBoard;
727 }
728 else if (NParam==3 && atoi(Param[1])>=0 && atoi(Param[1])<NumBoards &&
729 atoi(Param[2])>0 && atoi(Param[2])<NumBoards) {
730 FirstBoard = atoi(Param[1]);
731 LastBoard = atoi(Param[2]);
732 }
733 else PrintMessage("Cannot address board(s), out of range.\n");
734}
735
736// Print help (only to console or socket, not to log file)
737void DAQReadout::cmd_help() {
738 char Buffer[MAX_COM_SIZE];
739 for(unsigned int i=0; i<sizeof(CommandList)/sizeof(CL_Struct); i++) {
740 snprintf(Buffer, sizeof(Buffer), "%s %s", CommandList[i].Name, CommandList[i].Parameters);
741 PrintMessage(CmdFromSocket ? MsgToSocket:MsgToConsole,"%-28s%s\n", Buffer, CommandList[i].Help);
742 }
743 PrintMessage(CmdFromSocket ? MsgToSocket:MsgToConsole,".<command> Execute shell command\n\n"
744 "Items in <> are mandatory, in [] optional, | indicates mutual exclusive or.\n"
745 "Test data can also be written if no DRS boards are available.\n"
746 "Strings containing spaces have to be enclosed in \"double quotes\".\n");
747}
748
749// Exit programm
750void DAQReadout::cmd_exit() {
751 if (CmdFromSocket) {
752 PrintMessage("Exit command not allowed over socket.\n");
753 return;
754 }
755 if (daq_state==active) PrintMessage("Issue \"stop\" first to stop daq\n");
756 else {
757 Exit = true;
758 if(SocketThread != NULL) pthread_kill(*SocketThread, SIGUSR1);
759 }
760}
761
762// Set/get mode of feedback
763void DAQReadout::cmd_fmode() {
764 if(Match(Param[1],"off")) HVFB->SetFBMode(FB_Off);
765 if(Match(Param[1],"active")) HVFB->SetFBMode(FB_Active);
766 if(Match(Param[1],"targets")) HVFB->SetFBMode(FB_Targets);
767 HVFB->GetFBMode();
768}
769
770// Set/get current number of events
771void DAQReadout::cmd_faverage() {
772 if(NParam==1) PrintMessage("Current number of feedback events: %u (acting when %u events are reached)\n",
773 HVFB->GetCurrentCount(), HVFB->GetNumAverages());
774 else if(atoi(Param[1])>=0) HVFB->SetNumAverages(atoi(Param[1]));
775 else PrintUsage();
776}
777
778// Set/get feedback gain
779void DAQReadout::cmd_fgain() {
780 if(NParam==2) HVFB->SetGain(atof(Param[1]));
781 PrintMessage("Feedback gain is %.2f\n", HVFB->GetGain());
782}
783
784// Set/get target value
785void DAQReadout::cmd_ftarget() {
786 if(NParam==1) HVFB->GetTargets();
787 else if(NParam!=5) PrintUsage();
788 else for (int i=FirstBoard; i<=LastBoard; i++)
789 for (int j=0; j<GetBoard(i)->GetNumberOfChips(); j++)
790 for (int k=0; k<GetBoard(i)->GetNumberOfChannels(); k++)
791 if ((atoi(Param[1])==i || Match(Param[1],"all")) &&
792 (atoi(Param[2])==j || Match(Param[2],"all")) &&
793 (atoi(Param[3])==k || Match(Param[3],"all")))
794 HVFB->SetTarget(i,j,k,atof(Param[4]));
795}
796
797// Start response measurement
798void DAQReadout::cmd_fresponse() {
799 if(NParam==1) HVFB->GetResponse();
800 else if(atof(Param[1])) HVFB->MeasureResponse(atof(Param[1]));
801 else PrintUsage();
802}
803
804// Print feedback configuration
805void DAQReadout::cmd_fconfig() {
806 HVFB->PrintConfig(CmdFromSocket ? MsgToSocket : MsgToConsole);
807}
808
809// ----------------------------------------------
810// ***** Utility function for DRS control *****
811// ----------------------------------------------
812
813// Start domino wave
814void DAQReadout::StartDRS() {
815 for (int i=FirstBoard; i<=LastBoard; i++) GetBoard(i)->StartDomino();
816}
817
818// Stop domino wave
819void DAQReadout::StopDRS() {
820 for (int i=FirstBoard; i<=LastBoard; i++) GetBoard(i)->SoftTrigger();
821}
822
823// Transfer amplitude-calibrated waveforms to memory
824void DAQReadout::ReadCalibratedDRSData() {
825
826 for (int i=FirstBoard; i<=LastBoard; i++) {
827 GetBoard(i)->TransferWaves(GetBoard(i)->GetNumberOfChannels()*GetBoard(i)->GetNumberOfChips());
828
829 for (int j=0; j<GetBoard(i)->GetNumberOfChannels(); j++) {
830 for (int k=0; k<GetBoard(i)->GetNumberOfChips(); k++) {
831 GetBoard(i)->GetWave(k, j, WaveForm[i][k][j], true, GetBoard(i)->GetTriggerCell(k));
832 TriggerCell[i][k] = GetBoard(i)->GetTriggerCell(k);
833 }
834 }
835 }
836}
837
838// Read calibration file
839bool DAQReadout::ReadCalibration() {
840
841 for (int i=FirstBoard; i<=LastBoard; i++) {
842 if (!TCalib[i]) PrintMessage("Warning: No time calibration for board %d\n", i);
843
844 if (GetBoard(i)->GetDRSType() == 4) {
845 if (ACalib[i] == false) return false;
846 }
847 else {
848 if (!ACalib[i]) {
849 GetBoard(i)->SetCalibrationDirectory(fCalibDataPath);
850 PrintMessage("Reading response calibration file for board %d from: \"%s\"\n", i, fCalibDataPath);
851 for (int Chip=0; Chip<GetBoard(i)->GetNumberOfChips(); Chip++) {
852 if (GetBoard(i)->GetResponseCalibration()->ReadCalibration(Chip) == false) return false;
853 }
854 ACalib[i] = true;
855 }
856 }
857 } // Loop over boards
858 return true;
859}
860
861// Stop DAQ
862void DAQReadout::StopRun() {
863
864 if(daq_state != active) PrintMessage("DAQ is not active.\n");
865 else {
866 Stop = true;
867 PrintMessage("DAQ will stop.\n");
868 }
869}
870
871// Set DOMINO mode
872void DAQReadout::SetDOMINOMode(int mode) {
873
874 for (int i=FirstBoard; i<=LastBoard; i++) {
875 GetBoard(i)->SetDominoMode(mode==1 ? 1:0);
876 PrintMessage("Domino mode of board %d switched to %s.\n",i,mode==1 ? "continuous":"single shot");
877 }
878}
879
880// Set DOMINO readout mode
881void DAQReadout::SetDOMINOReadMode(int mode) {
882
883 for (int i=FirstBoard; i<=LastBoard; i++) {
884 GetBoard(i)->SetReadoutMode(mode);
885 PrintMessage("Start readout of board %d from %s.\n",i,mode==0 ? "first bin":"stop position");
886 }
887}
888
889// Set DOMINO wave mode
890void DAQReadout::SetDOMINOWaveMode(int mode) {
891
892 for (int i=FirstBoard; i<=LastBoard; i++) {
893 GetBoard(i)->SetDominoActive(mode);
894 PrintMessage("Domino wave of board %d is %s during readout\n",i,mode==1 ? "running":"stopped");
895 }
896}
897
898// Enable hardware trigger of all boards
899void DAQReadout::HWTrigger(int mode) {
900
901 if (NumBoards)
902 for (int i=FirstBoard; i<=LastBoard; i++) {
903 GetBoard(i)->EnableTrigger(mode, 0);
904 PrintMessage("Hardware trigger of board %d %s\n",i,mode==1 ? "enabled":"disabled");
905 }
906 else PrintMessage("No DRS boards available\n");
907}
908
909// Set DRS sampling frequency
910void DAQReadout::SetDRSFrequency(double freq, bool Regulation) {
911
912 PrintMessage("Setting frequency %s regulation\n",Regulation ? "with":"without");
913
914 for (int i=FirstBoard; i<=LastBoard; i++) {
915 if ((Regulation ? GetBoard(i)->RegulateFrequency(freq) :
916 GetBoard(i)->SetFrequency(freq, true)) == 0) {
917 PrintMessage("Warning: Board %d has not reached the requested value\n",i);
918 }
919
920 double f;
921 GetBoard(i)->ReadFrequency(0, &f);
922 DRSFreq[i] = f;
923 ACalib[i] = false;
924 TCalib[i] = false;
925 PrintMessage("Board %d is running at %1.3lf GHz\n",i,f);
926 }
927}
928
929// Check if DRS is sampling
930bool DAQReadout::IsDRSBusy() {
931
932 for (int i=FirstBoard; i<=LastBoard; i++)
933 if ((GetBoard(i))->IsBusy()) return true;
934 return false;
935}
936
937// Check if DRS frequency is set
938bool DAQReadout::IsDRSFreqSet() {
939
940 for (int i=FirstBoard; i<=LastBoard; i++)
941 if (DRSFreq[i] == 0) {
942 PrintMessage("Sampling frequency of DRS board %d not set\n", i);
943 return false;
944 }
945 return true;
946}
947
948// Open new raw data file
949bool DAQReadout::OpenRawFile() {
950
951 time_t rawtime;
952 struct tm *timeinfo;
953 char RunDate[MAX_COM_SIZE], Buffer[MAX_COM_SIZE];
954
955 // Write run date to status structure (if after 13:00, use next day)
956 time(&rawtime);
957 timeinfo = gmtime(&rawtime);
958 if(timeinfo->tm_hour>=13) rawtime += 12*60*60;
959 timeinfo = gmtime(&rawtime);
960 snprintf(RunDate,sizeof(RunDate),"%d%02d%02d",timeinfo->tm_year+1900,timeinfo->tm_mon + 1,timeinfo->tm_mday);
961
962 // Create direcory if not existing (ignore error if already existing) and change to it
963 snprintf(Buffer, sizeof(Buffer), "%s/%s", fRawDataPath, RunDate);
964 if(mkdir(Buffer, S_IRWXU|S_IRWXG)==-1 && errno!=EEXIST) {
965 PrintMessage("\rError: Could not create direcory \"%s\" (%s)\n", Buffer, strerror(errno));
966 return false;
967 }
968
969 // Generate filename
970 snprintf(FileName,sizeof(FileName),"%s/%s/%s_D1_%.8u.%.3u_%c_%s.raw", fRawDataPath, RunDate,
971 RunDate,RunNumber,FileNumber,toupper(daq_runtype_str[daq_runtype][0]),RHeader->Description);
972
973 // Open file with rwx right for owner and group, never overwrite file
974 Rawfile = open(FileName,O_WRONLY|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
975 if(Rawfile==-1) {
976 PrintMessage("\rError: Could not open file \"%s\" (%s)\n", FileName, strerror(errno));
977 return false;
978 }
979 return true;
980}
981
982// Write run header and board structures (revision number is zero for svn modified working copy)
983bool DAQReadout::WriteRunHeader() {
984
985 struct timeval Time;
986
987 RHeader->MagicNum = MAGICNUM_OPEN;
988 RHeader->DataFormat = DATA_FORMAT;
989 RHeader->SoftwareRevision = atoi(REVISION) * (strchr(REVISION, 'M')==NULL ? 1:-1);
990
991 RHeader->RunHeaderSize = sizeof(RunHeader);
992 RHeader->EventHeaderSize = sizeof(EventHeader);
993 RHeader->BoardStructureSize = sizeof(BoardStructure);
994
995 RHeader->Identification = IDENTIFICATION;
996 RHeader->Type = daq_runtype;
997 RHeader->RunNumber = RunNumber;
998 RHeader->FileNumber = FileNumber;
999
1000 gettimeofday(&Time, NULL);
1001 RHeader->StartSecond = Time.tv_sec;
1002 RHeader->StartMicrosecond = Time.tv_usec;
1003
1004 RHeader->NBoards = NumBoards==0 && daq_runtype==test ? 1 : (LastBoard - FirstBoard) + 1;
1005 RHeader->NChips = NumBoards==0 ? kNumberOfChipsMax : GetBoard(0)->GetNumberOfChips();
1006 RHeader->NChannels = NumBoards==0 ? kNumberOfChannelsMax : GetBoard(0)->GetNumberOfChannels();
1007 RHeader->NBytes = sizeof(short);
1008
1009 RHeader->Offset = fFirstSample;
1010 RHeader->Samples = fSamples;
1011
1012 if(write(Rawfile, RHeader, sizeof(RunHeader)) != sizeof(RunHeader)) {
1013 PrintMessage("Error: Could not write run header, terminating run (%s)\n", strerror(errno));
1014 return false;
1015 }
1016
1017 for (int i=FirstBoard; i<=LastBoard; i++) {
1018 BStruct[i].SerialNo = GetBoard(i)->GetBoardSerialNumber();
1019 BStruct[i].BoardTemp = GetBoard(i)->GetTemperature();
1020 BStruct[i].NomFreq = DRSFreq[i];
1021 BStruct[i].ScaleFactor = GetBoard(i)->GetPrecision();
1022 }
1023
1024 // In case no boards are available, dummy data is written for one board structure
1025 if (NumBoards == 0) {
1026 BStruct[0].NomFreq = 1;
1027 BStruct[0].ScaleFactor = 0.1;
1028 }
1029
1030 if(write(Rawfile, &BStruct[FirstBoard], sizeof(BoardStructure)*(LastBoard-FirstBoard+1+(NumBoards==0))) != (ssize_t) sizeof(BoardStructure)*(LastBoard-FirstBoard+1+(NumBoards==0))) {
1031 PrintMessage("Error: Could not write (all) board structures, terminating run (%s)\n", strerror(errno));
1032 return false;
1033 }
1034 return true;
1035}
1036
1037// Update run header before closing file
1038bool DAQReadout::UpdateRunHeader(unsigned int Events, bool Error) {
1039
1040 struct timeval Time;
1041
1042 RHeader->MagicNum = Error==false ? MAGICNUM_CLOSED:MAGICNUM_ERROR;
1043 RHeader->Events = Events;
1044
1045 gettimeofday(&Time, NULL);
1046 RHeader->EndSecond = Time.tv_sec;
1047 RHeader->EndMicrosecond = Time.tv_usec;
1048
1049 if(lseek(Rawfile,0,SEEK_SET)==-1) {
1050 PrintMessage("Error: Could not rewind file to write updated run header, terminating run (%s)\n", strerror(errno));
1051 return false;
1052 }
1053
1054 if(write(Rawfile, RHeader, sizeof(RunHeader)) != sizeof(RunHeader)) {
1055 PrintMessage("Error: Could not write updated run header, terminating run (%s)\n", strerror(errno));
1056 return false;
1057 }
1058 return true;
1059}
1060
1061// Write event
1062bool DAQReadout::WriteEvent() {
1063
1064 // Event header
1065 struct timeval Time;
1066
1067 gettimeofday(&Time, NULL);
1068
1069 EHeader->EventNumber = NumEvents;
1070 EHeader->TriggerType = daq_runtype==data ? 0 : 1;
1071 EHeader->Second = Time.tv_sec;
1072 EHeader->Microsecond = Time.tv_usec;
1073 EHeader->EventSize = sizeof(short)*RHeader->NBoards*RHeader->NChips*RHeader->NChannels*RHeader->Samples +
1074 sizeof(int)*RHeader->NBoards*RHeader->NChips;
1075
1076 if(write(Rawfile, EHeader, sizeof(EventHeader)) != sizeof(EventHeader)) {
1077 PrintMessage("Error: Could not write event header, terminating run (%s)\n", strerror(errno));
1078 return false;
1079 }
1080
1081 // Event data (It is required that at least three chunks can be written with writev(), therefore
1082 // IOV_MAX>=3 is checked at startup
1083
1084 unsigned int Start, Count = 0;
1085 ssize_t WriteResult, Size = 0;
1086 struct iovec DataPart[IOV_MAX];
1087
1088 // First chunk: trigger cells
1089 DataPart[Count].iov_base = (char *) TriggerCell + FirstBoard*RHeader->NChips*sizeof(int); // TriggerCell is without cast a pointer to an 8-byte unit (two ints) !
1090 DataPart[Count++].iov_len = RHeader->NBoards * RHeader->NChips * sizeof(int);
1091 Size += DataPart[Count-1].iov_len;
1092
1093 // Remaining chunks: ADC data (two chucks per channel if wrap around of pipeline occurred)
1094 for (int i=FirstBoard; (i<=LastBoard + (NumBoards==0)); i++) {
1095 for (unsigned int k=0; k<RHeader->NChips; k++) {
1096 // Start bin
1097 if (GetBoard(i)->GetDRSType() == 4) Start = 0;
1098 else Start = (TriggerCell[i][k]-fFirstSample+kNumberOfBins) % kNumberOfBins;
1099 for (unsigned int l=0; l<RHeader->NChannels; l++) {
1100 DataPart[Count].iov_base = &WaveForm[i][k][l][Start];
1101 DataPart[Count++].iov_len = (Start+fSamples<kNumberOfBins ? fSamples:(kNumberOfBins-Start)) * sizeof(short);
1102 Size += DataPart[Count-1].iov_len;
1103 // In case second part of waveform still missing, write now
1104 if(DataPart[Count-1].iov_len < fSamples * sizeof(short)) {
1105 DataPart[Count].iov_base = &WaveForm[i][k][l][0];
1106 DataPart[Count++].iov_len = (fSamples-(kNumberOfBins-Start)) * sizeof(short);
1107 Size += DataPart[Count-1].iov_len;
1108 }
1109
1110 // Write to disk if either maximum size of DataPart[] array or last loop interation is reached
1111 // Possibly 2 chunks are entered in array in the previous lines of code, therefore IOV_MAX-1
1112 if (Count>=IOV_MAX-1 || (l==(RHeader->NChannels-1) && k==(RHeader->NChips-1) && i==(LastBoard+(NumBoards==0)))) {
1113 if ((WriteResult=writev(Rawfile, DataPart, Count)) != (int) Size) {
1114 if (WriteResult==-1) PrintMessage("Error: Could not write event data, terminating run (%s)\n", strerror(errno));
1115 else PrintMessage("Error: Could only write %u out of %u bytes of event data, terminating run\n", WriteResult,Count*DataPart[0].iov_len);
1116 return false;
1117 }
1118 Count = 0; Size = 0;
1119 }
1120 } // Channels
1121 } // Chips
1122 } // Boards
1123
1124 return true;
1125}
1126
1127// Print configuration to target
1128void DAQReadout::PrintConfig(int Target) {
1129 PrintMessage(Target, "LogFile: %s\tMaxLogLines: %u\tRawDataPath: %s\n"
1130 "DefaultFrequency: %.2f\tFirstSample: %d\tSamples: %u\n"
1131 "MinDiskSpaceMB: %u\tMaxFileSizeMB: %d\tCCPort: %d\n"
1132 "CalibDataPath: %s\n"
1133 "SlowDataPath: %s\tHVFeedbackConfig: %s\n",
1134 fLogFile,fMaxLogLines,fRawDataPath,fDefaultFrequency,fFirstSample,fSamples,fMinDiskSpaceMB,
1135 fMaxFileSizeMB,fCCPort,fCalibDataPath,fSlowDataPath,fHVFeedbackConfig);
1136}
1137
1138// Print usage text for command
1139void DAQReadout::PrintUsage() {
1140 PrintMessage("Usage: %s %s\n", CommandList[CmdNumber].Name, CommandList[CmdNumber].Parameters);
1141}
1142
1143// Print progress (used in DRS class)
1144void DAQReadout::Progress(int Progress) {
1145 PrintMessage(MsgToConsole, "\rProgress: %d%% ", Progress);
1146 fflush(stdout);
1147};
1148
1149// Print message to selected target
1150void DAQReadout::PrintMessage(int Target, const char *Format, ...) {
1151
1152 va_list ArgumentPointer;
1153 va_start(ArgumentPointer, Format);
1154 DoPrintMessage(Format, ArgumentPointer, Target);
1155 va_end(ArgumentPointer);
1156}
1157
1158// Print message to log file, and screen or socket (depending on command origin)
1159void DAQReadout::PrintMessage(const char *Format, ...) {
1160 va_list ArgumentPointer;
1161 va_start(ArgumentPointer, Format);
1162 if(CmdFromSocket) DoPrintMessage(Format, ArgumentPointer, MsgToSocket|MsgToLog);
1163 else DoPrintMessage(Format, ArgumentPointer, MsgToConsole|MsgToLog);
1164 va_end(ArgumentPointer);
1165}
1166
1167// Function doing the actual printing work
1168// Note: Be careful when overloading variadic functions. va_list is
1169// in gcc an int, which can be interpreted as char *...
1170void DAQReadout::DoPrintMessage(const char *Format, va_list ArgumentPointer, int Target) {
1171
1172 static char Textbuffer[MAX_COM_SIZE]; // static: it is only allocated once
1173
1174 memset(Textbuffer, 0, sizeof(Textbuffer));
1175 vsnprintf(Textbuffer, sizeof(Textbuffer), Format, ArgumentPointer);
1176
1177 // Print to console
1178 if(Target & MsgToConsole) {
1179 if(strlen(Textbuffer)>0 && Textbuffer[strlen(Textbuffer)-1]=='\n') {
1180 printf("\r%s%s", Textbuffer, Prompt); // New prompt
1181 fflush(stdout);
1182 }
1183 else printf("%s", Textbuffer);
1184 }
1185 // Print to log file
1186 if((Target & MsgToLog) && Logfile!=NULL) {
1187 time_t Time;
1188 strftime(Textbuffer+strlen(Textbuffer)+1,MAX_COM_SIZE-strlen(Textbuffer)-1, "%d/%m/%y %X", localtime(&(Time=time(NULL))));
1189 fprintf(Logfile, "%s: %s", Textbuffer+strlen(Textbuffer)+1, Textbuffer);
1190 fflush(Logfile);
1191 }
1192 // Print to socket
1193 if((Target & MsgToSocket) && Socket!=-1) write(Socket, Textbuffer, strlen(Textbuffer));
1194}
1195
1196
1197// ---------------------------------------
1198// ***** Various utility functions *****
1199// ---------------------------------------
1200
1201// Check if two strings match (min 1 character must match)
1202bool Match(const char *str, const char *cmd) {
1203 return strncasecmp(str,cmd,strlen(str)==0 ? 1:strlen(str)) ? false:true;
1204}
1205
1206// Return current available storage space in given directory
1207int CheckDisk(char *Directory) {
1208 struct statfs FileSystemStats;
1209
1210 statfs(Directory, &FileSystemStats);
1211 return FileSystemStats.f_bavail / 1024 * (FileSystemStats.f_bsize / 1024);
1212}
1213
1214// Parse command line for white space and double-quote separated tokens
1215int ParseInput(char* Command, const char *Param[]) {
1216 int Count=0;
1217
1218 while(Count<MAX_NUM_TOKEN) {
1219 while (isspace(*Command)) Command++; // Ignore initial white spaces
1220 if(*Command=='\0') break;
1221 if (*Command == '\"') {
1222 Param[Count] = ++Command;
1223 while(*Command!='\"' && *Command!='\0') Command++;
1224 }
1225 else {
1226 Param[Count] = Command;
1227 while(!isspace(*Command) && *Command!='\0') Command++;
1228 }
1229 if(*Command != '\0') *Command++ = '\0';
1230 Count++;
1231 }
1232 return Count;
1233}
1234
1235// ReadCard function (original version by F. Goebel)
1236// Data is read into an array if MaxNum is larger than 1
1237bool ReadCard(const char *card_flag, void *store, char Type, FILE *File, unsigned int MaxNum) {
1238
1239 char *card_name, *card_val, Buffer[MAX_COM_SIZE];
1240 unsigned int Count=0;
1241
1242 rewind(File);
1243
1244 while (fgets(Buffer, sizeof(Buffer), File) != NULL) { // Read line by line
1245 card_name = strtok(Buffer," \t\n");
1246
1247 // Ignore empty lines, comments, and skip if card name does not match
1248 if (card_name==NULL || card_name[0]=='#' || strcmp(card_name, card_flag)!=0) continue;
1249
1250 // Read numbers of given type (if MaxNum>1 read array)
1251 while ((card_val=strtok(NULL," \t\n")) != NULL && Count++<MaxNum) {
1252 switch (Type) {
1253 case 'I': *(((int *&) store)++) = (int) strtol(card_val, NULL, 10);
1254 break;
1255 case 'i': *(((short *&) store)++) = (short) strtol(card_val, NULL, 10);
1256 break;
1257 case 'U': *(((unsigned int *&) store)++) = (unsigned int) strtoul(card_val, NULL, 10);
1258 break;
1259 case 'u': *(((unsigned short *&) store)++) = (unsigned short) strtoul(card_val, NULL, 10);
1260 break;
1261 case 'f': *(((float *&) store)++) = atof(card_val);
1262 break;
1263 case 'd': *(((double *&) store)++) = atof(card_val);
1264 break;
1265 case 's': sprintf((char *) store, "%s", card_val);
1266 break;
1267 case 'c': *((char *) store) = card_val[0];
1268 break;
1269 default: fprintf(stderr,"Warning: Unknown type '%c' for reading of configuration file\n", Type);
1270 return false;
1271 }
1272 }
1273 return true; // Finished reading data for card name
1274
1275 }
1276 fprintf(stderr,"Warning: Configuration value %s not found\n", card_flag);
1277 return false;
1278}
1279
1280
1281/********************************************************************\
1282
1283 DAQ Thread
1284
1285 This thread takes data until the requested number of events is reached,
1286 until no more disk space is available or until data taking is stopped.
1287 No mutex mechanism is used since variables will never be written
1288 simultaneoously by two threads.
1289
1290\********************************************************************/
1291
1292void DAQ(DAQReadout *m) {
1293
1294 struct timeval StartTime, StopTime;
1295 unsigned int EventsInFile;
1296 unsigned long long RunSize = 0;
1297 bool WriteError = false;
1298 off_t FileSize;
1299
1300 m->NumEvents = 0;
1301 m->FileNumber = 0;
1302 m->HVFB->ClearAverages();
1303 gettimeofday(&StartTime, NULL);
1304 m->PrintMessage("\rStarting run #%d (%s) with %u event(s)\n",m->RunNumber,daq_runtype_str[m->daq_runtype],m->NumEventsRequested);
1305
1306 do {
1307 // Check if enough disk space is left
1308 if (CheckDisk(m->fRawDataPath) <= m->fMinDiskSpaceMB+m->fMaxFileSizeMB) {
1309 m->PrintMessage("\rError: Disk space after next file (max. %d MByte) below %d MByte\n",m->fMaxFileSizeMB,m->fMinDiskSpaceMB);
1310 break;
1311 }
1312
1313 // Init run header, open raw file, write run header
1314 if (!m->OpenRawFile()) break;
1315 m->PrintMessage("\rData file \"%s\" opened.\n",m->FileName);
1316 EventsInFile = 0;
1317 FileSize = 0;
1318
1319 WriteError |= !m->WriteRunHeader();
1320
1321 if (m->daq_runtype != test) m->StartDRS();
1322
1323 // Take data until finished, stopped or file too large
1324 while ((m->NumEvents<m->NumEventsRequested || m->NumEventsRequested==0) &&
1325 !m->Stop && FileSize/1024/1024<m->fMaxFileSizeMB && !WriteError) {
1326
1327 if (m->daq_runtype == data) while (m->IsDRSBusy()); // Wait for hardware trigger (if DAQ stopped, DRS will not be busy anymore)
1328 else if (m->daq_runtype == pedestal) m->StopDRS(); // ..or for software trigger
1329
1330 // Read event data via VME or generate test data (for one board if no boards available)
1331 if (m->daq_runtype != test) {
1332 m->ReadCalibratedDRSData();
1333 m->StartDRS(); // Restart here: writing data is in parallel to waiting for next trigger
1334 }
1335 else {
1336 double Period = ((double) rand())/RAND_MAX*20;
1337 for (long unsigned int i=0; i<m->RHeader->NBoards*m->RHeader->NChips*m->RHeader->NChannels*m->RHeader->Samples; i++)
1338 *((short *) m->WaveForm+i) = (short) (sin(i/Period)*1000);
1339 }
1340
1341 // Write event to disk and update file size
1342 EventsInFile++; m->NumEvents++;
1343 WriteError |= !m->WriteEvent();
1344
1345 if((FileSize = lseek(m->Rawfile, 0, SEEK_CUR)) == -1) {
1346 m->PrintMessage("Error: Could not determine file size, terminating run (%s)\n", strerror(errno));
1347 WriteError = true;
1348 }
1349
1350 // Call feedback to process event
1351 m->HVFB->ProcessEvent();
1352 }
1353
1354 // Write updated run header, close file
1355 RunSize += FileSize;
1356 WriteError |= !m->UpdateRunHeader(EventsInFile, WriteError);
1357 if(close(m->Rawfile)==-1) m->PrintMessage("Error: Could not close data file (%s)\n", strerror(errno));
1358 else m->PrintMessage("Data file closed (size %lu MByte).\n", FileSize/1024/1024);
1359
1360 m->FileNumber += 1;
1361 } while((m->NumEvents<m->NumEventsRequested || m->NumEventsRequested==0) && !m->Stop && !WriteError);
1362
1363 m->StopDRS();
1364
1365 // Print run summary to screen
1366 if(!WriteError) m->PrintMessage("\rRun #%d (%s) %s, %d events\n",m->RunNumber,daq_runtype_str[m->daq_runtype],(m->NumEvents == m->NumEventsRequested) ? "completed":"stopped",m->NumEvents);
1367 else m->PrintMessage("\rRun #%d (%s) aborted due to error after %d events\n",m->RunNumber,daq_runtype_str[m->daq_runtype],m->NumEvents);
1368
1369 // Write run summary to slow data file
1370 m->SlowDataClass->NewEntry("Runinfo");
1371 m->SlowDataClass->AddToEntry("%d %s %s %d %d %s", m->RunNumber, WriteError?"Error":"OK", daq_runtype_str[m->daq_runtype], m->NumEvents, m->FileNumber, m->RHeader->Description);
1372 if(m->SlowDataClass->ErrorCode != 0) {
1373 m->PrintMessage("Error: Could not write DAQ slow data to file (%s), file closed\n", strerror(m->SlowDataClass->ErrorCode));
1374 }
1375
1376 // Print run statistics
1377 if (m->NumEvents>0 && !WriteError) {
1378 gettimeofday(&StopTime, NULL);
1379 float RunTime = StopTime.tv_sec-StartTime.tv_sec + (StopTime.tv_usec-StartTime.tv_usec)*1e-6;
1380 m->PrintMessage("Time for run %.2f seconds, trigger rate %.2f Hz.\n", RunTime, m->NumEvents/RunTime);
1381 m->PrintMessage("Run size %llu MByte, data rate %.1f MByte/s.\n", RunSize/1024/1024, RunSize/1024.0/1024/RunTime);
1382 }
1383
1384 m->daq_state = stopped;
1385}
1386
1387
1388/********************************************************************\
1389
1390 DAQ Thread - no disk writing, only hardware trigger, for feedback tests
1391
1392\********************************************************************/
1393
1394void DAQ_Silent(DAQReadout *m) {
1395
1396 m->PrintMessage("\rData taking started\n");
1397 do {
1398 // Start DRS and wait for hardware trigger
1399 m->StartDRS();
1400 while (m->IsDRSBusy());
1401
1402 // Read event data via VME and call feedback
1403 m->ReadCalibratedDRSData();
1404 m->HVFB->ProcessEvent();
1405 } while(!m->Stop);
1406
1407 m->PrintMessage("\rData taking stopped\n");
1408 m->daq_state = stopped;
1409}
Note: See TracBrowser for help on using the repository browser.