source: fact/FADctrl/FAD.cc@ 14260

Last change on this file since 14260 was 14260, checked in by ogrimm, 12 years ago
Default initialisation for FADctrl InitSequence
File size: 37.9 KB
Line 
1/********************************************************************\
2
3 Main class of FADCtrl
4
5 If outputting text with PrintMessage(), a '\r' is used on the console automatically
6 if the given text ends with '\n'.
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|none>" ,"Activate or deactivate board(s)"},
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 [rate]|stop|enable|disable]", "Issue software triggers"},
30 {"drsreset", &FAD::cmd_drsreset, true, 1, "<low|high>", "Set DRS reset line"},
31 {"reset", &FAD::cmd_reset, true, 0, "", "Reset internal trigger counter"},
32 {"runnumber", &FAD::cmd_runnumber, true, 1, "<n>", "Set runnumber"},
33 {"roi", &FAD::cmd_roi, true, 2, "<range> <value>", "Set ROI to for channel range to value"},
34 {"dac", &FAD::cmd_dac, true, 2, "<range> <value>", "Set DAC numbers in range to value"},
35 {"execute", &FAD::cmd_execute, true, 0, "", "confirm FAD configuration settings, e.g. DAC, ROI, run#"},
36 {"address", &FAD::cmd_address, true, 2, "<range> <value>", "Set addresses in range to value"},
37 {"send", &FAD::cmd_send, true, 1, "<value>", "Send arbitrary data to board"},
38 {"take", &FAD::cmd_take, true, 1, "<n> <dir>", "Start run with n events (n=0 -> unlimited)"},
39 {"acalib", &FAD::cmd_acalib, true, 0, "[n|inval|file]", "Perform or read amplitude calibration (n events)"},
40 //{"wmode", &FAD::cmd_wmode, 0, "<run|stop>", "Domino wave running or stopped during read out"},
41 //{"rmode", &FAD::cmd_rmode, 0, "<first|stop>", "Readout start at first bin or stop position (DRS4)"},
42 //{"dmode", &FAD::cmd_dmode, 0, "<single|continuous>", "Domino wave single shot or continuous"},
43 {"stop", &FAD::cmd_stop, false, 0, "", "Stop current operation/run"},
44 {"update", &FAD::cmd_update, false, 1, "<sec>", "Minimum delay between updates to DIM event service"},
45 {"socketmode", &FAD::cmd_socketmode, true, 1, "<com|daq>", "Choose which Sockets are used for data transmission"},
46 {"dynrange", &FAD::cmd_dynrange, true, 0, "", "Determine dynamic range using calibration DAC"},
47 {"exit", &FAD::cmd_exit, false, 0, "", "Exit program"},
48 {"help", &FAD::cmd_help, false, 0, "", "Print help"}};
49
50
51// ------------------------------------
52// ***** Constructor/Destructor *****
53// ------------------------------------
54
55//
56// Constructor
57//
58FAD::FAD(std::vector<std::string> List): EvidenceServer(SERVER_NAME) {
59
60 // Initialization
61 ConsoleText = NULL;
62 MainThread = pthread_self();
63 Mode = idle;
64 Datafile = -1;
65 EventUpdateDelay = atof(GetConfig("EventUpdateDelay", "2").c_str());
66
67 // Create pipe for data exchange
68 if (pipe(Pipe) == -1) Message(FATAL, "pipe() failed in FAD::FAD() (%s)", strerror(errno));
69
70 // DIM console service used in PrintMessage()
71 ConsoleOut = new DimService(SERVER_NAME"/ConsoleOut", (char *) "");
72
73 // Initialise configuration information (later non-blocking access in commandHandler())
74 GetConfig("CalibTempDiffWarn", "0");
75 GetConfig("CalibFreqDiffWarn", "0");
76
77 // Construct boards
78 if (List.empty()) BoardList = Tokenize(GetConfig("BoardList"));
79 else BoardList = List;
80
81 for (unsigned int i=0; i<BoardList.size(); i++) {
82 Boards.push_back(new class FADBoard(BoardList[i], PORT, this, i));
83 }
84
85 // Create DIM event service thread
86 int Ret;
87 if ((Ret = pthread_create(&Thread, NULL, (void * (*)(void *)) LaunchEventThread, (void *) this)) != 0) {
88 Message(FATAL, "pthread_create() failed in FAD::FAD() (%s)", strerror(Ret));
89 }
90
91 // Install DIM command (after all initialized)
92 Command = new DimCommand((char *) SERVER_NAME"/Command", (char *) "C", this);
93
94 // Initialise boards
95 vector<string> Init = Tokenize(GetConfig("InitSequence", "dac 0 28000; trigger enable; domino on;"), ";");
96
97 for (unsigned int i=0; i<Init.size(); i++) {
98 DimClient::sendCommand(SERVER_NAME"/Command", Init[i].c_str());
99 }
100}
101
102//
103// Destructor
104//
105FAD::~FAD() {
106
107 int Ret;
108
109 ExitRequest = true;
110
111 // Stop run if in progress
112 if (Mode != idle) cmd_stop();
113
114 // Close pipe (will make read() on pipe in DIM service thread return)
115 if (close(Pipe[0]) == -1) Message(ERROR, "close() on Pipe[0] failed in FAD::~FAD() (%s)", strerror(errno));
116 if (close(Pipe[1]) == -1) Message(ERROR, "close() on Pipe[1] failed in FAD::~FAD() (%s)", strerror(errno));
117
118 // Wait for DIM service thread to quit
119 if ((Ret = pthread_join(Thread, NULL)) != 0) Message(ERROR, "pthread_join() failed in ~FAD() (%s)", strerror(Ret));
120
121 // Delete all boards (cancels threads automatically)
122 for (unsigned int i=0; i<Boards.size(); i++) delete Boards[i];
123
124 delete Command;
125 delete ConsoleOut;
126 free(ConsoleText);
127}
128
129// ------------------------------
130// ***** Command handling *****
131// ------------------------------
132
133//
134// DIM command handler (non-blocking, otherwise a DIM rpc would dead-lock)
135//
136void FAD::commandHandler() {
137
138 char *Command = getCommand()->getString(), *Start;
139
140 // Ignore empty or illegal strings
141 if (getCommand()->getSize() == 0) return;
142 if( *(Command+getCommand()->getSize()-1) != '\0' || strlen(Command) == 0) return;
143
144 // Shell command
145 if (*Command == '.') {
146 if (system(Command+1) == -1) PrintMessage("Error with system() call\n");
147 return;
148 }
149
150 // Parse command into tokens
151 Parameter.clear();
152 while(true) {
153 while (isspace(*Command)) Command++; // Ignore initial white spaces
154 if(*Command=='\0') break;
155 if (*Command == '\"') {
156 Start = ++Command;
157 while(*Command!='\"' && *Command!='\0') Command++;
158 }
159 else {
160 Start = Command;
161 while(!isspace(*Command) && *Command!='\0') Command++;
162 }
163 if(*Command != '\0') *Command++ = '\0';
164 Parameter.push_back(Start);
165 }
166
167 // Search for command in command list
168 for(unsigned int n=0; n<sizeof(CommandList)/sizeof(CL_Struct); n++) {
169 if (Match(Parameter[0], CommandList[n].Name)) {
170 // Check if number of parameters
171 if(Parameter.size()-1 < CommandList[n].MinNumParameter) {
172 PrintMessage("Usage: %s %s\n", CommandList[n].Name, CommandList[n].Parameters);
173 return;
174 }
175 // Check if idle mode required
176 if (CommandList[n].NeedIdle && Mode != idle) {
177 PrintMessage("Current mode is not idle ('stop' will stop current operation)\n");
178 return;
179 }
180 // Jump to command function
181 (this->*CommandList[n].CommandPointer)();
182 return;
183 }
184 }
185
186 // Command not found
187 PrintMessage("Unknown command '%s'\n", Parameter[0].c_str());
188}
189
190//
191// Switch SRCLK
192//
193void FAD::cmd_srclk() {
194
195 for (unsigned int i=0; i<Boards.size(); i++) {
196 if (Match(Parameter[1],"on")) Boards[i]->Send(CMD_SRCLK_ON);
197 else if (Match(Parameter[1],"off")) Boards[i]->Send(CMD_SRCLK_OFF);
198 else {
199 PrintUsage();
200 return;
201 }
202 }
203}
204
205//
206// Reset internal trigger
207//
208
209void FAD::cmd_reset() {
210
211 for (unsigned int i=0; i<Boards.size(); i++) Boards[i]->Send(CMD_RESET_TRIGGER_ID);
212}
213
214
215//
216// Set DRS reset line
217//
218void FAD::cmd_drsreset() {
219
220 for (unsigned int i=0; i<Boards.size(); i++) {
221 if (Match(Parameter[1], "low")) Boards[i]->Send(CMD_DRS_RST_LOW);
222 else if (Match(Parameter[1], "high")) Boards[i]->Send(CMD_DRS_RST_HIGH);
223 else {
224 PrintUsage();
225 return;
226 }
227 }
228}
229
230//
231// Execute: Confirm new ROI, DAC or what ever settings
232//
233void FAD::cmd_execute() {
234
235 for (unsigned int i=0; i<Boards.size(); i++) Boards[i]->Send(CMD_Execute);
236}
237
238//
239// Set run number
240//
241void FAD::cmd_runnumber() {
242
243 unsigned short Buffer[4] = {0};
244 int Num;
245
246 if (!ConvertToInt(Parameter[1], &Num)) {
247 PrintMessage("Error, incorrect parameter for run number\n");
248 return;
249 }
250 Buffer[0] = htons(CMD_Write | ADDR_RUNNUMBER);
251 Buffer[1] = htons( (unsigned short)( ((unsigned int)Num) >> 16 ) );
252 Buffer[2] = htons(CMD_Write | (ADDR_RUNNUMBER + 1) );
253 Buffer[3] = htons( (unsigned short)Num );
254
255 for (unsigned int i=0; i<Boards.size(); i++) {
256 Boards[i]->Send(Buffer, sizeof(Buffer));
257 Boards[i]->Send(CMD_Execute);
258 }
259}
260
261//
262// Switch socket mode
263// "com" - command mode (only socket 0 is used for event data transmission)
264// "daq" - daq mode (only sockets 1 - 7 are used)
265void FAD::cmd_socketmode() {
266
267 for (unsigned int i=0; i<Boards.size(); i++) {
268 if (Match(Parameter[1],"com")) Boards[i]->Send(CMD_mode_command);
269 else if (Match(Parameter[1],"daq")) Boards[i]->Send(CMD_mode_all_sockets);
270 else {
271 PrintUsage();
272 return;
273 }
274 }
275}
276
277//
278// Switch SCLK
279//
280void FAD::cmd_sclk() {
281
282 for (unsigned int i=0; i<Boards.size(); i++) {
283 if (Match(Parameter[1],"on")) Boards[i]->Send(CMD_SCLK_ON);
284 else if (Match(Parameter[1],"off")) Boards[i]->Send(CMD_SCLK_OFF);
285 else {
286 PrintUsage();
287 return;
288 }
289 }
290}
291
292//
293// Switch Domino wave
294//
295void FAD::cmd_domino() {
296
297 for (unsigned int i=0; i<Boards.size(); i++) {
298 if (Match(Parameter[1],"on")) Boards[i]->Send(CMD_DENABLE);
299 else if (Match(Parameter[1],"off")) Boards[i]->Send(CMD_DDISABLE);
300 else {
301 PrintUsage();
302 return;
303 }
304 }
305}
306
307//
308// Switch DWRITE
309//
310void FAD::cmd_dwrite() {
311
312 for (unsigned int i=0; i<Boards.size(); i++) {
313 if (Match(Parameter[1],"on")) Boards[i]->Send(CMD_DWRITE_RUN);
314 else if (Match(Parameter[1],"off")) Boards[i]->Send(CMD_DWRITE_STOP);
315 else {
316 PrintUsage();
317 return;
318 }
319 }
320}
321
322//
323// Issue soft trigger
324//
325void FAD::cmd_trigger() {
326
327 int Num;
328
329 for (unsigned int i=0; i<Boards.size(); i++) {
330 if (Parameter.size() == 1) Boards[i]->Send(CMD_Trigger);
331 else if (ConvertToInt(Parameter[1], &Num)) {
332 for (int j=0; j<Num; j++) Boards[i]->Send(CMD_Trigger);
333 }
334 else if (Match(Parameter[1],"continuous")) {
335 Boards[i]->Send(CMD_Trigger_C);
336 if (Parameter.size() == 3 && ConvertToInt(Parameter[2], &Num)) {
337 if (Num == 0)
338 Boards[i]->Send(CMD_Trigger_S);
339 else {
340 //Boards[i]->Send(0x2100 + (unsigned char) (1000.0/Num/12.5));
341 Boards[i]->Send( CMD_Write | BADDR_CONT_TRIGGER_TIME );
342 Boards[i]->Send((unsigned short) (1000.0/Num/12.5));
343 }
344 }
345 }
346 else if (Match(Parameter[1],"stop")) Boards[i]->Send(CMD_Trigger_S);
347 else if (Match(Parameter[1],"enable")) Boards[i]->Send(CMD_TRIGGERS_ON);
348 else if (Match(Parameter[1],"disable")) Boards[i]->Send(CMD_TRIGGERS_OFF);
349 else {
350 PrintUsage();
351 break;
352 }
353 }
354}
355
356//
357// Set DAC
358//
359void FAD::cmd_dac() {
360
361 int Value;
362 struct Range R = {0, NDAC-1};
363 unsigned short Buffer[2*NDAC] = {0};
364
365 // Check ranges
366 if(!ConvertToRange(Parameter[1], R)) {
367 PrintMessage("Error, DAC number out of range.\n");
368 return;
369 }
370
371 if (!ConvertToInt(Parameter[2], &Value) || Value<0 || Value>MAX_DACVAL) {
372 PrintMessage("Error, DAC value out of range.\n");
373 return;
374 }
375
376 // Prepare command buffer
377 for (int i=R.Min; i<=R.Max; i++) {
378 Buffer[2*i] = htons(CMD_Write | (BADDR_DAC + i));
379 Buffer[2*i+1] = htons(Value);
380 }
381
382 // Send command buffer
383 for (unsigned int i=0; i<Boards.size(); i++) {
384 Boards[i]->Send(Buffer, sizeof(Buffer));
385 Boards[i]->Send(CMD_Execute);
386 }
387}
388
389//
390// Set region-of-interest
391//
392void FAD::cmd_roi() {
393
394 int Value;
395 struct Range R = {0, NChips*NChannels-1};
396 unsigned short Buffer[2*NChips*NChannels] = {0};
397
398 // Check ranges
399 if (!ConvertToRange(Parameter[1], R)) {
400 PrintMessage("Error, ROI number out of range.\n");
401 return;
402 }
403
404 if (!ConvertToInt(Parameter[2], &Value) || Value<0 || Value>MAX_ROIVAL) {
405 PrintMessage("Error, ROI value out of range.\n");
406 return;
407 }
408
409 // Prepare command buffer
410 for (int i=R.Min; i<=R.Max; i++) {
411 Buffer[2*i] = htons(CMD_Write | (BADDR_ROI + i));
412 Buffer[2*i+1] = htons(Value);
413 }
414
415
416 // Send command buffer and enable triggers again
417 for (unsigned int i=0; i<Boards.size(); i++) {
418 Boards[i]->Send(Buffer+R.Min*2, (R.Max-R.Min+1)*2*sizeof(unsigned short));
419 Boards[i]->Send(CMD_Execute);
420 }
421
422
423}
424
425//
426// Set addresses to value
427//
428void FAD::cmd_address() {
429
430 int Value;
431 struct Range R = {0, MAX_ADDR};
432 unsigned short Buffer[2*MAX_ADDR] = {0};
433
434 // Check ranges
435 if (!ConvertToRange(Parameter[1], R)) {
436 PrintMessage("Error, address out of range.\n");
437 return;
438 }
439
440 if (!ConvertToInt(Parameter[2], &Value) || Value<0 || Value>MAX_VAL) {
441 PrintMessage("Error, value out of range.\n");
442 return;
443 }
444
445 // Prepare command buffer
446 for (int i=R.Min; i<=R.Max; i++) {
447 Buffer[2*i] = htons(CMD_Write | i);
448 Buffer[2*i+1] = htons(Value);
449 }
450
451 // Send command buffer
452 for (unsigned int i=0; i<Boards.size(); i++) {
453 Boards[i]->Send(Buffer, 2*(R.Max-R.Min+1)*sizeof(unsigned short));
454 }
455}
456
457//
458// Set ADC phase
459//
460void FAD::cmd_phase() {
461
462 int Value;
463
464 if (!ConvertToInt(Parameter[1], &Value)) {
465 PrintMessage("Error, illegal phase value\n");
466 return;
467 }
468
469 // Prepare command buffer
470 unsigned short *Buffer = new unsigned short [abs(Value)];
471 for (int i=0; i<abs(Value); i++) Buffer[i] = htons(CMD_PS_DO);
472
473 // Execute phase setting
474 for (unsigned int i=0; i<Boards.size(); i++) {
475 Boards[i]->Send(CMD_PS_RESET);
476 if (Value < 0) Boards[i]->Send(CMD_PS_DIRDEC);
477 else Boards[i]->Send(CMD_PS_DIRINC);
478 Boards[i]->Send(Buffer, abs(Value)*sizeof(unsigned short));
479 }
480
481 delete[] Buffer;
482}
483
484//
485// Send arbitrary data to board
486//
487void FAD::cmd_send() {
488
489 int Value;
490
491 if (!ConvertToInt(Parameter[1], &Value) || Value<0 || Value>MAX_VAL) {
492 PrintMessage("Error, illegal value\n");
493 return;
494 }
495
496 for (unsigned int i=0; i<Boards.size(); i++) Boards[i]->Send(Value);
497}
498
499/*
500// Set Domino mode
501void FAD::cmd_dmode() {
502 if (Match(Param[1],"continuous")) SetDOMINOMode(1);
503 else if (Match(Param[1],"single")) SetDOMINOMode(0);
504 else PrintUsage();
505}
506
507// Set Domino readout mode
508void FAD::cmd_rmode() {
509 if (Match(Param[1],"first")) SetDOMINOReadMode(0);
510 else if (Match(Param[1],"stop")) SetDOMINOReadMode(1);
511 else PrintUsage();
512}
513
514// Set Domino wave mode
515void FAD::cmd_wmode() {
516 if (Match(Param[1],"run")) SetDOMINOWaveMode(1);
517 else if (Match(Param[1],"stop")) SetDOMINOWaveMode(0);
518 else PrintUsage();
519}
520*/
521
522//
523// Start data run
524//
525void FAD::cmd_take() {
526
527 time_t Time = time(NULL);
528 struct tm *T = localtime(&Time);
529 char Filename[500];
530 double Temp;
531
532 // Set number of requested events
533 NumEventsRequested = atoi(Parameter[1].c_str());
534 NumEvents = 0;
535
536 // Open file with rwx right for owner and group, never overwrite file
537 snprintf(Filename, sizeof(Filename),"%s/%d%02d%02dT%02d%02d%02d.raw", Parameter[2].c_str(), T->tm_year+1900, T->tm_mon+1, T->tm_mday, T->tm_hour, T->tm_min, T->tm_sec);
538
539 Datafile = open(Filename,O_WRONLY|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
540 if(Datafile == -1) {
541 PrintMessage("Error: Could not open file \"%s\" (%s)\n", Filename, strerror(errno));
542 return;
543 }
544
545 // Check conditions for run of all active boards
546 float MaxTempDiff = atof(GetConfig("CalibTempDiffWarn").c_str());
547 float MaxFreqDiff = atof(GetConfig("CalibFreqDiffWarn").c_str());
548
549 for (unsigned int i=0; i<Boards.size(); i++) {
550 if (!Boards[i]->Active) continue;
551
552 if (Boards[i]->ACalib.Time == -1) PrintMessage("Warning: Amplitude calibration missing for board %d\n", i);
553 else {
554 Temp = 0;
555 for (unsigned int j=0; j<NTemp; j++) Temp += Boards[i]->GetStatus().Temp[j] / NTemp;
556 if (fabs(Boards[i]->ACalib.Temp-Temp) > MaxTempDiff) PrintMessage("Warning: Calibration to current temperature difference larger than %.1f K for board %d\n", MaxTempDiff, i);
557 if (fabs(Boards[i]->ACalib.Frequency-Boards[i]->GetStatus().Frequency) > MaxFreqDiff) PrintMessage("Warning: Calibration to current frequency difference larger than %.1f GHz for board %d\n", MaxFreqDiff, i);
558 }
559 }
560
561 // Start run
562 Mode = datarun;
563 Message(INFO, "Starting run with %d events, filename '%s'", NumEventsRequested, Filename);
564}
565
566//
567// Amplitude calibration
568//
569void FAD::cmd_acalib() {
570
571 // Invalidate calibration?
572 if (Parameter.size() == 2 && Match(Parameter[1], "invalidate")) {
573 for (unsigned int i=0; i<Boards.size(); i++) Boards[i]->ACalib.Time = -1;
574 return;
575 }
576
577 // Read calibration data from file?
578 if (Parameter.size() == 2 && !ConvertToInt(Parameter[1], &NumEventsRequested)) {
579 FILE *File;
580 struct FADBoard::CalibData Data;
581 bool Found = false;
582
583 // Open file
584 if ((File = fopen(Parameter[1].c_str(), "r")) == NULL) {
585 PrintMessage("Error opening file '%s'\n", Parameter[1].c_str());
586 return;
587 }
588 // Read data and check if it applies to any board
589 while (fread(&Data, sizeof(Data), 1, File) == 1) {
590 for (unsigned int i=0; i<Boards.size(); i++) if (Data.DNA == Boards[i]->GetStatus().DNA) {
591 PrintMessage("Found calibration for board %d - %s", i, ctime(&Data.Time));
592 Boards[i]->ACalib = Data;
593 Found = true;
594 }
595 }
596 if (!Found) PrintMessage("Did not find calibration data for any board\n");
597
598 //Close file
599 if (fclose(File) != 0) PrintMessage("Could not close file '%s'\n", Parameter[1].c_str());
600 return;
601 } // Reading calibration from file
602
603 // Set number of events required for calibration
604 if (Parameter.size()==1 || !ConvertToInt(Parameter[1], &NumEventsRequested) || NumEventsRequested<=0) {
605 NumEventsRequested = DEFAULT_NUM_CALIB_EVENTS;
606 }
607
608 // Start calibration by setting mode
609 Mode = acalib;
610 Message(INFO, "Starting amplitude calibration run with 3x%d events", NumEventsRequested);
611}
612
613
614//
615// Determine dynamic range
616//
617void FAD::cmd_dynrange() {
618
619 Mode = dynrange;
620 Message(INFO, "Starting determination of dynamic range");
621}
622
623
624//
625// Print status
626//
627void FAD::cmd_status() {
628
629 int MinCount = std::numeric_limits<int>::max();
630 unsigned int SlowestBoard = 0;
631
632 // ==== Print board overview ====
633 if (Parameter.size() == 1) {
634
635 // Count active board
636 unsigned int Count = 0, Error = 0;
637 for (unsigned int i=0; i<Boards.size(); i++) {
638 if (Boards[i]->Active) Count++;
639 if (!Boards[i]->CommOK) Error++;
640 if (Boards[i]->Active && Boards[i]->Count < MinCount) {
641 MinCount = Boards[i]->Count;
642 SlowestBoard = i;
643 }
644 }
645
646 PrintMessage("\rTotal boards: %d (%d with communication errors)\n", Boards.size(), Error);
647
648 // Print list of active boards
649 PrintMessage("Active (%d)\t", Count);
650 for (unsigned int i=0; i<Boards.size(); i++) {
651 if (Boards[i]->Active) PrintMessage(" %d%s", i, Boards[i]->CommOK ? "":"!");
652 }
653 PrintMessage("\nInactive (%d) ", Boards.size()-Count);
654 for (unsigned int i=0; i<Boards.size(); i++) {
655 if (!Boards[i]->Active) PrintMessage(" %d%s", i, Boards[i]->CommOK ? "":"!");
656 }
657 PrintMessage("\n");
658
659 // Print current mode
660 if (Mode == idle) PrintMessage("Current mode is IDLE\n");
661 else if (Mode == acalib) PrintMessage("Current mode is ACALIB (3x%d events, slowest board %d has %d events)\n", NumEventsRequested, SlowestBoard, MinCount);
662 else if (Mode == datarun) PrintMessage("Current mode is DATARUN (%d events requested, %d events taken)\n", NumEventsRequested, NumEvents);
663 else if (Mode == dynrange) PrintMessage("Current mode is DYNRANGE\n");
664 return;
665 }
666
667 // ==== Print details for given range ====
668 struct Range R = {0, Boards.size()};
669
670 if (!ConvertToRange(Parameter[1], R)) {
671 PrintMessage("Error, out of range.\n");
672 return;
673 }
674
675 for (int i=0; i<(int) Boards.size(); i++) {
676 if (i<R.Min || i > R.Max) continue;
677
678 PrintMessage("\nBOARD #%d (%sactive) IP %s Communication %s\n", i, Boards[i]->Active ? "":"in", Boards[i]->Name, Boards[i]->CommOK ? "OK":"ERROR");
679
680 // Calibration information
681 if (Boards[i]->ACalib.Time == -1) PrintMessage("No amplitude calibration available\n");
682 else PrintMessage("Calibration data: Temperature %.1f Frequency %.2f Time %s" , Boards[i]->ACalib.Temp, Boards[i]->ACalib.Frequency, ctime(&Boards[i]->ACalib.Time));
683
684 // Status information
685 struct FADBoard::BoardStatus S = Boards[i]->GetStatus();
686
687 PrintMessage("Status: %s\n", S.Message);
688
689 if (S.Update.tv_sec == -1) {
690 PrintMessage("No event received yet, no further status information available\n");
691 continue;
692 }
693 PrintMessage("Event rate %.1f Hz Last event received %s", S.Rate, ctime(&S.Update.tv_sec));
694
695 // Board identification
696 PrintMessage("Board ID %.4x Firmware revision %.4x Serial %llx\n", S.BoardID, S.FirmwareRevision, S.DNA);
697 PrintMessage("Board time %g s Event counter %d\n", S.BoardTime/1.0e4 , S.EventCounter);
698
699 // Other data
700 PrintMessage("Frequency %.2f GHz (%s) Phase shift %d PLL lock %d %d %d %d\n", S.Frequency, S.RefClk_low ? "too low":"OK", S.PhaseShift, S.Lock[0], S.Lock[1], S.Lock[2], S.Lock[3]);
701 PrintMessage("DENABLE %d DWRITE %d SPI_clk %d DCM_lock %d DCM_ready %d\n", S.denable, S.dwrite, S.spi_clk, S.DCM_lock, S.DCM_ready);
702 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] );
703 PrintMessage("Temperature %.2f %.2f %.2f %.2f", S.Temp[0], S.Temp[1], S.Temp[2], S.Temp[3]);
704
705 for (unsigned int j=0; j<NChips*NChannels; j++) {
706 if (j%NChannels == 0) PrintMessage("\nROI %2d-%2d: ", j, j+NChannels-1);
707 PrintMessage("%4d ", S.ROI[j/NChannels][j%NChannels]);
708 }
709
710 PrintMessage("\nTrigger ID: Num %d Type %d CRC %d Run number %d\n", S.TriggerNum, S.TriggerType, S.TriggerCRC, S.Runnumber);
711 } // for()
712}
713
714//
715// Adress FAD boards
716//
717void FAD::cmd_board() {
718
719 struct Range R = {0, Boards.size()};
720 int Mode = 0;
721
722 // Check if given boards should be enabled or disabled
723 if (Parameter[1].size() >= 1) {
724 if (Parameter[1][0] == '+') Mode = 1;
725 if (Parameter[1][0] == '-') Mode = -1;
726 }
727 if (Mode != 0) Parameter[1][0] = ' ';
728
729 // Disable all boards
730 if (Match(Parameter[1], "none")) {
731 for (int i=0; i<(int) Boards.size(); i++) Boards[i]->Active = false;
732 return;
733 }
734
735 // Evaluate given range
736 if (!ConvertToRange(Parameter[1], R)) {
737 PrintMessage("Error, out of range.\n");
738 return;
739 }
740
741 // Enable or disable boards
742 for (int i=0; i<(int) Boards.size(); i++) {
743 if (Mode == 0) Boards[i]->Active = false;
744 if (i >= R.Min && i <= R.Max) {
745 if (Mode != -1) Boards[i]->Active = true;
746 else Boards[i]->Active = false;
747 }
748 }
749}
750
751//
752// Set DIM event update delay
753//
754void FAD::cmd_update() {
755
756 double Delay;
757
758 if (Parameter.size()==2 && ConvertToDouble(Parameter[1], &Delay) && Delay>=0) EventUpdateDelay = Delay;
759 else PrintUsage();
760}
761
762//
763// Print help
764//
765void FAD::cmd_help() {
766
767 char *Buffer;
768
769 for(unsigned int i=0; i<sizeof(CommandList)/sizeof(CL_Struct); i++) {
770 if (asprintf(&Buffer, "%s %s", CommandList[i].Name, CommandList[i].Parameters) == -1) {
771 PrintMessage("Error printing help, asprintf() failed\n");
772 break;
773 }
774 else {
775 if (strlen(Buffer) < 25) PrintMessage("%-25s%s\n", Buffer, CommandList[i].Help);
776 else PrintMessage("%s\n%-25s%s\n", Buffer, "", CommandList[i].Help);
777 }
778 free(Buffer);
779 }
780 PrintMessage(".<command> Execute shell command\n\n"
781 "Items in <> are mandatory, in [] optional, | indicates mutual exclusive.\n"
782 "Strings containing spaces have to be enclosed in \"double quotes\".\n"
783 "Ranges can be given as 'all', a single number or in the form 'a-b'.\n");
784}
785
786//
787// Stop current operation
788//
789void FAD::cmd_stop() {
790
791 static char Stop[] = "stop\n";
792
793 if (Mode == idle) {
794 PrintMessage("Nothing to stop\n");
795 return;
796 }
797
798 if (Mode == acalib || Mode == dynrange) {
799 Mode = idle;
800 Message(INFO, "Mode set to IDLE");
801 }
802
803 if (Mode == datarun) {
804 // Inform event thread to stop run in case datarun active
805 if (write(Pipe[1], Stop, strlen(Stop)) == -1) {
806 Message(ERROR, "write() to Pipe[1] failed in FAD::cmd_cancel() (%s)", strerror(errno));
807 }
808 }
809
810 PrintMessage("Requested stopping of current operation\n");
811}
812
813//
814// Exit programm
815// SIGTERM makes readline() return (in case command came over network)
816//
817void FAD::cmd_exit() {
818
819 ExitRequest = true;
820 pthread_kill(MainThread, SIGTERM);
821}
822
823
824// -----------------------------
825// ***** Other functions *****
826// -----------------------------
827
828//
829// DIM exit handler (overwriting handler in Evidence class)
830//
831void FAD::exitHandler(int Code) {
832
833 Message(INFO, "Exit handler called (DIM exit code %d)", Code);
834 cmd_exit();
835}
836
837//
838// Save amplitude calibration data to file
839//
840void FAD::SaveAmplitudeCalibration() {
841
842 // Open calibration data file
843 string Filename = string(getenv("HOME"))+"/FAD_ACal";
844 FILE *File = fopen(Filename.c_str(), "wb");
845
846 if (File == NULL) {
847 PrintMessage("Could not open calibration data file '%s'\n", Filename.c_str());
848 return;
849 }
850
851 // Write valid calibration information for active boards
852 for (unsigned int i=0; i<Boards.size(); i++) {
853 if (!Boards[i]->Active || Boards[i]->ACalib.Time == -1) continue;
854
855 if (fwrite(&Boards[i]->ACalib, sizeof(Boards[i]->ACalib), 1, File) != 1) {
856 PrintMessage("Could not write to calibration file '%s'\n", Filename.c_str());
857 break;
858 }
859 }
860
861 // Close file
862 if (fclose(File) != 0) PrintMessage("Could not close calibration file '%s'\n", Filename.c_str());
863
864 PrintMessage("Wrote amplitude calibration to file '%s'\n", Filename.c_str());
865}
866
867//
868// Event thread (publishes/writes M0 format)
869//
870void FAD::EventThread() {
871
872 struct timeval Time;
873 struct timeval LastUpdate;
874 struct FADBoard::BoardStatus S;
875 vector<unsigned long> EventNumbers(Boards.size());
876 vector<bool> AcalibDone(Boards.size());
877 vector<class FADBoard *> ActiveBoards;
878 double Temp;
879 string IDString;
880 char Buffer[100];
881 int Ret;
882 struct stat FileStat;
883 float FileSizeMB = 0;
884 RunHeader FileRHeader;
885
886 gettimeofday(&LastUpdate, NULL);
887
888 // Create DIM event data and number services
889 char *EventData = new char [sizeof(RunHeader)+ Boards.size()*sizeof(BoardStructure)+sizeof(EventHeader) + Boards.size()*(NChips*NChannels*NBins*sizeof(short) + NChips*sizeof(int))];
890
891 DimService EventService(SERVER_NAME"/EventData", (char *) "C", NULL, 0);
892 DimService EventNumService(SERVER_NAME"/EventNumber", NumEvents);
893 DimService FileSizeService(SERVER_NAME"/FileSizeMB", FileSizeMB);
894
895 // Set/allocate pointers
896 RunHeader *RHeader = (RunHeader *) EventData;
897 BoardStructure **BStruct = new BoardStructure * [Boards.size()];
898 EventHeader *EHeader;
899 int *TriggerCell;
900 short *Data;
901
902 // Fill fixed entries in M0 RunHeader
903 RHeader->MagicNum = MAGICNUM_CLOSED;
904 RHeader->DataFormat = DATA_FORMAT;
905 RHeader->RunHeaderSize = sizeof(RunHeader);
906 RHeader->EventHeaderSize = sizeof(EventHeader);
907 RHeader->BoardStructureSize = sizeof(BoardStructure);
908 RHeader->SoftwareRevision = atoi(REVISION) * (strchr(REVISION, 'M')==NULL ? 1:-1);
909 RHeader->Identification = 0;
910 RHeader->Type = 0; // Run type: 0=data, 1=pedestal, 3=test
911 RHeader->RunNumber = -1;
912 RHeader->FileNumber = 0;
913 snprintf(RHeader->Description, sizeof(RHeader->Description), "FADctrl");
914 RHeader->Events = 1;
915 RHeader->StartSecond = LastUpdate.tv_sec;
916 RHeader->StartMicrosecond = LastUpdate.tv_usec;
917 RHeader->NChips = NChips;
918 RHeader->NChannels = NChannels;
919 RHeader->Samples = NBins; // Always full pipeline
920 RHeader->Offset = 0;
921 RHeader->NBytes = sizeof(short);
922
923 // Update loop
924 while (!ExitRequest) {
925 // Removed processed data from IDString
926 size_t LastLF = IDString.find_last_of("\n");
927 if (LastLF != string::npos) IDString = IDString.substr(LastLF+1);
928
929 // Wait for data from TCP/IP reading threads
930 if ((Ret=read(Pipe[0], Buffer, sizeof(Buffer))) == -1) Message(FATAL, "read() from Pipe[0] failed in FAD::EventThread() (%s)", strerror(errno));
931
932 // Check if pipe closed
933 if (Ret == 0) break;
934
935 IDString.append(string(Buffer, Ret));
936
937 // Active boards must not change during data taking
938 if (Mode != datarun || NumEvents == 0) {
939 ActiveBoards.clear();
940 for (unsigned int i=0; i<Boards.size(); i++) {
941 if (Boards[i]->Active) ActiveBoards.push_back(Boards[i]);
942 }
943 RHeader->NBoards = ActiveBoards.size();
944 }
945
946 // Calculate pointers to EventData array
947 for (unsigned int i=0; i<ActiveBoards.size(); i++) BStruct[i] = ((BoardStructure *) (RHeader + 1)) + i;
948 EHeader = (EventHeader *) ((char *) (RHeader + 1) + ActiveBoards.size()*sizeof(BoardStructure));
949 TriggerCell = (int *) (EHeader + 1);
950 Data = (short *) (TriggerCell + NChips*ActiveBoards.size());
951
952 // If amplitude calibration mode, check if all boards finished procedure
953 if (Mode == acalib || Mode == dynrange) {
954 bool Done = true;
955 for (unsigned int i=0; i<Boards.size(); i++) {
956 if (IDString.find(string("ACALIBDONE")+Boards[i]->Name) != string::npos) AcalibDone[i] = true;
957 if (!AcalibDone[i] && Boards[i]->Active) Done = false;
958 }
959 // Amplitude calibration finished?
960 if (Done) {
961 if (Mode == acalib) {
962 SaveAmplitudeCalibration();
963 Message(INFO, "Amplitude calibration done, mode set to IDLE");
964 }
965 if (Mode == dynrange) {
966 Message(INFO, "Dynamic range measurement done, mode set to IDLE");
967 }
968 Mode = idle;
969 }
970 }
971 else for (unsigned int i=0; i<Boards.size(); i++) AcalibDone[i] = false;
972
973 // Update run and event header
974 gettimeofday(&Time, NULL);
975 RHeader->EndSecond = Time.tv_sec;
976 RHeader->EndMicrosecond = Time.tv_usec;
977
978 EHeader->EventSize = RHeader->NBoards * (NChips*NChannels*NBins*sizeof(short) + NChips*sizeof(int));
979 EHeader->Second = Time.tv_sec;
980 EHeader->Microsecond = Time.tv_usec;
981
982 // Check all boards that have new data
983 for (unsigned int Brd=0; Brd<ActiveBoards.size(); Brd++) {
984 if (IDString.find(string("EVENT")+ActiveBoards[Brd]->Name) == string::npos) continue;
985
986 // Fill M0 BoardStructure
987 S = ActiveBoards[Brd]->GetStatus();
988 BStruct[Brd]->SerialNo = (U32) S.DNA;
989 BStruct[Brd]->NomFreq = S.Frequency;
990 BStruct[Brd]->BoardTemp = 0;
991 for (unsigned int i=0; i<NTemp; i++) BStruct[Brd]->BoardTemp += S.Temp[i]/NTemp;
992 BStruct[Brd]->ScaleFactor = 1/2.048;
993
994 // Update event header with ID and Type of current board
995 EHeader->EventNumber = S.TriggerNum;
996 EHeader->TriggerType = S.TriggerType;
997
998 // Register event number for data writing below
999 EventNumbers[Brd] = S.TriggerNum;
1000
1001 // Write trigger cells
1002 for(unsigned int i=0; i<NChips; i++) TriggerCell[Brd*NChips+i] = (int) S.TriggerCell[i];
1003
1004 // Write channel data
1005 int Count = Brd*NChips*NChannels*NBins;
1006 memset(Data+Count, 0, NChips*NChannels*NBins*sizeof(short));
1007
1008 ActiveBoards[Brd]->Lock();
1009 for (unsigned int Chip=0; Chip<NChips; Chip++) for (unsigned int Chan=0; Chan<NChannels; Chan++) {
1010 for (int i=0; i<S.ROI[Chip][Chan]; i++) {
1011 if (ActiveBoards[Brd]->ACalib.Time == -1) Data[Count++] = ActiveBoards[Brd]->Data[Chip][Chan][i];
1012 else {
1013 Temp = (ActiveBoards[Brd]->Data[Chip][Chan][i] - ActiveBoards[Brd]->ACalib.Baseline[Chip][Chan][(i+S.TriggerCell[Chip])%NBins]);
1014 Temp *= ActiveBoards[Brd]->ACalib.Gain[Chip][Chan][0]/ActiveBoards[Brd]->ACalib.Gain[Chip][Chan][(i+S.TriggerCell[Chip])%NBins];
1015 //Temp -= ActiveBoards[Brd]->ACalib.Secondary[Chip][Chan][i];
1016 Data[Count++] = (short) Temp;
1017 }
1018 }
1019 Count += NBins - S.ROI[Chip][Chan];
1020 }
1021 ActiveBoards[Brd]->Unlock();
1022 }
1023
1024 // Inform TCP/IP thread of all boards that send data that processing is finished
1025 for (unsigned int Brd=0; Brd<Boards.size(); Brd++) if (IDString.find(string("EVENT")+Boards[Brd]->Name) != string::npos) {
1026 Boards[Brd]->Lock();
1027 Boards[Brd]->Continue = true;
1028 Boards[Brd]->Unlock();
1029
1030 if ((Ret = pthread_cond_signal(&Boards[Brd]->CondVar)) != 0) {
1031 Message(FATAL, "pthread_cond_signal() failed (%s)", strerror(Ret));
1032 }
1033 }
1034
1035 // Check if DIM service should be updated
1036 if ((Time.tv_sec-LastUpdate.tv_sec)*1e6 + Time.tv_usec-LastUpdate.tv_usec > EventUpdateDelay*1e6) {
1037 gettimeofday(&LastUpdate, NULL);
1038
1039 EventService.updateService(EventData, sizeof(RunHeader) + sizeof(EventHeader) + ActiveBoards.size()*(sizeof(BoardStructure) + NChips*NChannels*NBins*sizeof(short) + NChips*sizeof(int)));
1040 EventNumService.updateService();
1041
1042 if (Mode == datarun) FileSizeService.updateService();
1043 }
1044
1045 // ===== Data writing ===
1046 if (Mode != datarun) continue;
1047
1048 // Check if event numbers of all active boards are the same
1049 unsigned long CommonEventNum = numeric_limits<unsigned long>::max();
1050
1051 for (unsigned int i=0; i<Boards.size(); i++) if (Boards[i]->Active) {
1052 if (CommonEventNum == numeric_limits<unsigned long>::max()) CommonEventNum = EventNumbers[i];
1053 if (CommonEventNum != EventNumbers[i]) {
1054 CommonEventNum = numeric_limits<unsigned long>::max();
1055 break;
1056 }
1057 }
1058 if (CommonEventNum == numeric_limits<unsigned long>::max()) continue;
1059
1060 int Error = 0;
1061
1062 // Initialize run
1063 if (NumEvents == 0) {
1064 FileSizeMB = 0;
1065
1066 FileRHeader = *RHeader;
1067 FileRHeader.MagicNum = MAGICNUM_OPEN;
1068 FileRHeader.StartSecond = Time.tv_sec;
1069 FileRHeader.StartMicrosecond = Time.tv_usec;
1070
1071 // Write run header and board structures
1072 if (write(Datafile, &FileRHeader, sizeof(RunHeader)) == -1) Error = errno;
1073 else if (write(Datafile, BStruct[0], FileRHeader.NBoards*sizeof(BoardStructure)) == -1) Error = errno;
1074 }
1075
1076 // Write event header, trigger cells and ADC data to file
1077 if (write(Datafile, EHeader, sizeof(EventHeader)+FileRHeader.NBoards*NChips*(sizeof(int)+NChannels*NBins*sizeof(short))) == -1) Error = errno;
1078
1079 NumEvents++;
1080
1081 // Update file size
1082 if (fstat(Datafile, &FileStat) == -1) Error = errno;
1083 else FileSizeMB = FileStat.st_size/1024.0/1024.0;
1084
1085 // Check for write errors and for correct file size
1086 if (Error !=0) {
1087 Message(ERROR, "Error writing to data data file (%s), terminating run, setting mode to IDLE", strerror(Error));
1088 }
1089 else if ((size_t) FileStat.st_size != sizeof(RunHeader)+ FileRHeader.NBoards*sizeof(BoardStructure)+NumEvents*(sizeof(EventHeader) + FileRHeader.NBoards*(NChips*NChannels*NBins*sizeof(short) + NChips*sizeof(int)))) {
1090 Message(ERROR, "Could not write all data to file, terminating run, setting mode to IDLE");
1091 Error = 1;
1092 }
1093
1094 // Close file if error
1095 if (Error != 0) {
1096 if (close(Datafile) == -1) Message(ERROR, "Could not close data file (%s)", strerror(errno));
1097 Datafile = -1;
1098 Mode = idle;
1099 continue;
1100 }
1101
1102 // Close data file if requested or requested number of events reached
1103 if(IDString.find("stop")!=string::npos || (NumEvents==NumEventsRequested && NumEventsRequested!=0)) {
1104
1105 // Update run header for writing
1106 FileRHeader.MagicNum = MAGICNUM_CLOSED;
1107 FileRHeader.Events = NumEvents;
1108 FileRHeader.EndSecond = Time.tv_sec;
1109 FileRHeader.EndMicrosecond = Time.tv_usec;
1110
1111 if (lseek(Datafile, 0, SEEK_SET) == -1) {
1112 Message(ERROR, "Could not rewind file to write updated run header (%s)", strerror(errno));
1113 }
1114 else if (write(Datafile, &FileRHeader, sizeof(RunHeader)) != sizeof(RunHeader)) {
1115 Message(ERROR, "Could not write updated run header (%s)", strerror(errno));
1116 }
1117
1118 // Close data file and terminate run
1119 if(close(Datafile) == -1) Message(ERROR, "Could not close data file (%s)", strerror(errno));
1120 else PrintMessage("Data file closed (size %.1f MByte, rate %.1f MByte/s, %d events).\n", FileSizeMB, FileSizeMB/(FileRHeader.EndSecond-FileRHeader.StartSecond+(FileRHeader.EndMicrosecond-FileRHeader.StartMicrosecond)/1000000.0), NumEvents);
1121
1122 Datafile = -1;
1123 Mode = idle;
1124 Message(INFO, "Data run ended, mode set to IDLE");
1125 }
1126 }
1127
1128 delete[] BStruct;
1129 delete[] EventData;
1130}
1131
1132// Launch event thread inside class
1133void FAD::LaunchEventThread(class FAD *m) {
1134
1135 m->EventThread();
1136}
1137
1138
1139/*
1140// Set DOMINO mode
1141void FAD::SetDOMINOMode(int mode) {
1142
1143 for (int i=FirstBoard; i<=LastBoard; i++) {
1144 GetBoard(i)->SetDominoMode(mode==1 ? 1:0);
1145 PrintMessage("Domino mode of board %d switched to %s.\n",i,mode==1 ? "continuous":"single shot");
1146 }
1147}
1148
1149// Set DOMINO readout mode
1150void FAD::SetDOMINOReadMode(int mode) {
1151
1152 for (int i=FirstBoard; i<=LastBoard; i++) {
1153 GetBoard(i)->SetReadoutMode(mode);
1154 PrintMessage("Start readout of board %d from %s.\n",i,mode==0 ? "first bin":"stop position");
1155 }
1156}
1157
1158// Set DOMINO wave mode
1159void FAD::SetDOMINOWaveMode(int mode) {
1160
1161 for (int i=FirstBoard; i<=LastBoard; i++) {
1162 GetBoard(i)->SetDominoActive(mode);
1163 PrintMessage("Domino wave of board %d is %s during readout\n",i,mode==1 ? "running":"stopped");
1164 }
1165}
1166
1167*/
1168
1169
1170//
1171// Print usage text for command
1172//
1173void FAD::PrintUsage() {
1174
1175 for(unsigned int i=0; i<sizeof(CommandList)/sizeof(CL_Struct); i++) {
1176 if (Match(Parameter[0], CommandList[i].Name)) {
1177 PrintMessage("Usage: %s %s\n", CommandList[i].Name, CommandList[i].Parameters);
1178 }
1179 }
1180}
1181
1182//
1183// Print message to console
1184//
1185void FAD::PrintMessage(const char *Format, ...) {
1186
1187 static char Error[] = "vasprintf() failed in PrintMessage()";
1188 char *Text;
1189
1190 // Evaluate arguments
1191 va_list ArgumentPointer;
1192 va_start(ArgumentPointer, Format);
1193 if (vasprintf(&Text, Format, ArgumentPointer) == -1) Text = Error;
1194 va_end(ArgumentPointer);
1195
1196 if (strlen(Text) == 0) return;
1197
1198 // Print to console
1199 //if (Text[strlen(Text)-1] == '\n') printf("\r"); // Overwrite prompt
1200 printf("%s", Text);
1201 fflush(stdout);
1202 if (Text[strlen(Text)-1] == '\n') rl_on_new_line();
1203
1204 // Send to DIM text service
1205 ConsoleOut->updateService(Text);
1206
1207 // Free old text
1208 if (ConsoleText != Error) free(ConsoleText);
1209 ConsoleText = Text;
1210}
1211
1212//
1213// Check if two strings match (min 1 character must match)
1214//
1215bool FAD::Match(string str, const char *cmd) {
1216
1217 return strncasecmp(str.c_str(),cmd,strlen(str.c_str())==0 ? 1:strlen(str.c_str())) ? false:true;
1218}
1219
1220//
1221// Conversion function from string to double, int or range
1222//
1223// Return false if conversion did not stop on whitespace or EOL character
1224bool FAD::ConvertToDouble(string String, double *Result) {
1225
1226 char *EndPointer;
1227
1228 *Result = strtod(String.c_str(), &EndPointer);
1229 if(!isspace(*EndPointer) && *EndPointer!='\0') return false;
1230 return true;
1231}
1232
1233bool FAD::ConvertToInt(string String, int *Result) {
1234
1235 char *EndPointer;
1236
1237 *Result = (int) strtol(String.c_str(), &EndPointer, 0);
1238 if(!isspace(*EndPointer) && *EndPointer!='\0') return false;
1239 return true;
1240}
1241
1242bool FAD::ConvertToRange(string String, struct FAD::Range &R) {
1243
1244 int N=0, M=0;
1245
1246 // Full range
1247 if (Match(String, "all")) return true;
1248
1249 // Single number
1250 if (ConvertToInt(String, &N)) {
1251 if (N>= R.Min && N<=R.Max) {
1252 R.Max = R.Min = N;
1253 return true;
1254 }
1255 return false;
1256 }
1257
1258 // Range a-b
1259 vector<string> V = EvidenceServer::Tokenize(String, "-");
1260 if (V.size()==2 && ConvertToInt(V[0], &N) && ConvertToInt(V[1], &M) && N>=R.Min && M<=R.Max) {
1261 R.Min = N;
1262 R.Max = M;
1263 return true;
1264 }
1265
1266 return false;
1267}
Note: See TracBrowser for help on using the repository browser.