source: fact/FADctrl/FAD.cc@ 10120

Last change on this file since 10120 was 10120, checked in by ogrimm, 12 years ago
Moved OpenOtherSockets() to FADBoard class
File size: 32.9 KB
Line 
1/********************************************************************\
2
3 FAD.cc
4
5 Main class of FADCtrl
6
7
8 Comment 19/10/2010: It is assumed that boolean access is an atomic operation.
9
10\********************************************************************/
11
12#include "FAD.h"
13using namespace std;
14
15static const struct CL_Struct { const char *Name;
16 void (FAD::*CommandPointer)();
17 bool NeedIdle;
18 unsigned int MinNumParameter;
19 const char *Parameters;
20 const char *Help;
21 } CommandList[] =
22 {{"board", &FAD::cmd_board, true, 1, "[+|-]<range>" ,"Activate or deactivate boards"},
23 {"status", &FAD::cmd_status, false, 0, "[range]", "Show board status information"},
24 {"domino", &FAD::cmd_domino, true, 1, "<on|off>", "Switch Domino wave"},
25 {"dwrite", &FAD::cmd_dwrite, true, 1, "<on|off>", "Set DWRITE"},
26 {"phase", &FAD::cmd_phase, true, 1, "<phase>", "Adjust ADC phase (in 'steps')"},
27 {"srclk", &FAD::cmd_srclk, true, 1, "<on|off>", "Set SRCLK"},
28 {"sclk", &FAD::cmd_sclk, true, 1, "<on|off>", "Set SCLK"},
29 {"trigger", &FAD::cmd_trigger, false, 0, "[n|cont|stop|enable|disable]", "Issue software triggers"},
30 {"roi", &FAD::cmd_roi, true, 2, "<channel range> <value>", "Set region-of-interest to value"},
31 {"dac", &FAD::cmd_dac, true, 2, "<range> <value>", "Set DAC numbers in range to value"},
32 {"address", &FAD::cmd_address, true, 2, "<range> <value>", "Set addresses in range to value"},
33 {"send", &FAD::cmd_send, true, 1, "<value>", "Send arbitrary data to board"},
34 {"take", &FAD::cmd_take, true, 1, "<n> <dir>", "Start run with n events, write to directory"},
35 {"acalib", &FAD::cmd_acalib, true, 0, "[n|invalidate|file]", "Perform or read amplitude calibration (n events)"},
36 //{"wmode", &FAD::cmd_wmode, 0, "<run|stop>", "Domino wave running or stopped during read out"},
37 //{"rmode", &FAD::cmd_rmode, 0, "<first|stop>", "Readout start at first bin or stop position (DRS4)"},
38 //{"dmode", &FAD::cmd_dmode, 0, "<single|continuous>", "Domino wave single shot or continuous"},
39 {"stop", &FAD::cmd_stop, false, 0, "", "Stop current operation/run"},
40 {"update", &FAD::cmd_update, false, 1, "<sec>", "Minimum delay between updates to DIM event service"},
41 {"socketmode", &FAD::cmd_socketmode, true, 1, "<com|daq>", "Choose which Sockets are used for data transmission"},
42 {"exit", &FAD::cmd_exit, true, 0, "", "Exit program"},
43 {"help", &FAD::cmd_help, false, 0, "", "Print help"}};
44
45
46
47// ------------------------------------
48// ***** Constructor/Destructor *****
49// ------------------------------------
50
51//
52// Constructor
53//
54FAD::FAD(): EvidenceServer(SERVER_NAME) {
55
56 // Initialization
57 ConsoleText = NULL;
58 MainThread = pthread_self();
59 Mode = idle;
60 Datafile = -1;
61 EventUpdateDelay = atof(GetConfig("EventUpdateDelay", "0.5").c_str());
62
63 // Create pipe for data exchange
64 if (pipe(Pipe) == -1) Message(FATAL, "pipe() failed in FAD::FAD() (%s)", strerror(errno));
65
66 // DIM console service used in PrintMessage()
67 ConsoleOut = new DimService(SERVER_NAME"/ConsoleOut", (char *) "");
68
69 // Construct boards
70 BoardList = Tokenize(GetConfig("BoardList"));
71
72 for (unsigned int i=0; i<BoardList.size(); i++) {
73 Boards.push_back(new class FADBoard(BoardList[i], 5000, this, i));
74
75 // Check if initialised OK
76 if (!Boards.back()->InitOK) {
77 Message(WARN, "Failed to initialize board %s\n", BoardList[i].c_str());
78 delete Boards.back();
79 Boards.pop_back();
80 }
81 }
82
83 // Create DIM event service thread
84 int Ret;
85 if ((Ret = pthread_create(&Thread, NULL, (void * (*)(void *)) LaunchEventThread,(void *) this)) != 0) {
86 Message(FATAL, "pthread_create() failed in FAD::FAD() (%s)", strerror(Ret));
87 }
88
89 // Install DIM command (after all initialized)
90 Command = new DimCommand((char *) SERVER_NAME"/Command", (char *) "C", this);
91}
92
93//
94// Destructor
95//
96FAD::~FAD() {
97
98 int Ret;
99
100 // Close pipe (will make read() on pipe in DIM service thread return)
101 if (close(Pipe[0]) == -1) Message(ERROR, "close() on Pipe[0] failed in FAD::~FAD() (%s)", strerror(errno));;
102 if (close(Pipe[1]) == -1) Message(ERROR, "close() on Pipe[1] failed in FAD::~FAD() (%s)", strerror(errno));;
103
104 // Wait for DIM service thread to quit
105 if ((Ret = pthread_join(Thread, NULL)) != 0) Message(ERROR, "pthread_join() failed in ~FAD() (%s)", strerror(Ret));
106
107 // Delete all boards (cancels threads automatically)
108 for (unsigned int i=0; i<Boards.size(); i++) delete Boards[i];
109
110 delete Command;
111 delete ConsoleOut;
112 free(ConsoleText);
113}
114
115// ------------------------------
116// ***** Command handling *****
117// ------------------------------
118
119//
120// DIM command handler
121// Handler must be non-blocking, otherwise a DIM rpc would dead-lock.
122//
123void FAD::commandHandler() {
124
125 char *Command = getCommand()->getString();
126
127 // Ignore empty or illegal strings
128 if (getCommand()->getSize() == 0 || *(Command+getCommand()->getSize()-1) != '\0' ||
129 strlen(Command) == 0) return;
130
131 // Shell command
132 if (Command[0]=='.') {
133 system(&(Command[1]));
134 return;
135 }
136
137 // Parse command into tokens
138 Parameter.clear();
139 char *Start;
140 while(true) {
141 while (isspace(*Command)) Command++; // Ignore initial white spaces
142 if(*Command=='\0') break;
143 if (*Command == '\"') {
144 Start = ++Command;
145 while(*Command!='\"' && *Command!='\0') Command++;
146 }
147 else {
148 Start = Command;
149 while(!isspace(*Command) && *Command!='\0') Command++;
150 }
151 if(*Command != '\0') *Command++ = '\0';
152 Parameter.push_back(Start);
153 }
154
155 // Search for command in command list
156 for(unsigned int i=0; i<sizeof(CommandList)/sizeof(CL_Struct); i++) {
157 if (Match(Parameter[0], CommandList[i].Name)) {
158 // Check if number of parameters
159 if(Parameter.size()-1 < CommandList[i].MinNumParameter) {
160 PrintMessage("Usage: %s %s\n", CommandList[i].Name, CommandList[i].Parameters);
161 return;
162 }
163 // Check if idle mode required
164 if (CommandList[i].NeedIdle && Mode != idle) {
165 PrintMessage("Current mode is not idle ('stop' will stop current operation)\n");
166 return;
167 }
168 // Jump to command function
169 (this->*CommandList[i].CommandPointer)();
170 return;
171 }
172 }
173
174 PrintMessage("Unknown command '%s'\n", Parameter[0].c_str());
175}
176
177//
178// Switch SRCLK
179//
180void FAD::cmd_srclk() {
181
182 for (unsigned int i=0; i<Boards.size(); i++) {
183 if (Match(Parameter[1],"on")) Boards[i]->Send(CMD_SRCLK_ON);
184 else if (Match(Parameter[1],"off")) Boards[i]->Send(CMD_SRCLK_OFF);
185 }
186
187 if (Match(Parameter[1],"on")) PrintMessage("SRCLK switched on for all active boards\n");
188 else if (Match(Parameter[1],"off")) PrintMessage("SRCLK switched off for all active boards\n");
189 else PrintUsage();
190}
191
192//
193// Switch socket mode
194// "com" - command mode (only socket 0 is used)
195// "daq" - daq mode (only sockets 1 - 7 are used)
196//
197// Note that socket 0 is always used to issue commands
198//
199void FAD::cmd_socketmode() {
200
201 for (unsigned int i=0; i<Boards.size(); i++) {
202 if (Match(Parameter[1],"com")) Boards[i]->Send(CMD_Stop);
203 else if (Match(Parameter[1],"daq")) Boards[i]->Send(CMD_Start);
204 }
205
206 if (Match(Parameter[1],"com")) PrintMessage("All active boards switched to command mode - socket 0\n");
207 else if (Match(Parameter[1],"daq")) PrintMessage("All active boards switched to DAQ mode - socket 1..7\n");
208 else PrintUsage();
209}
210
211//
212// Switch SCLK
213//
214void FAD::cmd_sclk() {
215
216 for (unsigned int i=0; i<Boards.size(); i++) {
217 if (Match(Parameter[1],"on")) Boards[i]->Send(CMD_SCLK_ON);
218 else if (Match(Parameter[1],"off")) Boards[i]->Send(CMD_SCLK_OFF);
219 }
220
221 if (Match(Parameter[1],"on")) PrintMessage("SCLK switched on for all active boards\n");
222 else if (Match(Parameter[1],"off")) PrintMessage("SCLK switched off for all active boards\n");
223 else PrintUsage();
224}
225
226//
227// Switch Domino wave
228//
229void FAD::cmd_domino() {
230
231 for (unsigned int i=0; i<Boards.size(); i++) {
232 if (Match(Parameter[1],"on")) Boards[i]->Send(CMD_DENABLE);
233 else if (Match(Parameter[1],"off")) Boards[i]->Send(CMD_DDISABLE);
234 }
235
236 if (Match(Parameter[1],"on")) PrintMessage("Domino wave switched on for all active boards\n");
237 else if (Match(Parameter[1],"off")) PrintMessage("Domino wave switched off for all active boards\n");
238 else PrintUsage();
239}
240
241//
242// Switch DWRITE
243//
244void FAD::cmd_dwrite() {
245
246 for (unsigned int i=0; i<Boards.size(); i++) {
247 if (Match(Parameter[1],"on")) Boards[i]->Send(CMD_DWRITE_RUN);
248 else if (Match(Parameter[1],"off")) Boards[i]->Send(CMD_DWRITE_STOP);
249 }
250
251 if (Match(Parameter[1],"on")) PrintMessage("DWRITE set high for all active boards\n");
252 else if (Match(Parameter[1],"off")) PrintMessage("DWRITE set low for all active boards\n");
253 else PrintUsage();
254}
255
256//
257// Issue soft trigger
258//
259void FAD::cmd_trigger() {
260
261 int Num;
262
263 for (unsigned int i=0; i<Boards.size(); i++) {
264 if (Parameter.size() == 1) Boards[i]->Send(CMD_Trigger);
265 else if (ConvertToInt(Parameter[1], &Num)) {
266 for (int j=0; j<Num; j++) {
267 Boards[i]->Send(CMD_Trigger);
268 usleep(10000);
269 }
270 }
271 else if (Match(Parameter[1],"continuous")) Boards[i]->Send(CMD_Trigger_C);
272 else if (Match(Parameter[1],"stop")) Boards[i]->Send(CMD_Trigger_S);
273 else if (Match(Parameter[1],"enable")) Boards[i]->Send(CMD_TRIGGERS_ON);
274 else if (Match(Parameter[1],"disable")) Boards[i]->Send(CMD_TRIGGERS_OFF);
275 else {
276 PrintUsage();
277 break;
278 }
279 }
280
281 if (Match(Parameter[1],"enable")) PrintMessage("All active boards accept incoming triggers\n");
282 else if (Match(Parameter[1],"disable")) PrintMessage("No active board accepts incoming triggers\n");
283}
284
285//
286// Set DAC
287//
288void FAD::cmd_dac() {
289
290 int Value;
291 struct Range R = {0, NDAC-1};
292 unsigned short Buffer[2*NDAC] = {0};
293
294 // Check ranges
295 if(!ConvertToRange(Parameter[1], R)) {
296 PrintMessage("Error, DAC number out of range.\n");
297 return;
298 }
299
300 if (!ConvertToInt(Parameter[2], &Value) || Value<0 || Value>MAX_DACVAL) {
301 PrintMessage("Error, DAC value out of range.\n");
302 return;
303 }
304
305 // Prepare command buffer
306 for (int i=R.Min; i<=R.Max; i++) {
307 Buffer[2*i] = htons(CMD_Write | (BADDR_DAC + i));
308 Buffer[2*i+1] = htons(Value);
309 }
310
311 // Send command buffer
312 for (unsigned int i=0; i<Boards.size(); i++) {
313 Boards[i]->Send(Buffer, sizeof(Buffer));
314 }
315}
316
317//
318// Set region-of-interest
319//
320void FAD::cmd_roi() {
321
322 int Value;
323 struct Range R = {0, NChips*NChannels-1};
324 unsigned short Buffer[2*NChips*NChannels] = {0};
325
326 // Check ranges
327 if (!ConvertToRange(Parameter[1], R)) {
328 PrintMessage("Error, ROI number out of range.\n");
329 return;
330 }
331
332 if (!ConvertToInt(Parameter[2], &Value) || Value<0 || Value>MAX_ROIVAL) {
333 PrintMessage("Error, ROI value out of range.\n");
334 return;
335 }
336
337 // Prepare command buffer
338 for (int i=R.Min; i<=R.Max; i++) {
339 Buffer[2*i] = htons(CMD_Write | (BADDR_ROI + i));
340 Buffer[2*i+1] = htons(Value);
341 }
342
343 // Send command buffer
344 for (unsigned int i=0; i<Boards.size(); i++) {
345 Boards[i]->Send(Buffer, sizeof(Buffer));
346 }
347}
348
349//
350// Set addresses to value
351//
352void FAD::cmd_address() {
353
354 int Value;
355 struct Range R = {0, MAX_ADDR};
356 unsigned short Buffer[2*MAX_ADDR] = {0};
357
358 // Check ranges
359 if (!ConvertToRange(Parameter[1], R)) {
360 PrintMessage("Error, address out of range.\n");
361 return;
362 }
363
364 if (!ConvertToInt(Parameter[2], &Value) || Value<0 || Value>MAX_VAL) {
365 PrintMessage("Error, value out of range.\n");
366 return;
367 }
368
369 // Prepare command buffer
370 for (int i=R.Min; i<=R.Max; i++) {
371 Buffer[2*i] = htons(CMD_Write | i);
372 Buffer[2*i+1] = htons(Value);
373 }
374
375 // Send command buffer
376 for (unsigned int i=0; i<Boards.size(); i++) {
377 Boards[i]->Send(Buffer, 2*(R.Max-R.Min+1)*sizeof(unsigned short));
378 }
379}
380
381//
382// Set ADC phase
383//
384void FAD::cmd_phase() {
385
386 int Value;
387
388 if (!ConvertToInt(Parameter[1], &Value)) {
389 PrintMessage("Error, illegal phase value\n");
390 return;
391 }
392
393 // Prepare command buffer
394 unsigned short *Buffer = new unsigned short [abs(Value)];
395 for (int i=0; i<abs(Value); i++) Buffer[i] = htons(CMD_PS_DO);
396
397 // Execute phase setting
398 for (unsigned int i=0; i<Boards.size(); i++) {
399 Boards[i]->Send(CMD_PS_RESET);
400 if (Value < 0) Boards[i]->Send(CMD_PS_DIRDEC);
401 else Boards[i]->Send(CMD_PS_DIRINC);
402 Boards[i]->Send(Buffer, abs(Value)*sizeof(unsigned short));
403 }
404
405 delete[] Buffer;
406}
407
408//
409// Send arbitrary data to board
410//
411void FAD::cmd_send() {
412
413 int Value;
414
415 if (!ConvertToInt(Parameter[1], &Value) || Value<0 || Value>MAX_VAL) {
416 PrintMessage("Error, illegal value\n");
417 return;
418 }
419
420 for (unsigned int i=0; i<Boards.size(); i++) Boards[i]->Send(Value);
421}
422
423/*
424// Set Domino mode
425void FAD::cmd_dmode() {
426 if (Match(Param[1],"continuous")) SetDOMINOMode(1);
427 else if (Match(Param[1],"single")) SetDOMINOMode(0);
428 else PrintUsage();
429}
430
431// Set Domino readout mode
432void FAD::cmd_rmode() {
433 if (Match(Param[1],"first")) SetDOMINOReadMode(0);
434 else if (Match(Param[1],"stop")) SetDOMINOReadMode(1);
435 else PrintUsage();
436}
437
438// Set Domino wave mode
439void FAD::cmd_wmode() {
440 if (Match(Param[1],"run")) SetDOMINOWaveMode(1);
441 else if (Match(Param[1],"stop")) SetDOMINOWaveMode(0);
442 else PrintUsage();
443}
444*/
445
446//
447// Start data run
448//
449void FAD::cmd_take() {
450
451 time_t Time = time(NULL);
452 struct tm *T = localtime(&Time);
453 char Filename[500];
454
455 // Set number of requested events
456 NumEventsRequested = atoi(Parameter[1].c_str());
457 NumEvents = 0;
458
459 // Open file with rwx right for owner and group, never overwrite file
460 snprintf(Filename, sizeof(Filename),"%s/%d%02d%02dT%02d%02d%02d.raw", Parameter[2].c_str(), T->tm_year+1900, T->tm_mon+1, T->tm_mday, T->tm_hour, T->tm_min, T->tm_sec);
461
462 Datafile = open(Filename,O_WRONLY|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
463 if(Datafile == -1) {
464 PrintMessage("Error: Could not open file \"%s\" (%s)\n", Filename, strerror(errno));
465 return;
466 }
467
468 // Start run
469 Mode = datarun;
470 PrintMessage("Starting run with %d events, filename '%s'\n", NumEventsRequested, Filename);
471}
472
473//
474// Amplitude calibration
475//
476void FAD::cmd_acalib() {
477
478 int Count;
479 FILE *File;
480 vector<string> Items;
481
482 // Invalidate calibration?
483 if (Parameter.size() == 2 && Match(Parameter[1], "invalidate")) {
484 for (unsigned int i=0; i<Boards.size(); i++) Boards[i]->ACalibTime = -1;
485 return;
486 }
487
488 // Read calibration data from file?
489 //if (Parameter.size() == 2 && !ConvertToInt(Parameter[1], &NumCalibEvents)) {
490 if (Parameter.size() == 2 && !ConvertToInt(Parameter[1], &NumEventsRequested)) {
491 // Open file
492 if ((File = fopen(Parameter[1].c_str(), "r")) == NULL) {
493 PrintMessage("Error opening file '%s'\n", Parameter[1].c_str());
494 return;
495 }
496 PrintMessage("Reading amplitude calibration information from file '%s'\n", Parameter[1].c_str());
497
498 // Read file into buffer and close file
499 string Buffer;
500 while (feof(File)==0 && ferror(File)==0) Buffer.push_back((char) fgetc(File));
501 if (Buffer.size() > 0) Buffer = Buffer.substr(0, Buffer.size()-1);
502 if (fclose(File) != 0) PrintMessage("Could not close file '%s'\n", Parameter[1].c_str());
503
504 // Search for calibration data for boards
505 vector<string> Result = Tokenize(Buffer, "\n");
506
507 for (unsigned int Brd=0; Brd<Boards.size(); Brd++) {
508 for (unsigned int Line=0; Line<Result.size(); Line++) {
509 if (Result[Line].find(Boards[Brd]->Name) == string::npos) continue;
510
511 PrintMessage("Found calibration data for board '%s'\n", Boards[Brd]->Name);
512 Items = Tokenize(Result[Line]);
513
514 // Check if correct number of items
515 if (Items.size() != NChips*NChannels*NBins*3 + 3) {
516 PrintMessage("Error, data format invalid\n", Parameter[1].c_str());
517 return;
518 }
519
520 // Extract data
521 Boards[Brd]->ACalibTemp = atof(Items[1].c_str());
522 Boards[Brd]->ACalibTime = atoi(Items[2].c_str());
523
524 Count = 3;
525 for (unsigned int i=0; i<NChips; i++) {
526 for (unsigned int j=0; j<NChannels; j++) {
527 for (unsigned int k=0; k<NBins; k++) {
528 Boards[Brd]->Baseline[i][j][k] = atoi(Items[Count++].c_str());
529 Boards[Brd]->Gain[i][j][k] = atof(Items[Count++].c_str());
530 Boards[Brd]->SecondaryBaseline[i][j][k] = atof(Items[Count++].c_str());
531 }
532 }
533 }
534 }
535 } // Loop over boards
536
537 return;
538 } // Reading calibration from file
539
540 // Set number of events required for calibration
541 if (Parameter.size()==1 || !ConvertToInt(Parameter[1], &NumEventsRequested) || NumEventsRequested<=0) {
542 NumEventsRequested = DEFAULT_NUM_CALIB_EVENTS;
543 }
544
545 // Start ca;ibration by setting mode
546 Mode = acalib;
547}
548
549
550//
551// Print status
552//
553void FAD::cmd_status() {
554
555 // ==== Print board overview ====
556 if (Parameter.size() == 1) {
557
558 // Count active board
559 unsigned int Count = 0, Error = 0;
560 for (unsigned int i=0; i<Boards.size(); i++) {
561 if (Boards[i]->Active) Count++;
562 if (Boards[i]->CommError) Error++;
563 }
564
565 PrintMessage(" Number of FAD boards: %d Boards with communication error: %d Active boards: ", Boards.size(), Error);
566
567 // Print list of active boards
568 if (Count == 0) PrintMessage("none\n");
569 else if (Count == Boards.size()) PrintMessage("all\n");
570 else for (unsigned int i=0; i<Boards.size(); i++) {
571 if (Boards[i]->Active) PrintMessage(" %d", i);
572 }
573
574 // Current mode
575 if (Mode == idle) PrintMessage("Current mode is IDLE\n");
576 else if (Mode == acalib) PrintMessage("Current mode is ACALIB (3x%d events)\n", NumEventsRequested);
577 else if (Mode == datarun) PrintMessage("Current mode is DATARUN (%d events requested, %d events taken)\n", NumEventsRequested, NumEvents);
578
579 return;
580 }
581
582 // ==== Print details for given range ====
583 struct Range R = {0, Boards.size()};
584
585 if (!ConvertToRange(Parameter[1], R)) {
586 PrintMessage("Error, out of range.\n");
587 return;
588 }
589
590 for (int i=0; i<(int) Boards.size(); i++) {
591 if (i<R.Min || i > R.Max) continue;
592
593 struct FADBoard::BoardStatus S = Boards[i]->GetStatus();
594
595 PrintMessage("Board #%d - %s (%sactive) Communication %s\n", i, Boards[i]->Name, Boards[i]->Active ? "":"in", Boards[i]->CommError ? "ERROR":"OK");
596 PrintMessage("Board ID %d Firmware revision %d\n", S.BoardID, S.FirmwareRevision);
597 PrintMessage("DAC %d %d %d %d %d %d %d %d\n", S.DAC[0], S.DAC[1], S.DAC[2], S.DAC[3], S.DAC[4], S.DAC[5], S.DAC[6], S.DAC[7] );
598 PrintMessage("Temperature %.2f %.2f %.2f %.2f", S.Temp[0], S.Temp[1], S.Temp[2], S.Temp[3]);
599
600 for (unsigned int i=0; i<NChips*NChannels; i++) {
601 if (i%NChannels == 0) PrintMessage("\nROI %2d-%2d: ", i, i+NChannels-1);
602 PrintMessage("%4d ", S.ROI[i/NChannels][i%NChannels]);
603 }
604 PrintMessage("\n");
605
606 /*PrintMessage("Serial %d, firmware %d\n"
607 " Actual temperature: %1.1lf C\n"
608 " Calibration temp.: %1.1lf C\n"
609 GetBoard(i)->GetBoardSerialNumber(),
610 GetBoard(i)->GetFirmwareVersion(),
611 ACalibTemp[i]);
612
613
614 if (GetBoard(i)->GetStatusReg() & BIT_RUNNING)
615 PrintMessage(" Domino wave running\n");
616
617 if (GetBoard(i)->GetCtrlReg() & BIT_DMODE)
618 PrintMessage(" DMODE circular\n");
619 else
620 PrintMessage(" DMODE single shot\n");
621 if (GetBoard(i)->GetCtrlReg() & BIT_ACAL_EN)
622 PrintMessage(" ACAL enabled\n");
623 PrintMessage(" Trigger bus: 0x%08X\n", GetBoard(i)->GetTriggerBus());
624 else PrintMessage(" Domino wave stopped\n");
625 }
626 }*/
627 } // for()
628}
629
630
631//
632// Adress FAD boards
633//
634void FAD::cmd_board() {
635
636 struct Range R = {0, Boards.size()};
637 int Mode = 0;
638
639 // Check if given boards should be enabled or disabled
640 if (Parameter[1].size() >= 1) {
641 if (Parameter[1][0] == '+') Mode = 1;
642 if (Parameter[1][0] == '-') Mode = -1;
643 }
644 if (Mode != 0) Parameter[1][0] = ' ';
645
646 // Evaluate given range
647 if (!ConvertToRange(Parameter[1], R)) {
648 PrintMessage("Error, out of range.\n");
649 return;
650 }
651
652 // Enable or disable boards
653 for (int i=0; i<(int) Boards.size(); i++) {
654 if (Mode == 0) Boards[i]->Active = false;
655 if (i >= R.Min && i <= R.Max) {
656 if (Mode != -1) Boards[i]->Active = true;
657 else Boards[i]->Active = false;
658 }
659 }
660}
661
662//
663// Set DIM event update delay
664//
665void FAD::cmd_update() {
666
667 double Delay;
668
669 if (Parameter.size()==2 && ConvertToDouble(Parameter[1], &Delay) && Delay>0) EventUpdateDelay = Delay;
670 else PrintUsage();
671}
672
673//
674// Print help
675//
676void FAD::cmd_help() {
677
678 char *Buffer;
679
680 for(unsigned int i=0; i<sizeof(CommandList)/sizeof(CL_Struct); i++) {
681 if (asprintf(&Buffer, "%s %s", CommandList[i].Name, CommandList[i].Parameters) == -1) {
682 PrintMessage("Error printing help, asprintf() failed\n");
683 break;
684 }
685 else {
686 if (strlen(Buffer) < 25) PrintMessage("%-25s%s\n", Buffer, CommandList[i].Help);
687 else PrintMessage("%s\n%-25s%s\n", Buffer, "", CommandList[i].Help);
688 }
689 free(Buffer);
690 }
691 PrintMessage(".<command> Execute shell command\n\n"
692 "Items in <> are mandatory, in [] optional, | indicates mutual exclusive.\n"
693 "Strings containing spaces have to be enclosed in \"double quotes\".\n"
694 "Ranges can be given as 'all', a single number or in the form 'a-b'.\n");
695}
696
697//
698// Cancel current operation
699//
700void FAD::cmd_stop() {
701
702 static char Stop[] = "stop";
703
704 if (Mode == idle) {
705 PrintMessage("Nothing to stop\n");
706 return;
707 }
708
709 if (Mode == acalib) Mode = idle;
710
711 if (Mode == datarun) {
712 // Inform event thread to stop run in case datarun active
713 if (write(Pipe[1], Stop, strlen(Stop)+1) == -1) {
714 Message(ERROR, "write() to Pipe[1] failed in FAD::cmd_cancel() (%s)", strerror(errno));
715 }
716 }
717
718 PrintMessage("Requested stopping of current operation\n");
719}
720
721//
722// Exit programm
723// SIGTERM sets ExitRequest flag, and also makes readline() return (if command from DimCommand thread)
724//
725void FAD::cmd_exit() {
726
727 pthread_kill(MainThread, SIGTERM);
728}
729
730
731// -----------------------------
732// ***** Other functions *****
733// -----------------------------
734
735//
736// Save amplitude calibration data to file
737//
738void FAD::SaveAmplitudeCalibration() {
739
740 PrintMessage("Amplitude calibration of all active boards finished, original ROI and DAC set\n");
741
742 // Write calibration data to file
743 time_t Time = time(NULL);
744 struct tm *TimeInfo;
745 char Buffer[200];
746
747 // Generate filename
748 TimeInfo = localtime(&Time);
749 if (strftime(Buffer, sizeof(Buffer), "/FADcalib_%y-%m-%jT%X.txt", TimeInfo) == 0) {
750 PrintMessage("Could not generate calibration data file name, strftime() failed\n");
751 return;
752 }
753 string Filename = string(getenv("HOME"))+Buffer;
754
755 FILE *File = fopen(Filename.c_str(), "w");
756 if (File == NULL) {
757 PrintMessage("Could not open calibration data file '%s'\n", Filename.c_str());
758 return;
759 }
760
761 // Fix: Should actually contain serial number!
762 for (unsigned int Brd=0; Brd<Boards.size(); Brd++) {
763 fprintf(File, "\n%s: %f %d ", Boards[Brd]->Name, Boards[Brd]->ACalibTemp, (int) Boards[Brd]->ACalibTime);
764 for (unsigned int i=0; i<NChips; i++) {
765 for (unsigned int j=0; j<NChannels; j++) {
766 for (unsigned int k=0; k<NBins; k++) {
767 fprintf(File, "%d %lf %lf ", Boards[Brd]->Baseline[i][j][k], Boards[Brd]->Gain[i][j][k], Boards[Brd]->SecondaryBaseline[i][j][k]);
768 }
769 }
770 }
771 }
772
773 // Close file
774 if (fclose(File) != 0) {
775 PrintMessage("Could not close calibration file '%s'\n", Filename.c_str());
776 }
777
778 PrintMessage("Wrote amplitude calibration information to file '%s'\n", Filename.c_str());
779}
780
781//
782// Event thread (publishes/writes M0 format)
783//
784void FAD::EventThread() {
785
786 struct timeval Time, RunStart;
787 struct timeval LastUpdate;
788 struct FADBoard::BoardStatus S;
789 vector<unsigned long> EventNumbers(Boards.size());
790 vector<bool> AcalibDone(Boards.size());
791 double Temp;
792 string IDString;
793 char Buffer[100];
794 int Ret;
795 unsigned long long FileSize = 0;
796
797 gettimeofday(&LastUpdate, NULL);
798 RunStart = LastUpdate; // only to avoid 'uninitialized' warning from compiler
799
800 // Create DIM event data service
801 int EventSize = sizeof(RunHeader)+ Boards.size()*sizeof(BoardStructure)+sizeof(EventHeader) + Boards.size()*(NChips*NChannels*NBins*sizeof(short) + NChips*sizeof(int));
802 char *EventData = new char [EventSize];
803 DimService *EventService = new DimService (SERVER_NAME"/EventData", (char *) "C", NULL, 0);
804
805 memset(EventData, 0, EventSize);
806
807 // Calculate pointers to EventData array
808 RunHeader *RHeader = (RunHeader *) EventData;
809 BoardStructure **BStruct = new BoardStructure * [Boards.size()];
810 for (unsigned int i=0; i<Boards.size(); i++) BStruct[i] = ((BoardStructure *) (RHeader + 1)) + i;
811 EventHeader *EHeader = (EventHeader *) ((char *) (RHeader + 1) + Boards.size()*sizeof(BoardStructure));
812 int *TriggerCell = (int *) (EHeader + 1);
813 short *Data = (short *) (TriggerCell + NChips*Boards.size());
814
815 // M0 RunHeader
816 RHeader->DataFormat = DATA_FORMAT;
817 RHeader->RunHeaderSize = sizeof(RunHeader);
818 RHeader->EventHeaderSize = sizeof(EventHeader);
819 RHeader->BoardStructureSize = sizeof(BoardStructure);
820 RHeader->SoftwareRevision = 0xFFFF; // Update
821 RHeader->Identification = 0;
822
823 RHeader->Type = 0; // Run type: 0=data, 1=pedestal, 3=test
824
825 RHeader->RunNumber = -1;
826 RHeader->FileNumber = 0;
827 snprintf(RHeader->Description, sizeof(RHeader->Description), "FADctrl");
828
829 RHeader->NBoards = Boards.size();
830 RHeader->NChips = NChips;
831 RHeader->NChannels = NChannels;
832 RHeader->Samples = NBins; // Always full pipeline
833 RHeader->Offset = 0;
834 RHeader->NBytes = sizeof(short);
835
836 // M0 EventHeader
837 EHeader->EventSize = Boards.size()*(NChips*NChannels*NBins*sizeof(short) + NChips*sizeof(int));
838
839 // Update loop
840 while (!ExitRequest) {
841 // Wait for data from TCP/IP reading threads
842 if ((Ret=read(Pipe[0], Buffer, sizeof(Buffer))) == -1) Message(FATAL, "read() from Pipe[0] failed in FAD::EventThread() (%s)", strerror(errno));
843 IDString = string(Buffer, Ret);
844
845 // If amplitude calibration mode, check if board finished procedure
846 if (Mode == acalib) {
847 bool Done = true;
848 for (unsigned int i=0; i<Boards.size(); i++) {
849 if (IDString.find(string("ACALIBDONE")+Boards[i]->Name) != string::npos) AcalibDone[i] = true;
850 if (!AcalibDone[i]) Done = false;
851 }
852 // Amplitude calibration finished?
853 if (Done) {
854 SaveAmplitudeCalibration();
855 Mode = idle;
856 }
857 }
858 else for (unsigned int i=0; i<Boards.size(); i++) AcalibDone[i] = false;
859
860 // Update run and event header with current time
861 gettimeofday(&Time, NULL);
862
863 RHeader->MagicNum = MAGICNUM_CLOSED;
864 RHeader->EndSecond = Time.tv_sec;
865 RHeader->EndMicrosecond = Time.tv_usec;
866
867 EHeader->Second = Time.tv_sec;
868 EHeader->Microsecond = Time.tv_usec;
869
870 // Close data file if requested or requested number of events reached
871 if((IDString.find("stop")!=string::npos || NumEvents==NumEventsRequested) && Mode==datarun) {
872
873 // Update run header
874 RHeader->Events = NumEvents;
875 RHeader->StartSecond = RunStart.tv_sec;
876 RHeader->StartMicrosecond = RunStart.tv_usec;
877
878 if (lseek(Datafile, 0, SEEK_SET) == -1) {
879 PrintMessage("Error: Could not rewind file to write updated run header (%s)\n", strerror(errno));
880 }
881 else if (write(Datafile, RHeader, sizeof(RunHeader)) != sizeof(RunHeader)) {
882 PrintMessage("Error: Could not write updated run header (%s)\n", strerror(errno));
883 }
884
885 // Close data file and terminate run
886 if(close(Datafile) == -1) PrintMessage("Error: Could not close data file (%s)\n", strerror(errno));
887 else PrintMessage("Data file closed (size %.1f MByte).\n", FileSize/1024.0/1024);
888
889 Datafile = -1;
890 Mode = idle;
891 }
892
893 // These values might have changed while close file
894 RHeader->StartSecond = Time.tv_sec;
895 RHeader->StartMicrosecond = Time.tv_usec;
896 RHeader->Events = 1;
897
898 // Check all boards that have new data
899 for (unsigned int Brd=0; Brd<Boards.size(); Brd++) {
900 // Identify board
901 if (IDString.find(string("EVENT")+Boards[Brd]->Name) == string::npos) continue;
902
903 // Fill M0 BoardStructure
904 S = Boards[Brd]->GetStatus();
905 BStruct[Brd]->SerialNo = S.BoardID;
906 BStruct[Brd]->NomFreq = 2;
907 BStruct[Brd]->BoardTemp = 0;
908 for (unsigned int i=0; i<NTemp; i++) BStruct[Brd]->BoardTemp += S.Temp[i]/NTemp;
909 BStruct[Brd]->ScaleFactor = 1/2.048;
910
911 // Update event header with ID and Type of current board
912 EHeader->EventNumber = S.TriggerID;
913 EHeader->TriggerType = S.TriggerType;
914
915 // Register event number for data writing below
916 EventNumbers[Brd] = S.TriggerID;
917
918 // Write trigger cells
919 for(unsigned int i=0; i<NChips; i++) TriggerCell[Brd*NChips+i] = (int) S.TriggerCell[i];
920
921 // Write channel data (12 bit signed twis complement with out-of-range-bit and leading zeroes)
922 int Count = 0;
923 memset(Data, 0, Boards.size()*NChips*NChannels*NBins*sizeof(short));
924
925 Boards[Brd]->Lock();
926 for (unsigned int Chip=0; Chip<NChips; Chip++) for (unsigned int Chan=0; Chan<NChannels; Chan++) {
927 for (int i=0; i<S.ROI[Chip][Chan]; i++) {
928 if (Boards[Brd]->ACalibTime == -1) Data[Count++] = Boards[Brd]->Data[Chip][Chan][i];
929 else {
930 Temp = (Boards[Brd]->Data[Chip][Chan][i] - Boards[Brd]->Baseline[Chip][Chan][(i+S.TriggerCell[Chip])%NBins]);
931 Temp *= Boards[Brd]->Gain[Chip][Chan][0]/Boards[Brd]->Gain[Chip][Chan][(i+S.TriggerCell[Chip])%NBins];
932 //Temp -= Boards[Brd]->SecondaryBaseline[Chip][Chan][i];
933 Data[Count++] = (short) Temp;
934 }
935 }
936 Count += NBins - S.ROI[Chip][Chan];
937 }
938
939 // Inform TCP/IP thread that data has been processed
940 Boards[Brd]->Continue = true;
941 Boards[Brd]->Unlock();
942
943 if ((Ret = pthread_cond_signal(&Boards[Brd]->CondVar)) != 0) {
944 Message(FATAL, "pthread_cond_signal() failed (%s)", strerror(Ret));
945 }
946 } // Loop over boards
947
948 // Check if DIM service should be updated
949 if ((Time.tv_sec-LastUpdate.tv_sec)*1e6 + Time.tv_usec-LastUpdate.tv_usec > EventUpdateDelay*1e6) {
950 gettimeofday(&LastUpdate, NULL);
951 EventService->updateService(EventData, EventSize);
952 }
953
954 // ===== Data writing ===
955
956 if (Mode != datarun) continue;
957
958 // Check if all event numbers are the same
959 bool Same = true;
960 for (unsigned int i=0; i<Boards.size(); i++) {
961 if (Boards[i]->Active && EventNumbers[i] != EventNumbers[0]) Same = false;
962 }
963 if (!Same) continue;
964
965 // Write also run header if this is the first event
966 int Offset;
967 if (NumEvents == 0) {
968 RHeader->MagicNum = MAGICNUM_OPEN;
969 RunStart = Time;
970 Offset = 0;
971 FileSize = 0;
972 }
973 else Offset = sizeof(RunHeader) + Boards.size()*sizeof(BoardStructure);
974
975 // Write data to file
976 if(write(Datafile, EventData+Offset, EventSize-Offset) != (ssize_t) EventSize-Offset) {
977 PrintMessage("Error: Could not write all data to file, terminating run (%s)\n", strerror(errno));
978
979 // Close file if error
980 if (close(Datafile) == -1) PrintMessage("Error: Could not close data file (%s)\n", strerror(errno));
981 Datafile = -1;
982 Mode = idle;
983 continue;
984 }
985
986 NumEvents++;
987 FileSize += EventSize-Offset;
988 }
989
990 // Clean up
991 delete[] BStruct;
992 delete EventService;
993 delete[] EventData;
994}
995
996// Launch event thread inside class
997void FAD::LaunchEventThread(class FAD *m) {
998
999 m->EventThread();
1000}
1001
1002
1003/*
1004// Set DOMINO mode
1005void FAD::SetDOMINOMode(int mode) {
1006
1007 for (int i=FirstBoard; i<=LastBoard; i++) {
1008 GetBoard(i)->SetDominoMode(mode==1 ? 1:0);
1009 PrintMessage("Domino mode of board %d switched to %s.\n",i,mode==1 ? "continuous":"single shot");
1010 }
1011}
1012
1013// Set DOMINO readout mode
1014void FAD::SetDOMINOReadMode(int mode) {
1015
1016 for (int i=FirstBoard; i<=LastBoard; i++) {
1017 GetBoard(i)->SetReadoutMode(mode);
1018 PrintMessage("Start readout of board %d from %s.\n",i,mode==0 ? "first bin":"stop position");
1019 }
1020}
1021
1022// Set DOMINO wave mode
1023void FAD::SetDOMINOWaveMode(int mode) {
1024
1025 for (int i=FirstBoard; i<=LastBoard; i++) {
1026 GetBoard(i)->SetDominoActive(mode);
1027 PrintMessage("Domino wave of board %d is %s during readout\n",i,mode==1 ? "running":"stopped");
1028 }
1029}
1030
1031*/
1032
1033
1034//
1035// Print usage text for command
1036//
1037void FAD::PrintUsage() {
1038
1039 for(unsigned int i=0; i<sizeof(CommandList)/sizeof(CL_Struct); i++) {
1040 if (Match(Parameter[0], CommandList[i].Name)) {
1041 PrintMessage("Usage: %s %s\n", CommandList[i].Name, CommandList[i].Parameters);
1042 }
1043 }
1044}
1045
1046//
1047// Print message to console
1048//
1049void FAD::PrintMessage(const char *Format, ...) {
1050
1051 static char Error[] = "vasprintf() failed in PrintMessage()";
1052 char *Text;
1053
1054 // Evaluate arguments
1055 va_list ArgumentPointer;
1056 va_start(ArgumentPointer, Format);
1057 if (vasprintf(&Text, Format, ArgumentPointer) == -1) Text = Error;
1058 va_end(ArgumentPointer);
1059
1060 // Print to console
1061 printf("%s", Text);
1062 fflush(stdout);
1063 if (strlen(Text)>0 && Text[strlen(Text)-1]=='\n') rl_on_new_line(); // New prompt
1064
1065 // Send to DIM text service
1066 ConsoleOut->updateService(Text);
1067
1068 // Free old text
1069 if (ConsoleText != Error) free(ConsoleText);
1070 ConsoleText = Text;
1071}
1072
1073//
1074// Check if two strings match (min 1 character must match)
1075//
1076bool FAD::Match(string str, const char *cmd) {
1077
1078 return strncasecmp(str.c_str(),cmd,strlen(str.c_str())==0 ? 1:strlen(str.c_str())) ? false:true;
1079}
1080
1081//
1082// Conversion function from string to double, int or range
1083//
1084// Return false if conversion did not stop on whitespace or EOL character
1085bool FAD::ConvertToDouble(string String, double *Result) {
1086
1087 char *EndPointer;
1088
1089 *Result = strtod(String.c_str(), &EndPointer);
1090 if(!isspace(*EndPointer) && *EndPointer!='\0') return false;
1091 return true;
1092}
1093
1094bool FAD::ConvertToInt(string String, int *Result) {
1095
1096 char *EndPointer;
1097
1098 *Result = (int) strtol(String.c_str(), &EndPointer, 0);
1099 if(!isspace(*EndPointer) && *EndPointer!='\0') return false;
1100 return true;
1101}
1102
1103bool FAD::ConvertToRange(string String, struct FAD::Range &R) {
1104
1105 int N, M;
1106
1107 // Full range
1108 if (Match(String, "all")) return true;
1109
1110 // Single number
1111 if (ConvertToInt(String, &N)) {
1112 if (N>= R.Min && N<=R.Max) {
1113 R.Max = R.Min = N;
1114 return true;
1115 }
1116 return false;
1117 }
1118
1119 // Range a-b
1120 vector<string> V = EvidenceServer::Tokenize(String, "-");
1121 if (V.size()==2 && ConvertToInt(V[0], &N) && ConvertToInt(V[1], &M) && N>=R.Min && M<=R.Max) {
1122 R.Min = N;
1123 R.Max = M;
1124 return true;
1125 }
1126
1127 return false;
1128}
Note: See TracBrowser for help on using the repository browser.