source: drsdaq/DAQReadout.cc@ 44

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