source: fact/FADctrl/FAD.cc@ 10114

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