source: fact/FADctrl/FAD.cc@ 10067

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