source: fact/FADctrl/FAD.cc@ 10083

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