slstatus

status monitor
git clone git://git.suckless.org/slstatus
Log | Files | Refs | README | LICENSE

battery.c (5121B)


      1 /* See LICENSE file for copyright and license details. */
      2 #include <stdio.h>
      3 #include <string.h>
      4 
      5 #include "../slstatus.h"
      6 #include "../util.h"
      7 
      8 #if defined(__linux__)
      9 	#include <limits.h>
     10 	#include <stdint.h>
     11 	#include <unistd.h>
     12 
     13 	#define POWER_SUPPLY_CAPACITY "/sys/class/power_supply/%s/capacity"
     14 	#define POWER_SUPPLY_STATUS   "/sys/class/power_supply/%s/status"
     15 	#define POWER_SUPPLY_CHARGE   "/sys/class/power_supply/%s/charge_now"
     16 	#define POWER_SUPPLY_ENERGY   "/sys/class/power_supply/%s/energy_now"
     17 	#define POWER_SUPPLY_CURRENT  "/sys/class/power_supply/%s/current_now"
     18 	#define POWER_SUPPLY_POWER    "/sys/class/power_supply/%s/power_now"
     19 
     20 	static const char *
     21 	pick(const char *bat, const char *f1, const char *f2, char *path,
     22 	     size_t length)
     23 	{
     24 		if (esnprintf(path, length, f1, bat) > 0 &&
     25 		    access(path, R_OK) == 0)
     26 			return f1;
     27 
     28 		if (esnprintf(path, length, f2, bat) > 0 &&
     29 		    access(path, R_OK) == 0)
     30 			return f2;
     31 
     32 		return NULL;
     33 	}
     34 
     35 	const char *
     36 	battery_perc(const char *bat)
     37 	{
     38 		int perc;
     39 		char path[PATH_MAX];
     40 
     41 		if (esnprintf(path, sizeof(path), POWER_SUPPLY_CAPACITY, bat) < 0)
     42 			return NULL;
     43 		if (pscanf(path, "%d", &perc) != 1)
     44 			return NULL;
     45 
     46 		return bprintf("%d", perc);
     47 	}
     48 
     49 	const char *
     50 	battery_state(const char *bat)
     51 	{
     52 		static struct {
     53 			char *state;
     54 			char *symbol;
     55 		} map[] = {
     56 			{ "Charging",    "+" },
     57 			{ "Discharging", "-" },
     58 			{ "Full",        "o" },
     59 			{ "Not charging", "o" },
     60 		};
     61 		size_t i;
     62 		char path[PATH_MAX], state[12];
     63 
     64 		if (esnprintf(path, sizeof(path), POWER_SUPPLY_STATUS, bat) < 0)
     65 			return NULL;
     66 		if (pscanf(path, "%12[a-zA-Z ]", state) != 1)
     67 			return NULL;
     68 
     69 		for (i = 0; i < LEN(map); i++)
     70 			if (!strcmp(map[i].state, state))
     71 				break;
     72 
     73 		return (i == LEN(map)) ? "?" : map[i].symbol;
     74 	}
     75 
     76 	const char *
     77 	battery_remaining(const char *bat)
     78 	{
     79 		uintmax_t charge_now, current_now, m, h;
     80 		double timeleft;
     81 		char path[PATH_MAX], state[12];
     82 
     83 		if (esnprintf(path, sizeof(path), POWER_SUPPLY_STATUS, bat) < 0)
     84 			return NULL;
     85 		if (pscanf(path, "%12[a-zA-Z ]", state) != 1)
     86 			return NULL;
     87 
     88 		if (!pick(bat, POWER_SUPPLY_CHARGE, POWER_SUPPLY_ENERGY, path,
     89 		          sizeof(path)) ||
     90 		    pscanf(path, "%ju", &charge_now) < 0)
     91 			return NULL;
     92 
     93 		if (!strcmp(state, "Discharging")) {
     94 			if (!pick(bat, POWER_SUPPLY_CURRENT, POWER_SUPPLY_POWER, path,
     95 			          sizeof(path)) ||
     96 			    pscanf(path, "%ju", &current_now) < 0)
     97 				return NULL;
     98 
     99 			if (current_now == 0)
    100 				return NULL;
    101 
    102 			timeleft = (double)charge_now / (double)current_now;
    103 			h = timeleft;
    104 			m = (timeleft - (double)h) * 60;
    105 
    106 			return bprintf("%juh %jum", h, m);
    107 		}
    108 
    109 		return "";
    110 	}
    111 #elif defined(__OpenBSD__)
    112 	#include <fcntl.h>
    113 	#include <machine/apmvar.h>
    114 	#include <sys/ioctl.h>
    115 	#include <unistd.h>
    116 
    117 	static int
    118 	load_apm_power_info(struct apm_power_info *apm_info)
    119 	{
    120 		int fd;
    121 
    122 		fd = open("/dev/apm", O_RDONLY);
    123 		if (fd < 0) {
    124 			warn("open '/dev/apm':");
    125 			return 0;
    126 		}
    127 
    128 		memset(apm_info, 0, sizeof(struct apm_power_info));
    129 		if (ioctl(fd, APM_IOC_GETPOWER, apm_info) < 0) {
    130 			warn("ioctl 'APM_IOC_GETPOWER':");
    131 			close(fd);
    132 			return 0;
    133 		}
    134 		return close(fd), 1;
    135 	}
    136 
    137 	const char *
    138 	battery_perc(const char *unused)
    139 	{
    140 		struct apm_power_info apm_info;
    141 
    142 		if (load_apm_power_info(&apm_info))
    143 			return bprintf("%d", apm_info.battery_life);
    144 
    145 		return NULL;
    146 	}
    147 
    148 	const char *
    149 	battery_state(const char *unused)
    150 	{
    151 		struct {
    152 			unsigned int state;
    153 			char *symbol;
    154 		} map[] = {
    155 			{ APM_AC_ON,      "+" },
    156 			{ APM_AC_OFF,     "-" },
    157 		};
    158 		struct apm_power_info apm_info;
    159 		size_t i;
    160 
    161 		if (load_apm_power_info(&apm_info)) {
    162 			for (i = 0; i < LEN(map); i++)
    163 				if (map[i].state == apm_info.ac_state)
    164 					break;
    165 
    166 			return (i == LEN(map)) ? "?" : map[i].symbol;
    167 		}
    168 
    169 		return NULL;
    170 	}
    171 
    172 	const char *
    173 	battery_remaining(const char *unused)
    174 	{
    175 		struct apm_power_info apm_info;
    176 		unsigned int h, m;
    177 
    178 		if (load_apm_power_info(&apm_info)) {
    179 			if (apm_info.ac_state != APM_AC_ON) {
    180 				h = apm_info.minutes_left / 60;
    181 				m = apm_info.minutes_left % 60;
    182 				return bprintf("%uh %02um", h, m);
    183 			} else {
    184 				return "";
    185 			}
    186 		}
    187 
    188 		return NULL;
    189 	}
    190 #elif defined(__FreeBSD__)
    191 	#include <sys/sysctl.h>
    192 
    193 	#define BATTERY_LIFE  "hw.acpi.battery.life"
    194 	#define BATTERY_STATE "hw.acpi.battery.state"
    195 	#define BATTERY_TIME  "hw.acpi.battery.time"
    196 
    197 	const char *
    198 	battery_perc(const char *unused)
    199 	{
    200 		int cap;
    201 		size_t len;
    202 
    203 		len = sizeof(cap);
    204 		if (sysctlbyname(BATTERY_LIFE, &cap, &len, NULL, 0) < 0 || !len)
    205 			return NULL;
    206 
    207 		return bprintf("%d", cap);
    208 	}
    209 
    210 	const char *
    211 	battery_state(const char *unused)
    212 	{
    213 		int state;
    214 		size_t len;
    215 
    216 		len = sizeof(state);
    217 		if (sysctlbyname(BATTERY_STATE, &state, &len, NULL, 0) < 0 || !len)
    218 			return NULL;
    219 
    220 		switch (state) {
    221 		case 0: /* FALLTHROUGH */
    222 		case 2:
    223 			return "+";
    224 		case 1:
    225 			return "-";
    226 		default:
    227 			return "?";
    228 		}
    229 	}
    230 
    231 	const char *
    232 	battery_remaining(const char *unused)
    233 	{
    234 		int rem;
    235 		size_t len;
    236 
    237 		len = sizeof(rem);
    238 		if (sysctlbyname(BATTERY_TIME, &rem, &len, NULL, 0) < 0 || !len
    239 		    || rem < 0)
    240 			return NULL;
    241 
    242 		return bprintf("%uh %02um", rem / 60, rem % 60);
    243 	}
    244 #endif