source: drsdaq/DAQReadout.cc@ 229

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