source: fact/BIASctrl/User.cc@ 12596

Last change on this file since 12596 was 11919, checked in by ogrimm, 13 years ago
Added simple bias current calibration
File size: 21.8 KB
Line 
1//
2// Class processing user input
3//
4
5#include "User.h"
6#include <readline/readline.h>
7
8using namespace std;
9
10// Branch table for command evaluation
11static const struct CL_Struct { const char *Name;
12 void (User::*CommandPointer)();
13 unsigned int MinNumParameter;
14 bool NeedCrate;
15 const char *Parameters;
16 const char *Help;
17 } CommandList[] =
18 {{"pixel", &User::cmd_hv, 2, true, "<range> <voltage|default|info>", "Change bias of pixels"},
19 {"channel", &User::cmd_hv, 2, true, "<range> <voltage|default|info>", "Change bias of channels of active crate"},
20 {"gs", &User::cmd_gs, 1, true, "[crate] <volt>", "Global voltage set active crate"},
21 {"reset", &User::cmd_reset, 0, true, "", "Reset active crate"},
22 {"synch", &User::cmd_synch, 0, true, "", "Synchronize active crate"},
23 {"voltage", &User::cmd_status, 0, false, "[dac]", "Show voltage setpoints"},
24 {"current", &User::cmd_status, 0, false, "", "Show currents"},
25 {"status", &User::cmd_status, 0, false, "[R|I0]", "Show status information"},
26 {"calib", &User::cmd_calib, 1, true, "<V1 V2 Num|invalidate>", "Calibrate current measurement (linear fit between V1 and V2)"},
27 {"mode", &User::cmd_mode, 1, true, "<static|dynamic>", "Set voltage stabilization mode (experimental)"},
28 {"load", &User::cmd_load, 1, true, "<file>", "Load and set bias settings from file"},
29 {"save", &User::cmd_save, 1, true, "<file>", "Save current bias settings to file"},
30 {"help", &User::cmd_help, 0, false, "", "Print help"},
31 {"exit", &User::cmd_exit, 0, false, "", "Exit program"},
32 {".", &User::cmd_shell, 1, false, "<command>", "Execute shell command"}};
33
34//
35// Constructor
36//
37User::User(string Board): EvidenceServer(SERVER_NAME) {
38
39 vector<string> Text;
40
41 MainThread = pthread_self();
42
43 // DIM console service used in PrintMessage()
44 ConsoleText = NULL;
45 ConsoleOut = new DimService(SERVER_NAME"/ConsoleOut", (char *) "");
46
47 // Initialize current calibration constants
48 R.resize(MAX_NUM_BOARDS*NUM_CHANNELS, numeric_limits<double>::infinity());
49 I0.resize(MAX_NUM_BOARDS*NUM_CHANNELS, 0);
50
51 // Get/initialize configuration data
52 if (Board.empty()) Board = GetConfig("Boards", "dummy");
53 GetConfig("TimeOut");
54 GetConfig("VoltageLimit");
55 GetConfig("MinResetPeriod");
56 GetConfig("RampSpeed");
57 GetConfig("UpdatePeriod");
58
59 Text = Tokenize(GetConfig("DefaultVoltage", ""), " \t");
60 for (unsigned int i=0; i<Text.size(); i++) {
61 DefaultVoltage.push_back(atof(Text[i].c_str()));
62 }
63
64 Text = Tokenize(GetConfig("Calibration_R"), " \t");
65 for (unsigned int i=0; i<Text.size() && i<R.size(); i++) {
66 R[i] = atof(Text[i].c_str())/1000.0;
67 }
68
69 Text = Tokenize(GetConfig("Calibration_I0"), " \t");
70 for (unsigned int i=0; i<Text.size() && i<I0.size(); i++) {
71 I0[i] = atof(Text[i].c_str());
72 }
73
74 // Open device
75 Dev = new class Crate(Board, 0, this);
76
77 if (Dev->InitOK) PrintMessage("Synchronized and reset crate %s\n", Board.c_str());
78 else {
79 Message(WARN, "Failed to synchronize crate %s", Board.c_str());
80 delete Dev;
81 Dev = NULL;
82 }
83
84 // Create PixelMap instance (map from config server)
85 DimRpcInfo RPC((char *) "ConfigRequest", (char *) "");
86 RPC.setData((char *) "Misc PixelMap");
87 PixMap = new PixelMap(std::string(RPC.getString(), RPC.getSize()));
88
89 // Install DIM command (after all initialized)
90 DIMCommand = new DimCommand((char *) SERVER_NAME"/Command", (char *) "C", this);
91
92 // Create monitor thread and make accessible for sending signal
93 if ((pthread_create(&Thread, NULL, (void * (*)(void *)) LaunchMonitor,(void *) this)) != 0) {
94 Message(FATAL, "pthread_create() failed with Monitor thread");
95 }
96}
97
98//
99// Destructor
100//
101User::~User() {
102
103 int Ret;
104
105 // Wait for thread to quit (ignore error if thread did already exit)
106 if ((Ret = pthread_cancel(Thread)) != 0) {
107 if (Ret != ESRCH) Message(ERROR, "pthread_cancel() failed (%s)", strerror(Ret));
108 }
109 if ((Ret = pthread_join(Thread, NULL)) != 0) Message(ERROR, "pthread_join() failed (%s)", strerror(Ret));
110
111 // Delete crate
112 delete Dev;
113
114 delete DIMCommand;
115 delete PixMap;
116 delete ConsoleOut;
117 free(ConsoleText);
118}
119
120//
121// Process user input
122//
123void User::commandHandler() {
124
125 // Build string safely
126 string Command = string(getCommand()->getString(), getCommand()->getSize());
127
128 // Check if command is legal and ignore empty commands
129 if (getCommand() != DIMCommand || Command.size() < 2) return;
130
131 // Parse command into tokens
132 Parameter = Tokenize(Command, " ");
133
134 // Special handling of shell execution
135 if (Command[0] == '.') {
136 Parameter.clear();
137 Parameter.push_back(".");
138 Parameter.push_back(Command.substr(1));
139 }
140
141 // Search for command in command list
142 for(unsigned int CmdNumber=0; CmdNumber<sizeof(CommandList)/sizeof(CL_Struct); CmdNumber++) {
143 if (Match(Parameter[0], CommandList[CmdNumber].Name)) {
144 // Requested command help?
145 if (Parameter.size() == 2 && Match(Parameter[1], "?")) {
146 PrintMessage("Usage: %s %s\n%s\n", CommandList[CmdNumber].Name, CommandList[CmdNumber].Parameters, CommandList[CmdNumber].Help);
147 return;
148 }
149
150 // Incorrect number of parameters?
151 if (Parameter.size()-1 < CommandList[CmdNumber].MinNumParameter) {
152 PrintMessage("Usage: %s %s\n", CommandList[CmdNumber].Name, CommandList[CmdNumber].Parameters);
153 return;
154 }
155
156 // Check if crate needed
157 if (CommandList[CmdNumber].NeedCrate && Dev==NULL) {
158 PrintMessage("No crate available\n");
159 return;
160 }
161
162 // Jump to command function
163 (this->*CommandList[CmdNumber].CommandPointer)();
164 return;
165 }
166 }
167 PrintMessage("Unknown command '%s'\n", Parameter[0].c_str());
168}
169
170
171// Print help
172void User::cmd_help() {
173
174 for(unsigned int i=0; i<sizeof(CommandList)/sizeof(CL_Struct); i++) {
175 PrintMessage("%-10s%s\n", CommandList[i].Name, CommandList[i].Help);
176 }
177
178 PrintMessage("\nUse '?' as argument to get more extensive help.\n"
179 "Commands 'pixel' and 'channel' allow and arbitary number of argument pairs.\n"
180 "Items in <> are mandatory, in [] optional, | indicates mutual exclusive or.\n"
181 "Ranges can be 'all', a single number or in the form 'a-b'.\n");
182}
183
184//
185// Synchronize crate
186//
187void User::cmd_synch() {
188
189 if (Dev->Synch()) PrintMessage("Synchronized crate\n");
190 else PrintMessage("Failed to synchronize crate\n");
191}
192
193//
194// Set new bias voltage
195//
196void User::cmd_hv() {
197
198 unsigned int Channel, Errors = 0;
199 double Double;
200 struct Range Chan, Pixel;
201 map<unsigned int, double> Voltages;
202 vector<unsigned int> Channels;
203
204 // Loop over all parameters
205 for (unsigned int n=1; n < Parameter.size()-1; n+=2) {
206
207 // Convert voltage value and check format
208 if (!ConvertToDouble(Parameter[n+1], &Double) && !Match(Parameter[n+1], "default") && !Match(Parameter[n+1], "info")) {
209 PrintMessage("Error: Wrong number format for voltage setting\n");
210 continue;
211 }
212
213 // Extract affected channels for this argument pair
214 Channels.clear();
215
216 // Pixel identification?
217 if (Match(Parameter[0], "pixel")) {
218 Pixel.Min = 0;
219 Pixel.Max = 1439;
220
221 if (!ConvertToRange(Parameter[n], Pixel)) {
222 PrintMessage("Pixel ID out-of-range for parameter %d, skipping channel\n", n);
223 continue;
224 }
225
226 for (int i=Pixel.Min; i<=Pixel.Max; i++) {
227 Channel = PixMap->Pixel_to_HVboard(i)*NUM_CHANNELS + PixMap->Pixel_to_HVchannel(i);
228
229 // Skip if pixel ID or corresponding channels not existing
230 if (PixMap->Pixel_to_HVcrate(i) == 0 && Channel<MAX_NUM_BOARDS*NUM_CHANNELS) {
231 Channels.push_back(Channel);
232 }
233 }
234 }
235 // Channel identification
236 else {
237 Chan.Min = 0;
238 Chan.Max = MAX_NUM_BOARDS*NUM_CHANNELS-1;
239
240 if (!ConvertToRange(Parameter[n], Chan)) {
241 PrintMessage("Numeric conversion or out-of-range error for parameter %d, skipping channel\n", n);
242 continue;
243 }
244
245 for (int i=Chan.Min; i<=Chan.Max; i++) Channels.push_back(i);
246 }
247
248 // Loop over all given channels
249 for (unsigned int i=0; i<Channels.size(); i++) {
250 Channel = Channels[i];
251
252 // Should only information be printed?
253 if (Match(Parameter[n+1], "info")) {
254 PrintMessage("Channel %d ", Channel);
255 if (!Dev->Present[Channel]) PrintMessage(" is not present in crate\n");
256 else PrintMessage("is on board %d, board channel %d\n", Channel/32, Channel%32);
257
258 // Print pixel information
259 vector<unsigned int> List = PixMap->HV_to_Pixel(0, Channel/NUM_CHANNELS, Channel%NUM_CHANNELS);
260 PrintMessage("\n Default voltage: %.2f Pixel IDs: ", Channel < DefaultVoltage.size() ? DefaultVoltage[Channel] : 0);
261 for (unsigned int j=0; j<List.size(); j++) PrintMessage("%u ", List[j]);
262 if (List.empty()) PrintMessage("none");
263
264 // Print voltage and current
265 PrintMessage("\n Voltage setpoint: %.2f V (DAC %u) Current: %.2f uA ", Dev->GetVoltage(Channel), Dev->GetDAC(Channel), Dev->GetCurrent(Channel));
266
267 if (Dev->OC[Channel]) PrintMessage("(overcurrent)\n");
268 else PrintMessage("\n");
269
270 continue;
271 }
272
273 // Get current voltage on first change of a channel
274 if (Voltages.count(Channel) == 0) Voltages[Channel] = Dev->GetVoltage(Channel);
275
276 // Voltage change (number starts with + oder -) ignored if voltage is zero
277 if (Parameter[n+1][0]=='+' || Parameter[n+1][0]=='-') if (Voltages[Channel] == 0) continue;
278
279 // Should the default value be set?
280 if (Match(Parameter[n+1], "default")) {
281 if (Channel < DefaultVoltage.size()) Double = DefaultVoltage[Channel];
282 else Double = 0;
283 }
284
285 // Relative or absolute change?
286 if (Parameter[n+1][0]=='+' || Parameter[n+1][0]=='-') Voltages[Channel] += Double;
287 else Voltages[Channel] = Double;
288 } // Channels
289 } // Loop over command argument
290
291 // Ramp voltages and update DIM services
292 Errors += RampVoltages(Voltages);
293 Dev->UpdateDIM();
294
295 // Error message only if not yet too many errors
296 if (Errors > 0) {
297 if (Dev->ErrorCount > MAX_ERR_COUNT) return;
298 Message(ERROR, "%d errors occurred from SetChannels()", Errors);
299 }
300}
301
302//
303// Load bias settings from file
304//
305void User::cmd_load() {
306
307 char Buffer[MAX_COM_SIZE];
308 int Errors = 0;
309 unsigned int Channel;
310 double Value;
311 FILE *File;
312 map<unsigned int, double> Voltages;
313
314 // Open file
315 if ((File=fopen(Parameter[1].c_str(), "r")) == NULL) {
316 PrintMessage("Error: Could not open file '%s' (%s)\n", Parameter[1].c_str(), strerror(errno));
317 return;
318 }
319
320 // Scan through file line by line
321 while (fgets(Buffer, sizeof(Buffer), File) != NULL) if (Match(Dev->Name, Buffer)) {
322 PrintMessage("Found bias settings for crate %s\n\r", Dev->Name);
323
324 Voltages.clear();
325 Channel = 0;
326 while (fscanf(File, "%lf", &Value)==1 && Channel<MAX_NUM_BOARDS*NUM_CHANNELS) {
327 Voltages[Channel++] = Value;
328 }
329
330 // Ramp channels
331 Errors += RampVoltages(Voltages);
332
333 // Update DIM service
334 Dev->UpdateDIM();
335
336 if (ferror(File) != 0) {
337 PrintMessage("Error reading DAC value from file, terminating. (%s)\n",strerror(errno));
338 return;
339 }
340 else PrintMessage("\nFinished updating board\n");
341 } // if()
342
343 if (Errors != 0) PrintMessage("Warning: %d error(s) occurred\n", Errors);
344 if (fclose(File) != 0) PrintMessage("Error: Could not close file '%s'\n", Parameter[1].c_str());
345}
346
347//
348// Reset crate
349//
350void User::cmd_reset() {
351
352 if (Dev->SystemReset()) PrintMessage("System reset of crate\n");
353 else PrintMessage("Error: Could not reset crate\n");
354}
355
356//
357// Read channel
358//
359void User::cmd_gs() {
360
361 double Voltage;
362
363 if (!ConvertToDouble(Parameter[1], &Voltage)) {
364 PrintMessage("Error: Wrong number format\n");
365 return;
366 }
367
368 if (!Dev->GlobalSet(Voltage)) {
369 PrintMessage("Error: Could not global set crate\n");
370 }
371}
372
373//
374// Save bias settings of all boards
375//
376void User::cmd_save() {
377
378 FILE *File;
379 time_t Time = time(NULL);
380
381 if ((File = fopen(Parameter[1].c_str(), "w")) == NULL) {
382 PrintMessage("Error: Could not open file '%s' (%s)\n", Parameter[1].c_str(), strerror(errno));
383 return;
384 }
385
386 fprintf(File,"********** Bias settings of %s **********\n\n", ctime(&Time));
387 fprintf(File, "%s\n\n", Dev->Name);
388
389 for (unsigned int j=0; j<MAX_NUM_BOARDS*NUM_CHANNELS; j++) fprintf(File,"%.3f ", Dev->GetVoltage(j));
390 fprintf(File, "\n");
391
392 if (fclose(File) != 0) {
393 PrintMessage("Error: Could not close file '%s' (%s)\n", Parameter[1].c_str(), strerror(errno));
394 }
395}
396
397//
398// Set operation mode
399//
400void User::cmd_mode() {
401
402 if (Match(Parameter[1], "static")) Mode = mode_static;
403 else {
404 Mode = mode_dynamic;
405 Dev->SetRefCurrent();
406 }
407}
408
409//
410// Calibrate current measurement
411//
412void User::cmd_calib() {
413
414 map<unsigned int, double> Voltages, Initial, Current[2];
415 int Errors, Num;
416 double Volt[2];
417
418 // Clear current calibration values?
419 if (Match(Parameter[1], "invalidate")) {
420 PrintMessage("Current calibration invalidated\n");
421 R.assign(MAX_NUM_BOARDS*NUM_CHANNELS, numeric_limits<double>::infinity());
422 I0.assign(MAX_NUM_BOARDS*NUM_CHANNELS, 0);
423 return;
424 }
425
426 // Check number of parameters and convert
427 if (Parameter.size() != 4) {
428 PrintMessage("Error: Number of parameters incorrect\n");
429 return;
430 }
431
432 if (!ConvertToDouble(Parameter[1], &Volt[0]) || !ConvertToDouble(Parameter[2], &Volt[1])) {
433 PrintMessage("Error: Wrong number format for voltages\n");
434 return;
435 }
436
437 if (!ConvertToInt(Parameter[3], &Num)) {
438 PrintMessage("Error: Wrong number format for number of iterations\n");
439 return;
440 }
441
442 // Check if infinity can be represented for double
443 if (!numeric_limits<double>::has_infinity) {
444 PrintMessage("Cannot perform calibration, double cannot represent infinity\n");
445 return;
446 }
447
448 // Save initial voltages
449 for (unsigned int i=0; i<MAX_NUM_BOARDS*NUM_CHANNELS; i++) Initial[i] = Dev->GetVoltage(i);
450
451 // Make current measurements at given voltages
452 for (unsigned int Round=0; Round<2; Round++) {
453 // Set voltage
454 for (unsigned int i=0; i<MAX_NUM_BOARDS*NUM_CHANNELS; i++) Voltages[i] = Volt[Round];
455
456 if ((Errors = RampVoltages(Voltages)) != 0) {
457 PrintMessage("%d errors occurred while ramping to %.2f V\n", Errors, Volt[Round]);
458 return;
459 }
460 else PrintMessage("Ramped all channels to %.2f V\n", Volt[Round]);
461
462 // Read currenty repeatably
463 for (int Count=0; Count<Num; Count++) {
464 if (Count % 20 == 0) PrintMessage("Reading current iteration %d \r", Count);
465 if (!Dev->ReadAll()) {
466 PrintMessage("\nError from ReadAll()\n");
467 return;
468 }
469 for (unsigned int i=0; i<MAX_NUM_BOARDS*NUM_CHANNELS; i++) {
470 Current[Round][i] += Dev->GetCurrent(i)/Num;
471 }
472 }
473 } // for()
474
475
476 // Set initial voltages
477 if ((Errors = RampVoltages(Initial)) != 0) {
478 PrintMessage("%d errors occurred while ramping back to inital voltages\n", Errors);
479 return;
480 }
481 else PrintMessage("Ramped all channels back to inital voltages\n");
482
483 // Calculate calibration constants (R in MOhm)
484 for (unsigned int i=0; i<MAX_NUM_BOARDS*NUM_CHANNELS; i++) {
485 R[i] = (Volt[1] - Volt[0]) / (Current[1][i]-Current[0][i]);
486 I0[i] = Current[0][i] - Volt[0]/R[i];
487 }
488}
489
490//
491// Print status
492//
493void User::cmd_status() {
494
495 enum {M_V,M_DAC,M_I,M_R,M_I0,M_notset} M = M_notset;
496
497 // Overview information
498 PrintMessage("Update delay: %2d sec Time out: %.2f sec Minium reset delay: %u sec\n",
499 min(atoi(GetConfig("UpdatePeriod").c_str()), 1), atof(GetConfig("TimeOut").c_str()),
500 atoi(GetConfig("MinResetPeriod").c_str()));
501 PrintMessage("Voltage limit: %.2f V Ramp speed: %.2f V/10 ms\n",
502 atof(GetConfig("VoltageLimit").c_str()), atof(GetConfig("RampSpeed").c_str()));
503
504 if (Dev == NULL) return;
505
506 // Details
507 PrintMessage("\nCRATE %s Wrap counter: %s (%d) Reset: %s Error count: %d %s\n ",
508 Dev->Name, Dev->WrapOK ? "ok":"error", Dev->WrapCount,
509 Dev->ResetHit ? "yes" : "no", Dev->ErrorCount, Dev->Disabled ? "(DISABLED)":"");
510
511 // Read all channels
512 if (!Dev->ReadAll()) {
513 PrintMessage("Could not update status, ReadAll() failed\n");
514 return;
515 }
516
517 // Voltage or current list
518 if (Match(Parameter[0], "voltage")) {
519 if (Parameter.size() == 1) M = M_V;
520 else M = M_DAC;
521 }
522 else if (Match(Parameter[0], "current")) M = M_I;
523 else if (Parameter.size() == 2) {
524 if (Match(Parameter[1], "R")) M = M_R;
525 if (Match(Parameter[1], "I0")) M = M_I0;
526 }
527
528 if (M == M_notset) return;
529 if (M == M_V) PrintMessage("Channel voltages (in V)");
530 if (M == M_DAC) PrintMessage("Channel voltages (in DAC values)");
531 if (M == M_R) PrintMessage("Channel internal resistance (in kOhm)");
532 if (M == M_I0) PrintMessage("Channel current offset (in uA)");
533 if (M == M_I) PrintMessage("Channel currents (in uA)");
534
535 for (unsigned int j=0; j<MAX_NUM_BOARDS*NUM_CHANNELS; j++) {
536 if (j%12 == 0) PrintMessage("\n%3.1d: ", j);
537 if (!Dev->Present[j]) PrintMessage(" -");
538 else if (M == M_V) PrintMessage("%#5.2f", Dev->GetVoltage(j));
539 else if (M == M_DAC) PrintMessage("%5d", Dev->GetDAC(j));
540 else if (M == M_R) PrintMessage("%#5.2f", R[j]*1000);
541 else if (M == M_I0) PrintMessage("%#5.2f", I0[j]);
542 else if (M == M_I) PrintMessage("%#5.1f", Dev->GetCurrent(j) - Dev->GetVoltage(j)/R[j] - I0[j]);
543
544 // Print overcurrent marker
545 PrintMessage("%s ", Dev->OC[j] ? "*":" ");
546 }
547 PrintMessage("\n");
548}
549
550//
551// Exit program (Signal makes readline return and sets ExitRequest)
552//
553void User::cmd_exit() {
554
555 pthread_kill(MainThread, SIGTERM);
556}
557
558//
559// Execute shell command
560//
561void User::cmd_shell() {
562
563 if (system(Parameter[1].c_str()) == -1) PrintMessage("Error with system() call\n");
564}
565
566
567//
568// Print message to screen and to DIM text service
569//
570void User::PrintMessage(const char *Format, ...) {
571
572 static char Error[] = "vasprintf() failed in PrintMessage()";
573 char *Text;
574
575 // Evaluate arguments
576 va_list ArgumentPointer;
577 va_start(ArgumentPointer, Format);
578 if (vasprintf(&Text, Format, ArgumentPointer) == -1) Text = Error;
579 va_end(ArgumentPointer);
580
581 if (strlen(Text) == 0) return;
582
583 // Print to console
584 printf("%s", Text);
585 fflush(stdout);
586 if (Text[strlen(Text)-1] == '\n') rl_on_new_line(); // New prompt
587
588 // Send to DIM text service
589 ConsoleOut->updateService(Text);
590
591 // Free old text
592 if (ConsoleText != Error) free(ConsoleText);
593 ConsoleText = Text;
594}
595
596
597// Ramp to new voltage with given maximum step
598unsigned int User::RampVoltages(map<unsigned int, double> Voltages) {
599
600 map<unsigned int, double> Target;
601 int Errors = 0;
602 double V, Lim, MaxDiff = atof(GetConfig("RampSpeed").c_str());
603
604 while (!Voltages.empty() && Errors < MAX_ERR_COUNT) {
605 // Voltage limit evaluate here in case of asynchronous update in config file
606 Lim = atof(GetConfig("VoltageLimit").c_str());
607
608 // Remove channels already at target or at voltage limit
609 for (map<unsigned int, double>::iterator it = Voltages.begin(); it != Voltages.end(); ++it) {
610 // Channel at target?
611 if (fabs(Dev->GetVoltage(it->first)-it->second) < 0.001) Voltages.erase(it);
612 // Channel at voltage limit?
613 if (it->second > Lim && Dev->GetVoltage(it->first) == Lim) Voltages.erase(it);
614 if (it->second < 0 && Dev->GetVoltage(it->first) == 0) Voltages.erase(it);
615 }
616
617 // Limit voltage changes to MaxDiff
618 Target = Voltages;
619 for (map<unsigned int, double>::iterator it = Target.begin(); it != Target.end(); ++it) {
620 V = Dev->GetVoltage(it->first);
621 // Ramp up
622 if ((V < it->second) && (V + MaxDiff < it->second)) it->second = V + MaxDiff;
623 // Ramp down
624 if ((V > it->second) && (V - MaxDiff > it->second)) it->second = V - MaxDiff;
625 }
626
627 // Set channels to next target and wait 10 ms
628 if (!Dev->SetChannels(Target)) Errors++;
629 usleep(10000);
630 }
631
632 return Errors;
633}
634
635
636//
637// Check status
638//
639void User::Monitor() {
640
641 int Ret;
642
643 // End if no crate available
644 if (Dev == NULL) return;
645
646 while (!ExitRequest) {
647 // Wait (this is the only allowed cancelation point)
648 if ((Ret=pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL)) != 0) {
649 Message(FATAL, "pthread_setcancelstate() failed (%s)", strerror(Ret));
650 }
651 sleep(min(atoi(GetConfig("UpdatePeriod").c_str()), 1));
652 if ((Ret=pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL)) != 0) {
653 Message(FATAL, "pthread_setcancelstate() failed (%s)", strerror(Ret));
654 }
655
656 // Check crate
657 if (Dev->Disabled) continue;
658
659 // Read all channels
660 if (!Dev->ReadAll()) {
661 Message(ERROR, "Monitor thread could not read status, ReadAll() failed\n");
662 continue;
663 }
664
665 // Check if crate push button was hit
666 if (Dev->ResetHit) {
667 Message(INFO, "Manual reset of crate, setting voltages to zero and issuing system reset");
668 if (!Dev->GlobalSet(0)) Message(ERROR, "Global set to zero voltage of crate failed");
669 if (!Dev->SystemReset()) Message(ERROR, "System reset of crate failed");
670 }
671
672 // Check for overcurrent and set voltage to zero if occurred
673 map<unsigned int, double> Voltages;
674
675 for (unsigned int j=0; j<MAX_NUM_BOARDS*NUM_CHANNELS; j++) if (Dev->OC[j]) Voltages[j] = 0;
676 if (!Voltages.empty()) {
677 if (!Dev->SetChannels(Voltages)) Message(ERROR, "Error setting voltage to zero for channels with overcurrent");
678 Dev->UpdateDIM();
679 }
680
681 if (Mode == mode_dynamic) Dev->AdaptVoltages();
682 } // while
683}
684
685// Call monitor loop inside class
686void User::LaunchMonitor(User *m) {
687
688 m->Monitor();
689}
690
691
692//
693// Check if two strings match (min 1 character must match)
694//
695bool User::Match(string str, const char *cmd) {
696
697 return strncasecmp(str.c_str(),cmd,strlen(str.c_str())==0 ? 1:strlen(str.c_str())) ? false:true;
698}
699
700//
701// Conversion function from string to double or int
702//
703// Return false if conversion did not stop on whitespace or EOL character
704bool User::ConvertToDouble(string String, double *Result) {
705
706 char *EndPointer;
707
708 *Result = strtod(String.c_str(), &EndPointer);
709 if(!isspace(*EndPointer) && *EndPointer!='\0') return false;
710 return true;
711}
712
713bool User::ConvertToInt(string String, int *Result) {
714
715 char *EndPointer;
716
717 *Result = (int) strtol(String.c_str(), &EndPointer, 0);
718 if(!isspace(*EndPointer) && *EndPointer!='\0') return false;
719 return true;
720}
721
722//
723// Interprets a range
724//
725bool User::ConvertToRange(string String, struct User::Range &R) {
726
727 int N=0, M=0; // Init to avoid compiler warning
728
729 // Full range
730 if (Match(String, "all")) return true;
731
732 // Single number
733 if (ConvertToInt(String, &N)) {
734 if (N>= R.Min && N<=R.Max) {
735 R.Max = R.Min = N;
736 return true;
737 }
738 return false;
739 }
740
741 // Range a-b
742 vector<string> V = EvidenceServer::Tokenize(String, "-");
743 if (V.size()==2 && ConvertToInt(V[0], &N) && ConvertToInt(V[1], &M) && N>=R.Min && M<=R.Max) {
744 R.Min = N;
745 R.Max = M;
746 return true;
747 }
748
749 return false;
750}
Note: See TracBrowser for help on using the repository browser.