source: drsdaq/DAQReadout.cc@ 103

Last change on this file since 103 was 99, checked in by ogrimm, 15 years ago
Streamlined DRS2 reponse calibration interface, updated HV feedback socket communication
File size: 46.1 KB
Line 
1/********************************************************************\
2
3 DAQReadout.cc
4
5 Main DAQ routines.
6
7 Sebastian Commichau, Oliver Grimm
8
9\********************************************************************/
10
11#include "DAQReadout.h"
12#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 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!=2 || !atof(Param[1])) {
451 PrintUsage();
452 return;
453 }
454 if (!IsDRSFreqSet()) {
455 PrintMessage("Set sampling frequency first\n");
456 return;
457 }
458
459 getcwd(str, sizeof(str));
460 strcat(str,"/calib");
461
462 for (int i=FirstBoard; i<=LastBoard; i++) {
463 PrintMessage("Creating calibration of board %d (serial number %d)\n", i, drs->GetBoard(i)->GetCMCSerialNumber());
464
465 drs->GetBoard(i)->EnableTcal(1);
466 if (drs->GetBoard(i)->GetChipVersion() == 3) drs->GetBoard(i)->GetResponseCalibration()->SetCalibrationParameters(1,21,0,20,0,0,0,0,0);
467 else drs->GetBoard(i)->GetResponseCalibration()->SetCalibrationParameters(1,36,110,20,19,40,15,atof(Param[1]),0);
468 drs->GetBoard(i)->SetCalibrationDirectory(str);
469
470 for (int j=0; j<kNumberOfChips; j++) {
471 drs->GetBoard(i)->GetResponseCalibration()->ResetCalibration();
472
473 while (!drs->GetBoard(i)->GetResponseCalibration()->RecordCalibrationPoints(j)) {}
474 PrintMessage("Calibration points recorded.\n");
475
476 while (!drs->GetBoard(i)->GetResponseCalibration()->FitCalibrationPoints(j)) {}
477 PrintMessage("Calibration points fitted.\n");
478
479 while (!drs->GetBoard(i)->GetResponseCalibration()->OffsetCalibration(j)) {}
480 PrintMessage("Offset calibration done.\n");
481
482 if (!drs->GetBoard(i)->GetResponseCalibration()->WriteCalibration(j)) break;
483 }
484 } // Loop over boards
485 PrintMessage("End of calibration\n");
486 CalibrationRead = false;
487}
488
489// Set DRS sampling frequency
490void DAQReadout::cmd_freq() {
491 if (NParam>=2 && atof(Param[1])) {
492 SetDRSFrequency(atof(Param[1]), NParam==2 ? false : true);
493 CalibrationRead = false;
494 }
495 else PrintUsage();
496}
497
498// Set LED
499void DAQReadout::cmd_led() {
500 if (Match(Param[1], "on") || Match(Param[1], "off"))
501 for (int i=FirstBoard; i<=LastBoard; i++)
502 (drs->GetBoard(i))->SetLED(Match(Param[1], "on") ? 1 : 0);
503 else PrintUsage();
504}
505
506// Print status
507void DAQReadout::cmd_status() {
508
509 double freq;
510
511 if(NParam==1 || Match(Param[1],"daq")) {
512 PrintMessage("********** DAQ STATUS **********\n"
513 " DAQ: %s\n"
514 " Run number: %d\n"
515 " Run type: %s\n"
516 " Event: %d\n"
517 " Requested events per run: %d\n"
518 " Storage directory: %s\n"
519 " Disk space: %lu MByte\n"
520 " Socket state: %s\n"
521 " Total number of CMC boards: %d\n"
522 " Active CMC boards: %d\n",
523 daq_state_str[daq_state], daq_state==active ? (int) RunNumber:-1,
524 daq_runtype_str[daq_runtype], NumEvents,
525 NumEventsRequested, fRawDataPath,
526 CheckDisk(fRawDataPath), Socket==-1 ? "disconnected":"connected",
527 NumBoards, LastBoard - FirstBoard + 1);
528
529 for (int i=FirstBoard;i<=LastBoard;i++)
530 PrintMessage(" Frequency of board %d set: %s\n",i,(DRSFreq[i]!=0 ? "yes":"no"));
531 }
532
533 if(NParam==1 || Match(Param[1],"drs")) {
534 PrintMessage("\n********** DRS STATUS **********\n");
535 if (NumBoards) {
536 for (int i=FirstBoard; i<=LastBoard; i++) {
537
538 PrintMessage(" Mezz. board index: %d\n"
539 " Slot: %d %s\n",i,((drs->GetBoard(i))->GetSlotNumber() >> 1)+2,((drs->GetBoard(i))->GetSlotNumber() & 1)==0 ? "upper":"lower");
540 PrintMessage(" Chip version: DRS%d\n"
541 " Board version: %d\n"
542 " Serial number: %d\n"
543 " Firmware revision: %d\n"
544 " Temperature: %1.1lf C\n"
545 " Status reg.: 0X%08X\n",
546 (drs->GetBoard(i))->GetChipVersion(),
547 (drs->GetBoard(i))->GetCMCVersion(),
548 (drs->GetBoard(i))->GetCMCSerialNumber(),
549 (drs->GetBoard(i))->GetFirmwareVersion(),
550 (drs->GetBoard(i))->GetTemperature(),
551 (drs->GetBoard(i))->GetStatusReg());
552
553
554 if ((drs->GetBoard(i))->GetStatusReg() & BIT_RUNNING)
555 PrintMessage(" Domino wave running\n");
556 if ((drs->GetBoard(i))->GetStatusReg() & BIT_NEW_FREQ1)
557 PrintMessage(" New Freq1 ready\n");
558 if ((drs->GetBoard(i))->GetStatusReg() & BIT_NEW_FREQ2)
559 PrintMessage(" New Freq2 ready\n");
560
561 PrintMessage(" Control reg.: 0X%08X\n", (drs->GetBoard(i))->GetCtrlReg());
562 if ((drs->GetBoard(i))->GetCtrlReg() & BIT_AUTOSTART)
563 PrintMessage(" AUTOSTART enabled\n");
564 if ((drs->GetBoard(i))->GetCtrlReg() & BIT_DMODE)
565 PrintMessage(" DMODE circular\n");
566 else
567 PrintMessage(" DMODE single shot\n");
568 if ((drs->GetBoard(i))->GetCtrlReg() & BIT_LED)
569 PrintMessage(" LED\n");
570 if ((drs->GetBoard(i))->GetCtrlReg() & BIT_TCAL_EN)
571 PrintMessage(" TCAL enabled\n");
572 if ((drs->GetBoard(i))->GetCtrlReg() & BIT_ZERO_SUPP)
573 PrintMessage(" ZERO_SUPP enabled\n");
574 if ((drs->GetBoard(i))->GetCtrlReg() & BIT_FREQ_AUTO_ADJ)
575 PrintMessage(" FREQ_AUTO_ADJ enabled\n");
576 if ((drs->GetBoard(i))->GetCtrlReg() & BIT_ENABLE_TRIGGER)
577 PrintMessage(" ENABLE_TRIGGER\n");
578 if ((drs->GetBoard(i))->GetCtrlReg() & BIT_LONG_START_PULSE)
579 PrintMessage(" LONG_START_PULSE\n");
580 if ((drs->GetBoard(i))->GetCtrlReg() & BIT_DELAYED_START)
581 PrintMessage(" DELAYED_START\n");
582 if ((drs->GetBoard(i))->GetCtrlReg() & BIT_ACAL_EN)
583 PrintMessage(" ACAL enabled\n");
584 PrintMessage(" Trigger bus: 0X%08X\n", (drs->GetBoard(i))->GetTriggerBus());
585 if ((drs->GetBoard(i))->IsBusy()) {
586 (drs->GetBoard(i))->ReadFrequency(0, &freq);
587 PrintMessage(" Frequency0: %1.4lf GHz\n", freq);
588 (drs->GetBoard(i))->ReadFrequency(1, &freq);
589 PrintMessage(" Frequency1: %1.4lf GHz\n", freq);
590 }
591 else PrintMessage(" Domino wave stopped\n");
592 }
593 }
594 else PrintMessage("No DRS boards available!\n\n");
595 }
596}
597
598// Adress DRS boards
599void DAQReadout::cmd_board() {
600 if (Match(Param[1],"all")) {
601 FirstBoard = 0;
602 LastBoard = drs->GetNumberOfBoards()-1;
603 }
604 else if (NParam==2 && atoi(Param[1])>=0 && atoi(Param[1])<NumBoards) {
605 FirstBoard = atoi(Param[1]);
606 LastBoard = FirstBoard;
607 }
608 else if (NParam==3 && atoi(Param[1])>=0 && atoi(Param[1])<NumBoards &&
609 atoi(Param[2])>0 && atoi(Param[2])<NumBoards) {
610 FirstBoard = atoi(Param[1]);
611 LastBoard = atoi(Param[2]);
612 }
613 else PrintMessage("Cannot address board(s), out of range.\n");
614 CalibrationRead = false;
615}
616
617// Print help (only to console or socket, not to log file)
618void DAQReadout::cmd_help() {
619 char Buffer[MAX_COM_SIZE];
620 for(unsigned int i=0; i<sizeof(CommandList)/sizeof(CL_Struct); i++) {
621 snprintf(Buffer, sizeof(Buffer), "%s %s", CommandList[i].Name, CommandList[i].Parameters);
622 PrintMessage(CmdFromSocket ? MsgToSocket:MsgToConsole,"%-28s%s\n", Buffer, CommandList[i].Help);
623 }
624 PrintMessage(CmdFromSocket ? MsgToSocket:MsgToConsole,".<command> Execute shell command\n\n"
625 "Items in <> are mandatory, in [] optional, | indicates mutual exclusive or.\n"
626 "Test data can also be written if no DRS boards are available.\n"
627 "Strings containing spaces have to be enclosed in \"double quotes\".\n");
628}
629
630// Exit programm
631void DAQReadout::cmd_exit() {
632 if (CmdFromSocket) {
633 PrintMessage("Exit command not allowed over socket.\n");
634 return;
635 }
636 if (daq_state==active) PrintMessage("Issue \"stop\" first to stop daq\n");
637 else {
638 Exit = true;
639 if(SocketThread != NULL) pthread_kill(*SocketThread, SIGUSR1);
640 }
641}
642
643// Set/get mode of feedback
644void DAQReadout::cmd_fmode() {
645 if(Match(Param[1],"off")) HVFB->SetFBMode(FB_Off);
646 if(Match(Param[1],"active")) HVFB->SetFBMode(FB_Active);
647 if(Match(Param[1],"targets")) HVFB->SetFBMode(FB_Targets);
648 HVFB->GetFBMode();
649}
650
651// Set/get current number of events
652void DAQReadout::cmd_faverage() {
653 if(NParam==1) PrintMessage("Current number of feedback events: %u (acting when %u events are reached)\n",
654 HVFB->GetCurrentCount(), HVFB->GetNumAverages());
655 else if(atoi(Param[1])>=0) HVFB->SetNumAverages(atoi(Param[1]));
656 else PrintUsage();
657}
658
659// Set/get feedback gain
660void DAQReadout::cmd_fgain() {
661 if(NParam==2) HVFB->SetGain(atof(Param[1]));
662 PrintMessage("Feedback gain is %.2f\n", HVFB->GetGain());
663}
664
665// Set/get target value
666void DAQReadout::cmd_ftarget() {
667 if(NParam==1) HVFB->GetTargets();
668 else if(NParam!=5) PrintUsage();
669 else for (int i=FirstBoard; i<=LastBoard; i++)
670 for (int j=0; j<kNumberOfChips; j++)
671 for (int k=0; k<kNumberOfChannels; k++)
672 if ((atoi(Param[1])==i || Match(Param[1],"all")) &&
673 (atoi(Param[2])==j || Match(Param[2],"all")) &&
674 (atoi(Param[3])==k || Match(Param[3],"all")))
675 HVFB->SetTarget(i,j,k,atof(Param[4]));
676}
677
678// Start response measurement
679void DAQReadout::cmd_fresponse() {
680 if(NParam==1) HVFB->GetResponse();
681 else if(atof(Param[1])) HVFB->MeasureResponse(atof(Param[1]));
682 else PrintUsage();
683}
684
685// Print feedback configuration
686void DAQReadout::cmd_fconfig() {
687 HVFB->PrintConfig(CmdFromSocket ? MsgToSocket : MsgToConsole);
688}
689
690// ----------------------------------------------
691// ***** Utility function for DRS control *****
692// ----------------------------------------------
693
694// Start domino wave
695void DAQReadout::StartDRS() {
696 for (int i=FirstBoard; i<=LastBoard; i++) drs->GetBoard(i)->StartDomino();
697}
698
699// Stop domino wave
700void DAQReadout::StopDRS() {
701 for (int i=FirstBoard; i<=LastBoard; i++) drs->GetBoard(i)->SoftTrigger();
702}
703
704// Transfer data to memory
705void DAQReadout::ReadCalibratedDRSData() {
706
707 for (int i=FirstBoard; i<=LastBoard; i++) {
708 (drs->GetBoard(i))->TransferWaves(kNumberOfChannels*kNumberOfChips);
709 for (int j=0; j<kNumberOfChannels; j++) {
710 drs->GetBoard(i)->GetWave(0, j, WaveForm[i][0][j], true); // Chip #1
711 TriggerCell[i][0] = drs->GetBoard(i)->GetTriggerCell((unsigned int) 0);
712 drs->GetBoard(i)->GetWave(1, j, WaveForm[i][1][j], true); // Chip #2
713 TriggerCell[i][1] = drs->GetBoard(i)->GetTriggerCell((unsigned int) 1);
714 }
715 }
716}
717
718// Read calibration file
719bool DAQReadout::ReadCalibration() {
720
721 char dir[MAX_COM_SIZE];
722
723 getcwd(dir, sizeof(dir));
724 strcat(dir,"/calib");
725 for (int i=FirstBoard; i<=LastBoard; i++) {
726 (drs->GetBoard(i))->SetCalibrationDirectory(dir);
727 PrintMessage("Reading response calibration file for board %d from: \"%s\"\n", i, dir);
728 for (int Chip=0; Chip<kNumberOfChips; Chip++)
729 if (drs->GetBoard(i)->GetResponseCalibration()->ReadCalibration(Chip)==false) {
730 CalibrationRead = false;
731 return false;
732 }
733 }
734 CalibrationRead = true;
735 return true;
736}
737
738// Stop DAQ
739void DAQReadout::StopRun() {
740
741 if(daq_state != active) PrintMessage("DAQ is not active.\n");
742 else {
743 Stop = true;
744 PrintMessage("DAQ will stop.\n");
745 }
746}
747
748// Set DOMINO mode
749void DAQReadout::SetDOMINOMode(int mode) {
750
751 if (NumBoards)
752 for (int i=FirstBoard; i<=LastBoard; i++) {
753 (drs->GetBoard(i))->SetDominoMode(mode==1 ? 1:0);
754 PrintMessage("Domino mode of board %d switched to %s.\n",i,mode==1 ? "continuous":"single shot");
755 }
756 else PrintMessage("No DRS boards available\n");
757}
758
759// Set DOMINO readout mode
760void DAQReadout::SetDOMINOReadMode(int mode) {
761
762 if (NumBoards)
763 for (int i=FirstBoard; i<=LastBoard; i++) {
764 (drs->GetBoard(i))->SetReadoutMode(mode==1 ? 1:0);
765 PrintMessage("Start readout of board %d from %s.\n",i,mode==1 ? "first bin":"stop position");
766 }
767 else PrintMessage("No DRS boards available\n");
768}
769
770// Set DOMINO wave mode
771void DAQReadout::SetDOMINOWaveMode(int mode) {
772
773 if (NumBoards)
774 for (int i=FirstBoard; i<=LastBoard; i++) {
775 (drs->GetBoard(i))->SetDominoActive(mode==1 ? 1:0);
776 PrintMessage("Domino wave of board %d is %s during readout\n",i,mode==1 ? "running":"stopped");
777 }
778 else PrintMessage("No DRS boards available\n");
779}
780
781// Delayed start on/off
782void DAQReadout::SetDelayedStart(int mode) {
783
784 if (NumBoards)
785 for (int i=FirstBoard; i<=LastBoard; i++) {
786 (drs->GetBoard(i))->SetDelayedStart(mode==1 ? 1:0);
787 PrintMessage("Delayed start of board %d is %s\n",i,mode==1 ? "on":"off");
788 }
789 else PrintMessage("No DRS boards available\n");
790}
791
792// Enable hardware trigger of all boards
793void DAQReadout::HWTrigger(int mode) {
794
795 if (NumBoards)
796 for (int i=FirstBoard; i<=LastBoard; i++) {
797 drs->GetBoard(i)->EnableTrigger(mode==1 ? 1:0);
798 PrintMessage("Hardware trigger of board %d %s\n",i,mode==1 ? "enabled":"disabled");
799 }
800 else PrintMessage("No DRS boards available\n");
801}
802
803// Set DRS sampling frequency
804void DAQReadout::SetDRSFrequency(double freq, bool Regulation) {
805
806 double currentfreq;
807
808 PrintMessage("Setting frequency %s regulation:\n",Regulation ? "with":"without");
809 for (int i=FirstBoard; i<=LastBoard; i++) {
810 drs->GetBoard(i)->SetDebug(1);
811
812 if (Regulation ? drs->GetBoard(i)->RegulateFrequency(freq) : drs->GetBoard(i)->SetFrequency(freq)) {
813 drs->GetBoard(i)->ReadFrequency(0, &currentfreq);
814 DRSFreq[i] = freq;
815 PrintMessage("Domino wave of board %d is running at %1.3lf GHz\n",i,currentfreq);
816 } else {
817 DRSFreq[i] = 0;
818 PrintMessage("Warning: Domino wave of board %d has changed but not reached the requested value\n",i);
819 }
820 }
821}
822
823// Check if DRS is sampling
824bool DAQReadout::IsDRSBusy() {
825
826 for (int i=FirstBoard; i<=LastBoard; i++)
827 if ((drs->GetBoard(i))->IsBusy()) return true;
828 return false;
829}
830
831// Check if DRS frequency is set
832bool DAQReadout::IsDRSFreqSet() {
833
834 for (int i=FirstBoard; i<=LastBoard; i++)
835 if (DRSFreq[i]==0) {
836 PrintMessage("DRS sampling frequency of board %d not set!\n",i);
837 return false;
838 }
839 return true;
840}
841
842// Open new raw data file
843bool DAQReadout::OpenRawFile() {
844
845 time_t rawtime;
846 struct tm *timeinfo;
847 char RunDate[MAX_COM_SIZE], Buffer[MAX_COM_SIZE];
848
849 // Write run date to status structure (if after 13:00, use next day)
850 time(&rawtime);
851 timeinfo = gmtime(&rawtime);
852 if(timeinfo->tm_hour>=13) rawtime += 12*60*60;
853 timeinfo = gmtime(&rawtime);
854 snprintf(RunDate,sizeof(RunDate),"%d%02d%02d",timeinfo->tm_year+1900,timeinfo->tm_mon + 1,timeinfo->tm_mday);
855
856 // Create direcory if not existing (ignore error if already existing) and change to it
857 snprintf(Buffer, sizeof(Buffer), "%s/%s", fRawDataPath, RunDate);
858 if(mkdir(Buffer, S_IRWXU|S_IRWXG)==-1 && errno!=EEXIST) {
859 PrintMessage("\rError: Could not create direcory \"%s\" (%s)\n", Buffer, strerror(errno));
860 return false;
861 }
862
863 // Generate filename
864 snprintf(FileName,sizeof(FileName),"%s/%s/%s_D1_%.8u.%.3u_%c_%s.raw", fRawDataPath, RunDate,
865 RunDate,RunNumber,FileNumber,toupper(daq_runtype_str[daq_runtype][0]),RHeader->Description);
866
867 // Open file with rwx right for owner and group, never overwrite file
868 Rawfile = open(FileName,O_WRONLY|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
869 if(Rawfile==-1) {
870 PrintMessage("\rError: Could not open file \"%s\" (%s)\n", FileName, strerror(errno));
871 return false;
872 }
873 return true;
874}
875
876// Write run header and board structures (revision number is zero for svn modified working copy)
877bool DAQReadout::WriteRunHeader() {
878
879 struct timeval Time;
880
881 RHeader->MagicNum = MAGICNUM_OPEN;
882 RHeader->DataFormat = DATA_FORMAT;
883 RHeader->SoftwareRevision = atoi(REVISION) * (strchr(REVISION, 'M')==NULL ? 1:-1);
884
885 RHeader->RunHeaderSize = sizeof(RunHeader);
886 RHeader->EventHeaderSize = sizeof(EventHeader);
887 RHeader->BoardStructureSize = sizeof(BoardStructure);
888
889 RHeader->Identification = IDENTIFICATION;
890 RHeader->Type = daq_runtype;
891 RHeader->RunNumber = RunNumber;
892 RHeader->FileNumber = FileNumber;
893
894 gettimeofday(&Time, NULL);
895 RHeader->StartSecond = Time.tv_sec;
896 RHeader->StartMicrosecond = Time.tv_usec;
897
898 RHeader->NBoards = NumBoards==0 && daq_runtype==test ? 1 : (LastBoard - FirstBoard) + 1;
899 RHeader->NChips = kNumberOfChips;
900 RHeader->NChannels = kNumberOfChannels;
901 RHeader->NBytes = sizeof(short);
902
903 RHeader->Offset = fFirstSample;
904 RHeader->Samples = fSamples;
905
906 if(write(Rawfile, RHeader, sizeof(RunHeader)) != sizeof(RunHeader)) {
907 PrintMessage("Error: Could not write run header, terminating run (%s)\n", strerror(errno));
908 return false;
909 }
910
911 for (int i=FirstBoard; i<=LastBoard; i++) {
912 BStruct[i].SerialNo = drs->GetBoard(i)->GetCMCSerialNumber();
913 BStruct[i].BoardTemp = drs->GetBoard(i)->GetTemperature();
914 BStruct[i].NomFreq = DRSFreq[i];
915 BStruct[i].ScaleFactor = drs->GetBoard(i)->GetPrecision();
916 }
917
918 // In case no boards are available, dummy data is written for one board structure
919 if (NumBoards == 0) {
920 BStruct[0].NomFreq = 1;
921 BStruct[0].ScaleFactor = 0.1;
922 }
923
924 if(write(Rawfile, &BStruct[FirstBoard], sizeof(BoardStructure)*(LastBoard-FirstBoard+1+(NumBoards==0))) != (ssize_t) sizeof(BoardStructure)*(LastBoard-FirstBoard+1+(NumBoards==0))) {
925 PrintMessage("Error: Could not write (all) board structures, terminating run (%s)\n", strerror(errno));
926 return false;
927 }
928 return true;
929}
930
931// Update run header before closing file
932bool DAQReadout::UpdateRunHeader(unsigned int Events, bool Error) {
933
934 struct timeval Time;
935
936 RHeader->MagicNum = Error==false ? MAGICNUM_CLOSED:MAGICNUM_ERROR;
937 RHeader->Events = Events;
938
939 gettimeofday(&Time, NULL);
940 RHeader->EndSecond = Time.tv_sec;
941 RHeader->EndMicrosecond = Time.tv_usec;
942
943 if(lseek(Rawfile,0,SEEK_SET)==-1) {
944 PrintMessage("Error: Could not rewind file to write updated run header, terminating run (%s)\n", strerror(errno));
945 return false;
946 }
947
948 if(write(Rawfile, RHeader, sizeof(RunHeader)) != sizeof(RunHeader)) {
949 PrintMessage("Error: Could not write updated run header, terminating run (%s)\n", strerror(errno));
950 return false;
951 }
952 return true;
953}
954
955// Write event
956bool DAQReadout::WriteEvent() {
957
958 // Event header
959 struct timeval Time;
960
961 gettimeofday(&Time, NULL);
962
963 EHeader->EventNumber = NumEvents;
964 EHeader->TriggerType = daq_runtype==data ? 0 : 1;
965 EHeader->Second = Time.tv_sec;
966 EHeader->Microsecond = Time.tv_usec;
967 EHeader->EventSize = sizeof(short)*RHeader->NBoards*RHeader->NChips*RHeader->NChannels*RHeader->Samples +
968 sizeof(int)*RHeader->NBoards*RHeader->NChips;
969
970 if(write(Rawfile, EHeader, sizeof(EventHeader)) != sizeof(EventHeader)) {
971 PrintMessage("Error: Could not write event header, terminating run (%s)\n", strerror(errno));
972 return false;
973 }
974
975 // Event data (It is required that at least three chunks can be written with writev(), therefore
976 // IOV_MAX>=3 is checked at startup
977
978 unsigned int Start, Count = 0;
979 ssize_t WriteResult, Size = 0;
980 struct iovec DataPart[IOV_MAX];
981
982 // First chunk: trigger cells
983 DataPart[Count].iov_base = (char *) TriggerCell + FirstBoard*kNumberOfChips*sizeof(int); // TriggerCell is without cast a pointer to an 8-byte unit (two ints) !
984 DataPart[Count++].iov_len = RHeader->NBoards * kNumberOfChips * sizeof(int);
985 Size += DataPart[Count-1].iov_len;
986
987 // Remaining chunks: ADC data (two chucks per channel if wrap around of pipeline occurred)
988 for (int i=FirstBoard; (i<=LastBoard + (NumBoards==0)); i++) {
989 for (unsigned int k=0; k<RHeader->NChips; k++) {
990 Start = (TriggerCell[i][k]-fFirstSample+kNumberOfBins) % kNumberOfBins; // Start bin for this chip
991 for (unsigned int l=0; l<RHeader->NChannels; l++) {
992 DataPart[Count].iov_base = &WaveForm[i][k][l][Start];
993 DataPart[Count++].iov_len = (Start+fSamples<kNumberOfBins ? fSamples:(kNumberOfBins-Start)) * sizeof(short);
994 Size += DataPart[Count-1].iov_len;
995 // In case second part of waveform still missing, write now
996 if(DataPart[Count-1].iov_len < fSamples * sizeof(short)) {
997 DataPart[Count].iov_base = &WaveForm[i][k][l][0];
998 DataPart[Count++].iov_len = (fSamples-(kNumberOfBins-Start)) * sizeof(short);
999 Size += DataPart[Count-1].iov_len;
1000 }
1001
1002 // Write to disk if either maximum size of DataPart[] array or last loop interation is reached
1003 // Possibly 2 chunks are entered in array in the previous lines of code, therefore IOV_MAX-1
1004 if (Count>=IOV_MAX-1 || (l==(RHeader->NChannels-1) && k==(RHeader->NChips-1) && i==(LastBoard+(NumBoards==0)))) {
1005 if ((WriteResult=writev(Rawfile, DataPart, Count)) != (int) Size) {
1006 if (WriteResult==-1) PrintMessage("Error: Could not write event data, terminating run (%s)\n", strerror(errno));
1007 else PrintMessage("Error: Could only write %u out of %u bytes of event data, terminating run\n", WriteResult,Count*DataPart[0].iov_len);
1008 return false;
1009 }
1010 Count = 0; Size = 0;
1011 }
1012 } // Channels
1013 } // Chips
1014 } // Boards
1015
1016 return true;
1017}
1018
1019// Print configuration to target
1020void DAQReadout::PrintConfig(int Target) {
1021 PrintMessage(Target, "LogFile: %s\tMaxLogLines: %u\tRawDataPath: %s\n"
1022 "DefaultFrequency: %.2f\tFirstSample: %d\tSamples: %u\n"
1023 "MinDiskSpaceMB: %u\tMaxFileSizeMB: %d\tCCPort: %d\n"
1024 "FirstVMESlot: %d\t\tLastVMESlot: %d\n"
1025 "SlowDataPath: %s\tHVFeedbackConfig: %s\n",
1026 fLogFile,fMaxLogLines,fRawDataPath,fDefaultFrequency,fFirstSample,fSamples,fMinDiskSpaceMB,
1027 fMaxFileSizeMB,fCCPort,fFirstVMESlot,fLastVMESlot,fSlowDataPath,fHVFeedbackConfig);
1028}
1029
1030// Print usage text for command
1031void DAQReadout::PrintUsage() {
1032 PrintMessage("Usage: %s %s\n", CommandList[CmdNumber].Name, CommandList[CmdNumber].Parameters);
1033}
1034
1035// Print message to selected target
1036void DAQReadout::PrintMessage(int Target, const char *Format, ...) {
1037 va_list ArgumentPointer;
1038 va_start(ArgumentPointer, Format);
1039 PrintMessage(Target, Format, ArgumentPointer);
1040 va_end(ArgumentPointer);
1041}
1042
1043// Print message to log file, and screen or socket (depending on command origin)
1044void DAQReadout::PrintMessage(const char *Format, ...) {
1045 va_list ArgumentPointer;
1046 va_start(ArgumentPointer, Format);
1047 if(CmdFromSocket) PrintMessage(MsgToSocket|MsgToLog, Format, ArgumentPointer);
1048 else PrintMessage(MsgToConsole|MsgToLog, Format, ArgumentPointer);
1049 va_end(ArgumentPointer);
1050}
1051
1052// Function doing the actual printing work
1053void DAQReadout::PrintMessage(int Target, const char *Format, va_list ArgumentPointer) {
1054
1055 char Textbuffer[MAX_COM_SIZE];
1056
1057 memset(Textbuffer, 0, sizeof(Textbuffer));
1058 vsnprintf(Textbuffer, sizeof(Textbuffer), Format, ArgumentPointer);
1059
1060 // Print to console
1061 if(Target & MsgToConsole) {
1062 if(strlen(Textbuffer)>0 && Textbuffer[strlen(Textbuffer)-1]=='\n') {
1063 printf("\r%s%s", Textbuffer, Prompt); // New prompt
1064 fflush(stdout);
1065 }
1066 else printf("%s", Textbuffer);
1067 }
1068 // Print to log file
1069 if((Target & MsgToLog) && Logfile!=NULL) {
1070 fprintf(Logfile, "%s", Textbuffer);
1071 fflush(Logfile);
1072 }
1073 // Print to socket
1074 if((Target & MsgToSocket) && Socket!=-1) write(Socket, Textbuffer, strlen(Textbuffer));
1075}
1076
1077
1078// ---------------------------------------
1079// ***** Various utility functions *****
1080// ---------------------------------------
1081
1082// Check if two strings match (min 1 character must match)
1083bool Match(const char *str, const char *cmd) {
1084 return strncasecmp(str,cmd,strlen(str)==0 ? 1:strlen(str)) ? false:true;
1085}
1086
1087// Return current available storage space in given directory
1088int CheckDisk(char *Directory) {
1089 struct statfs FileSystemStats;
1090
1091 statfs(Directory, &FileSystemStats);
1092 return FileSystemStats.f_bavail / 1024 * (FileSystemStats.f_bsize / 1024);
1093}
1094
1095// Parse command line for white space and double-quote separated tokens
1096int ParseInput(char* Command, const char *Param[]) {
1097 int Count=0;
1098
1099 while(Count<MAX_NUM_TOKEN) {
1100 while (isspace(*Command)) Command++; // Ignore initial white spaces
1101 if(*Command=='\0') break;
1102 if (*Command == '\"') {
1103 Param[Count] = ++Command;
1104 while(*Command!='\"' && *Command!='\0') Command++;
1105 }
1106 else {
1107 Param[Count] = Command;
1108 while(!isspace(*Command) && *Command!='\0') Command++;
1109 }
1110 if(*Command != '\0') *Command++ = '\0';
1111 Count++;
1112 }
1113 return Count;
1114}
1115
1116// ReadCard function (original version by F. Goebel)
1117// Data is read into an array if MaxNum is larger than 1
1118bool ReadCard(const char *card_flag, void *store, char Type, FILE *File, unsigned int MaxNum) {
1119
1120 char *card_name, *card_val, Buffer[MAX_COM_SIZE];
1121 unsigned int Count=0;
1122
1123 rewind(File);
1124
1125 while (fgets(Buffer, sizeof(Buffer), File) != NULL) { // Read line by line
1126 card_name = strtok(Buffer," \t\n");
1127
1128 // Ignore empty lines, comments, and skip if card name does not match
1129 if (card_name==NULL || card_name[0]=='#' || strcmp(card_name, card_flag)!=0) continue;
1130
1131 // Read numbers of given type (if MaxNum>1 read array)
1132 while ((card_val=strtok(NULL," \t\n")) != NULL && Count++<MaxNum) {
1133 switch (Type) {
1134 case 'I': *(((int *&) store)++) = (int) strtol(card_val, NULL, 10);
1135 break;
1136 case 'i': *(((short *&) store)++) = (short) strtol(card_val, NULL, 10);
1137 break;
1138 case 'U': *(((unsigned int *&) store)++) = (unsigned int) strtoul(card_val, NULL, 10);
1139 break;
1140 case 'u': *(((unsigned short *&) store)++) = (unsigned short) strtoul(card_val, NULL, 10);
1141 break;
1142 case 'f': *(((float *&) store)++) = atof(card_val);
1143 break;
1144 case 'd': *(((double *&) store)++) = atof(card_val);
1145 break;
1146 case 's': sprintf((char *) store, "%s", card_val);
1147 break;
1148 case 'c': *((char *) store) = card_val[0];
1149 break;
1150 default: fprintf(stderr,"Warning: Unknown type '%c' for reading of configuration file\n", Type);
1151 return false;
1152 }
1153 }
1154 return true; // Finished reading data for card name
1155
1156 }
1157 fprintf(stderr,"Warning: Configuration value %s not found\n", card_flag);
1158 return false;
1159}
1160
1161
1162/********************************************************************\
1163
1164 DAQ Thread
1165
1166 This thread takes data until the requested number of events is reached,
1167 until no more disk space is available or until data taking is stopped.
1168 No mutex mechanism is used since variables will never be written
1169 simultaneoously by two threads.
1170
1171\********************************************************************/
1172
1173void DAQ(DAQReadout *m) {
1174
1175 struct timeval StartTime, StopTime;
1176 unsigned int EventsInFile;
1177 unsigned long long RunSize = 0;
1178 bool WriteError = false;
1179 off_t FileSize;
1180
1181 m->NumEvents = 0;
1182 m->FileNumber = 0;
1183 m->HVFB->ClearAverages();
1184 gettimeofday(&StartTime, NULL);
1185 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);
1186
1187 do {
1188 // Check if enough disk space is left
1189 if (CheckDisk(m->fRawDataPath) <= m->fMinDiskSpaceMB+m->fMaxFileSizeMB) {
1190 m->PrintMessage("\rError: Disk space after next file (max. %d MByte) below %d MByte\n",m->fMaxFileSizeMB,m->fMinDiskSpaceMB);
1191 break;
1192 }
1193
1194 // Init run header, open raw file, write run header
1195 if (!m->OpenRawFile()) break;
1196 m->PrintMessage("\rData file \"%s\" opened.\n",m->FileName);
1197 EventsInFile = 0;
1198 FileSize = 0;
1199
1200 WriteError |= !m->WriteRunHeader();
1201
1202 if (m->daq_runtype != test) m->StartDRS();
1203
1204 // Take data until finished, stopped or file too large
1205 while ((m->NumEvents<m->NumEventsRequested || m->NumEventsRequested==0) &&
1206 !m->Stop && FileSize/1024/1024<m->fMaxFileSizeMB && !WriteError) {
1207
1208 if (m->daq_runtype == data) while (m->IsDRSBusy()); // Wait for hardware trigger (if DAQ stopped, DRS will not be busy anymore)
1209 else if (m->daq_runtype == pedestal) m->StopDRS(); // ..or for software trigger
1210
1211 // Read event data via VME or generate test data (for one board if no boards available)
1212 if (m->daq_runtype != test) {
1213 m->ReadCalibratedDRSData();
1214 m->StartDRS(); // Restart here: writing data is in parallel to waiting for next trigger
1215 }
1216 else {
1217 double Period = ((double) rand())/RAND_MAX*20;
1218 for (long unsigned int i=0; i<m->RHeader->NBoards*kNumberOfChips*kNumberOfChannels*kNumberOfBins; i++)
1219 *((short *) m->WaveForm+i) = (short) (sin(i/Period)*1000);
1220 }
1221
1222 // Write event to disk and update file size
1223 EventsInFile++; m->NumEvents++;
1224 WriteError |= !m->WriteEvent();
1225
1226 if((FileSize = lseek(m->Rawfile, 0, SEEK_CUR)) == -1) {
1227 m->PrintMessage("Error: Could not determine file size, terminating run (%s)\n", strerror(errno));
1228 WriteError = true;
1229 }
1230
1231 // Call feedback to process event
1232 m->HVFB->ProcessEvent();
1233 }
1234
1235 // Write updated run header, close file
1236 RunSize += FileSize;
1237 WriteError |= !m->UpdateRunHeader(EventsInFile, WriteError);
1238 if(close(m->Rawfile)==-1) m->PrintMessage("Error: Could not close data file (%s)\n", strerror(errno));
1239 else m->PrintMessage("Data file closed (size %lu MByte).\n", FileSize/1024/1024);
1240
1241 m->FileNumber += 1;
1242 } while((m->NumEvents<m->NumEventsRequested || m->NumEventsRequested==0) && !m->Stop && !WriteError);
1243
1244 m->StopDRS();
1245
1246 // Print run summary to screen
1247 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);
1248 else m->PrintMessage("\rRun #%d (%s) aborted due to error after %d events\n",m->RunNumber,daq_runtype_str[m->daq_runtype],m->NumEvents);
1249
1250 // Write run summary to slow data file
1251 m->SlowDataClass->NewEntry("Runinfo");
1252 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);
1253 if(m->SlowDataClass->ErrorCode != 0) {
1254 m->PrintMessage("Error, could not write DAQ data to file (%s), file closed\n", strerror(m->SlowDataClass->ErrorCode));
1255 }
1256
1257 // Print run statistics
1258 if (m->NumEvents>0 && !WriteError) {
1259 gettimeofday(&StopTime, NULL);
1260 float RunTime = StopTime.tv_sec-StartTime.tv_sec + (StopTime.tv_usec-StartTime.tv_usec)*1e-6;
1261 m->PrintMessage("Time for run %.2f seconds, trigger rate %.2f Hz.\n", RunTime, m->NumEvents/RunTime);
1262 m->PrintMessage("Run size %llu MByte, data rate %.1f MByte/s.\n", RunSize/1024/1024, RunSize/1024.0/1024/RunTime);
1263 }
1264
1265 m->daq_state = stopped;
1266}
Note: See TracBrowser for help on using the repository browser.