source: drsdaq/DAQReadout.cc@ 228

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