source: drsdaq/DAQReadout.cc@ 208

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