source: fact/FADctrl/FAD.cc@ 10100

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