source: drsdaq/DAQReadout.cc@ 31

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