source: drsdaq/DAQReadout.cc@ 170

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