slstatus

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

battery.c (4803B)


      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 		};
     56 		size_t i;
     57 		char path[PATH_MAX], state[12];
     58 
     59 		if (esnprintf(path, sizeof(path),
     60 		              "/sys/class/power_supply/%s/status", bat) < 0) {
     61 			return NULL;
     62 		}
     63 		if (pscanf(path, "%12s", state) != 1) {
     64 			return NULL;
     65 		}
     66 
     67 		for (i = 0; i < LEN(map); i++) {
     68 			if (!strcmp(map[i].state, state)) {
     69 				break;
     70 			}
     71 		}
     72 		return (i == LEN(map)) ? "?" : map[i].symbol;
     73 	}
     74 
     75 	const char *
     76 	battery_remaining(const char *bat)
     77 	{
     78 		uintmax_t charge_now, current_now, m, h;
     79 		double timeleft;
     80 		char path[PATH_MAX], state[12];
     81 
     82 		if (esnprintf(path, sizeof(path),
     83 		              "/sys/class/power_supply/%s/status", bat) < 0) {
     84 			return NULL;
     85 		}
     86 		if (pscanf(path, "%12s", state) != 1) {
     87 			return NULL;
     88 		}
     89 
     90 		if (!pick(bat, "/sys/class/power_supply/%s/charge_now",
     91 		          "/sys/class/power_supply/%s/energy_now", path,
     92 		          sizeof(path)) ||
     93 		    pscanf(path, "%ju", &charge_now) < 0) {
     94 			return NULL;
     95 		}
     96 
     97 		if (!strcmp(state, "Discharging")) {
     98 			if (!pick(bat, "/sys/class/power_supply/%s/current_now",
     99 			          "/sys/class/power_supply/%s/power_now", path,
    100 			          sizeof(path)) ||
    101 			    pscanf(path, "%ju", &current_now) < 0) {
    102 				return NULL;
    103 			}
    104 
    105 			if (current_now == 0) {
    106 				return NULL;
    107 			}
    108 
    109 			timeleft = (double)charge_now / (double)current_now;
    110 			h = timeleft;
    111 			m = (timeleft - (double)h) * 60;
    112 
    113 			return bprintf("%juh %jum", h, m);
    114 		}
    115 
    116 		return "";
    117 	}
    118 #elif defined(__OpenBSD__)
    119 	#include <fcntl.h>
    120 	#include <machine/apmvar.h>
    121 	#include <sys/ioctl.h>
    122 	#include <unistd.h>
    123 
    124 	static int
    125 	load_apm_power_info(struct apm_power_info *apm_info)
    126 	{
    127 		int fd;
    128 
    129 		fd = open("/dev/apm", O_RDONLY);
    130 		if (fd < 0) {
    131 			warn("open '/dev/apm':");
    132 			return 0;
    133 		}
    134 
    135 		memset(apm_info, 0, sizeof(struct apm_power_info));
    136 		if (ioctl(fd, APM_IOC_GETPOWER, apm_info) < 0) {
    137 			warn("ioctl 'APM_IOC_GETPOWER':");
    138 			close(fd);
    139 			return 0;
    140 		}
    141 		return close(fd), 1;
    142 	}
    143 
    144 	const char *
    145 	battery_perc(const char *unused)
    146 	{
    147 		struct apm_power_info apm_info;
    148 
    149 		if (load_apm_power_info(&apm_info)) {
    150 			return bprintf("%d", apm_info.battery_life);
    151 		}
    152 
    153 		return NULL;
    154 	}
    155 
    156 	const char *
    157 	battery_state(const char *unused)
    158 	{
    159 		struct {
    160 			unsigned int state;
    161 			char *symbol;
    162 		} map[] = {
    163 			{ APM_AC_ON,      "+" },
    164 			{ APM_AC_OFF,     "-" },
    165 		};
    166 		struct apm_power_info apm_info;
    167 		size_t i;
    168 
    169 		if (load_apm_power_info(&apm_info)) {
    170 			for (i = 0; i < LEN(map); i++) {
    171 				if (map[i].state == apm_info.ac_state) {
    172 					break;
    173 				}
    174 			}
    175 			return (i == LEN(map)) ? "?" : map[i].symbol;
    176 		}
    177 
    178 		return NULL;
    179 	}
    180 
    181 	const char *
    182 	battery_remaining(const char *unused)
    183 	{
    184 		struct apm_power_info apm_info;
    185 
    186 		if (load_apm_power_info(&apm_info)) {
    187 			if (apm_info.ac_state != APM_AC_ON) {
    188 				return bprintf("%uh %02um",
    189 			                       apm_info.minutes_left / 60,
    190 				               apm_info.minutes_left % 60);
    191 			} else {
    192 				return "";
    193 			}
    194 		}
    195 
    196 		return NULL;
    197 	}
    198 #elif defined(__FreeBSD__)
    199 	#include <sys/sysctl.h>
    200 
    201 	const char *
    202 	battery_perc(const char *unused)
    203 	{
    204 		int cap;
    205 		size_t len;
    206 
    207 		len = sizeof(cap);
    208 		if (sysctlbyname("hw.acpi.battery.life", &cap, &len, NULL, 0) == -1
    209 				|| !len)
    210 			return NULL;
    211 
    212 		return bprintf("%d", cap);
    213 	}
    214 
    215 	const char *
    216 	battery_state(const char *unused)
    217 	{
    218 		int state;
    219 		size_t len;
    220 
    221 		len = sizeof(state);
    222 		if (sysctlbyname("hw.acpi.battery.state", &state, &len, NULL, 0) == -1
    223 				|| !len)
    224 			return NULL;
    225 
    226 		switch(state) {
    227 			case 0:
    228 			case 2:
    229 				return "+";
    230 			case 1:
    231 				return "-";
    232 			default:
    233 				return "?";
    234 		}
    235 	}
    236 
    237 	const char *
    238 	battery_remaining(const char *unused)
    239 	{
    240 		int rem;
    241 		size_t len;
    242 
    243 		len = sizeof(rem);
    244 		if (sysctlbyname("hw.acpi.battery.time", &rem, &len, NULL, 0) == -1
    245 				|| !len
    246 				|| rem == -1)
    247 			return NULL;
    248 
    249 		return bprintf("%uh %02um", rem / 60, rem % 60);
    250 	}
    251 #endif