source: fact/FADctrl/FAD.cc@ 10097

Last change on this file since 10097 was 10097, checked in by neise, 13 years ago
switching SCLK ON and OFF during acalib-process
File size: 30.4 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 // Switch off SCLK
688 Boards[Brd]->Send(CMD_SCLK_OFF);
689
690 // Start accumulation
691 Boards[Brd]->AccumulateSum(NumCalibEvents);
692 //Boards[Brd]->Send(CMD_Trigger_C);
693 }
694
695 // Wait until data for all boards taken
696 bool Done = false;
697 while (!Done && !Cancel) {
698 usleep(300000);
699 for (unsigned int Brd=0; Brd<Boards.size(); Brd++) {
700 Done = true;
701 if (Boards[Brd]->Active && Boards[Brd]->DoSum) Done = false;
702 }
703 }
704 printf("Got first average\n");
705
706 for (unsigned int Brd=0; Brd<Boards.size(); Brd++) {
707 // Determine baseline
708 for (unsigned int i=0; i<NChips; i++) for (unsigned int j=0; j<NChannels; j++) {
709 for (unsigned int k=0; k<NBins; k++) Boards[Brd]->Baseline[i][j][k] = Boards[Brd]->Sum[i][j][k] / NumCalibEvents;
710 }
711 // Switch on SCLK
712 Boards[Brd]->Send(CMD_SCLK_ON);
713
714
715 // Set second DAC value
716 DACCmd[1] = htons(50000);
717 Boards[Brd]->Send(DACCmd, sizeof(DACCmd));
718
719 // Switch off SCLK
720 Boards[Brd]->Send(CMD_SCLK_OFF);
721
722 // Start accumulation
723 Boards[Brd]->AccumulateSum(NumCalibEvents);
724 }
725
726 // Wait until data for all boards taken
727 Done = false;
728 while (!Done && !Cancel) {
729 usleep(300000);
730 for (unsigned int Brd=0; Brd<Boards.size(); Brd++) {
731 Done = true;
732 if (Boards[Brd]->Active && Boards[Brd]->DoSum) Done = false;
733 }
734 }
735
736 // Switch on SCLK
737 Boards[Brd]->Send(CMD_SCLK_ON);
738
739
740 // Stop triggering, write back original ROI and DAC settings
741 for (unsigned int Brd=0; Brd<Boards.size(); Brd++) {
742 //Boards[Brd]->Send(CMD_Trigger_S);
743
744 // Determine gain
745 for (unsigned int i=0; i<NChips; i++) for (unsigned int j=0; j<NChannels; j++) {
746 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;
747 }
748
749 ROICmd.clear();
750 for (unsigned int i=0; i<NChips*NChannels; i++) {
751 ROICmd.push_back(htons(CMD_Write | (BADDR_ROI + i)));
752 ROICmd.push_back(htons(Status[Brd].ROI[i/NChannels][i%NChannels]));
753 }
754 Boards[Brd]->Send(&ROICmd[0], ROICmd.size()*sizeof(unsigned short));
755
756 DACCmd[1] = htons(Status[Brd].DAC[2]);
757 Boards[Brd]->Send(DACCmd, sizeof(DACCmd));
758
759 // Store calibration time and temperature
760 Boards[Brd]->ACalibTime = Cancel ? -1 : time(NULL);
761 Boards[Brd]->ACalibTemp = 0;
762 for (unsigned int i=0; i<NTemp; i++) Boards[Brd]->ACalibTemp += Status[Brd].Temp[i] / NTemp;
763 }
764
765 PrintMessage("Amplitude calibration of all active boards finished, original ROI and DAC set\n");
766 Mode = idle;
767
768 // Write short calibration information
769 /*time_t Time = time(NULL);
770 FILE *InfoFile = fopen(CalibInfoFilename, "w");
771 if (InfoFile != NULL) {
772 fprintf(InfoFile, "# Calibration information as of %s\n", ctime(&Time));
773 for (int i=0; i<GetNumberOfBoards(); i++) {
774 fprintf(InfoFile, "%d %d %.1f %d %.2f\n", GetBoard(i)->GetBoardSerialNumber(), ACalib[i], ACalibTemp[i], TCalib[i], DRSFreq[i]);
775 }
776 fclose(InfoFile);
777 }
778 else PrintMessage("Could not write calibration information to file '%s'\n", CalibInfoFilename);
779*/
780}
781
782// Launch read thread inside class
783void FAD::LaunchAmplitudeCalibration(class FAD *m) {
784
785 m->AmplitudeCalibration();
786}
787
788
789//
790// DIM event service update thread (publishes M0 format)
791//
792void FAD::EventThread() {
793
794 struct timeval Time;
795 struct timeval LastUpdate;
796 bool Update;
797 struct FADBoard::BoardStatus S;
798
799 gettimeofday(&LastUpdate, NULL);
800
801 // Create DIM event data service
802 int EventSize = sizeof(RunHeader)+ Boards.size()*sizeof(BoardStructure)+sizeof(EventHeader) + Boards.size()*(NChips*NChannels*NBins*sizeof(short) + NChips*sizeof(int));
803 char *EventData = new char [EventSize];
804 DimService *EventService = new DimService (SERVER_NAME"/EventData", (char *) "C", NULL, 0);
805
806 memset(EventData, 0, EventSize);
807
808 // Calculate pointers to EventData array
809 RunHeader *RHeader = (RunHeader *) EventData;
810 BoardStructure **BStruct = new BoardStructure * [Boards.size()];
811 for (unsigned int i=0; i<Boards.size(); i++) BStruct[i] = ((BoardStructure *) (RHeader + 1)) + i;
812 EventHeader *EHeader = (EventHeader *) ((char *) (RHeader + 1) + Boards.size()*sizeof(BoardStructure));
813 int *TriggerCell = (int *) (EHeader + 1);
814 short *Data = (short *) (TriggerCell + NChips*Boards.size());
815
816 // M0 RunHeader
817 RHeader->MagicNum = 0xE0E0;
818 RHeader->DataFormat = 1;
819 RHeader->RunHeaderSize = sizeof(RunHeader);
820 RHeader->EventHeaderSize = sizeof(EventHeader);
821 RHeader->BoardStructureSize = sizeof(BoardStructure);
822 RHeader->SoftwareRevision = 0xFFFF; // Update
823 RHeader->Identification = 0;
824
825 RHeader->Type = 0; // Run type: 0=data, 1=pedestal, 3=test
826 RHeader->Events = 1;
827
828 RHeader->RunNumber = -1;
829 RHeader->FileNumber = 0;
830 snprintf(RHeader->Description, sizeof(RHeader->Description), "FADctrl_Event");
831
832 RHeader->NBoards = Boards.size();
833 RHeader->NChips = NChips;
834 RHeader->NChannels = NChannels;
835 RHeader->Samples = NBins; // Always full pipeline
836 RHeader->Offset = 0;
837 RHeader->NBytes = 2;
838
839 // M0 EventHeader
840 EHeader->EventSize = Boards.size()*(NChips*NChannels*NBins*sizeof(short) + NChips*sizeof(int));
841
842 // Update loop
843 while (!ExitRequest) {
844 usleep(EventUpdateDelay);
845
846 // Update run and event header with current time
847 gettimeofday(&Time, NULL);
848 RHeader->StartSecond = Time.tv_sec;
849 RHeader->StartMicrosecond = Time.tv_usec;
850 RHeader->EndSecond = Time.tv_sec;
851 RHeader->EndMicrosecond = Time.tv_usec;
852
853 EHeader->Second = Time.tv_sec;
854 EHeader->Microsecond = Time.tv_usec;
855
856 // Check boards for new data since last update
857 Update = false;
858 for (unsigned int Brd=0; Brd<Boards.size(); Brd++) {
859 S = Boards[Brd]->GetStatus();
860 if (S.Update.tv_sec>LastUpdate.tv_sec || ((S.Update.tv_sec==LastUpdate.tv_sec) && (S.Update.tv_usec>LastUpdate.tv_usec))) {
861
862 Update = true;
863
864 // Fill M0 BoardStructure
865 BStruct[Brd]->SerialNo = S.BoardID;
866 BStruct[Brd]->NomFreq = 2;
867 BStruct[Brd]->BoardTemp = 0;
868 for (unsigned int i=0; i<NTemp; i++) BStruct[Brd]->BoardTemp += S.Temp[i]/NTemp;
869 BStruct[Brd]->ScaleFactor = 1/2.048;
870
871 // Update event header with ID and Type of current board
872 EHeader->EventNumber = S.TriggerID;
873 EHeader->TriggerType = S.TriggerType;
874
875 // Write trigger cells
876 for(unsigned int i=0; i<NChips; i++) TriggerCell[Brd*NChips+i] = (int) S.TriggerCell[i];
877
878 // Write channel data (stored in 12 bit signed twis complement with out-of-range-bit and leading zeroes)
879 int Count = 0;
880 memset(Data, 0, Boards.size()*NChips*NChannels*NBins*sizeof(short));
881
882 Boards[Brd]->Lock();
883 for (unsigned int Chip=0; Chip<NChips; Chip++) for (unsigned int Chan=0; Chan<NChannels; Chan++) {
884 for (int i=0; i<S.ROI[Chip][Chan]; i++) {
885 if (Boards[Brd]->ACalibTime == -1) Data[Count++] = Boards[Brd]->Data[Chip][Chan][i];
886 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];
887 }
888 Count += NBins - S.ROI[Chip][Chan];
889 }
890 Boards[Brd]->Unlock();
891 }
892 }
893
894 if (Update) {
895 gettimeofday(&LastUpdate, NULL);
896 EventService->updateService(EventData, EventSize);
897 }
898 }
899
900 // Clean up
901 delete[] BStruct;
902 delete EventService;
903 delete[] EventData;
904}
905
906// Launch event thread inside class
907void FAD::LaunchEventThread(class FAD *m) {
908
909 m->EventThread();
910}
911
912/*
913// Read calibration data
914bool FAD::ReadCalibration() {
915
916 static char Buffer[MAX_COM_SIZE];
917 int Serial, Calib;
918 float Temp, Freq;
919
920 for (int i=FirstBoard; i<=LastBoard; i++) {
921 if (GetBoard(i)->GetDRSType() == 4) {
922 if (ACalib[i] == false) {
923 // Check calibration info file if EEPROM data on DRS board still valild
924 FILE *CalibInfo = fopen(CalibInfoFilename, "r");
925 if (CalibInfo == NULL) return false;
926 fgets(Buffer, sizeof(Buffer), CalibInfo); // skip first two lines
927 fgets(Buffer, sizeof(Buffer), CalibInfo);
928
929 while (fgets(Buffer, sizeof(Buffer), CalibInfo) != NULL) {
930 if (sscanf(Buffer, "%d %d %f %*d %f", &Serial, &Calib, &Temp, &Freq) != 4) {
931 fclose(CalibInfo);
932 return false;
933 }
934
935 if (Serial==GetBoard(i)->GetBoardSerialNumber() && int(Freq*100)==int(DRSFreq[i]*100) && Calib==1) {
936 ACalib[i] = true;
937 ACalibTemp[i] = Temp;
938 break;
939 }
940 }
941 fclose(CalibInfo);
942 }
943 }
944 else {
945 if (!ACalib[i]) {
946 GetBoard(i)->SetCalibrationDirectory(fCalibDataPath);
947 PrintMessage("Reading response calibration file for board %d from: \"%s\"\n", i, fCalibDataPath);
948 for (int Chip=0; Chip<GetBoard(i)->GetNumberOfChips(); Chip++) {
949 if (GetBoard(i)->GetResponseCalibration()->ReadCalibration(Chip) == false) return false;
950 }
951 ACalib[i] = true;
952 }
953 }
954 if (fabs(ACalibTemp[i]-GetBoard(i)->GetTemperature())>2) PrintMessage("Warning: Large difference to calibration temperature for board %d\n", i);
955 } // Loop over boards
956 return true;
957}
958
959// Set DOMINO mode
960void FAD::SetDOMINOMode(int mode) {
961
962 for (int i=FirstBoard; i<=LastBoard; i++) {
963 GetBoard(i)->SetDominoMode(mode==1 ? 1:0);
964 PrintMessage("Domino mode of board %d switched to %s.\n",i,mode==1 ? "continuous":"single shot");
965 }
966}
967
968// Set DOMINO readout mode
969void FAD::SetDOMINOReadMode(int mode) {
970
971 for (int i=FirstBoard; i<=LastBoard; i++) {
972 GetBoard(i)->SetReadoutMode(mode);
973 PrintMessage("Start readout of board %d from %s.\n",i,mode==0 ? "first bin":"stop position");
974 }
975}
976
977// Set DOMINO wave mode
978void FAD::SetDOMINOWaveMode(int mode) {
979
980 for (int i=FirstBoard; i<=LastBoard; i++) {
981 GetBoard(i)->SetDominoActive(mode);
982 PrintMessage("Domino wave of board %d is %s during readout\n",i,mode==1 ? "running":"stopped");
983 }
984}
985
986*/
987
988
989//
990// Print usage text for command
991//
992void FAD::PrintUsage() {
993
994 for(unsigned int i=0; i<sizeof(CommandList)/sizeof(CL_Struct); i++) {
995 if (Match(Parameter[0], CommandList[i].Name)) {
996 PrintMessage("Usage: %s %s\n", CommandList[i].Name, CommandList[i].Parameters);
997 }
998 }
999}
1000
1001//
1002// Print message to console
1003//
1004void FAD::PrintMessage(const char *Format, ...) {
1005
1006 static char Error[] = "vasprintf() failed in PrintMessage()";
1007 char *Text;
1008
1009 // Evaluate arguments
1010 va_list ArgumentPointer;
1011 va_start(ArgumentPointer, Format);
1012 if (vasprintf(&Text, Format, ArgumentPointer) == -1) Text = Error;
1013 va_end(ArgumentPointer);
1014
1015 // Print to console
1016 printf("%s", Text);
1017 fflush(stdout);
1018 if (strlen(Text)>0 && Text[strlen(Text)-1]=='\n') rl_on_new_line(); // New prompt
1019
1020 // Send to DIM text service
1021 ConsoleOut->updateService(Text);
1022
1023 // Free old text
1024 if (ConsoleText != Error) free(ConsoleText);
1025 ConsoleText = Text;
1026}
1027
1028//
1029// Check if two strings match (min 1 character must match)
1030//
1031bool FAD::Match(string str, const char *cmd) {
1032
1033 return strncasecmp(str.c_str(),cmd,strlen(str.c_str())==0 ? 1:strlen(str.c_str())) ? false:true;
1034}
1035
1036//
1037// Conversion function from string to double, int or range
1038//
1039// Return false if conversion did not stop on whitespace or EOL character
1040bool FAD::ConvertToDouble(string String, double *Result) {
1041
1042 char *EndPointer;
1043
1044 *Result = strtod(String.c_str(), &EndPointer);
1045 if(!isspace(*EndPointer) && *EndPointer!='\0') return false;
1046 return true;
1047}
1048
1049bool FAD::ConvertToInt(string String, int *Result) {
1050
1051 char *EndPointer;
1052
1053 *Result = (int) strtol(String.c_str(), &EndPointer, 0);
1054 if(!isspace(*EndPointer) && *EndPointer!='\0') return false;
1055 return true;
1056}
1057
1058bool FAD::ConvertToRange(string String, struct FAD::Range &R) {
1059
1060 int N, M;
1061
1062 // Full range
1063 if (Match(String, "all")) return true;
1064
1065 // Single number
1066 if (ConvertToInt(String, &N)) {
1067 if (N>= R.Min && N<=R.Max) {
1068 R.Max = R.Min = N;
1069 return true;
1070 }
1071 return false;
1072 }
1073
1074 // Range a-b
1075 vector<string> V = EvidenceServer::Tokenize(String, "-");
1076 if (V.size()==2 && ConvertToInt(V[0], &N) && ConvertToInt(V[1], &M) && N>=R.Min && M<=R.Max) {
1077 R.Min = N;
1078 R.Max = M;
1079 return true;
1080 }
1081
1082 return false;
1083}
Note: See TracBrowser for help on using the repository browser.