source: fact/FADctrl/FAD.cc@ 10077

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