slstatus

Fork of suckless' slstatus with my personal patches
git clone https://git.instinctive.eu/slstatus.git
Log | Files | Refs | README | LICENSE

battery.c (5232B)


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