source: fact/FADctrl/FAD.cc@ 10102

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