tags 527810 +patch
thanks

I've implemented support for parsing the files under
/sys/class/power_supply. Works for me here on 2.6.32-3-amd64.

-- 
Steve McIntyre, Cambridge, UK.                                [email protected]
"Because heaters aren't purple!" -- Catherine Pitt
Add support for new-style Linux /sys/class/power battery stats
Steve McIntyre <[email protected]>
diff -uNrBb a/linux/btrymeter.cc b/linux/btrymeter.cc
--- a/linux/btrymeter.cc	2006-02-18 05:20:19.000000000 +0000
+++ b/linux/btrymeter.cc	2010-03-21 01:47:12.000000000 +0000
@@ -27,17 +27,21 @@
 
 static const char APMFILENAME[] = "/proc/apm";
 static const char ACPIBATTERYDIR[] = "/proc/acpi/battery";
+static const char SYSPOWERDIR[] = "/sys/class/power_supply";
 
 BtryMeter::BtryMeter( XOSView *parent )
   : FieldMeter( parent, 2, "BTRY", "AVAIL/USED", 1, 1, 0 ){
 
-  // find out ONCE whether to use ACPI or APM
-  use_acpi = use_apm = false;
+  // find out ONCE whether to use ACPI, APM or sysfs
+  use_acpi = use_apm = use_syspower = false;
   if ( has_apm() ) {
-	use_apm=true; use_acpi=false;
+      use_apm=true; use_acpi=false; use_syspower=false;
   }
   if ( has_acpi() ) {
-	use_acpi=true; use_apm=false;
+      use_acpi=true; use_apm=false; use_syspower=false;
+  }
+  if ( has_syspower() ) {
+      use_acpi=false; use_apm=false; use_syspower=true;
   }
 
   old_apm_battery_state = apm_battery_state = 0xFF;
@@ -87,7 +90,7 @@
      return false;
   }
   if ( S_ISDIR(stbuf.st_mode) ) {
-     XOSDEBUG("exists and is a DIR.\n");
+     XOSDEBUG("%s exists and is a DIR.\n", ACPIBATTERYDIR);
   } else {
      XOSDEBUG("no ACPI dir\n");
      return false;
@@ -98,6 +101,27 @@
 
 }
 
+// determine if /sys/class/power_supply exists and is a DIR
+// (XXX: too lazy -  no tests for actual readability is done)
+bool BtryMeter::has_syspower( void ){
+
+  struct stat stbuf;
+
+  if ( stat(SYSPOWERDIR, &stbuf) != 0 ) {
+     XOSDEBUG("has_syspower(): stat failed: %d\n",errno);
+     return false;
+  }
+  if ( S_ISDIR(stbuf.st_mode) ) {
+     XOSDEBUG("%s exists and is a DIR.\n", SYSPOWERDIR);
+  } else {
+     XOSDEBUG("no /sys/class/power_supply dir\n");
+     return false;
+  }
+
+  // declare syspower as usable
+  return true;
+
+}
 
 void BtryMeter::checkResources( void ){
   FieldMeter::checkResources();
@@ -220,8 +244,8 @@
 
 void BtryMeter::getpwrinfo( void ){
 
-  if ( use_acpi ) {
-	getacpiinfo(); return;
+  if ( use_acpi || use_syspower ) {
+	getacpi_or_sys_info(); return;
   }
   if ( use_apm ) {
 	getapminfo(); return;
@@ -330,11 +354,20 @@
 // but munging it into something usefull is ugly
 // esp. as you can have more than one battery ...
 
-bool BtryMeter::getacpiinfo( void ){
+bool BtryMeter::getacpi_or_sys_info( void ){
+
+  DIR *dir = NULL;
+  std::string abs_battery_dir;
+
+  if (use_acpi) {
+    abs_battery_dir = ACPIBATTERYDIR;
+  } else {
+    abs_battery_dir = SYSPOWERDIR;
+  }
 
-  DIR *dir = opendir(ACPIBATTERYDIR);
+  dir = opendir(abs_battery_dir.c_str());
   if (dir==NULL) {
-    XOSDEBUG("ACPI: Cannot open directory : %s\n", ACPIBATTERYDIR);
+    XOSDEBUG("ACPI/SYS: Cannot open directory : %s\n", abs_battery_dir.c_str());
     return false;
   }
 
@@ -351,7 +384,6 @@
 
   acpi_charge_state=0; // assume charged
 
-  std::string abs_battery_dir = ACPIBATTERYDIR;
   for (struct dirent *dirent; (dirent = readdir(dir)) != NULL; ) {
     if (strncmp(dirent->d_name, ".", 1) == 0
     	|| strncmp(dirent->d_name, "..", 2) == 0)
@@ -359,12 +391,15 @@
 
     std::string abs_battery_name = abs_battery_dir + "/" + dirent->d_name;
 
-    XOSDEBUG("ACPI Batt: %s\n", dirent->d_name);
+    XOSDEBUG("ACPI/SYS Batt: %s\n", dirent->d_name);
 
     // still can happen that it's not present:
-    if ( battery_present( abs_battery_name + "/info" ) ) {
-      // ok, worth to parse out all the fields
-      if ( parse_battery( abs_battery_name ) ) {
+    if ( (use_acpi &&
+          (acpi_battery_present(abs_battery_name + "/info" )) &&
+          (acpi_parse_battery(abs_battery_name))) ||
+         (use_syspower &&
+          (sys_battery_present(abs_battery_name + "/present" )) &&
+          (sys_parse_battery(abs_battery_name))) ) {
 
 		// sum up:
 
@@ -385,7 +420,6 @@
 	      found = true; // found at least one
       }
     }
-  }
 
   closedir(dir);
 
@@ -418,7 +452,7 @@
 
 // present yes/no can change anytime !
 // by adding/removing a battery
-bool BtryMeter::battery_present(const std::string& filename)
+bool BtryMeter::acpi_battery_present(const std::string& filename)
 {
   std::ifstream loadinfo( filename.c_str() );
 
@@ -439,7 +473,7 @@
   return false;
 }
 
-bool BtryMeter::parse_battery(const std::string& dirname)
+bool BtryMeter::acpi_parse_battery(const std::string& dirname)
 {
   // actually there are THREE files to check:
   // 'alarm', 'info' and 'state'
@@ -535,3 +569,97 @@
 
 return true;
 }
+
+// present yes/no can change anytime !
+// by adding/removing a battery
+bool BtryMeter::sys_battery_present(const std::string& filename)
+{
+  std::ifstream loadinfo( filename.c_str() );
+  std::string value;
+
+  while ( loadinfo.good() ) {
+
+	value.clear();
+	loadinfo >> value;
+
+    if (value == "1")
+	  return true;
+  }
+  XOSDEBUG("batt %s not present\n",filename.c_str() );
+  return false;
+}
+
+bool BtryMeter::sys_parse_battery(const std::string& dirname)
+{
+  std::string filename;
+  std::ifstream loadinfo;
+  std::string value;
+
+  filename = dirname + "/alarm";
+  loadinfo.open(filename.c_str() );
+  while ( loadinfo.good() ) {
+	value.clear();
+	loadinfo >> value;
+	//XOSDEBUG("alarm (%s): v=\"%s\"\n", filename.c_str(), value.c_str() );
+    battery.alarm = atoi(value.c_str());
+    break;
+  }
+  loadinfo.close();
+  loadinfo.clear();
+
+  filename = dirname + "/energy_full_design";
+  loadinfo.open(filename.c_str() );
+  while ( loadinfo.good() ) {
+	value.clear();
+	loadinfo >> value;
+	//XOSDEBUG("design_capacity (%s): v=\"%s\"\n", filename.c_str(), value.c_str() );
+    battery.design_capacity = atoi(value.c_str());
+    break;
+  }
+  loadinfo.close();
+  loadinfo.clear();
+
+  filename = dirname + "/energy_full";
+  loadinfo.open(filename.c_str() );
+  while ( loadinfo.good() ) {
+	value.clear();
+	loadinfo >> value;
+	//XOSDEBUG("last_full_capacity (%s): v=\"%s\"\n", filename.c_str(), value.c_str() );
+    battery.last_full_capacity = atoi(value.c_str());
+    break;
+  }
+  loadinfo.close();
+  loadinfo.clear();
+
+  filename = dirname + "/energy_now";
+  loadinfo.open(filename.c_str() );
+  while ( loadinfo.good() ) {
+	value.clear();
+	loadinfo >> value;
+	//XOSDEBUG("remaining_capacity (%s): v=\"%s\"\n", filename.c_str(), value.c_str() );
+    battery.remaining_capacity = atoi(value.c_str());
+    break;
+  }
+  loadinfo.close();
+  loadinfo.clear();
+
+  filename = dirname + "/status";
+  loadinfo.open(filename.c_str() );
+  while ( loadinfo.good() ) {
+	value.clear();
+	loadinfo >> value;
+	//XOSDEBUG("status (%s): v=\"%s\"\n", filename.c_str(), value.c_str() );
+
+    if ( value == "Full" )
+        battery.charging_state=0;
+    if ( value == "Discharging" )
+        battery.charging_state=-1;
+    if ( value == "Charging" )
+        battery.charging_state=1;
+    break;
+  }
+  loadinfo.close();
+  loadinfo.clear();
+
+  return true;
+}
diff -uNrBb a/linux/btrymeter.h b/linux/btrymeter.h
--- a/linux/btrymeter.h	2006-02-18 04:33:06.000000000 +0000
+++ b/linux/btrymeter.h	2010-03-21 01:32:31.000000000 +0000
@@ -43,15 +43,20 @@
 private:
 
   bool getapminfo( void );
-  bool getacpiinfo( void );
+  bool getacpi_or_sys_info( void );
 
   bool use_apm;
   bool use_acpi;
+  bool use_syspower;
+
+  bool acpi_battery_present(const std::string& filename);
+  bool acpi_parse_battery(const std::string& filename);
+  bool sys_battery_present(const std::string& filename);
+  bool sys_parse_battery(const std::string& filename);
 
-  bool battery_present(const std::string& filename);
-  bool parse_battery(const std::string& filename);
   bool has_acpi(void);
   bool has_apm(void);
+  bool has_syspower(void);
 
   int apm_battery_state;
   int old_apm_battery_state;

Reply via email to