source: drsdaq/DAQReadout.cc@ 90

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