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;

