source: fact/FADctrl/FAD.cc@ 11247

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