source: drsdaq/DAQReadout.cc@ 183

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