source: fact/FADctrl/FAD.cc@ 10080

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