source: fact/FADctrl/FAD.cc@ 10107

Last change on this file since 10107 was 10103, checked in by neise, 14 years ago
supports trigger disable & enable. enables during init.
File size: 32.1 KB
Line 
1/********************************************************************\
2
3 FAD.cc
4
5 Main class of FADCtrl
6
7
8 Comment 19/10/2010: It is assumed that boolean access is an atomic operation.
9
10\********************************************************************/
11
12#include "FAD.h"
13using namespace std;
14
15static const struct CL_Struct { const char *Name;
16 void (FAD::*CommandPointer)();
17 bool NeedIdle;
18 unsigned int MinNumParameter;
19 const char *Parameters;
20 const char *Help;
21 } CommandList[] =
22 {{"board", &FAD::cmd_board, true, 1, "[+|-]<range>" ,"Activate or deactivate boards"},
23 {"status", &FAD::cmd_status, false, 0, "[range]", "Show board status information"},
24 {"domino", &FAD::cmd_domino, true, 1, "<on|off>", "Switch Domino wave"},
25 {"dwrite", &FAD::cmd_dwrite, true, 1, "<on|off>", "Set DWRITE"},
26 {"phase", &FAD::cmd_phase, true, 1, "<phase>", "Adjust ADC phase (in 'steps')"},
27 {"srclk", &FAD::cmd_srclk, true, 1, "<on|off>", "Set SRCLK"},
28 {"sclk", &FAD::cmd_sclk, true, 1, "<on|off>", "Set SCLK"},
29 {"trigger", &FAD::cmd_trigger, false, 0, "[n|cont|stop|enable|disable]", "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>", "Send arbitrary data to board"},
34 {"acalib", &FAD::cmd_acalib, true, 0, "[n|invalidate|file]", "Perform or read 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 // Construct boards
65 BoardList = Tokenize(GetConfig("BoardList","129.217.160.119"));
66 BoardList = Tokenize("192.33.99.225");
67
68 for (unsigned int i=0; i<BoardList.size(); i++) {
69 Boards.push_back(new class FADBoard(BoardList[i], 5000, this, i));
70
71 // Check if initialised OK
72 if (!Boards.back()->InitOK) {
73 Message(WARN, "Failed to initialize board %s\n", BoardList[i].c_str());
74 delete Boards.back();
75 Boards.pop_back();
76 }
77 }
78
79 // Create DIM event service thread
80 int Ret;
81 if ((Ret = pthread_create(&Thread, NULL, (void * (*)(void *)) LaunchEventThread,(void *) this)) != 0) {
82 Message(ERROR, "pthread_create() failed in FAD::FAD() (%s)", strerror(Ret));
83 Thread = pthread_self();
84 }
85
86 // Install DIM command (after all initialized)
87 Command = new DimCommand((char *) SERVER_NAME"/Command", (char *) "C", this);
88}
89
90//
91// Destructor
92//
93FAD::~FAD() {
94
95 int Ret;
96
97 // Wait for DIM service thread to quit
98 if (pthread_equal(Thread, pthread_self()) == 0) {
99 if ((Ret = pthread_join(Thread, NULL)) != 0) Message(ERROR, "pthread_join() failed in ~FAD() (%s)", strerror(Ret));
100 }
101
102 // Delete all boards (cancels threads automatically)
103 for (unsigned int i=0; i<Boards.size(); i++) delete Boards[i];
104
105 delete Command;
106 delete ConsoleOut;
107 free(ConsoleText);
108}
109
110// ------------------------------
111// ***** Command handling *****
112// ------------------------------
113
114//
115// DIM command handler
116// Handler must be non-blocking, otherwise a DIM rpc would dead-lock.
117//
118void FAD::commandHandler() {
119
120 char *Command = getCommand()->getString();
121
122 // Ignore empty or illegal strings
123 if (getCommand()->getSize() == 0 || *(Command+getCommand()->getSize()-1) != '\0' ||
124 strlen(Command) == 0) return;
125
126 // Shell command
127 if (Command[0]=='.') {
128 system(&(Command[1]));
129 return;
130 }
131
132 // Parse command into tokens
133 Parameter.clear();
134 char *Start;
135 while(true) {
136 while (isspace(*Command)) Command++; // Ignore initial white spaces
137 if(*Command=='\0') break;
138 if (*Command == '\"') {
139 Start = ++Command;
140 while(*Command!='\"' && *Command!='\0') Command++;
141 }
142 else {
143 Start = Command;
144 while(!isspace(*Command) && *Command!='\0') Command++;
145 }
146 if(*Command != '\0') *Command++ = '\0';
147 Parameter.push_back(Start);
148 }
149
150 // Search for command in command list
151 for(unsigned int i=0; i<sizeof(CommandList)/sizeof(CL_Struct); i++) {
152 if (Match(Parameter[0], CommandList[i].Name)) {
153 // Check if number of parameters
154 if(Parameter.size()-1 < CommandList[i].MinNumParameter) {
155 PrintMessage("Usage: %s %s\n", CommandList[i].Name, CommandList[i].Parameters);
156 return;
157 }
158 // Check if idle mode required
159 if (CommandList[i].NeedIdle && Mode != idle) {
160 PrintMessage("Current mode is not idle ('cancel' will stop current operation)\n");
161 return;
162 }
163 // Jump to command function
164 (this->*CommandList[i].CommandPointer)();
165 return;
166 }
167 }
168
169 PrintMessage("Unknown command '%s'\n", Parameter[0].c_str());
170}
171
172//
173// Switch SRCLK
174//
175void FAD::cmd_srclk() {
176
177 for (unsigned int i=0; i<Boards.size(); i++) {
178 if (Match(Parameter[1],"on")) Boards[i]->Send(CMD_SRCLK_ON);
179 else if (Match(Parameter[1],"off")) Boards[i]->Send(CMD_SRCLK_OFF);
180 }
181
182 if (Match(Parameter[1],"on")) PrintMessage("SRCLK switched on for all active boards\n");
183 else if (Match(Parameter[1],"off")) PrintMessage("SRCLK switched off for all active boards\n");
184 else PrintUsage();
185}
186
187//
188// Switch which sockets are used to send data away
189// case parameter is: "com" - command mode is enabled.
190// thus only socket 0 is used
191// case parameter is: "daq" - daq mode is enabled
192// thus only sockets 1 - 7 are used.
193//
194// note: socket 0 is always used to issue commands
195//
196void FAD::cmd_socketmode() {
197
198 for (unsigned int i=0; i<Boards.size(); i++) {
199 if (Match(Parameter[1],"com")) Boards[i]->Send(CMD_Stop);
200 else if (Match(Parameter[1],"daq")) Boards[i]->Send(CMD_Start);
201 }
202
203 if (Match(Parameter[1],"com")) PrintMessage("all active boards switched to command mode - socket 0\n");
204 else if (Match(Parameter[1],"daq")) PrintMessage("all active boards switched to DAQ mode - socket 1..7\n");
205 else PrintUsage();
206}
207
208//
209// Switch SCLK
210//
211void FAD::cmd_sclk() {
212
213 for (unsigned int i=0; i<Boards.size(); i++) {
214 if (Match(Parameter[1],"on")) Boards[i]->Send(CMD_SCLK_ON);
215 else if (Match(Parameter[1],"off")) Boards[i]->Send(CMD_SCLK_OFF);
216 }
217
218 if (Match(Parameter[1],"on")) PrintMessage("SCLK switched on for all active boards\n");
219 else if (Match(Parameter[1],"off")) PrintMessage("SCLK switched off for all active boards\n");
220 else PrintUsage();
221}
222
223//
224// Switch Domino wave
225//
226void FAD::cmd_domino() {
227
228 for (unsigned int i=0; i<Boards.size(); i++) {
229 if (Match(Parameter[1],"on")) Boards[i]->Send(CMD_DENABLE);
230 else if (Match(Parameter[1],"off")) Boards[i]->Send(CMD_DDISABLE);
231 }
232
233 if (Match(Parameter[1],"on")) PrintMessage("Domino wave switched on for all active boards\n");
234 else if (Match(Parameter[1],"off")) PrintMessage("Domino wave switched off for all active boards\n");
235 else PrintUsage();
236}
237
238//
239// Switch DWRITE
240//
241void FAD::cmd_dwrite() {
242
243 for (unsigned int i=0; i<Boards.size(); i++) {
244 if (Match(Parameter[1],"on")) Boards[i]->Send(CMD_DWRITE_RUN);
245 else if (Match(Parameter[1],"off")) Boards[i]->Send(CMD_DWRITE_STOP);
246 }
247
248 if (Match(Parameter[1],"on")) PrintMessage("DWRITE set high for all active boards\n");
249 else if (Match(Parameter[1],"off")) PrintMessage("DWRITE set low for all active boards\n");
250 else PrintUsage();
251}
252
253//
254// Issue soft trigger
255//
256void FAD::cmd_trigger() {
257
258 int Num;
259
260 for (unsigned int i=0; i<Boards.size(); i++) {
261 if (Parameter.size() == 1) Boards[i]->Send(CMD_Trigger);
262 else if (ConvertToInt(Parameter[1], &Num)) {
263 for (int j=0; j<Num; j++) {
264 Boards[i]->Send(CMD_Trigger);
265 usleep(10000);
266 }
267 }
268 else if (Match(Parameter[1],"continuous")) Boards[i]->Send(CMD_Trigger_C);
269 else if (Match(Parameter[1],"stop")) Boards[i]->Send(CMD_Trigger_S);
270 else if (Match(Parameter[1],"enable")) Boards[i]->Send(CMD_TRIGGERS_ON);
271 else if (Match(Parameter[1],"disable")) Boards[i]->Send(CMD_TRIGGERS_OFF);
272 else {
273 PrintUsage();
274 break;
275 }
276 }
277 if (Match(Parameter[1],"enable")) PrintMessage("all active boards accept now incoming triggers\n");
278 else if (Match(Parameter[1],"disable")) PrintMessage("no active board accepts any incoming trigger anymore.\n");
279 // else PrintUsage();
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, Count;
452 FILE *File;
453 vector<string> Items;
454
455 // Invalidate calibration?
456 if (Parameter.size() == 2 && Match(Parameter[1], "invalidate")) {
457 for (unsigned int i=0; i<Boards.size(); i++) Boards[i]->ACalibTime = -1;
458 return;
459 }
460
461 // Read calibration data from file?
462 if (Parameter.size() == 2 && !ConvertToInt(Parameter[1], &NumCalibEvents)) {
463 // Open file
464 if ((File = fopen(Parameter[1].c_str(), "r")) == NULL) {
465 PrintMessage("Error opening file '%s'\n", Parameter[1].c_str());
466 return;
467 }
468 PrintMessage("Reading amplitude calibration information from file '%s'\n", Parameter[1].c_str());
469
470 // Read file into buffer and close file
471 string Buffer;
472 while (feof(File)==0 && ferror(File)==0) Buffer.push_back((char) fgetc(File));
473 if (Buffer.size() > 0) Buffer = Buffer.substr(0, Buffer.size()-1);
474 if (fclose(File) != 0) PrintMessage("Could not close file '%s'\n", Parameter[1].c_str());
475
476 // Search for calibration data for boards
477 vector<string> Result = Tokenize(Buffer, "\n");
478
479 for (unsigned int Brd=0; Brd<Boards.size(); Brd++) {
480 for (unsigned int Line=0; Line<Result.size(); Line++) {
481 if (Result[Line].find(Boards[Brd]->Name) == string::npos) continue;
482
483 PrintMessage("Found calibration data for board '%s'\n", Boards[Brd]->Name);
484 Items = Tokenize(Result[Line]);
485
486 // Check if correct number of items
487 if (Items.size() != NChips*NChannels*NBins*2 + 3) {
488 PrintMessage("Error, data format invalid\n", Parameter[1].c_str());
489 return;
490 }
491
492 // Extract data
493 Boards[Brd]->ACalibTemp = atof(Items[1].c_str());
494 Boards[Brd]->ACalibTime = atoi(Items[2].c_str());
495
496 Count = 3;
497 for (unsigned int i=0; i<NChips; i++) {
498 for (unsigned int j=0; j<NChannels; j++) {
499 for (unsigned int k=0; k<NBins; k++) {
500 Boards[Brd]->Baseline[i][j][k] = atoi(Items[Count++].c_str());
501 Boards[Brd]->Gain[i][j][k] = atof(Items[Count++].c_str());
502 }
503 }
504 }
505 }
506 } // Loop over boards
507
508 return;
509 } // Reading calibration from file
510
511 // Set number of events required for calibration
512 if (Parameter.size()==1 || !ConvertToInt(Parameter[1], &NumCalibEvents) || NumCalibEvents<=0) {
513 NumCalibEvents = DEFAULT_NUM_CALIB_EVENTS;
514 }
515
516 // Set mode before launching thread
517 Mode = acalib;
518 Cancel = false;
519
520 // Create detached thread
521 if ((Code = pthread_create(&Thread, NULL, (void * (*)(void *)) FAD::LaunchAmplitudeCalibration,(void *) this)) != 0) {
522 Message(ERROR, "pthread_create() failed in FAD::cmd_acalib() (%s)\n", strerror(Code));
523 Mode = idle;
524 return;
525 }
526
527 if ((Code = pthread_detach(Thread)) != 0) {
528 Message(ERROR, "pthread_detach() failed in FAD::cmd_acalib() (%s)\n", strerror(Code));
529 }
530}
531
532
533//
534// Print status
535//
536void FAD::cmd_status() {
537
538 // ==== Print board overview ====
539 if (Parameter.size() == 1) {
540
541 // Count active board
542 unsigned int Count = 0, Error = 0;
543 for (unsigned int i=0; i<Boards.size(); i++) {
544 if (Boards[i]->Active) Count++;
545 if (Boards[i]->CommError) Error++;
546 }
547
548 PrintMessage(" Number of FAD boards: %d Boards with communication error: %d Active boards: ", Boards.size(), Error);
549
550 // Print list of active boards
551 if (Count == 0) PrintMessage("none\n");
552 else if (Count == Boards.size()) PrintMessage("all\n");
553 else for (unsigned int i=0; i<Boards.size(); i++) {
554 if (Boards[i]->Active) PrintMessage(" %d", i);
555 }
556 return;
557 }
558
559 // ==== Print details for given range ====
560 struct Range R = {0, Boards.size()};
561
562 if (!ConvertToRange(Parameter[1], R)) {
563 PrintMessage("Error, out of range.\n");
564 return;
565 }
566
567 for (int i=0; i<(int) Boards.size(); i++) {
568 if (i<R.Min || i > R.Max) continue;
569
570 struct FADBoard::BoardStatus S = Boards[i]->GetStatus();
571
572 PrintMessage("Board #%d - %s (%sactive) Communication %s\n", i, Boards[i]->Name, Boards[i]->Active ? "":"in", Boards[i]->CommError ? "ERROR":"OK");
573 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] );
574 PrintMessage("Temperature %.2f %.2f %.2f %.2f", S.Temp[0], S.Temp[1], S.Temp[2], S.Temp[3]);
575
576 for (unsigned int i=0; i<NChips*NChannels; i++) {
577 if (i%NChannels == 0) PrintMessage("\nROI %2d-%2d: ", i, i+NChannels-1);
578 PrintMessage("%4d ", S.ROI[i/NChannels][i%NChannels]);
579 }
580 PrintMessage("\n");
581
582 /*PrintMessage("Serial %d, firmware %d\n"
583 " Actual temperature: %1.1lf C\n"
584 " Calibration temp.: %1.1lf C\n"
585 GetBoard(i)->GetBoardSerialNumber(),
586 GetBoard(i)->GetFirmwareVersion(),
587 GetBoard(i)->GetTemperature(),
588 ACalibTemp[i]);
589
590
591 if (GetBoard(i)->GetStatusReg() & BIT_RUNNING)
592 PrintMessage(" Domino wave running\n");
593
594 if (GetBoard(i)->GetCtrlReg() & BIT_DMODE)
595 PrintMessage(" DMODE circular\n");
596 else
597 PrintMessage(" DMODE single shot\n");
598 if (GetBoard(i)->GetCtrlReg() & BIT_ACAL_EN)
599 PrintMessage(" ACAL enabled\n");
600 PrintMessage(" Trigger bus: 0x%08X\n", GetBoard(i)->GetTriggerBus());
601 else PrintMessage(" Domino wave stopped\n");
602 }
603 }*/
604 } // for()
605}
606
607
608//
609// Adress FAD boards
610//
611void FAD::cmd_board() {
612
613 struct Range R = {0, Boards.size()};
614 int Mode = 0;
615
616 // Check if given boards should be enabled or disabled
617 if (Parameter[1].size() >= 1) {
618 if (Parameter[1][0] == '+') Mode = 1;
619 if (Parameter[1][0] == '-') Mode = -1;
620 }
621 if (Mode != 0) Parameter[1][0] = ' ';
622
623 // Evaluate given range
624 if (!ConvertToRange(Parameter[1], R)) {
625 PrintMessage("Error, out of range.\n");
626 return;
627 }
628
629 // Enable or disable boards
630 for (int i=0; i<(int) Boards.size(); i++) {
631 if (Mode == 0) Boards[i]->Active = false;
632 if (i >= R.Min && i <= R.Max) {
633 if (Mode != -1) Boards[i]->Active = true;
634 else Boards[i]->Active = false;
635 }
636 }
637}
638
639//
640// Set DIM event update delay
641//
642void FAD::cmd_update() {
643
644 double Delay;
645
646 if (Parameter.size()==2 && ConvertToDouble(Parameter[1], &Delay) && Delay>0) EventUpdateDelay = Delay;
647 else PrintUsage();
648}
649
650//
651// Print help
652//
653void FAD::cmd_help() {
654
655 char *Buffer;
656
657 for(unsigned int i=0; i<sizeof(CommandList)/sizeof(CL_Struct); i++) {
658 if (asprintf(&Buffer, "%s %s", CommandList[i].Name, CommandList[i].Parameters) == -1) {
659 PrintMessage("Error printing help, asprintf() failed\n");
660 break;
661 }
662 else PrintMessage("%-28s%s\n", Buffer, CommandList[i].Help);
663 free(Buffer);
664 }
665 PrintMessage(".<command> Execute shell command\n\n"
666 "Items in <> are mandatory, in [] optional, | indicates mutual exclusive.\n"
667 "Strings containing spaces have to be enclosed in \"double quotes\".\n"
668 "Ranges can be given as 'all', a single number or in the form 'a-b'.\n");
669}
670
671//
672// Cancel current operation
673//
674void FAD::cmd_cancel() {
675
676 if (Mode == idle) PrintMessage("Nothing to cancel\n");
677 else {
678 PrintMessage("Requested cancelation of current operation\n");
679 Cancel = true;
680 }
681}
682
683//
684// Exit programm
685// SIGTERM sets ExitRequest flag, and also makes readline() return (if command from DimCommand thread)
686//
687void FAD::cmd_exit() {
688
689 pthread_kill(MainThread, SIGTERM);
690}
691
692
693// -----------------------------
694// ***** Other functions *****
695// -----------------------------
696
697//
698// Amplitude calibration (lauched as thread by cmd_acalib())
699//
700void FAD::AmplitudeCalibration() {
701
702 vector<struct FADBoard::BoardStatus> Status;
703 vector<unsigned short> ROICmd;
704 unsigned short DACCmd[] = {htons(CMD_Write | (BADDR_DAC + 1)), 0, htons(CMD_Write | (BADDR_DAC + 2)), 0, htons(CMD_Write | (BADDR_DAC + 3)), 0};
705
706 /* Procedure
707
708 5. Issue single trigger and verify settings
709 ...
710 11. Secondary calibration
711*/
712
713 PrintMessage("Staring amplitude calibration of all active boards (%d events)\n"
714 " Note: No input signals must be connected\n", NumCalibEvents);
715
716 // Prepare command to set all ROIs to 1024
717 for (unsigned int i=0; i<NChips*NChannels; i++) {
718 ROICmd.push_back(htons(CMD_Write | (BADDR_ROI + i)));
719 ROICmd.push_back(htons(NBins));
720 }
721
722 // Initialise settings for calibration
723 for (unsigned int Brd=0; Brd<Boards.size(); Brd++) {
724
725 // Invalidate current calibration
726 Boards[Brd]->ACalibTime = -1;
727
728 // Save initial board status
729 Status.push_back(Boards[Brd]->GetStatus());
730
731 // Disarm first, in order to change ROI & DAC settings
732 //Boards[Brd]->Send(CMD_TRIGGERS_OFF);
733
734 // Set all ROI to 1024
735 Boards[Brd]->Send(&ROICmd[0], ROICmd.size()*sizeof(unsigned short));
736
737 // Set first DAC value
738 DACCmd[1] = htons(0);
739 DACCmd[3] = htons(0);
740 DACCmd[5] = htons(0);
741 Boards[Brd]->Send(DACCmd, sizeof(DACCmd));
742
743 // Switch off SCLK
744 //Boards[Brd]->Send(CMD_SCLK_OFF);
745
746 // Arm again, in order to take data
747 //Boards[Brd]->Send(CMD_TRIGGERS_ON);
748
749
750 // Start accumulation
751 Boards[Brd]->AccumulateSum(NumCalibEvents);
752 }
753
754 // Wait until data for all boards taken
755 bool Done = false;
756 while (!Done && !Cancel) {
757 usleep(300000);
758 for (unsigned int Brd=0; Brd<Boards.size(); Brd++) {
759 Done = true;
760 if (Boards[Brd]->Active && Boards[Brd]->DoSum) Done = false;
761 }
762 }
763
764 for (unsigned int Brd=0; Brd<Boards.size(); Brd++) {
765 // Determine baseline
766 for (unsigned int i=0; i<NChips; i++) for (unsigned int j=0; j<NChannels; j++) {
767 for (unsigned int k=0; k<NBins; k++) {
768 Boards[Brd]->Baseline[i][j][k] = Boards[Brd]->Sum[i][j][k] / NumCalibEvents;
769 }
770 }
771
772 // Switch on SCLK
773 Boards[Brd]->Send(CMD_SCLK_ON);
774
775 // Disarm first, in order to change ROI & DAC settings
776 //Boards[Brd]->Send(CMD_TRIGGERS_OFF);
777
778 // Set second DAC value
779 DACCmd[1] = htons(50000);
780 DACCmd[3] = htons(50000);
781 DACCmd[5] = htons(50000);
782 Boards[Brd]->Send(DACCmd, sizeof(DACCmd));
783
784 // Switch off SCLK
785 //Boards[Brd]->Send(CMD_SCLK_OFF);
786
787 // Arm again
788 //Boards[Brd]->Send(CMD_TRIGGERS_ON);
789
790 // Start accumulation
791 Boards[Brd]->AccumulateSum(NumCalibEvents);
792 }
793
794 // Wait until data for all boards taken
795 Done = false;
796 while (!Done && !Cancel) {
797 usleep(300000);
798 for (unsigned int Brd=0; Brd<Boards.size(); Brd++) {
799 Done = true;
800 if (Boards[Brd]->Active && Boards[Brd]->DoSum) Done = false;
801 }
802 }
803
804 // Stop triggering, write back original ROI and DAC settings
805 for (unsigned int Brd=0; Brd<Boards.size(); Brd++) {
806 // Switch on SCLK
807 Boards[Brd]->Send(CMD_SCLK_ON);
808
809 // Determine gain
810 for (unsigned int i=0; i<NChips; i++) for (unsigned int j=0; j<NChannels; j++) {
811 for (unsigned int k=0; k<NBins; k++) {
812 Boards[Brd]->Gain[i][j][k] = (Boards[Brd]->Sum[i][j][k] / NumCalibEvents)-Boards[Brd]->Baseline[i][j][k];
813 }
814 }
815
816 ROICmd.clear();
817 for (unsigned int i=0; i<NChips*NChannels; i++) {
818 ROICmd.push_back(htons(CMD_Write | (BADDR_ROI + i)));
819 ROICmd.push_back(htons(Status[Brd].ROI[i/NChannels][i%NChannels]));
820 }
821 Boards[Brd]->Send(&ROICmd[0], ROICmd.size()*sizeof(unsigned short));
822
823 DACCmd[1] = htons(Status[Brd].DAC[1]);
824 DACCmd[3] = htons(Status[Brd].DAC[2]);
825 DACCmd[5] = htons(Status[Brd].DAC[3]);
826 Boards[Brd]->Send(DACCmd, sizeof(DACCmd));
827
828 // Store calibration time and temperature
829 Boards[Brd]->ACalibTime = Cancel ? -1 : time(NULL);
830 Boards[Brd]->ACalibTemp = 0;
831 for (unsigned int i=0; i<NTemp; i++) Boards[Brd]->ACalibTemp += Status[Brd].Temp[i] / NTemp;
832 }
833
834 Mode = idle;
835
836 if (Cancel) {
837 PrintMessage("Amplitude calibration cancelled\n");
838 return;
839 }
840
841 PrintMessage("Amplitude calibration of all active boards finished, original ROI and DAC set\n");
842
843 // Write calibration data to file
844 time_t Time = time(NULL);
845 struct tm *TimeInfo;
846 char Buffer[200];
847
848 // Generate filename
849 TimeInfo = localtime(&Time);
850 if (strftime(Buffer, sizeof(Buffer), "/FADcalib_%y-%m-%jT%X.txt", TimeInfo) == 0) {
851 PrintMessage("Could not generate calibration data file name, strftime() failed\n");
852 return;
853 }
854 string Filename = string(getenv("HOME"))+Buffer;
855
856 FILE *File = fopen(Filename.c_str(), "w");
857 if (File == NULL) {
858 PrintMessage("Could not open calibration data file '%s'\n", Filename.c_str());
859 return;
860 }
861
862 // Fix: Should actually contain serial number!
863 for (unsigned int Brd=0; Brd<Boards.size(); Brd++) {
864 fprintf(File, "\n%s: %f %d ", Boards[Brd]->Name, Boards[Brd]->ACalibTemp, (int) Boards[Brd]->ACalibTime);
865 for (unsigned int i=0; i<NChips; i++) {
866 for (unsigned int j=0; j<NChannels; j++) {
867 for (unsigned int k=0; k<NBins; k++) {
868 fprintf(File, "%d %lf ", Boards[Brd]->Baseline[i][j][k], Boards[Brd]->Gain[i][j][k]);
869 }
870 }
871 }
872 }
873
874 // Close file
875 if (fclose(File) != 0) {
876 PrintMessage("Could not close calibration file '%s'\n", Filename.c_str());
877 }
878
879 PrintMessage("Wrote amplitude calibration information to file '%s'\n", Filename.c_str());
880}
881
882// Launch read thread inside class
883void FAD::LaunchAmplitudeCalibration(class FAD *m) {
884
885 m->AmplitudeCalibration();
886}
887
888
889//
890// DIM event service update thread (publishes M0 format)
891//
892void FAD::EventThread() {
893
894 struct timeval Time;
895 struct timeval LastUpdate;
896 bool Update;
897 struct FADBoard::BoardStatus S;
898 double Temp;
899
900 gettimeofday(&LastUpdate, NULL);
901
902 // Create DIM event data service
903 int EventSize = sizeof(RunHeader)+ Boards.size()*sizeof(BoardStructure)+sizeof(EventHeader) + Boards.size()*(NChips*NChannels*NBins*sizeof(short) + NChips*sizeof(int));
904 char *EventData = new char [EventSize];
905 DimService *EventService = new DimService (SERVER_NAME"/EventData", (char *) "C", NULL, 0);
906
907 memset(EventData, 0, EventSize);
908
909 // Calculate pointers to EventData array
910 RunHeader *RHeader = (RunHeader *) EventData;
911 BoardStructure **BStruct = new BoardStructure * [Boards.size()];
912 for (unsigned int i=0; i<Boards.size(); i++) BStruct[i] = ((BoardStructure *) (RHeader + 1)) + i;
913 EventHeader *EHeader = (EventHeader *) ((char *) (RHeader + 1) + Boards.size()*sizeof(BoardStructure));
914 int *TriggerCell = (int *) (EHeader + 1);
915 short *Data = (short *) (TriggerCell + NChips*Boards.size());
916
917 // M0 RunHeader
918 RHeader->MagicNum = 0xE0E0;
919 RHeader->DataFormat = 1;
920 RHeader->RunHeaderSize = sizeof(RunHeader);
921 RHeader->EventHeaderSize = sizeof(EventHeader);
922 RHeader->BoardStructureSize = sizeof(BoardStructure);
923 RHeader->SoftwareRevision = 0xFFFF; // Update
924 RHeader->Identification = 0;
925
926 RHeader->Type = 0; // Run type: 0=data, 1=pedestal, 3=test
927 RHeader->Events = 1;
928
929 RHeader->RunNumber = -1;
930 RHeader->FileNumber = 0;
931 snprintf(RHeader->Description, sizeof(RHeader->Description), "FADctrl_Event");
932
933 RHeader->NBoards = Boards.size();
934 RHeader->NChips = NChips;
935 RHeader->NChannels = NChannels;
936 RHeader->Samples = NBins; // Always full pipeline
937 RHeader->Offset = 0;
938 RHeader->NBytes = 2;
939
940 // M0 EventHeader
941 EHeader->EventSize = Boards.size()*(NChips*NChannels*NBins*sizeof(short) + NChips*sizeof(int));
942
943 // Update loop
944 while (!ExitRequest) {
945 usleep(EventUpdateDelay*1e6);
946
947 // Update run and event header with current time
948 gettimeofday(&Time, NULL);
949 RHeader->StartSecond = Time.tv_sec;
950 RHeader->StartMicrosecond = Time.tv_usec;
951 RHeader->EndSecond = Time.tv_sec;
952 RHeader->EndMicrosecond = Time.tv_usec;
953
954 EHeader->Second = Time.tv_sec;
955 EHeader->Microsecond = Time.tv_usec;
956
957 // Check boards for new data since last update
958 Update = false;
959 for (unsigned int Brd=0; Brd<Boards.size(); Brd++) {
960 S = Boards[Brd]->GetStatus();
961 if (S.Update.tv_sec>LastUpdate.tv_sec || ((S.Update.tv_sec==LastUpdate.tv_sec) && (S.Update.tv_usec>LastUpdate.tv_usec))) {
962
963 Update = true;
964
965 // Fill M0 BoardStructure
966 BStruct[Brd]->SerialNo = S.BoardID;
967 BStruct[Brd]->NomFreq = 2;
968 BStruct[Brd]->BoardTemp = 0;
969 for (unsigned int i=0; i<NTemp; i++) BStruct[Brd]->BoardTemp += S.Temp[i]/NTemp;
970 BStruct[Brd]->ScaleFactor = 1/2.048;
971
972 // Update event header with ID and Type of current board
973 EHeader->EventNumber = S.TriggerID;
974 EHeader->TriggerType = S.TriggerType;
975
976 // Write trigger cells
977 for(unsigned int i=0; i<NChips; i++) TriggerCell[Brd*NChips+i] = (int) S.TriggerCell[i];
978
979 // Write channel data (stored in 12 bit signed twis complement with out-of-range-bit and leading zeroes)
980 int Count = 0;
981 memset(Data, 0, Boards.size()*NChips*NChannels*NBins*sizeof(short));
982
983 Boards[Brd]->Lock();
984 for (unsigned int Chip=0; Chip<NChips; Chip++) for (unsigned int Chan=0; Chan<NChannels; Chan++) {
985 for (int i=0; i<S.ROI[Chip][Chan]; i++) {
986 if (Boards[Brd]->ACalibTime == -1) Data[Count++] = Boards[Brd]->Data[Chip][Chan][i];
987 else {
988 Temp = (Boards[Brd]->Data[Chip][Chan][i] - Boards[Brd]->Baseline[Chip][Chan][(i+S.TriggerCell[Chip])%NBins]);
989 Temp *= Boards[Brd]->Gain[Chip][Chan][0]/Boards[Brd]->Gain[Chip][Chan][(i+S.TriggerCell[Chip])%NBins];
990 Data[Count++] = (short) Temp;
991 }
992 }
993 Count += NBins - S.ROI[Chip][Chan];
994 }
995 Boards[Brd]->Unlock();
996 }
997 }
998
999 if (Update) {
1000 gettimeofday(&LastUpdate, NULL);
1001 EventService->updateService(EventData, EventSize);
1002 }
1003 }
1004
1005 // Clean up
1006 delete[] BStruct;
1007 delete EventService;
1008 delete[] EventData;
1009}
1010
1011// Launch event thread inside class
1012void FAD::LaunchEventThread(class FAD *m) {
1013
1014 m->EventThread();
1015}
1016
1017
1018/*
1019// Set DOMINO mode
1020void FAD::SetDOMINOMode(int mode) {
1021
1022 for (int i=FirstBoard; i<=LastBoard; i++) {
1023 GetBoard(i)->SetDominoMode(mode==1 ? 1:0);
1024 PrintMessage("Domino mode of board %d switched to %s.\n",i,mode==1 ? "continuous":"single shot");
1025 }
1026}
1027
1028// Set DOMINO readout mode
1029void FAD::SetDOMINOReadMode(int mode) {
1030
1031 for (int i=FirstBoard; i<=LastBoard; i++) {
1032 GetBoard(i)->SetReadoutMode(mode);
1033 PrintMessage("Start readout of board %d from %s.\n",i,mode==0 ? "first bin":"stop position");
1034 }
1035}
1036
1037// Set DOMINO wave mode
1038void FAD::SetDOMINOWaveMode(int mode) {
1039
1040 for (int i=FirstBoard; i<=LastBoard; i++) {
1041 GetBoard(i)->SetDominoActive(mode);
1042 PrintMessage("Domino wave of board %d is %s during readout\n",i,mode==1 ? "running":"stopped");
1043 }
1044}
1045
1046*/
1047
1048
1049//
1050// Print usage text for command
1051//
1052void FAD::PrintUsage() {
1053
1054 for(unsigned int i=0; i<sizeof(CommandList)/sizeof(CL_Struct); i++) {
1055 if (Match(Parameter[0], CommandList[i].Name)) {
1056 PrintMessage("Usage: %s %s\n", CommandList[i].Name, CommandList[i].Parameters);
1057 }
1058 }
1059}
1060
1061//
1062// Print message to console
1063//
1064void FAD::PrintMessage(const char *Format, ...) {
1065
1066 static char Error[] = "vasprintf() failed in PrintMessage()";
1067 char *Text;
1068
1069 // Evaluate arguments
1070 va_list ArgumentPointer;
1071 va_start(ArgumentPointer, Format);
1072 if (vasprintf(&Text, Format, ArgumentPointer) == -1) Text = Error;
1073 va_end(ArgumentPointer);
1074
1075 // Print to console
1076 printf("%s", Text);
1077 fflush(stdout);
1078 if (strlen(Text)>0 && Text[strlen(Text)-1]=='\n') rl_on_new_line(); // New prompt
1079
1080 // Send to DIM text service
1081 ConsoleOut->updateService(Text);
1082
1083 // Free old text
1084 if (ConsoleText != Error) free(ConsoleText);
1085 ConsoleText = Text;
1086}
1087
1088//
1089// Check if two strings match (min 1 character must match)
1090//
1091bool FAD::Match(string str, const char *cmd) {
1092
1093 return strncasecmp(str.c_str(),cmd,strlen(str.c_str())==0 ? 1:strlen(str.c_str())) ? false:true;
1094}
1095
1096//
1097// Conversion function from string to double, int or range
1098//
1099// Return false if conversion did not stop on whitespace or EOL character
1100bool FAD::ConvertToDouble(string String, double *Result) {
1101
1102 char *EndPointer;
1103
1104 *Result = strtod(String.c_str(), &EndPointer);
1105 if(!isspace(*EndPointer) && *EndPointer!='\0') return false;
1106 return true;
1107}
1108
1109bool FAD::ConvertToInt(string String, int *Result) {
1110
1111 char *EndPointer;
1112
1113 *Result = (int) strtol(String.c_str(), &EndPointer, 0);
1114 if(!isspace(*EndPointer) && *EndPointer!='\0') return false;
1115 return true;
1116}
1117
1118bool FAD::ConvertToRange(string String, struct FAD::Range &R) {
1119
1120 int N, M;
1121
1122 // Full range
1123 if (Match(String, "all")) return true;
1124
1125 // Single number
1126 if (ConvertToInt(String, &N)) {
1127 if (N>= R.Min && N<=R.Max) {
1128 R.Max = R.Min = N;
1129 return true;
1130 }
1131 return false;
1132 }
1133
1134 // Range a-b
1135 vector<string> V = EvidenceServer::Tokenize(String, "-");
1136 if (V.size()==2 && ConvertToInt(V[0], &N) && ConvertToInt(V[1], &M) && N>=R.Min && M<=R.Max) {
1137 R.Min = N;
1138 R.Max = M;
1139 return true;
1140 }
1141
1142 return false;
1143}
Note: See TracBrowser for help on using the repository browser.