slstatus

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

battery.c (4830B)


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