battery.c - slstatus - status monitor
(HTM) git clone git://git.suckless.org/slstatus
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
(DIR) 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", ¤t_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