source: drsdaq/DAQReadout.cc@ 67

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