source: drsdaq/DAQReadout.cc@ 56

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