suckless/slstatus

components/battery.c in master
Repositories | Summary | Log | Files | README | LICENSE

battery.c (5517B) download


  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
115  int battery_discharge(const char *bat) {
116    char path[PATH_MAX], state[12];
117
118    if (esnprintf(path, sizeof(path), POWER_SUPPLY_STATUS, bat) < 0)
119      return NULL;
120    if (pscanf(path, "%12[a-zA-Z ]", state) != 1)
121      return NULL;
122
123    return !strcmp(state, "Discharging");
124  }
125#elif defined(__OpenBSD__)
126	#include <fcntl.h>
127	#include <machine/apmvar.h>
128	#include <sys/ioctl.h>
129	#include <unistd.h>
130
131	static int
132	load_apm_power_info(struct apm_power_info *apm_info)
133	{
134		int fd;
135
136		fd = open("/dev/apm", O_RDONLY);
137		if (fd < 0) {
138			warn("open '/dev/apm':");
139			return 0;
140		}
141
142		memset(apm_info, 0, sizeof(struct apm_power_info));
143		if (ioctl(fd, APM_IOC_GETPOWER, apm_info) < 0) {
144			warn("ioctl 'APM_IOC_GETPOWER':");
145			close(fd);
146			return 0;
147		}
148		return close(fd), 1;
149	}
150
151	const char *
152	battery_perc(const char *unused)
153	{
154		struct apm_power_info apm_info;
155
156		if (load_apm_power_info(&apm_info))
157			return bprintf("%d", apm_info.battery_life);
158
159		return NULL;
160	}
161
162	const char *
163	battery_state(const char *unused)
164	{
165		struct {
166			unsigned int state;
167			char *symbol;
168		} map[] = {
169			{ APM_AC_ON,      "+" },
170			{ APM_AC_OFF,     "-" },
171		};
172		struct apm_power_info apm_info;
173		size_t i;
174
175		if (load_apm_power_info(&apm_info)) {
176			for (i = 0; i < LEN(map); i++)
177				if (map[i].state == apm_info.ac_state)
178					break;
179
180			return (i == LEN(map)) ? "?" : map[i].symbol;
181		}
182
183		return NULL;
184	}
185
186	const char *
187	battery_remaining(const char *unused)
188	{
189		struct apm_power_info apm_info;
190		unsigned int h, m;
191
192		if (load_apm_power_info(&apm_info)) {
193			if (apm_info.ac_state != APM_AC_ON) {
194				h = apm_info.minutes_left / 60;
195				m = apm_info.minutes_left % 60;
196				return bprintf("%uh %02um", h, m);
197			} else {
198				return "";
199			}
200		}
201
202		return NULL;
203	}
204#elif defined(__FreeBSD__)
205	#include <sys/sysctl.h>
206
207	#define BATTERY_LIFE  "hw.acpi.battery.life"
208	#define BATTERY_STATE "hw.acpi.battery.state"
209	#define BATTERY_TIME  "hw.acpi.battery.time"
210
211	const char *
212	battery_perc(const char *unused)
213	{
214		int cap_perc;
215		size_t len;
216
217		len = sizeof(cap_perc);
218		if (sysctlbyname(BATTERY_LIFE, &cap_perc, &len, NULL, 0) < 0 || !len)
219			return NULL;
220
221		return bprintf("%d", cap_perc);
222	}
223
224	const char *
225	battery_state(const char *unused)
226	{
227		int state;
228		size_t len;
229
230		len = sizeof(state);
231		if (sysctlbyname(BATTERY_STATE, &state, &len, NULL, 0) < 0 || !len)
232			return NULL;
233
234		switch (state) {
235		case 0: /* FALLTHROUGH */
236		case 2:
237			return "+";
238		case 1:
239			return "-";
240		default:
241			return "?";
242		}
243	}
244
245	const char *
246	battery_remaining(const char *unused)
247	{
248		int rem;
249		size_t len;
250
251		len = sizeof(rem);
252		if (sysctlbyname(BATTERY_TIME, &rem, &len, NULL, 0) < 0 || !len
253		    || rem < 0)
254			return NULL;
255
256		return bprintf("%uh %02um", rem / 60, rem % 60);
257	}
258#endif