diff --git a/modules/battery.c b/modules/battery.c index 9e2a27b..564d917 100644 --- a/modules/battery.c +++ b/modules/battery.c @@ -30,11 +30,14 @@ struct private { char *model; long energy_full_design; long energy_full; + long charge_full_design; + long charge_full; enum state state; long capacity; long energy; long power; + long time_to_empty; }; static void @@ -62,19 +65,27 @@ content(struct module *mod) m->state == STATE_CHARGING || m->state == STATE_DISCHARGING); - unsigned long energy = m->state == STATE_CHARGING - ? m->energy_full - m->energy : m->energy; + unsigned long hours; + unsigned long minutes; - double hours_as_float; - if (m->state == STATE_FULL) - hours_as_float = 0.0; - else if (m->power > 0) - hours_as_float = (double)energy / m->power; - else - hours_as_float = 99.0; + if (m->time_to_empty < 0) { + unsigned long energy = m->state == STATE_CHARGING + ? m->energy_full - m->energy : m->energy; - unsigned long hours = hours_as_float; - unsigned long minutes = (hours_as_float - (double)hours) * 60; + double hours_as_float; + if (m->state == STATE_FULL) + hours_as_float = 0.0; + else if (m->power > 0) + hours_as_float = (double)energy / m->power; + else + hours_as_float = 99.0; + + hours = hours_as_float; + minutes = (hours_as_float - (double)hours) * 60; + } else { + hours = m->time_to_empty / 60; + minutes = m->time_to_empty % 60; + } char estimate[64]; snprintf(estimate, sizeof(estimate), "%02lu:%02lu", hours, minutes); @@ -181,26 +192,60 @@ initialize(struct private *m) } } + if (faccessat(base_dir_fd, "energy_full_design", O_RDONLY, 0) == 0 && + faccessat(base_dir_fd, "energy_full", O_RDONLY, 0) == 0) { - int fd = openat(base_dir_fd, "energy_full_design", O_RDONLY); - if (fd == -1) { - LOG_ERRNO("/sys/class/power_supply/%s/energy_full_design", m->battery); - goto err; + { + int fd = openat(base_dir_fd, "energy_full_design", O_RDONLY); + if (fd == -1) { + LOG_ERRNO("/sys/class/power_supply/%s/energy_full_design", m->battery); + goto err; + } + + m->energy_full_design = readint_from_fd(fd); + close(fd); } - m->energy_full_design = readint_from_fd(fd); - close(fd); + { + int fd = openat(base_dir_fd, "energy_full", O_RDONLY); + if (fd == -1) { + LOG_ERRNO("/sys/class/power_supply/%s/energy_full", m->battery); + goto err; + } + + m->energy_full = readint_from_fd(fd); + close(fd); + } + } else { + m->energy_full = m->energy_full_design = -1; } + if (faccessat(base_dir_fd, "charge_full_design", O_RDONLY, 0) == 0 && + faccessat(base_dir_fd, "charge_full", O_RDONLY, 0) == 0) { - int fd = openat(base_dir_fd, "energy_full", O_RDONLY); - if (fd == -1) { - LOG_ERRNO("/sys/class/power_supply/%s/energy_full", m->battery); - goto err; + { + int fd = openat(base_dir_fd, "charge_full_design", O_RDONLY); + if (fd == -1) { + LOG_ERRNO("/sys/class/power_supply/%s/charge_full_design", m->battery); + goto err; + } + + m->charge_full_design = readint_from_fd(fd); + close(fd); } - m->energy_full = readint_from_fd(fd); - close(fd); + { + int fd = openat(base_dir_fd, "charge_full", O_RDONLY); + if (fd == -1) { + LOG_ERRNO("/sys/class/power_supply/%s/charge_full", m->battery); + goto err; + } + + m->charge_full = readint_from_fd(fd); + close(fd); + } + } else { + m->charge_full = m->charge_full_design = -1; } return base_dir_fd; @@ -212,13 +257,14 @@ err: static void update_status(struct module *mod, int capacity_fd, int energy_fd, int power_fd, - int status_fd) + int status_fd, int time_to_empty_fd) { struct private *m = mod->private; long capacity = readint_from_fd(capacity_fd); - long energy = readint_from_fd(energy_fd); - long power = readint_from_fd(power_fd); + long energy = energy_fd >= 0 ? readint_from_fd(energy_fd) : -1; + long power = power_fd >= 0 ? readint_from_fd(power_fd) : -1; + long time_to_empty = time_to_empty_fd >= 0 ? readint_from_fd(time_to_empty_fd) : -1; const char *status = readline_from_fd(status_fd); enum state state; @@ -236,13 +282,15 @@ update_status(struct module *mod, int capacity_fd, int energy_fd, int power_fd, state = STATE_DISCHARGING; } - LOG_DBG("capacity: %ld, energy: %ld, power: %ld", capacity, energy, power); + LOG_DBG("capacity: %ld, energy: %ld, power: %ld, time-to-empty: %ld", + capacity, energy, power, time_to_empty); mtx_lock(&mod->lock); m->state = state; m->capacity = capacity; m->energy = energy; m->power = power; + m->time_to_empty = time_to_empty; mtx_unlock(&mod->lock); } @@ -258,27 +306,30 @@ run(struct module *mod) LOG_INFO("%s: %s %s (at %.1f%% of original capacity)", m->battery, m->manufacturer, m->model, - 100.0 * m->energy_full / m->energy_full_design); + (m->energy_full > 0 + ? 100.0 * m->energy_full / m->energy_full_design + : m->charge_full > 0 + ? 100.0 * m->charge_full / m->charge_full_design + : 0.0)); int ret = 1; int status_fd = openat(base_dir_fd, "status", O_RDONLY); int capacity_fd = openat(base_dir_fd, "capacity", O_RDONLY); int energy_fd = openat(base_dir_fd, "energy_now", O_RDONLY); int power_fd = openat(base_dir_fd, "power_now", O_RDONLY); + int time_to_empty_fd = openat(base_dir_fd, "time_to_empty_now", O_RDONLY); struct udev *udev = udev_new(); struct udev_monitor *mon = udev_monitor_new_from_netlink(udev, "udev"); - if (status_fd == -1 || capacity_fd == -1 || energy_fd == -1 || - power_fd == -1 || udev == NULL || mon == NULL) - { + if (status_fd < 0 || capacity_fd < 0 || udev == NULL || mon == NULL) goto out; - } udev_monitor_filter_add_match_subsystem_devtype(mon, "power_supply", NULL); udev_monitor_enable_receiving(mon); - update_status(mod, capacity_fd, energy_fd, power_fd, status_fd); + update_status(mod, capacity_fd, energy_fd, power_fd, status_fd, + time_to_empty_fd); bar->refresh(bar); while (true) { @@ -304,7 +355,8 @@ run(struct module *mod) continue; } - update_status(mod, capacity_fd, energy_fd, power_fd, status_fd); + update_status(mod, capacity_fd, energy_fd, power_fd, status_fd, + time_to_empty_fd); bar->refresh(bar); } @@ -322,6 +374,8 @@ out: close(capacity_fd); if (status_fd != -1) close(status_fd); + if (time_to_empty_fd != -1) + close(time_to_empty_fd); close(base_dir_fd); return ret;