diff options
author | Simon Quigley <tsimonq2@ubuntu.com> | 2017-06-19 15:19:47 -0500 |
---|---|---|
committer | Simon Quigley <tsimonq2@ubuntu.com> | 2017-06-19 15:19:47 -0500 |
commit | 79c11b29d78a70ae1b04af3b7ca4ec9bb12dd8d7 (patch) | |
tree | c4577e59ae13a8031f937991dcc3a63f68d18db5 /modules/devices/battery.c | |
parent | 62eb92d94fa902b4a34dafce45547680a2655b40 (diff) | |
parent | 7aacc9f2510901c9e97b30fa9bcb550bb7f99c03 (diff) |
Merge tag 'upstream/0.5.1+git20170605'
Upstream version 0.5.1+git20170605
Diffstat (limited to 'modules/devices/battery.c')
-rw-r--r-- | modules/devices/battery.c | 388 |
1 files changed, 388 insertions, 0 deletions
diff --git a/modules/devices/battery.c b/modules/devices/battery.c new file mode 100644 index 00000000..cbcebb12 --- /dev/null +++ b/modules/devices/battery.c @@ -0,0 +1,388 @@ +/* + * HardInfo - Displays System Information + * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <string.h> +#include <time.h> + +#include "hardinfo.h" +#include "devices.h" + +const struct { + gchar *key, *name; +} ups_fields[] = { + { "UPS Status", NULL }, + { "STATUS", "Status" }, + { "TIMELEFT", "Time Left" }, + { "LINEV", "Line Voltage" }, + { "LOADPCT", "Load Percent" }, + + { "UPS Battery Information", NULL }, + { "BATTV", "Battery Voltage" }, + { "BCHARGE", "Battery Charge" }, + { "BATTDATE", "Battery Date" }, + + { "UPS Information", NULL }, + { "APCMODEL", "Model" }, + { "FIRMWARE", "Firmware Version" }, + { "SERIALNO", "Serial Number" }, + { "UPSMODE", "UPS Mode" }, + { "CABLE", "Cable" }, + { "UPSNAME", "UPS Name" }, + + { "UPS Nominal Values", NULL }, + { "NOMINV", "Voltage" }, + { "NOMBATTV", "Battery Voltage" }, + { "NOMPOWER", "Power" } +}; + + +static void +__scan_battery_apcupsd(void) +{ + GHashTable *ups_data; + FILE *apcaccess; + char buffer[512], *apcaccess_path; + int i; + + apcaccess_path = find_program("apcaccess"); + if (apcaccess_path && (apcaccess = popen(apcaccess_path, "r"))) { + /* first line isn't important */ + if (fgets(buffer, 512, apcaccess)) { + /* allocate the key, value hash table */ + ups_data = g_hash_table_new(g_str_hash, g_str_equal); + + /* read up all the apcaccess' output, saving it in the key, value hash table */ + while (fgets(buffer, 512, apcaccess)) { + buffer[9] = '\0'; + + g_hash_table_insert(ups_data, + g_strdup(g_strstrip(buffer)), + g_strdup(g_strstrip(buffer + 10))); + } + + /* builds the ups info string, respecting the field order as found in ups_fields */ + for (i = 0; i < G_N_ELEMENTS(ups_fields); i++) { + if (!ups_fields[i].name) { + /* there's no name: make a group with the key as its name */ + battery_list = h_strdup_cprintf("[%s]\n", battery_list, ups_fields[i].key); + } else { + /* there's a name: adds a line */ + battery_list = h_strdup_cprintf("%s=%s\n", battery_list, + ups_fields[i].name, + g_hash_table_lookup(ups_data, ups_fields[i].key)); + } + } + + g_hash_table_destroy(ups_data); + } + + pclose(apcaccess); + } + + g_free(apcaccess_path); +} + +static void +__scan_battery_acpi(void) +{ + gchar *acpi_path; + + gchar *present = NULL; + gchar *capacity = NULL; + gchar *technology = NULL; + gchar *voltage = NULL; + gchar *model = NULL, *serial = NULL, *type = NULL; + gchar *state = NULL, *rate = NULL; + gchar *remaining = NULL; + gchar *manufacturer = NULL; + + acpi_path = g_strdup("/proc/acpi/battery"); + if (g_file_test(acpi_path, G_FILE_TEST_EXISTS)) { + GDir *acpi; + + if ((acpi = g_dir_open(acpi_path, 0, NULL))) { + const gchar *entry; + + while ((entry = g_dir_read_name(acpi))) { + gchar *path = g_strdup_printf("%s/%s/info", acpi_path, entry); + FILE *f; + gchar buffer[256]; + gdouble charge_rate = 1.0; + + f = fopen(path, "r"); + g_free(path); + + if (!f) + goto cleanup; + + while (fgets(buffer, 256, f)) { + gchar **tmp = g_strsplit(buffer, ":", 2); + + GET_STR("present", present); + GET_STR("design capacity", capacity); + GET_STR("battery technology", technology); + GET_STR("design voltage", voltage); + GET_STR("model number", model); + GET_STR("serial number", serial); + GET_STR("battery type", type); + GET_STR("OEM info", manufacturer); + + g_strfreev(tmp); + } + fclose(f); + + path = g_strdup_printf("%s/%s/state", acpi_path, entry); + f = fopen(path, "r"); + g_free(path); + + if (!f) + goto cleanup; + + while (fgets(buffer, 256, f)) { + gchar **tmp = g_strsplit(buffer, ":", 2); + + GET_STR("charging state", state); + GET_STR("present rate", rate); + GET_STR("remaining capacity", remaining); + + g_strfreev(tmp); + } + + fclose(f); + + const gchar *url = vendor_get_url(manufacturer); + if (url) { + char *tmp = g_strdup_printf("%s (%s)", vendor_get_name(manufacturer), url); + g_free(manufacturer); + manufacturer = tmp; + } + + if (g_str_equal(present, "yes")) { + if (remaining && capacity) + charge_rate = atof(remaining) / atof(capacity); + else + charge_rate = 0; + + battery_list = h_strdup_cprintf(_("\n[Battery: %s]\n" + "State=%s (load: %s)\n" + "Capacity=%s / %s (%.2f%%)\n" + "Battery Technology=%s (%s)\n" + "Manufacturer=%s\n" + "Model Number=%s\n" + "Serial Number=%s\n"), + battery_list, + entry, + state, rate, + remaining, capacity, charge_rate * 100.0, + technology, type, + manufacturer, + model, + serial); + } + + cleanup: + g_free(present); + g_free(capacity); + g_free(technology); + g_free(type); + g_free(model); + g_free(serial); + g_free(state); + g_free(remaining); + g_free(rate); + g_free(manufacturer); + + present = capacity = technology = type = \ + model = serial = state = remaining = rate = manufacturer = NULL; + } + + g_dir_close(acpi); + } + } + + g_free(acpi_path); +} + +static gchar * +read_contents(const gchar *base, const gchar *key) +{ + gchar *value; + gchar *path; + + path = g_strdup_printf("%s/%s", base, key); + if (!path) + return NULL; + + if (!g_file_get_contents(path, &value, NULL, NULL)) { + free(path); + return NULL; + } + + free(path); + return g_strchomp(value); +} + +static void +__scan_battery_sysfs_add_battery(const gchar *name) +{ + gchar *path = g_strdup_printf("/sys/class/power_supply/%s", name); + gchar *status, *capacity, *capacity_level, *technology, *manufacturer, + *model_name, *serial_number; + + if (!path) + return; + + status = read_contents(path, "status"); + capacity = read_contents(path, "capacity"); + capacity_level = read_contents(path, "capacity_level"); + technology = read_contents(path, "technology"); + manufacturer = read_contents(path, "manufacturer"); + model_name = read_contents(path, "model_name"); + serial_number = read_contents(path, "serial_number"); + + battery_list = h_strdup_cprintf(_("\n[Battery: %s]\n" + "State=%s\n" + "Capacity=%s / %s\n" + "Battery Technology=%s\n" + "Manufacturer=%s\n" + "Model Number=%s\n" + "Serial Number=%s\n"), + battery_list, + name, + status, + capacity, capacity_level, + technology, + manufacturer, + model_name, + serial_number); + + free(status); + free(capacity); + free(capacity_level); + free(technology); + free(manufacturer); + free(model_name); + free(serial_number); +} + +static void +__scan_battery_sysfs(void) +{ + GDir *dir; + const gchar *entry; + + dir = g_dir_open("/sys/class/power_supply", 0, NULL); + if (!dir) + return; + + while ((entry = g_dir_read_name(dir))) { + if (g_str_has_prefix(entry, "BAT")) + __scan_battery_sysfs_add_battery(entry); + } + + g_dir_close(dir); +} + +static void +__scan_battery_apm(void) +{ + FILE *procapm; + static char *sremaining = NULL, *stotal = NULL; + static unsigned int last_time = 0; + static int percentage = 0; + const char *ac_status[] = { "Battery", + "AC Power", + "Charging" }; + int ac_bat; + char apm_bios_ver[16], apm_drv_ver[16]; + char trash[10]; + + if ((procapm = fopen("/proc/apm", "r"))) { + int old_percentage = percentage; + + (void)fscanf(procapm, "%s %s %s 0x%x %s %s %d%%", + apm_drv_ver, apm_bios_ver, trash, + &ac_bat, trash, trash, &percentage); + fclose(procapm); + + if (last_time == 0) { + last_time = time(NULL); + sremaining = stotal = NULL; + } + + if (old_percentage - percentage > 0) { + if (sremaining && stotal) { + g_free(sremaining); + g_free(stotal); + } + + int secs_remaining = (time(NULL) - last_time) * percentage / + (old_percentage - percentage); + sremaining = seconds_to_string(secs_remaining); + stotal = seconds_to_string((secs_remaining * 100) / percentage); + + last_time = time(NULL); + } + } else { + return; + } + + if (stotal && sremaining) { + battery_list = h_strdup_cprintf(_("\n[Battery (APM)]\n" + "Charge=%d%%\n" + "Remaining Charge=%s of %s\n" + "Using=%s\n" + "APM driver version=%s\n" + "APM BIOS version=%s\n"), + battery_list, + percentage, + sremaining, stotal, + ac_status[ac_bat], + apm_drv_ver, apm_bios_ver); + } else { + battery_list = h_strdup_cprintf(_("\n[Battery (APM)]\n" + "Charge=%d%%\n" + "Using=%s\n" + "APM driver version=%s\n" + "APM BIOS version=%s\n"), + battery_list, + percentage, + ac_status[ac_bat], + apm_drv_ver, apm_bios_ver); + + } +} + +void +scan_battery_do(void) +{ + g_free(battery_list); + battery_list = g_strdup(""); + + __scan_battery_sysfs(); + __scan_battery_acpi(); + __scan_battery_apm(); + __scan_battery_apcupsd(); + + if (*battery_list == '\0') { + g_free(battery_list); + + battery_list = g_strdup(_("[No batteries]\n" + "No batteries found on this system=\n")); + } +} |