source: drsdaq/DAQReadout.cc@ 40

Last change on this file since 40 was 36, checked in by ogrimm, 16 years ago
Various changes, see History.txt
File size: 44.5 KB
Line 
1/********************************************************************\
2
3 DAQReadout.cc
4
5 Main DAQ routines.
6
7 Sebastian Commichau, Oliver Grimm
8
9\********************************************************************/
10
11#include "DAQReadout.h"
12#include "SlowData.h"
13
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 snprintf(Source,sizeof(Source),"DUMMY");
77
78 // Read configuration file
79 FILE *File;
80 if ((File = fopen(Configfile,"r")) == NULL) {
81 printf("Error: Could not open drsdaq configuration file '%s'\n", Configfile);
82 }
83 else {
84 printf("Reading drsdaq configuration file %s\n", Configfile);
85 ReadCard("LogFile", fLogFile, 's', File);
86 ReadCard("RawDataPath", fRawDataPath, 's', File);
87 ReadCard("RotateWave", &fRotateWave, 'I', File);
88 ReadCard("FirstSample", &fFirstSample, 'I', File);
89 ReadCard("LastSample", &fLastSample, 'I', File);
90 ReadCard("MinDiskSpaceMB", &fMinDiskSpaceMB, 'U', File);
91 ReadCard("MaxFileSizeMB", &fMaxFileSizeMB, 'I', File);
92 ReadCard("CCPort", &fCCPort, 'I', File);
93 ReadCard("FirstVMESlot", &fFirstVMESlot, 'I', File);
94 ReadCard("LastVMESlot", &fLastVMESlot, 'I', File);
95 ReadCard("HVFeedbackConfig", fHVFeedbackConfig, 's', File);
96 fclose(File);
97 }
98 if (fFirstSample < 0 || fFirstSample >= kNumberOfBins || fLastSample < 0 || fLastSample >= kNumberOfBins) {
99 PrintMessage("Warning: Sample range in configuration beyond limits, setting to full range\n");
100 fFirstSample = 0;
101 fLastSample = kNumberOfBins;
102 }
103
104 // Open log file and print configuration
105 if ((Logfile = fopen(fLogFile, "a")) == NULL)
106 fprintf(stderr,"Warning: Could not open log file '%s'\n", fLogFile);
107 else PrintMessage(MsgToLog,"********** Logging started **********\n");
108 cmd_config();
109
110 // Create DRS instance and perform initial scan
111 drs = new DRS();
112 drs->SetFirstVMESlot(fFirstVMESlot);
113 drs->SetLastVMESlot(fLastVMESlot);
114 drs->InitialScan();
115
116 RHeader = new RunHeader;
117 EHeader = new EventHeader;
118 DRSFreq = new float [drs->GetNumberOfBoards()];
119
120 // Scan for DRS boards
121 if (drs->GetNumberOfBoards()==0)
122 PrintMessage("No DRS boards found - check VME crate and configuration file!\n");
123
124 for (int i=0; i<drs->GetNumberOfBoards(); i++) {
125 PrintMessage("Init. mezz. board %2d on VME slot %2d %s, serial #%d, firmware revision %d\n",
126 i, (drs->GetBoard(i)->GetSlotNumber() >> 1)+2, ((drs->GetBoard(i)->GetSlotNumber() & 1) == 0) ? "upper" : "lower",
127 drs->GetBoard(i)->GetCMCSerialNumber(), drs->GetBoard(i)->GetFirmwareVersion());
128 NumCMCBoards++;
129 LastBoard++;
130 drs->GetBoard(i)->Init();
131 drs->GetBoard(i)->SetRotation(fRotateWave);
132 DRSFreq[i] = 0;
133 }
134 BStruct = new BoardStructure [NumCMCBoards == 0 ? 1:drs->GetNumberOfBoards()];
135 WaveForm = new short [NumCMCBoards == 0 ? 1:NumCMCBoards][kNumberOfChips][kNumberOfChannels][kNumberOfBins];
136
137 // Create instance of HV feedback (must be called after CMC board detection)
138 HVFB = new HVFeedback(this, fHVFeedbackConfig);
139
140 // Create instance of slow data class for DAQ
141 char Filename[MAX_PATH];
142 snprintf(Filename,sizeof(Filename),"%s/SlowData/", fRawDataPath);
143 SlowDataClass = new SlowData(this, "DAQ", Filename);
144}
145
146// ------------------------
147// ***** Destructor *****
148// ------------------------
149
150DAQReadout::~DAQReadout() {
151 delete SlowDataClass;
152 delete RHeader; delete EHeader;
153 delete drs; delete HVFB;
154 delete[] DRSFreq; delete[] BStruct;
155 delete[] WaveForm;
156
157 PrintMessage(MsgToLog,"********** Logging ended **********\n\n");
158 if(Logfile) {
159 if(!fclose(Logfile)) printf("Closing logfile\n");
160 else perror("Error closing logfile");
161 }
162}
163
164// --------------------------------
165// ***** Command evaluation *****
166// --------------------------------
167
168int DAQReadout::CommandControl(char *Command, bool FromSocket) {
169
170 if (strlen(Command) < 2 ) return 0; // Ignore commands with only '/n'
171 if (Command[strlen(Command)-1]=='\n') Command[strlen(Command)-1]='\0'; // Remove '/n'
172
173 if(Command[0]=='.') { // Shell command
174 system(&(Command[1]));
175 return 0;
176 }
177
178 for(int i=0; i<MAX_NUM_TOKEN; i++) Param[i] = ""; // All pointers point initially to empty string
179 NParam = ParseInput(Command, Param);
180
181 CmdFromSocket = FromSocket;
182 for(CmdNumber=0; CmdNumber<sizeof(CommandList)/sizeof(CL_Struct); CmdNumber++)
183 if (Match(Param[0], CommandList[CmdNumber].Name)) {
184 if(CommandList[CmdNumber].NeedNotBusy && daq_state==active) PrintMessage("DAQ is busy\n");
185 else if(CommandList[CmdNumber].NeedNotBusy && NumCMCBoards==0) PrintMessage("No mezzanine boards available\n");
186 else (this->*CommandList[CmdNumber].CommandPointer)();
187 return 0;
188 }
189 PrintMessage("Unknown command: %s\n",Param[0]);
190 return 0;
191}
192
193// Get uptime
194void DAQReadout::cmd_uptime() {
195 time_t ActualT;
196 time (&ActualT);
197 PrintMessage(CmdFromSocket ? MsgToSocket:MsgToConsole, "%d:%02d:%02d\n", (int) difftime(ActualT, StartTime)/3600, ((int) difftime(ActualT, StartTime)/60)%60, (int) difftime(ActualT, StartTime)%60);
198}
199
200// Print disk space
201void DAQReadout::cmd_disk() {
202 PrintMessage(CmdFromSocket ? MsgToSocket:MsgToConsole, "Free disk space (%s) [MB]: %lu\n", fRawDataPath, CheckDisk(fRawDataPath));
203}
204
205// Print current number of events
206void DAQReadout::cmd_events() {
207 if(daq_state != active) PrintMessage("DAQ not active.\n");
208 else PrintMessage("Current number of events: %d\n", NumEvents);
209}
210
211// Print DAQ configuration
212void DAQReadout::cmd_config() {
213 PrintMessage("LogFile: %s\tRawDataPath: %s\n"
214 "RotateWave: %d\t\tFirstSample: %d\t\tLastSample: %d\n"
215 "MinDiskSpaceMB: %u\tMaxFileSizeMB: %d\tCCPort: %d\n"
216 "FirstVMESlot: %d\t\tLastVMESlot: %d\n"
217 "HVFeedbackConfig: \t%s\n",
218 fLogFile,fRawDataPath,fRotateWave,fFirstSample,fLastSample,fMinDiskSpaceMB,
219 fMaxFileSizeMB,fCCPort,fFirstVMESlot,fLastVMESlot,fHVFeedbackConfig);
220}
221
222// Start DAQ
223void DAQReadout::cmd_take() {
224
225 if(!Match(Param[1],"test")) {
226 if (daq_state==active || NumCMCBoards==0) {
227 PrintMessage("DAQ is busy or no boards available.\n");
228 return;
229 }
230 if (!IsDRSFreqSet()) return;
231 if (!CalibrationRead && !ReadCalibration()) {
232 PrintMessage("Cannot start run if response calibration not read.\n");
233 return;
234 }
235 }
236
237 if (Match(Param[1],"data")) {
238 HWTrigger(1);
239 daq_runtype = data;
240 }
241 else if (Match(Param[1],"pedestal")) {
242 HWTrigger(0);
243 daq_runtype = pedestal;
244 }
245 else if (Match(Param[1],"test")) {
246 daq_runtype = test;
247 }
248 else {
249 PrintUsage();
250 return;
251 }
252
253 if (NParam==3) NumEventsRequested = atoi(Param[2]);
254 if (NParam==4) {
255 NumEventsRequested = atoi(Param[2]);
256 strcpy(Source, Param[3]);
257 }
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: %c\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][0], 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,Source,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 time_t time_now_secs;
899 struct tm *time_now;
900
901 RHeader->MagicNum = MAGICNUM_OPEN;
902 RHeader->DataFormat = DATA_FORMAT;
903 RHeader->RunHeaderSize = sizeof(RunHeader);
904 RHeader->EventHeaderSize = sizeof(EventHeader);
905 RHeader->BoardStructureSize = sizeof(BoardStructure);
906 strcpy(RHeader->DAQVersion, __DATE__);
907
908 strcpy(RHeader->Source, Source);
909 RHeader->Type = daq_runtype_str[daq_runtype][0];
910 RHeader->RunNumber = RunNumber;
911 RHeader->FileNumber = FileNumber;
912
913 time(&time_now_secs);
914 time_now = localtime(&time_now_secs);
915
916 RHeader->StartYear = 1900 + time_now->tm_year;
917 RHeader->StartMonth = 1 + time_now->tm_mon;
918 RHeader->StartDay = time_now->tm_mday;
919 RHeader->StartHour = time_now->tm_hour;
920 RHeader->StartMinute = time_now->tm_min;
921 RHeader->StartSecond = time_now->tm_sec;
922
923 RHeader->SourceRA = -1;
924 RHeader->SourceDEC = -1;
925 RHeader->TelescopeRA = -1;
926 RHeader->TelescopeDEC = -1;
927
928 RHeader->NCMCBoards = NumCMCBoards==0 && daq_runtype==test ? 1 : (LastBoard - FirstBoard) + 1;
929 RHeader->NChips = kNumberOfChips;
930 RHeader->NChannels = kNumberOfChannels;
931
932 RHeader->Offset = fFirstSample;
933 RHeader->Samples = fLastSample - fFirstSample + 1;
934
935 if(write(Rawfile, RHeader, sizeof(RunHeader)) != sizeof(RunHeader)) {
936 PrintMessage("Error: Could not write run header, terminating run (%s)\n", strerror(errno));
937 return false;
938 }
939
940 for (int i=FirstBoard; i<=LastBoard; i++) {
941 BStruct[i].SerialNo = drs->GetBoard(i)->GetCMCSerialNumber();
942 BStruct[i].BoardTemp = drs->GetBoard(i)->GetTemperature();
943 BStruct[i].NomFreq = DRSFreq[i];
944 BStruct[i].ScaleFactor = drs->GetBoard(i)->GetPrecision();
945 }
946
947 // In case no boards are available, dummy data is written for one board structure
948 if (NumCMCBoards == 0) {
949 BStruct[0].NomFreq = 1;
950 BStruct[0].ScaleFactor = 0.1;
951 }
952
953 if(write(Rawfile, BStruct, sizeof(BoardStructure)*(LastBoard-FirstBoard+1+(NumCMCBoards==0))) != (ssize_t) sizeof(BoardStructure)*(LastBoard-FirstBoard+1+(NumCMCBoards==0))) {
954 PrintMessage("Error: Could not write (all) board structures, terminating run (%s)\n", strerror(errno));
955 return false;
956 }
957 return true;
958}
959
960// Update the run header
961bool DAQReadout::UpdateRunHeader(unsigned int Events, bool Error) {
962
963 time_t time_now_secs;
964 struct tm *time_now;
965
966 RHeader->MagicNum = Error==false ? MAGICNUM_CLOSED:MAGICNUM_ERROR;
967 RHeader->Events = Events;
968
969 time(&time_now_secs);
970 time_now = localtime(&time_now_secs);
971
972 RHeader->EndYear = 1900 + time_now->tm_year;
973 RHeader->EndMonth = 1 + time_now->tm_mon;
974 RHeader->EndDay = time_now->tm_mday;
975 RHeader->EndHour = time_now->tm_hour;
976 RHeader->EndMinute = time_now->tm_min;
977 RHeader->EndSecond = time_now->tm_sec;
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 strcpy(EHeader->Name,"EVTH");
999 EHeader->EventNumber = NumEvents;
1000 EHeader->TriggerType = 0XFFFF;
1001 EHeader->TimeSec = Time.tv_sec + (float) Time.tv_usec/1000000.;
1002
1003 if(write(Rawfile, EHeader, sizeof(EventHeader)) != sizeof(EventHeader)) {
1004 PrintMessage("Error: Could not write event header, terminating run (%s)\n", strerror(errno));
1005 return false;
1006 }
1007 return true;
1008}
1009
1010// Print usage text for command
1011void DAQReadout::PrintUsage() {
1012 PrintMessage("Usage: %s %s\n", CommandList[CmdNumber].Name, CommandList[CmdNumber].Parameters);
1013}
1014
1015// Print message to selected target
1016void DAQReadout::PrintMessage(int Target, const char *Format, ...) {
1017 va_list ArgumentPointer;
1018 va_start(ArgumentPointer, Format);
1019 PrintMessage(Target, Format, ArgumentPointer);
1020 va_end(ArgumentPointer);
1021}
1022
1023// Print message to screen, log file and socket
1024void DAQReadout::PrintMessage(const char *Format, ...) {
1025 va_list ArgumentPointer;
1026 va_start(ArgumentPointer, Format);
1027 PrintMessage(MsgToConsole|MsgToLog|MsgToSocket, Format, ArgumentPointer);
1028 va_end(ArgumentPointer);
1029}
1030
1031// Function doing the actual printing work
1032void DAQReadout::PrintMessage(int Target, const char *Format, va_list ArgumentPointer) {
1033
1034 char Textbuffer[MAX_COM_SIZE];
1035
1036 memset(Textbuffer, 0, sizeof(Textbuffer));
1037 vsnprintf(Textbuffer, sizeof(Textbuffer), Format, ArgumentPointer);
1038
1039 // Print to console and generate new prompt
1040 if(Target & MsgToConsole) {
1041 if(strlen(Textbuffer)>0 && Textbuffer[strlen(Textbuffer)-1]=='\n') printf("\r%s", Textbuffer);
1042 else printf("%s", Textbuffer);
1043
1044 // New prompt only after newline
1045 if(Textbuffer[strlen(Textbuffer)-1]=='\n' || strlen(Textbuffer)==0) {
1046 if (NumCMCBoards == 0) printf("\rDAQ> ");
1047 else if (FirstBoard == LastBoard) printf("\rDAQ|B%d> ",FirstBoard);
1048 else printf("\rDAQ|B%d-%d> ",FirstBoard,LastBoard);
1049 fflush(stdout);
1050 }
1051 }
1052
1053 // Print to log file and socket only if length not zero (then only prompt)
1054 if (strlen(Textbuffer)>0) {
1055 if((Target & MsgToLog) && Logfile!=NULL) {
1056 fprintf(Logfile, "%s", Textbuffer);
1057 fflush(Logfile);
1058 }
1059 if((Target & MsgToSocket) && Socket!=-1) write(Socket, Textbuffer, strlen(Textbuffer));
1060 }
1061}
1062
1063
1064// ---------------------------------------
1065// ***** Various utility functions *****
1066// ---------------------------------------
1067
1068// Check if two strings match (min 1 character must match)
1069bool Match(const char *str, const char *cmd) {
1070 return strncasecmp(str,cmd,strlen(str)==0 ? 1:strlen(str)) ? false:true;
1071}
1072
1073// Return current available storage space in given directory
1074int CheckDisk(char *Directory) {
1075 struct statfs FileSystemStats;
1076
1077 statfs(Directory, &FileSystemStats);
1078 return FileSystemStats.f_bavail / 1024 * (FileSystemStats.f_bsize / 1024);
1079}
1080
1081// Parse command line for white space and double-quote separated tokens
1082int ParseInput(char* Command, const char *Param[]) {
1083 int Count=0;
1084
1085 while(Count<MAX_NUM_TOKEN) {
1086 while (isspace(*Command)) Command++; // Ignore initial white spaces
1087 if(*Command=='\0') break;
1088 if (*Command == '\"') {
1089 Param[Count] = ++Command;
1090 while(*Command!='\"' && *Command!='\0') Command++;
1091 }
1092 else {
1093 Param[Count] = Command;
1094 while(!isspace(*Command) && *Command!='\0') Command++;
1095 }
1096 *Command++ = '\0';
1097 Count++;
1098 };
1099 return Count;
1100}
1101
1102// ReadCard function by F. Goebel
1103int ReadCard(const char *card_flag, void *store, char type, FILE *fptr) {
1104
1105 char *card_name, *card_val, line[160];
1106
1107 rewind(fptr);
1108
1109 while (fgets(line, 160, fptr) != NULL) { // Read line by line
1110 card_name = strtok(line," \t\n");
1111 card_val = strtok(NULL," \t\n");
1112
1113 if ( card_name != NULL && card_val != NULL // Comment or empty line?
1114 && card_name[0] != '*' && card_name[0] != '#') {
1115
1116 if (strcmp(card_name, card_flag)!=0) { // Is this the card name we are looking for?
1117 continue;
1118 }
1119
1120 switch (type) {
1121 case 'I': *((int *) store) = (int) strtol(card_val, (char**)NULL, 10);
1122 break;
1123 case 'i': *((short *) store) = (short) strtol(card_val, (char**)NULL, 10);
1124 break;
1125 case 'U': *((unsigned int *) store) = (unsigned int) strtoul(card_val, (char**)NULL, 10);
1126 break;
1127 case 'u': *((unsigned short *) store) = (unsigned short) strtoul(card_val, (char**)NULL, 10);
1128 break;
1129 case 'f': *((float *) store) = atof(card_val);
1130 break;
1131 case 'd': *((double *) store) = atof(card_val);
1132 break;
1133 case 's': sprintf((char *) store,"%s",card_val);
1134 break;
1135 case 'c': *((char *) store) = card_val[0];
1136 break;
1137 default: fprintf(stderr,"WARNING: ReadCard: unknown type: %c\n", type);
1138 return -2;
1139 }
1140 return 0; // Found card name
1141 }
1142 }
1143 fprintf(stderr,"WARNING: ReadCard: card: %s not found\n", card_flag);
1144 return -1;
1145}
1146
1147
1148/********************************************************************\
1149
1150 DAQ Thread
1151
1152 This thread takes data until the requested number of events is reached,
1153 until no more disk space is available or until data taking is stopped.
1154 No mutex mechanism is used since variables will never be written
1155 simultaneoously by two threads.
1156
1157\********************************************************************/
1158
1159void DAQ(DAQReadout *m) {
1160
1161 struct timeval StartTime, StopTime;
1162 int Count;
1163 unsigned int EventsInFile;
1164 unsigned long long RunSize = 0;
1165 bool WriteError = false;
1166 struct iovec DataPart[IOV_MAX];
1167 ssize_t WriteResult;
1168 off_t FileSize;
1169
1170 m->NumEvents = 0;
1171 m->FileNumber = 0;
1172 m->HVFB->ClearAverages();
1173 gettimeofday(&StartTime, NULL);
1174
1175 m->PrintMessage("\rStarting run #%d (%s) on \"%s\" with %u event(s)\n",m->RunNumber,daq_runtype_str[m->daq_runtype],m->Source,m->NumEventsRequested);
1176 do {
1177 // Check if enough disk space is left
1178 if (CheckDisk(m->fRawDataPath) <= m->fMinDiskSpaceMB+m->fMaxFileSizeMB) {
1179 m->PrintMessage("\rError: Disk space after next file (max. %d MByte) below %d MByte\n",m->fMaxFileSizeMB,m->fMinDiskSpaceMB);
1180 break;
1181 }
1182
1183 // Init run header, open raw file, write run header
1184 if (!m->OpenRawFile()) break;
1185 m->PrintMessage("\rData file \"%s\" opened.\n",m->FileName);
1186 EventsInFile = 0;
1187 FileSize = 0;
1188 WriteError |= !m->WriteRunHeader();
1189
1190 if (m->daq_runtype != test) m->StartDRS();
1191
1192 // Take data until finished, stopped or file too large
1193 while ((m->NumEvents<m->NumEventsRequested || m->NumEventsRequested==0) &&
1194 !m->Stop && FileSize/1024/1024<m->fMaxFileSizeMB && !WriteError) {
1195
1196 if (m->daq_runtype == data) while (m->IsDRSBusy()); // Wait for hardware trigger (if DAQ stopped, DRS will not be busy anymore)
1197 else if (m->daq_runtype == pedestal) m->StopDRS(); // ..or for software trigger
1198
1199 EventsInFile++; m->NumEvents++;
1200 WriteError |= !m->WriteEventHeader();
1201
1202 // Read event data via VME or generate test data (for one board if no boards available)
1203 if (m->daq_runtype != test) {
1204 m->ReadCalibratedDRSData();
1205 m->StartDRS(); // Restart here: writing data is in parallel to waiting for next trigger
1206 }
1207 else {
1208 double Period = ((double) rand())/RAND_MAX*20;
1209 for (long int i=0; i<(m->NumCMCBoards>0 ? m->NumCMCBoards : 1)*kNumberOfChips*kNumberOfChannels*kNumberOfBins; i++)
1210 *((short *) m->WaveForm+i) = (short) (sin(i/Period)*1000);
1211 }
1212
1213 // Write data to disk (using writev() for performance reason)
1214 Count = 0;
1215 for (int i=m->FirstBoard; (i<=m->LastBoard + (m->NumCMCBoards==0)) && !WriteError; i++) {
1216 for (unsigned int k=0; k<m->RHeader->NChips*m->RHeader->NChannels; k++) {
1217 DataPart[Count].iov_base = &m->WaveForm[i][k/m->RHeader->NChannels][k%m->RHeader->NChannels][m->RHeader->Offset];
1218 DataPart[Count++].iov_len = m->RHeader->Samples * sizeof(short);
1219
1220 // Write to disk if either maximum size of DataPart[] array or last loop interation is reached
1221 if (Count==IOV_MAX || (k==(m->RHeader->NChips*m->RHeader->NChannels-1) && i==(m->LastBoard+(m->NumCMCBoards==0)))) {
1222 if ((WriteResult=writev(m->Rawfile, DataPart, Count)) != (int) (Count*DataPart[0].iov_len)) {
1223 if (WriteResult==-1) m->PrintMessage("Error: Could not write event data, terminating run (%s)\n", strerror(errno));
1224 else m->PrintMessage("Error: Could only write %u out of %u bytes of event data, terminating run\n", WriteResult,Count*DataPart[0].iov_len);
1225 WriteError = true;
1226 break;
1227 }
1228 Count = 0;
1229 }
1230 }
1231 }
1232
1233 // Update file size
1234 if((FileSize = lseek(m->Rawfile, 0, SEEK_CUR)) == -1) {
1235 m->PrintMessage("Error: Could not determine file size, terminating run (%s)\n", strerror(errno));
1236 WriteError = true;
1237 }
1238 // Call feedback to process event
1239 m->HVFB->ProcessEvent();
1240 }
1241
1242 // Write updated run header, close file
1243 RunSize += FileSize;
1244 WriteError |= !m->UpdateRunHeader(EventsInFile, WriteError);
1245 if(close(m->Rawfile)==-1) m->PrintMessage("Error: Could not close data file (%s)\n", strerror(errno));
1246 else m->PrintMessage("Data file closed (size %lu MByte).\n", FileSize/1024/1024);
1247
1248 m->FileNumber += 1;
1249 } while(m->NumEvents<m->NumEventsRequested && !m->Stop && !WriteError);
1250
1251 m->StopDRS();
1252 if(!WriteError) {
1253 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);
1254 m->SlowDataClass->NewEntry("Runinfo");
1255 m->SlowDataClass->AddToEntry("%d %s %s %d",m->RunNumber,daq_runtype_str[m->daq_runtype],m->Source,m->NumEvents);
1256 }
1257 else m->PrintMessage("\rRun #%d (%s) aborted due to error after %d events\n",m->RunNumber,daq_runtype_str[m->daq_runtype],m->NumEvents);
1258 if (m->NumEvents>0 && !WriteError) {
1259 gettimeofday(&StopTime, NULL);
1260 float RunTime = StopTime.tv_sec-StartTime.tv_sec + (StopTime.tv_usec-StartTime.tv_usec)*1e-6;
1261 m->PrintMessage("Time for run %.2f seconds, trigger rate %.2f Hz.\n", RunTime, m->NumEvents/RunTime);
1262 m->PrintMessage("Run size %llu MByte, data rate %.1f MByte/s.\n", RunSize/1024/1024, RunSize/1024.0/1024/RunTime);
1263 }
1264 m->daq_state = stopped;
1265}
Note: See TracBrowser for help on using the repository browser.