source: drsdaq/DAQReadout.cc@ 97

Last change on this file since 97 was 92, checked in by ogrimm, 15 years ago
Added some configuration parameters. Log file written outside of repository.
File size: 46.6 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 {"freq", &DAQReadout::cmd_freq, true, "<GHz> [reg]", "Set DRS sampling frequency (regulated)"},
28 {"calib", &DAQReadout::cmd_calib, true, "<t_f> <c_f>", "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 domino wave"},
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 = 100;
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}
310
311// RAM test
312void DAQReadout::cmd_ramtest() {
313 for (int i=FirstBoard; i<=LastBoard; i++) {
314 PrintMessage("RAM integrity and speed test (board #%d):\n",i);
315 (drs->GetBoard(i))->RAMTest(3);
316 }
317}
318
319// Register test
320void DAQReadout::cmd_regtest() {
321 for (int i=FirstBoard; i<=LastBoard; i++) {
322 PrintMessage("Register test (board #%d):\n",i);
323 (drs->GetBoard(i))->RegisterTest();
324 }
325}
326
327// Test VME transfer
328void DAQReadout::cmd_test() {
329 int Type=-1, i;
330
331 if (Match(Param[1], "2eblt64")) Type = 2;
332 else if (Match(Param[1], "blt32")) Type = 0;
333 else if (Match(Param[1], "blt64")) Type = 1;
334 else {
335 PrintMessage("Unknown type for testing.\n");
336 return;
337 }
338
339 if (NumBoards) for (i=FirstBoard; i<=LastBoard; i++) {
340 PrintMessage("BLT test started (board #%d)\n",i);
341 (drs->GetBoard(i))->TestRead(Param[2][0] && atoi(Param[2])<=10000 && atoi(Param[2])>0 ? atoi(Param[2]):1, Type);
342 }
343 else PrintMessage("No DRS boards available\n");
344}
345
346// Stop DAQ
347void DAQReadout::cmd_stop() {
348 if(!daq_state==active && !IsDRSBusy()) PrintMessage("Nothing to stop\n");
349 if (daq_state==active) StopRun();
350 if (IsDRSBusy()) {
351 StopDRS();
352 PrintMessage("Domino wave stopped\n");
353 }
354}
355
356// Read current data
357// For socket transmission: all numbers must be separated by exactly one
358// whitespace; the first number is the number of numbers that follow, the
359// second number the sampling frequency in GHz, the third the conversion factor
360
361void DAQReadout::cmd_read() {
362 if(NumBoards==0) {
363 PrintMessage("No mezzanine boards available\n");
364 return;
365 }
366 if (NParam<4) {
367 PrintUsage();
368 return;
369 }
370 if (atoi(Param[1])>LastBoard || atoi(Param[1])<FirstBoard) {
371 PrintMessage("Error: Board number out of range\n");
372 return;
373 }
374 if (atoi(Param[3])<0 || atoi(Param[3])>=kNumberOfChannels) {
375 PrintMessage("Error: Channel number out of range\n");
376 return;
377 }
378 if (atoi(Param[2])<0 || atoi(Param[2])>=kNumberOfChips) {
379 PrintMessage("Error: Chip number out of range\n");
380 return;
381 }
382
383 if (daq_state!=active) {
384 if (!CalibrationRead) ReadCalibration();
385 if(NParam==5) StopDRS();
386 ReadCalibratedDRSData();
387 if(NParam==5) StartDRS();
388 }
389 PrintMessage(CmdFromSocket ? MsgToSocket:MsgToConsole|MsgToLog, "==START== %d %.2f %.2f ",kNumberOfBins+2,DRSFreq[atoi(Param[1])],drs->GetBoard(atoi(Param[1]))->GetPrecision());
390 for (int k=0; k<kNumberOfBins; k++) PrintMessage(CmdFromSocket ? MsgToSocket:MsgToConsole|MsgToLog, "%.1f ",
391 (float) WaveForm[atoi(Param[1])][atoi(Param[2])][atoi(Param[3])][(k+TriggerCell[atoi(Param[1])][atoi(Param[2])])%kNumberOfBins]);
392 PrintMessage(CmdFromSocket ? MsgToSocket:MsgToConsole|MsgToLog, "==END==");
393 PrintMessage(CmdFromSocket ? MsgToSocket:MsgToConsole|MsgToLog, "\n");
394}
395
396// Set Domino mode
397void DAQReadout::cmd_mode() {
398 if (Match(Param[1],"continuous")) SetDOMINOMode(1);
399 else if (Match(Param[1],"single")) SetDOMINOMode(0);
400 else PrintUsage();
401}
402
403// Set Domino readout mode
404void DAQReadout::cmd_rmode() {
405 if (Match(Param[1],"1")) SetDOMINOReadMode(1);
406 else if (Match(Param[1],"0")) SetDOMINOReadMode(0);
407 else PrintUsage();
408}
409
410// Set Domino wave mode
411void DAQReadout::cmd_wmode() {
412 if (Match(Param[1],"1")) SetDOMINOWaveMode(1);
413 else if (Match(Param[1],"0")) SetDOMINOWaveMode(0);
414 else PrintUsage();
415}
416
417// Switch delayed start on/off
418void DAQReadout::cmd_delayed() {
419 if (Match(Param[1],"on")) SetDelayedStart(1);
420 else if (Match(Param[1],"off")) SetDelayedStart(0);
421 else PrintUsage();
422}
423
424// Set trigger mode
425void DAQReadout::cmd_trigger() {
426 if (Match(Param[1],"on")) HWTrigger(1);
427 else if (Match(Param[1],"off")) HWTrigger(0);
428 else PrintUsage();
429}
430
431// Set serial number of board
432void DAQReadout::cmd_serial() {
433 if (NParam==4 && Match(Param[3], "expert")) {
434 if ((atoi(Param[1]) < FirstBoard) || (atoi(Param[1]) > LastBoard))
435 PrintMessage("Board number out of range (%d...%d)!\n",FirstBoard,LastBoard);
436 else if (atoi(Param[2]) < 100 || atoi(Param[2]) >= 1000)
437 PrintMessage("Serial number out of range (100...999)!\n");
438 else {
439 PrintMessage("Flashing EEPROM of board %d...\n", atoi(Param[1]));
440 (drs->GetBoard(atoi(Param[1])))->FlashEEPROM(atoi(Param[2]));
441 }
442 }
443 else PrintMessage("You are not allowed to change the serial number!\n");
444}
445
446// Do internal calibration
447void DAQReadout::cmd_calib() {
448 char str[MAX_COM_SIZE];
449
450 if (NParam!=3 || !atof(Param[1]) || !atof(Param[2])) {
451 PrintUsage();
452 return;
453 }
454
455 getcwd(str, sizeof(str));
456 strcat(str,"/calib");
457 PrintMessage("Writing calibration data to directory '%s'\n",str);
458
459 for (int i=FirstBoard; i<=LastBoard; i++) {
460 drs->GetBoard(i)->Init();
461 drs->GetBoard(i)->SetFrequency(atof(Param[2]));
462 drs->GetBoard(i)->SoftTrigger();
463
464 PrintMessage("Creating calibration of board %d (%d)\n", i, drs->GetBoard(i)->GetCMCSerialNumber());
465
466 drs->GetBoard(i)->EnableTcal(1);
467 PrintMessage("Tcal enabled\n");
468
469 if (drs->GetBoard(i)->GetChipVersion() == 3) drs->GetBoard(i)->GetResponseCalibration()->SetCalibrationParameters(1,21,0,20,0,0,0,0,0);
470 else drs->GetBoard(i)->GetResponseCalibration()->SetCalibrationParameters(1,36,110,20,19,40,15,atof(Param[1]),0);
471 drs->GetBoard(i)->SetCalibrationDirectory(str);
472
473 for (int j=0; j<2; j++) {
474 drs->GetBoard(i)->GetResponseCalibration()->ResetCalibration();
475 PrintMessage("Calibration reset done.\n");
476
477 while (!drs->GetBoard(i)->GetResponseCalibration()->RecordCalibrationPoints(j)) {}
478 PrintMessage("Record calibration points done.\n");
479 while (!drs->GetBoard(i)->GetResponseCalibration()->FitCalibrationPoints(j)) {}
480 PrintMessage("Calibration points fitted.\n");
481 while (!drs->GetBoard(i)->GetResponseCalibration()->OffsetCalibration(j)) {}
482 PrintMessage("Offset calibration done.\n");
483
484 if (!drs->GetBoard(i)->GetResponseCalibration()->WriteCalibration(j)) break;
485 }
486 drs->GetBoard(i)->Init(); // Reset linear range -0.2 ... 0.8 V
487 } // Loop over boards
488}
489
490// Set DRS sampling frequency
491void DAQReadout::cmd_freq() {
492 if (NParam>=2 && atof(Param[1])) {
493 SetDRSFrequency(atof(Param[1]), NParam==2 ? false : true);
494 CalibrationRead = false;
495 }
496 else PrintUsage();
497}
498
499// Set LED
500void DAQReadout::cmd_led() {
501 if (Match(Param[1], "on") || Match(Param[1], "off"))
502 for (int i=FirstBoard; i<=LastBoard; i++)
503 (drs->GetBoard(i))->SetLED(Match(Param[1], "on") ? 1 : 0);
504 else PrintUsage();
505}
506
507// Print status
508void DAQReadout::cmd_status() {
509
510 double freq;
511
512 if(NParam==1 || Match(Param[1],"daq")) {
513 PrintMessage("********** DAQ STATUS **********\n"
514 " DAQ: %s\n"
515 " Run number: %d\n"
516 " Run type: %s\n"
517 " Event: %d\n"
518 " Requested events per run: %d\n"
519 " Storage directory: %s\n"
520 " Disk space: %lu MByte\n"
521 " Socket state: %s\n"
522 " Total number of CMC boards: %d\n"
523 " Active CMC boards: %d\n",
524 daq_state_str[daq_state], daq_state==active ? (int) RunNumber:-1,
525 daq_runtype_str[daq_runtype], NumEvents,
526 NumEventsRequested, fRawDataPath,
527 CheckDisk(fRawDataPath), Socket==-1 ? "disconnected":"connected",
528 NumBoards, LastBoard - FirstBoard + 1);
529
530 for (int i=FirstBoard;i<=LastBoard;i++)
531 PrintMessage(" Frequency of board %d set: %s\n",i,(DRSFreq[i]!=0 ? "yes":"no"));
532 }
533
534 if(NParam==1 || Match(Param[1],"drs")) {
535 PrintMessage("\n********** DRS STATUS **********\n");
536 if (NumBoards) {
537 for (int i=FirstBoard; i<=LastBoard; i++) {
538
539 PrintMessage(" Mezz. board index: %d\n"
540 " Slot: %d %s\n",i,((drs->GetBoard(i))->GetSlotNumber() >> 1)+2,((drs->GetBoard(i))->GetSlotNumber() & 1)==0 ? "upper":"lower");
541 PrintMessage(" Chip version: DRS%d\n"
542 " Board version: %d\n"
543 " Serial number: %d\n"
544 " Firmware revision: %d\n"
545 " Temperature: %1.1lf C\n"
546 " Status reg.: 0X%08X\n",
547 (drs->GetBoard(i))->GetChipVersion(),
548 (drs->GetBoard(i))->GetCMCVersion(),
549 (drs->GetBoard(i))->GetCMCSerialNumber(),
550 (drs->GetBoard(i))->GetFirmwareVersion(),
551 (drs->GetBoard(i))->GetTemperature(),
552 (drs->GetBoard(i))->GetStatusReg());
553
554
555 if ((drs->GetBoard(i))->GetStatusReg() & BIT_RUNNING)
556 PrintMessage(" Domino wave running\n");
557 if ((drs->GetBoard(i))->GetStatusReg() & BIT_NEW_FREQ1)
558 PrintMessage(" New Freq1 ready\n");
559 if ((drs->GetBoard(i))->GetStatusReg() & BIT_NEW_FREQ2)
560 PrintMessage(" New Freq2 ready\n");
561
562 PrintMessage(" Control reg.: 0X%08X\n", (drs->GetBoard(i))->GetCtrlReg());
563 if ((drs->GetBoard(i))->GetCtrlReg() & BIT_AUTOSTART)
564 PrintMessage(" AUTOSTART enabled\n");
565 if ((drs->GetBoard(i))->GetCtrlReg() & BIT_DMODE)
566 PrintMessage(" DMODE circular\n");
567 else
568 PrintMessage(" DMODE single shot\n");
569 if ((drs->GetBoard(i))->GetCtrlReg() & BIT_LED)
570 PrintMessage(" LED\n");
571 if ((drs->GetBoard(i))->GetCtrlReg() & BIT_TCAL_EN)
572 PrintMessage(" TCAL enabled\n");
573 if ((drs->GetBoard(i))->GetCtrlReg() & BIT_ZERO_SUPP)
574 PrintMessage(" ZERO_SUPP enabled\n");
575 if ((drs->GetBoard(i))->GetCtrlReg() & BIT_FREQ_AUTO_ADJ)
576 PrintMessage(" FREQ_AUTO_ADJ enabled\n");
577 if ((drs->GetBoard(i))->GetCtrlReg() & BIT_ENABLE_TRIGGER)
578 PrintMessage(" ENABLE_TRIGGER\n");
579 if ((drs->GetBoard(i))->GetCtrlReg() & BIT_LONG_START_PULSE)
580 PrintMessage(" LONG_START_PULSE\n");
581 if ((drs->GetBoard(i))->GetCtrlReg() & BIT_DELAYED_START)
582 PrintMessage(" DELAYED_START\n");
583 if ((drs->GetBoard(i))->GetCtrlReg() & BIT_ACAL_EN)
584 PrintMessage(" ACAL enabled\n");
585 PrintMessage(" Trigger bus: 0X%08X\n", (drs->GetBoard(i))->GetTriggerBus());
586 if ((drs->GetBoard(i))->IsBusy()) {
587 (drs->GetBoard(i))->ReadFrequency(0, &freq);
588 PrintMessage(" Frequency0: %1.4lf GHz\n", freq);
589 (drs->GetBoard(i))->ReadFrequency(1, &freq);
590 PrintMessage(" Frequency1: %1.4lf GHz\n", freq);
591 }
592 else PrintMessage(" Domino wave stopped\n");
593 }
594 }
595 else PrintMessage("No DRS boards available!\n\n");
596 }
597}
598
599// Adress DRS boards
600void DAQReadout::cmd_board() {
601 if (Match(Param[1],"all")) {
602 FirstBoard = 0;
603 LastBoard = drs->GetNumberOfBoards()-1;
604 }
605 else if (NParam==2 && atoi(Param[1])>=0 && atoi(Param[1])<NumBoards) {
606 FirstBoard = atoi(Param[1]);
607 LastBoard = FirstBoard;
608 }
609 else if (NParam==3 && atoi(Param[1])>=0 && atoi(Param[1])<NumBoards &&
610 atoi(Param[2])>0 && atoi(Param[2])<NumBoards) {
611 FirstBoard = atoi(Param[1]);
612 LastBoard = atoi(Param[2]);
613 }
614 else PrintMessage("Cannot address board(s), out of range.\n");
615 CalibrationRead = false;
616}
617
618// Print help (only to console or socket, not to log file)
619void DAQReadout::cmd_help() {
620 char Buffer[MAX_COM_SIZE];
621 for(unsigned int i=0; i<sizeof(CommandList)/sizeof(CL_Struct); i++) {
622 snprintf(Buffer, sizeof(Buffer), "%s %s", CommandList[i].Name, CommandList[i].Parameters);
623 PrintMessage(CmdFromSocket ? MsgToSocket:MsgToConsole,"%-28s%s\n", Buffer, CommandList[i].Help);
624 }
625 PrintMessage(CmdFromSocket ? MsgToSocket:MsgToConsole,".<command> Execute shell command\n\n"
626 "Items in <> are mandatory, in [] optional, | indicates mutual exclusive or.\n"
627 "Test data can also be written if no DRS boards are available.\n"
628 "Strings containing spaces have to be enclosed in \"double quotes\".\n");
629}
630
631// Exit programm
632void DAQReadout::cmd_exit() {
633 if (CmdFromSocket) {
634 PrintMessage("Exit command not allowed over socket.\n");
635 return;
636 }
637 if (daq_state==active) PrintMessage("Issue \"stop\" first to stop daq\n");
638 else {
639 Exit = true;
640 if(SocketThread != NULL) pthread_kill(*SocketThread, SIGUSR1);
641 }
642}
643
644// Set/get mode of feedback
645void DAQReadout::cmd_fmode() {
646 if(Match(Param[1],"off")) HVFB->SetFBMode(FB_Off);
647 if(Match(Param[1],"active")) HVFB->SetFBMode(FB_Active);
648 if(Match(Param[1],"targets")) HVFB->SetFBMode(FB_Targets);
649 HVFB->GetFBMode();
650}
651
652// Set/get current number of events
653void DAQReadout::cmd_faverage() {
654 if(NParam==1) PrintMessage("Current number of feedback events: %u (acting when %u events are reached)\n",
655 HVFB->GetCurrentCount(), HVFB->GetNumAverages());
656 else if(atoi(Param[1])>=0) HVFB->SetNumAverages(atoi(Param[1]));
657 else PrintUsage();
658}
659
660// Set/get feedback gain
661void DAQReadout::cmd_fgain() {
662 if(NParam==2) HVFB->SetGain(atof(Param[1]));
663 PrintMessage("Feedback gain is %.2f\n", HVFB->GetGain());
664}
665
666// Set/get target value
667void DAQReadout::cmd_ftarget() {
668 if(NParam==1) HVFB->GetTargets();
669 else if(NParam!=5) PrintUsage();
670 else for (int i=FirstBoard; i<=LastBoard; i++)
671 for (int j=0; j<kNumberOfChips; j++)
672 for (int k=0; k<kNumberOfChannels; k++)
673 if ((atoi(Param[1])==i || Match(Param[1],"all")) &&
674 (atoi(Param[2])==j || Match(Param[2],"all")) &&
675 (atoi(Param[3])==k || Match(Param[3],"all")))
676 HVFB->SetTarget(i,j,k,atof(Param[4]));
677}
678
679// Start response measurement
680void DAQReadout::cmd_fresponse() {
681 if(NParam==1) HVFB->GetResponse();
682 else if(atof(Param[1])) HVFB->MeasureResponse(atof(Param[1]));
683 else PrintUsage();
684}
685
686// Print feedback configuration
687void DAQReadout::cmd_fconfig() {
688 HVFB->PrintConfig(CmdFromSocket ? MsgToSocket : MsgToConsole);
689}
690
691// ----------------------------------------------
692// ***** Utility function for DRS control *****
693// ----------------------------------------------
694
695// Start domino wave
696void DAQReadout::StartDRS() {
697 for (int i=FirstBoard; i<=LastBoard; i++) drs->GetBoard(i)->StartDomino();
698}
699
700// Stop domino wave
701void DAQReadout::StopDRS() {
702 for (int i=FirstBoard; i<=LastBoard; i++) drs->GetBoard(i)->SoftTrigger();
703}
704
705// Transfer data to memory
706void DAQReadout::ReadCalibratedDRSData() {
707
708 for (int i=FirstBoard; i<=LastBoard; i++) {
709 (drs->GetBoard(i))->TransferWaves(kNumberOfChannels*kNumberOfChips);
710 for (int j=0; j<kNumberOfChannels; j++) {
711 drs->GetBoard(i)->GetWave(0, j, WaveForm[i][0][j], true); // Chip #1
712 TriggerCell[i][0] = drs->GetBoard(i)->GetTriggerCell((unsigned int) 0);
713 drs->GetBoard(i)->GetWave(1, j, WaveForm[i][1][j], true); // Chip #2
714 TriggerCell[i][1] = drs->GetBoard(i)->GetTriggerCell((unsigned int) 1);
715 }
716 }
717}
718
719// Read calibration file
720bool DAQReadout::ReadCalibration() {
721
722 char dir[MAX_COM_SIZE];
723
724 getcwd(dir, sizeof(dir));
725 strcat(dir,"/calib");
726 for (int i=FirstBoard; i<=LastBoard; i++) {
727 (drs->GetBoard(i))->SetCalibrationDirectory(dir);
728 PrintMessage("Reading response calibration file for board %d from: \"%s\"\n", i, dir);
729 for (int Chip=0; Chip<kNumberOfChips; Chip++)
730 if (drs->GetBoard(i)->GetResponseCalibration()->ReadCalibration(Chip)==false) {
731 CalibrationRead = false;
732 return false;
733 }
734 }
735 CalibrationRead = true;
736 return true;
737}
738
739// Check if calibration file has been read
740bool DAQReadout::IsCalibrationRead() {
741
742 for (int i=FirstBoard; i<=LastBoard; i++) {
743 for (int Chip=0; Chip<kNumberOfChips; Chip++)
744 if (!(drs->GetBoard(i)->GetResponseCalibration()->IsRead(Chip))) {
745 PrintMessage("Warning: Response calibration of board %d chip %d not yet read!\n",i,Chip);
746 return false;
747 }
748 }
749 return true;
750}
751
752// Stop DAQ
753void DAQReadout::StopRun() {
754
755 if(daq_state != active) PrintMessage("DAQ is not active.\n");
756 else {
757 Stop = true;
758 PrintMessage("DAQ will stop.\n");
759 }
760}
761
762// Set DOMINO mode
763void DAQReadout::SetDOMINOMode(int mode) {
764
765 if (NumBoards)
766 for (int i=FirstBoard; i<=LastBoard; i++) {
767 (drs->GetBoard(i))->SetDominoMode(mode==1 ? 1:0);
768 PrintMessage("Domino mode of board %d switched to %s.\n",i,mode==1 ? "continuous":"single shot");
769 }
770 else PrintMessage("No DRS boards available\n");
771}
772
773// Set DOMINO readout mode
774void DAQReadout::SetDOMINOReadMode(int mode) {
775
776 if (NumBoards)
777 for (int i=FirstBoard; i<=LastBoard; i++) {
778 (drs->GetBoard(i))->SetReadoutMode(mode==1 ? 1:0);
779 PrintMessage("Start readout of board %d from %s.\n",i,mode==1 ? "first bin":"stop position");
780 }
781 else PrintMessage("No DRS boards available\n");
782}
783
784// Set DOMINO wave mode
785void DAQReadout::SetDOMINOWaveMode(int mode) {
786
787 if (NumBoards)
788 for (int i=FirstBoard; i<=LastBoard; i++) {
789 (drs->GetBoard(i))->SetDominoActive(mode==1 ? 1:0);
790 PrintMessage("Domino wave of board %d is %s during readout\n",i,mode==1 ? "running":"stopped");
791 }
792 else PrintMessage("No DRS boards available\n");
793}
794
795// Delayed start on/off
796void DAQReadout::SetDelayedStart(int mode) {
797
798 if (NumBoards)
799 for (int i=FirstBoard; i<=LastBoard; i++) {
800 (drs->GetBoard(i))->SetDelayedStart(mode==1 ? 1:0);
801 PrintMessage("Delayed start of board %d is %s\n",i,mode==1 ? "on":"off");
802 }
803 else PrintMessage("No DRS boards available\n");
804}
805
806// Enable hardware trigger of all boards
807void DAQReadout::HWTrigger(int mode) {
808
809 if (NumBoards)
810 for (int i=FirstBoard; i<=LastBoard; i++) {
811 drs->GetBoard(i)->EnableTrigger(mode==1 ? 1:0);
812 PrintMessage("Hardware trigger of board %d %s\n",i,mode==1 ? "enabled":"disabled");
813 }
814 else PrintMessage("No DRS boards available\n");
815}
816
817// Set DRS sampling frequency
818void DAQReadout::SetDRSFrequency(double freq, bool Regulation) {
819
820 double currentfreq;
821
822 PrintMessage("Setting frequency %s regulation:\n",Regulation ? "with":"without");
823 for (int i=FirstBoard; i<=LastBoard; i++) {
824 drs->GetBoard(i)->SetDebug(1);
825
826 if (Regulation ? drs->GetBoard(i)->RegulateFrequency(freq) : drs->GetBoard(i)->SetFrequency(freq)) {
827 drs->GetBoard(i)->ReadFrequency(0, &currentfreq);
828 DRSFreq[i] = freq;
829 PrintMessage("Domino wave of board %d is running at %1.3lf GHz\n",i,currentfreq);
830 } else {
831 DRSFreq[i] = 0;
832 PrintMessage("Warning: Domino wave of board %d has changed but not reached the requested value\n",i);
833 }
834 }
835}
836
837// Check if DRS is sampling
838bool DAQReadout::IsDRSBusy() {
839
840 for (int i=FirstBoard; i<=LastBoard; i++)
841 if ((drs->GetBoard(i))->IsBusy()) return true;
842 return false;
843}
844
845// Check if DRS frequency is set
846bool DAQReadout::IsDRSFreqSet() {
847
848 for (int i=FirstBoard; i<=LastBoard; i++)
849 if (DRSFreq[i]==0) {
850 PrintMessage("DRS sampling frequency of board %d not set!\n",i);
851 return false;
852 }
853 return true;
854}
855
856// Open new raw data file
857bool DAQReadout::OpenRawFile() {
858
859 time_t rawtime;
860 struct tm *timeinfo;
861 char RunDate[MAX_COM_SIZE], Buffer[MAX_COM_SIZE];
862
863 // Write run date to status structure (if after 13:00, use next day)
864 time(&rawtime);
865 timeinfo = gmtime(&rawtime);
866 if(timeinfo->tm_hour>=13) rawtime += 12*60*60;
867 timeinfo = gmtime(&rawtime);
868 snprintf(RunDate,sizeof(RunDate),"%d%02d%02d",timeinfo->tm_year+1900,timeinfo->tm_mon + 1,timeinfo->tm_mday);
869
870 // Create direcory if not existing (ignore error if already existing) and change to it
871 snprintf(Buffer, sizeof(Buffer), "%s/%s", fRawDataPath, RunDate);
872 if(mkdir(Buffer, S_IRWXU|S_IRWXG)==-1 && errno!=EEXIST) {
873 PrintMessage("\rError: Could not create direcory \"%s\" (%s)\n", Buffer, strerror(errno));
874 return false;
875 }
876
877 // Generate filename
878 snprintf(FileName,sizeof(FileName),"%s/%s/%s_D1_%.8u.%.3u_%c_%s.raw", fRawDataPath, RunDate,
879 RunDate,RunNumber,FileNumber,toupper(daq_runtype_str[daq_runtype][0]),RHeader->Description);
880
881 // Open file with rwx right for owner and group, never overwrite file
882 Rawfile = open(FileName,O_WRONLY|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
883 if(Rawfile==-1) {
884 PrintMessage("\rError: Could not open file \"%s\" (%s)\n", FileName, strerror(errno));
885 return false;
886 }
887 return true;
888}
889
890// Write run header and board structures (revision number is zero for svn modified working copy)
891bool DAQReadout::WriteRunHeader() {
892
893 struct timeval Time;
894
895 RHeader->MagicNum = MAGICNUM_OPEN;
896 RHeader->DataFormat = DATA_FORMAT;
897 RHeader->SoftwareRevision = atoi(REVISION) * (strchr(REVISION, 'M')==NULL ? 1:-1);
898
899 RHeader->RunHeaderSize = sizeof(RunHeader);
900 RHeader->EventHeaderSize = sizeof(EventHeader);
901 RHeader->BoardStructureSize = sizeof(BoardStructure);
902
903 RHeader->Identification = IDENTIFICATION;
904 RHeader->Type = daq_runtype;
905 RHeader->RunNumber = RunNumber;
906 RHeader->FileNumber = FileNumber;
907
908 gettimeofday(&Time, NULL);
909 RHeader->StartSecond = Time.tv_sec;
910 RHeader->StartMicrosecond = Time.tv_usec;
911
912 RHeader->NBoards = NumBoards==0 && daq_runtype==test ? 1 : (LastBoard - FirstBoard) + 1;
913 RHeader->NChips = kNumberOfChips;
914 RHeader->NChannels = kNumberOfChannels;
915 RHeader->NBytes = sizeof(short);
916
917 RHeader->Offset = fFirstSample;
918 RHeader->Samples = fSamples;
919
920 if(write(Rawfile, RHeader, sizeof(RunHeader)) != sizeof(RunHeader)) {
921 PrintMessage("Error: Could not write run header, terminating run (%s)\n", strerror(errno));
922 return false;
923 }
924
925 for (int i=FirstBoard; i<=LastBoard; i++) {
926 BStruct[i].SerialNo = drs->GetBoard(i)->GetCMCSerialNumber();
927 BStruct[i].BoardTemp = drs->GetBoard(i)->GetTemperature();
928 BStruct[i].NomFreq = DRSFreq[i];
929 BStruct[i].ScaleFactor = drs->GetBoard(i)->GetPrecision();
930 }
931
932 // In case no boards are available, dummy data is written for one board structure
933 if (NumBoards == 0) {
934 BStruct[0].NomFreq = 1;
935 BStruct[0].ScaleFactor = 0.1;
936 }
937
938 if(write(Rawfile, &BStruct[FirstBoard], sizeof(BoardStructure)*(LastBoard-FirstBoard+1+(NumBoards==0))) != (ssize_t) sizeof(BoardStructure)*(LastBoard-FirstBoard+1+(NumBoards==0))) {
939 PrintMessage("Error: Could not write (all) board structures, terminating run (%s)\n", strerror(errno));
940 return false;
941 }
942 return true;
943}
944
945// Update run header before closing file
946bool DAQReadout::UpdateRunHeader(unsigned int Events, bool Error) {
947
948 struct timeval Time;
949
950 RHeader->MagicNum = Error==false ? MAGICNUM_CLOSED:MAGICNUM_ERROR;
951 RHeader->Events = Events;
952
953 gettimeofday(&Time, NULL);
954 RHeader->EndSecond = Time.tv_sec;
955 RHeader->EndMicrosecond = Time.tv_usec;
956
957 if(lseek(Rawfile,0,SEEK_SET)==-1) {
958 PrintMessage("Error: Could not rewind file to write updated run header, terminating run (%s)\n", strerror(errno));
959 return false;
960 }
961
962 if(write(Rawfile, RHeader, sizeof(RunHeader)) != sizeof(RunHeader)) {
963 PrintMessage("Error: Could not write updated run header, terminating run (%s)\n", strerror(errno));
964 return false;
965 }
966 return true;
967}
968
969// Write event
970bool DAQReadout::WriteEvent() {
971
972 // Event header
973 struct timeval Time;
974
975 gettimeofday(&Time, NULL);
976
977 EHeader->EventNumber = NumEvents;
978 EHeader->TriggerType = daq_runtype==data ? 0 : 1;
979 EHeader->Second = Time.tv_sec;
980 EHeader->Microsecond = Time.tv_usec;
981 EHeader->EventSize = sizeof(short)*RHeader->NBoards*RHeader->NChips*RHeader->NChannels*RHeader->Samples +
982 sizeof(int)*RHeader->NBoards*RHeader->NChips;
983
984 if(write(Rawfile, EHeader, sizeof(EventHeader)) != sizeof(EventHeader)) {
985 PrintMessage("Error: Could not write event header, terminating run (%s)\n", strerror(errno));
986 return false;
987 }
988
989 // Event data (It is required that at least three chunks can be written with writev(), therefore
990 // IOV_MAX>=3 is checked at startup
991
992 unsigned int Start, Count = 0;
993 ssize_t WriteResult, Size = 0;
994 struct iovec DataPart[IOV_MAX];
995
996 // First chunk: trigger cells
997 DataPart[Count].iov_base = (char *) TriggerCell + FirstBoard*kNumberOfChips*sizeof(int); // TriggerCell is without cast a pointer to an 8-byte unit (two ints) !
998 DataPart[Count++].iov_len = RHeader->NBoards * kNumberOfChips * sizeof(int);
999 Size += DataPart[Count-1].iov_len;
1000
1001 // Remaining chunks: ADC data (two chucks per channel if wrap around of pipeline occurred)
1002 for (int i=FirstBoard; (i<=LastBoard + (NumBoards==0)); i++) {
1003 for (unsigned int k=0; k<RHeader->NChips; k++) {
1004 Start = (TriggerCell[i][k]-fFirstSample+kNumberOfBins) % kNumberOfBins; // Start bin for this chip
1005 for (unsigned int l=0; l<RHeader->NChannels; l++) {
1006 DataPart[Count].iov_base = &WaveForm[i][k][l][Start];
1007 DataPart[Count++].iov_len = (Start+fSamples<kNumberOfBins ? fSamples:(kNumberOfBins-Start)) * sizeof(short);
1008 Size += DataPart[Count-1].iov_len;
1009 // In case second part of waveform still missing, write now
1010 if(DataPart[Count-1].iov_len < fSamples * sizeof(short)) {
1011 DataPart[Count].iov_base = &WaveForm[i][k][l][0];
1012 DataPart[Count++].iov_len = (fSamples-(kNumberOfBins-Start)) * sizeof(short);
1013 Size += DataPart[Count-1].iov_len;
1014 }
1015
1016 // Write to disk if either maximum size of DataPart[] array or last loop interation is reached
1017 // Possibly 2 chunks are entered in array in the previous lines of code, therefore IOV_MAX-1
1018 if (Count>=IOV_MAX-1 || (l==(RHeader->NChannels-1) && k==(RHeader->NChips-1) && i==(LastBoard+(NumBoards==0)))) {
1019 if ((WriteResult=writev(Rawfile, DataPart, Count)) != (int) Size) {
1020 if (WriteResult==-1) PrintMessage("Error: Could not write event data, terminating run (%s)\n", strerror(errno));
1021 else PrintMessage("Error: Could only write %u out of %u bytes of event data, terminating run\n", WriteResult,Count*DataPart[0].iov_len);
1022 return false;
1023 }
1024 Count = 0; Size = 0;
1025 }
1026 } // Channels
1027 } // Chips
1028 } // Boards
1029
1030 return true;
1031}
1032
1033// Print configuration to target
1034void DAQReadout::PrintConfig(int Target) {
1035 PrintMessage(Target, "LogFile: %s\tMaxLogLines: %u\tRawDataPath: %s\n"
1036 "DefaultFrequency: %.2f\tFirstSample: %d\tSamples: %u\n"
1037 "MinDiskSpaceMB: %u\tMaxFileSizeMB: %d\tCCPort: %d\n"
1038 "FirstVMESlot: %d\t\tLastVMESlot: %d\n"
1039 "SlowDataPath: %s\tHVFeedbackConfig: %s\n",
1040 fLogFile,fMaxLogLines,fRawDataPath,fDefaultFrequency,fFirstSample,fSamples,fMinDiskSpaceMB,
1041 fMaxFileSizeMB,fCCPort,fFirstVMESlot,fLastVMESlot,fSlowDataPath,fHVFeedbackConfig);
1042}
1043
1044// Print usage text for command
1045void DAQReadout::PrintUsage() {
1046 PrintMessage("Usage: %s %s\n", CommandList[CmdNumber].Name, CommandList[CmdNumber].Parameters);
1047}
1048
1049// Print message to selected target
1050void DAQReadout::PrintMessage(int Target, const char *Format, ...) {
1051 va_list ArgumentPointer;
1052 va_start(ArgumentPointer, Format);
1053 PrintMessage(Target, Format, ArgumentPointer);
1054 va_end(ArgumentPointer);
1055}
1056
1057// Print message to log file, and screen or socket (depending on command origin)
1058void DAQReadout::PrintMessage(const char *Format, ...) {
1059 va_list ArgumentPointer;
1060 va_start(ArgumentPointer, Format);
1061 if(CmdFromSocket) PrintMessage(MsgToSocket|MsgToLog, Format, ArgumentPointer);
1062 else PrintMessage(MsgToConsole|MsgToLog, Format, ArgumentPointer);
1063 va_end(ArgumentPointer);
1064}
1065
1066// Function doing the actual printing work
1067void DAQReadout::PrintMessage(int Target, const char *Format, va_list ArgumentPointer) {
1068
1069 char Textbuffer[MAX_COM_SIZE];
1070
1071 memset(Textbuffer, 0, sizeof(Textbuffer));
1072 vsnprintf(Textbuffer, sizeof(Textbuffer), Format, ArgumentPointer);
1073
1074 // Print to console
1075 if(Target & MsgToConsole) {
1076 if(strlen(Textbuffer)>0 && Textbuffer[strlen(Textbuffer)-1]=='\n') {
1077 printf("\r%s%s", Textbuffer, Prompt); // New prompt
1078 fflush(stdout);
1079 }
1080 else printf("%s", Textbuffer);
1081 }
1082 // Print to log file
1083 if((Target & MsgToLog) && Logfile!=NULL) {
1084 fprintf(Logfile, "%s", 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) on \"%s\" with %u event(s)\n",m->RunNumber,daq_runtype_str[m->daq_runtype],m->RHeader->Description,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}
Note: See TracBrowser for help on using the repository browser.