xosview  1.23
About: xosview is an X Windows based system monitor (cpu, memory, swap and network usage; interrupt and serial activities; load average).
  Fossies Dox: xosview-1.23.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

btrymeter.cc
Go to the documentation of this file.
1 //
2 // Copyright (c) 1997, 2006 by Mike Romberg ( mike.romberg@noaa.gov )
3 //
4 // This file may be distributed under terms of the GPL
5 //
6 
7 #include "btrymeter.h"
8 #include <stdlib.h>
9 #include <stdio.h>
10 #include <sys/types.h>
11 #include <sys/stat.h>
12 #include <unistd.h>
13 #include <fcntl.h>
14 #include <dirent.h>
15 #include <string.h>
16 #include <errno.h>
17 #include <fstream>
18 #include <string>
19 #include <iostream>
20 #include <sstream>
21 
22 static const char APMFILENAME[] = "/proc/apm";
23 static const char ACPIBATTERYDIR[] = "/proc/acpi/battery";
24 static const char SYSPOWERDIR[] = "/sys/class/power_supply";
25 
26 
28  : FieldMeter( parent, 2, "BTRY", "CHRG/USED", 1, 1, 0 ){
29 
30  // find out ONCE whether to use ACPI, APM or sysfs
31  use_acpi = use_apm = use_syspower = false;
32  if ( has_apm() ) {
33  use_apm=true; use_acpi=false; use_syspower=false;
34  }
35  if ( has_acpi() ) {
36  use_acpi=true; use_apm=false; use_syspower=false;
37  }
38  if ( has_syspower() ) {
39  use_acpi=false; use_apm=false; use_syspower=true;
40  }
41 
42  old_apm_battery_state = apm_battery_state = 0xFF;
43  old_acpi_charge_state = acpi_charge_state = -2;
44 
45 }
46 
47 BtryMeter::~BtryMeter( void ){
48 }
49 
50 // determine if any usable source of battery information
51 bool BtryMeter::has_source( void ){
52  return has_apm() || has_acpi() || has_syspower();
53 }
54 
55 // determine if /proc/apm exists and is readable
56 bool BtryMeter::has_apm( void ){
57 
58  struct stat stbuf;
59  int fd;
60 
61  if ( stat(APMFILENAME, &stbuf) != 0 ) {
62  XOSDEBUG("APM: stat failed: %d - not APM ?\n",errno);
63  return false;
64  }
65  if ( S_ISREG(stbuf.st_mode) ) {
66  XOSDEBUG("apm: %s exists and is a file\n",APMFILENAME);
67  } else {
68  XOSDEBUG("no APM file\n");
69  return false;
70  }
71  fd=open(APMFILENAME,O_RDONLY);
72  if ( fd < 0 ) {
73  XOSDEBUG("open failed on %s: with errno=%d\n",APMFILENAME,errno);
74  return false;
75  } else
76  close(fd); // good enough ...
77 
78  // all our tests succeeded - apm seems usable
79  return true;
80 
81 }
82 
83 // determine if /proc/acpi/battery exists and is a DIR
84 // (XXX: too lazy - no tests for actual readability is done)
85 bool BtryMeter::has_acpi( void ){
86 
87  struct stat stbuf;
88 
89  if ( stat(ACPIBATTERYDIR, &stbuf) != 0 ) {
90  XOSDEBUG("has_acpi(): stat failed: %d\n",errno);
91  return false;
92  }
93  if ( S_ISDIR(stbuf.st_mode) ) {
94  XOSDEBUG("%s exists and is a DIR.\n", ACPIBATTERYDIR);
95  } else {
96  XOSDEBUG("no ACPI dir\n");
97  return false;
98  }
99 
100  // declare ACPI as usable
101  return true;
102 
103 }
104 
105 /*
106  * Look for something resembling a battery in /sys/class/power_supply
107  */
108 
110  bool found;
111  DIR *dir;
112  struct dirent *dp;
113  struct stat buf;
114  char dirname[80], f[80];
115  std::ifstream type;
116  std::string t;
117 
118  dir = opendir(SYSPOWERDIR);
119  if (dir == NULL)
120  return false;
121 
122  found = false;
123  while (!found && (dp = readdir(dir))) {
124  if (!strncmp(dp->d_name, ".", 1))
125  continue;
126  if (!strncmp(dp->d_name, "..", 2))
127  continue;
128  snprintf(dirname, 80, "%s/%s", SYSPOWERDIR, dp->d_name);
129  if (stat(dirname, &buf) == 0 && S_ISDIR(buf.st_mode)) {
130  snprintf(f, 80, "%s/%s", dirname, "/type");
131  type.open(f);
132  if (type.good()) {
133  type >> t;
134  if (strncmp(t.c_str(), "Battery", 7) == 0) {
135  found = true;
136  break;
137  }
138  }
139  type.close();
140  }
141  }
142  if (closedir(dir) != 0)
143  abort();
144 
145  return found;
146 }
147 
148 void BtryMeter::checkResources( void ){
150 
151  setfieldcolor( 0, parent_->getResource( "batteryLeftColor" ) );
152  setfieldcolor( 1, parent_->getResource( "batteryUsedColor" ) );
153 
154  priority_ = atoi (parent_->getResource( "batteryPriority" ) );
155  SetUsedFormat(parent_->getResource( "batteryUsedFormat" ) );
156 }
157 
159  switch ( apm_battery_state ) {
160  case 0: /* high (e.g. over 25% on my box) */
161  XOSDEBUG("battery_status HIGH\n");
162  setfieldcolor( 0, parent_->getResource("batteryLeftColor"));
163  legend("High AVAIL/USED");
164  break;
165 
166  case 1: /* low ( e.g. under 25% on my box ) */
167  XOSDEBUG("battery_status LOW\n");
168  setfieldcolor( 0, parent_->getResource("batteryLowColor"));
169  legend("LOW avail/used");
170  break;
171 
172  case 2: /* critical ( less than 5% on my box ) */
173  XOSDEBUG("battery_status CRITICAL\n");
174  setfieldcolor( 0, parent_->getResource("batteryCritColor"));
175  legend( "Crit LOW/Used");
176  break;
177 
178  case 3: /* Charging */
179  XOSDEBUG("battery_status CHARGING\n");
180  setfieldcolor( 0, parent_->getResource("batteryChargeColor"));
181  legend( "AC/Charging");
182  break;
183 
184  case 4: /* selected batt not present */
185  /* no idea how this state ever could happen with APM */
186  XOSDEBUG("battery_status not present\n");
187  setfieldcolor( 0, parent_->getResource("batteryNoneColor"));
188  legend( "Not Present/N.A.");
189  break;
190 
191  case 255: /* unknown - do nothing - maybe not APM */
192  // on my system this state comes if you pull both batteries
193  // ( while on AC of course :-)) )
194  XOSDEBUG("apm battery_state not known\n");
195  setfieldcolor( 0, parent_->getResource("batteryNoneColor"));
196  legend( "Unknown/N.A.");
197  break;
198  }
199 }
200 
202  switch ( acpi_charge_state ) {
203  case 0: // charged
204  XOSDEBUG("battery_status CHARGED\n");
205  setfieldcolor( 0, parent_->getResource("batteryFullColor"));
206  legend( "CHRG/FULL");
207  break;
208 
209  case -1: // discharging
210  XOSDEBUG("battery_status DISCHARGING\n");
211  setfieldcolor( 0, parent_->getResource("batteryLeftColor"));
212  legend( "CHRG/USED");
213  break;
214 
215  case -2: // discharging - below alarm
216  XOSDEBUG("battery_status ALARM DISCHARGING\n");
217  setfieldcolor( 0, parent_->getResource("batteryCritColor"));
218  legend( "CHRG/USED");
219  break;
220 
221  case -3: // not present
222  XOSDEBUG("battery_status NOT PRESENT\n");
223  setfieldcolor( 0, parent_->getResource("batteryNoneColor"));
224  legend( "NONE/NONE");
225  break;
226 
227  case 1: // charging
228  XOSDEBUG("battery_status CHARGING\n");
229  setfieldcolor( 0, parent_->getResource("batteryChargeColor"));
230  legend( "CHRG/AC");
231  break;
232  }
233 }
234 
235 /*
236  * All redraws come from this function (not children)
237  */
238 
239 void BtryMeter::checkevent( void ){
240 
241  getpwrinfo();
242 
244  /* APM only changes if we have APM */
246  drawlegend();
247  drawfields(1);
248  return;
249  }
250 
253  drawlegend();
254  drawfields(1);
255  return;
256  }
257 
258  drawfields();
259 }
260 
261 
263 
264  if ( use_acpi || use_syspower ) {
265  getacpi_or_sys_info(); return;
266  }
267  if ( use_apm ) {
268  getapminfo(); return;
269  }
270 
271  // We can hit this spot in any of two cases:
272  // - We have an ACPI system and the battery is removed
273  // - We have neither ACPI nor APM in the system
274  // We report an empty battery (i.e., we are running off AC power) instead of
275  // original behavior of just exiting the program.
276  // (Refer to Debian bug report #281565)
277  total_ = 100;
278  fields_[0] = 0;
279  fields_[1] = 100;
280  setUsed(fields_[0], total_);
281 }
282 
283 
285  std::ifstream loadinfo( APMFILENAME );
286 
287 /* just a tiny note here about APM states:
288  See: arch/i386/kernel/apm.c apm_get_info()
289 
290  Arguments, with symbols from linux/apm_bios.h. Information is
291  from the Get Power Status (0x0a) call unless otherwise noted.
292 
293  0) Linux driver version (this will change if format changes)
294  1) APM BIOS Version. Usually 1.0, 1.1 or 1.2.
295  2) APM flags from APM Installation Check (0x00):
296  bit 0: APM_16_BIT_SUPPORT
297  bit 1: APM_32_BIT_SUPPORT
298  bit 2: APM_IDLE_SLOWS_CLOCK
299  bit 3: APM_BIOS_DISABLED
300  bit 4: APM_BIOS_DISENGAGED
301  3) AC line status
302  0x00: Off-line
303  0x01: On-line
304  0x02: On backup power (BIOS >= 1.1 only)
305  0xff: Unknown
306  4) Battery status
307  0x00: High
308  0x01: Low
309  0x02: Critical
310  0x03: Charging
311  0x04: Selected battery not present (BIOS >= 1.2 only)
312  0xff: Unknown
313  5) Battery flag
314  bit 0: High
315  bit 1: Low
316  bit 2: Critical
317  bit 3: Charging
318  bit 7: No system battery
319  0xff: Unknown
320  6) Remaining battery life (percentage of charge):
321  0-100: valid
322  -1: Unknown
323  7) Remaining battery life (time units):
324  Number of remaining minutes or seconds
325  -1: Unknown
326  8) min = minutes; sec = seconds
327 */
328 
329  if ( !loadinfo.good() ){
330  XOSDEBUG("Can not open file : %s\n", APMFILENAME);
331  return false;
332  }
333 
334  int battery_status=0xff; // assume unknown as default
335  char buff[256];
336 
337  loadinfo >> buff >> buff >> buff >> buff >> std::hex >> battery_status >> buff >> fields_[0];
338 
339 
340  // XOSDEBUG("apm battery_status is: %d\n",battery_status);
341 
342  // save previous state
343  // if there was no state-change - the gui won't do full redraw
344 
346  apm_battery_state=battery_status;
347 
348  // If the battery status is reported as a negative number, it means we are
349  // running on AC power and no battery status is available - Report it as
350  // completely empty (0). (Refer to Debian bug report #281565)
351  if (fields_[0] < 0)
352  fields_[0] = 0;
353 
354  total_ = 100;
355 
356  if ( apm_battery_state != 0xFF ) {
357 
358  fields_[1] = total_ - fields_[0];
359 
360  } else { // prevent setting it to '-1' if no batt
361 
362  fields_[0] = 0; fields_[1] = total_;
363  }
364 
365  setUsed (fields_[0], total_);
366 
367  return true;
368 }
369 
370 // ACPI provides a lot of info,
371 // but munging it into something usefull is ugly
372 // esp. as you can have more than one battery ...
373 
375 
376  DIR *dir = NULL;
377  std::string abs_battery_dir;
378 
379  if (use_acpi) {
380  abs_battery_dir = ACPIBATTERYDIR;
381  } else {
382  abs_battery_dir = SYSPOWERDIR;
383  }
384 
385  dir = opendir(abs_battery_dir.c_str());
386  if (dir==NULL) {
387  XOSDEBUG("ACPI/SYS: Cannot open directory : %s\n", abs_battery_dir.c_str());
388  return false;
389  }
390 
391  bool found = false; // whether we found at least ONE battery
392 
393  // reset all sums
394  acpi_sum_cap=0;
395  acpi_sum_remain=0;
396  acpi_sum_rate=0;
397  acpi_sum_alarm=0;
398 
399  // save old state
401 
402  acpi_charge_state=0; // assume charged
403 
404  for (struct dirent *dirent; (dirent = readdir(dir)) != NULL; ) {
405  if (strncmp(dirent->d_name, ".", 1) == 0
406  || strncmp(dirent->d_name, "..", 2) == 0)
407  continue;
408 
409  std::string abs_battery_name = abs_battery_dir + "/" + dirent->d_name;
410 
411  XOSDEBUG("ACPI/SYS Batt: %s\n", dirent->d_name);
412 
413  // still can happen that it's not present:
414  if ( (use_acpi &&
415  (acpi_battery_present(abs_battery_name + "/info" )) &&
416  (acpi_parse_battery(abs_battery_name))) ||
417  (use_syspower &&
418  (sys_battery_present(abs_battery_name + "/present" )) &&
419  (sys_parse_battery(abs_battery_name))) ) {
420 
421  // sum up:
422 
423  // clip values to get realistic on full-charged batteries
424 
427 
432 
433  // sum up charge state ...
434  // works only w. signed formats
436 
437  found = true; // found at least one
438  }
439  }
440 
441  closedir(dir);
442 
443  total_ = 100;
444 
445  // convert into percent vals
446  // XOSDEBUG("acpi: total max=%d, remain=%d\n",acpi_sum_cap,acpi_sum_remain);
447 
448  // below alarm ?
451 
452  // if NONE of the batts is present:
453  if ( found ) {
454  fields_[0] = (float)acpi_sum_remain/(float)acpi_sum_cap*100.0;
455  } else {
456  // none of the batts is present
457  // (just pull out both while on AC)
458  fields_[0] = 0;
460  }
461 
462  fields_[1] = total_ - fields_[0];
463 
464  setUsed (fields_[0], total_);
465 
466  return true;
467 
468 }
469 
470 // present yes/no can change anytime !
471 // by adding/removing a battery
472 bool BtryMeter::acpi_battery_present(const std::string& filename)
473 {
474  std::ifstream loadinfo( filename.c_str() );
475 
476  std::string argname;
477  std::string argval;
478 
479  while ( !loadinfo.eof() ) {
480 
481  argname.clear(); argval.clear();
482  loadinfo >> argname >> argval;
483 
484  XOSDEBUG("batt ?: a=\"%s\" v=\"%s\"\n",argname.c_str(),argval.c_str() );
485  if ( argname == "present:" )
486  if ( argval == "yes" )
487  return true;
488  }
489  XOSDEBUG("batt %s not present\n",filename.c_str() );
490  return false;
491 }
492 
493 bool BtryMeter::acpi_parse_battery(const std::string& dirname)
494 {
495  // actually there are THREE files to check:
496  // 'alarm', 'info' and 'state'
497 
498  std::string filename;
499  std::ifstream loadinfo;
500  std::istringstream inp_strm;
501  std::string inp_line;
502 
503  std::string argname;
504  std::string argval;
505 
506  filename = dirname + "/alarm";
507  loadinfo.open(filename.c_str() );
508  while ( loadinfo.good() ) {
509  std::getline(loadinfo,inp_line);
510  inp_strm.str(inp_line.c_str() );
511  argname.clear(); argval.clear();
512  inp_strm >> argname >> argval;
513  XOSDEBUG("alarm: a=\"%s\" v=\"%s\"\n",argname.c_str(),argval.c_str() );
514 
515  if ( argname == "alarm:" ) {
516  battery.alarm = atoi(argval.c_str());
517  break;
518  }
519  }
520  loadinfo.close(); loadinfo.clear();
521 
522  filename = dirname + "/info";
523  loadinfo.open(filename.c_str() );
524  while ( loadinfo.good() ) {
525 
526  argname.clear();
527  std::getline(loadinfo,argname,':');
528 
529  argval.clear();
530  std::getline(loadinfo,argval);
531 
532  XOSDEBUG("info: a=\"%s\" v=\"%s\"\n",argname.c_str(),argval.c_str() );
533 
534  if ( argname == "design capacity" ) {
535  battery.design_capacity=atoi(argval.c_str() );
536  }
537  if ( argname == "last full capacity" ) {
538  battery.last_full_capacity=atoi(argval.c_str() );
539  }
540  if ( argname == "last full capacity" ) {
541  battery.last_full_capacity=atoi(argval.c_str() );
542  }
543 
544  }
545  loadinfo.close(); loadinfo.clear(); // clear eof-bit
546 
547  filename = dirname + "/state";
548  loadinfo.open(filename.c_str() );
549  while ( loadinfo.good() ) {
550 
551  // argname can contain spaces
552  argname.clear();
553  std::getline(loadinfo,argname,':');
554 
555  // argval should NOT contain blanks
556  inp_line.clear();
557  std::getline(loadinfo,inp_line);
558  inp_strm.clear(); inp_strm.seekg(0);
559  inp_strm.str(inp_line.c_str() );
560 
561  argval.clear();
562  inp_strm >> argval; // this ignores leading spaces
563 
564  XOSDEBUG("state: a=\"%s\" v=\"%s\"\n",argname.c_str(),argval.c_str() );
565 
566  if ( argname == "charging state" ) {
567  if ( argval == "charged" )
569  if ( argval == "discharging" )
571  if ( argval == "charging" )
573  }
574 
575  if ( argname == "last full capacity" ) {
576  battery.last_full_capacity=atoi(argval.c_str() );
577  }
578  if ( argname == "last full capacity" ) {
579  battery.last_full_capacity=atoi(argval.c_str() );
580  }
581  if ( argname == "remaining capacity" ) {
582  battery.remaining_capacity=atoi(argval.c_str() );
583  }
584 
585  }
586 
587 return true;
588 }
589 
590 // present yes/no can change anytime !
591 // by adding/removing a battery
592 bool BtryMeter::sys_battery_present(const std::string& filename)
593 {
594  std::ifstream loadinfo( filename.c_str() );
595  std::string value;
596 
597  while ( loadinfo.good() ) {
598 
599  value.clear();
600  loadinfo >> value;
601 
602  if (value == "1")
603  return true;
604  }
605  XOSDEBUG("batt %s not present\n",filename.c_str() );
606  return false;
607 }
608 
609 bool BtryMeter::sys_parse_battery(const std::string& dirname)
610 {
611  std::string filename;
612  std::ifstream loadinfo;
613  std::string value;
614  struct stat stbuf;
615 
616  filename = dirname + "/alarm";
617  loadinfo.open(filename.c_str() );
618  while ( loadinfo.good() ) {
619  value.clear();
620  loadinfo >> value;
621  XOSDEBUG("alarm (%s): v=\"%s\"\n", filename.c_str(), value.c_str() );
622  battery.alarm = atoi(value.c_str());
623  break;
624  }
625  loadinfo.close();
626  loadinfo.clear();
627 
628  filename = dirname + "/energy_full_design";
629  if (stat(filename.c_str(),&stbuf)!=0)
630  filename=dirname+"/charge_full_design";
631  loadinfo.open(filename.c_str() );
632  while ( loadinfo.good() ) {
633  value.clear();
634  loadinfo >> value;
635  XOSDEBUG("design_capacity (%s): v=\"%s\"\n", filename.c_str(), value.c_str() );
636  battery.design_capacity = atoi(value.c_str());
637  break;
638  }
639  loadinfo.close();
640  loadinfo.clear();
641 
642  filename = dirname + "/energy_full";
643  if (stat(filename.c_str(),&stbuf)!=0)
644  filename=dirname+"/charge_full";
645  loadinfo.open(filename.c_str() );
646  if (!loadinfo.good()) {
647  loadinfo.close();
648  loadinfo.clear();
649  filename=dirname+"/charge_full_design";
650  loadinfo.open(filename.c_str());
651  }
652 
653  while ( loadinfo.good() ) {
654  value.clear();
655  loadinfo >> value;
656  XOSDEBUG("last_full_capacity (%s): v=\"%s\"\n", filename.c_str(), value.c_str() );
657  battery.last_full_capacity = atoi(value.c_str());
658  break;
659  }
660  loadinfo.close();
661  loadinfo.clear();
662 
663  filename = dirname + "/energy_now";
664  if (stat(filename.c_str(),&stbuf)!=0)
665  filename=dirname+"/charge_now";
666  loadinfo.open(filename.c_str() );
667  while ( loadinfo.good() ) {
668  value.clear();
669  loadinfo >> value;
670  XOSDEBUG("remaining_capacity (%s): v=\"%s\"\n", filename.c_str(), value.c_str() );
671  battery.remaining_capacity = atoi(value.c_str());
672  break;
673  }
674  loadinfo.close();
675  loadinfo.clear();
676 
677  filename = dirname + "/status";
678  loadinfo.open(filename.c_str() );
679  while ( loadinfo.good() ) {
680  value.clear();
681  loadinfo >> value;
682  XOSDEBUG("status (%s): v=\"%s\"\n", filename.c_str(), value.c_str() );
683 
685  if ( value == "Discharging" )
687  if ( value == "Charging" )
689  break;
690  }
691  loadinfo.close();
692  loadinfo.clear();
693 
694  return true;
695 }
int acpi_sum_cap
Definition: btrymeter.h:68
~BtryMeter(void)
Definition: btrymeter.cc:20
int acpi_sum_remain
Definition: btrymeter.h:69
int old_acpi_charge_state
Definition: btrymeter.h:66
static bool has_syspower(void)
Definition: btrymeter.cc:109
static bool has_source(void)
Definition: btrymeter.cc:51
BtryMeter(XOSView *parent)
Definition: btrymeter.cc:15
static bool has_acpi(void)
Definition: btrymeter.cc:85
void handle_acpi_state(void)
Definition: btrymeter.cc:201
void checkevent(void)
Definition: btrymeter.cc:41
bool sys_parse_battery(const std::string &filename)
Definition: btrymeter.cc:609
int apm_battery_state
Definition: btrymeter.h:62
bool getacpi_or_sys_info(void)
Definition: btrymeter.cc:374
acpi_batt battery
Definition: btrymeter.h:35
void handle_apm_state(void)
Definition: btrymeter.cc:158
bool getapminfo(void)
Definition: btrymeter.cc:284
int acpi_charge_state
Definition: btrymeter.h:65
int acpi_sum_rate
Definition: btrymeter.h:70
bool acpi_battery_present(const std::string &filename)
Definition: btrymeter.cc:472
bool sys_battery_present(const std::string &filename)
Definition: btrymeter.cc:592
bool use_acpi
Definition: btrymeter.h:47
void getpwrinfo(void)
Definition: btrymeter.cc:262
int old_apm_battery_state
Definition: btrymeter.h:63
static bool has_apm(void)
Definition: btrymeter.cc:56
bool acpi_parse_battery(const std::string &filename)
Definition: btrymeter.cc:493
bool use_apm
Definition: btrymeter.h:46
void checkResources(void)
Definition: btrymeter.cc:23
bool use_syspower
Definition: btrymeter.h:48
int acpi_sum_alarm
Definition: btrymeter.h:71
double total_
Definition: fieldmeter.h:41
virtual void checkResources(void)
Definition: fieldmeter.cc:54
void setfieldcolor(int field, const char *color)
Definition: fieldmeter.cc:108
void drawlegend(void)
Definition: fieldmeter.cc:136
void setUsed(double val, double total)
Definition: fieldmeter.cc:76
virtual void drawfields(int mandatory=0)
Definition: fieldmeter.cc:221
double * fields_
Definition: fieldmeter.h:40
void SetUsedFormat(const char *const str)
Definition: fieldmeter.cc:60
int priority_
Definition: meter.h:54
const char * legend(void)
Definition: meter.h:27
XOSView * parent_
Definition: meter.h:52
const char * getResource(const char *name)
Definition: xwin.cc:362
static const char SYSPOWERDIR[]
Definition: btrymeter.cc:24
static const char ACPIBATTERYDIR[]
Definition: btrymeter.cc:23
static const char APMFILENAME[]
Definition: btrymeter.cc:22
#define XOSDEBUG(...)
Definition: xosview.h:84