source: drsdaq/DAQReadout.cc@ 73

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