source: fact/drsdaq/DAQReadout.cc@ 15063

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