source: fact/FADctrl/FAD.cc@ 10099

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