Xinqi Bao's Git

82e0baf3537a649f8c0f54ce90c2984ef73a043a
[slstatus.git] / components / battery.c
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 <unistd.h>
10
11 static const char *
12 pick(const char *bat, const char *f1, const char *f2, char *path,
13 size_t length)
14 {
15 if (esnprintf(path, length, f1, bat) > 0 &&
16 access(path, R_OK) == 0) {
17 return f1;
18 }
19
20 if (esnprintf(path, length, f2, bat) > 0 &&
21 access(path, R_OK) == 0) {
22 return f2;
23 }
24
25 return NULL;
26 }
27
28 const char *
29 battery_perc(const char *bat)
30 {
31 int perc;
32 char path[PATH_MAX];
33
34 if (esnprintf(path, sizeof(path),
35 "/sys/class/power_supply/%s/capacity",
36 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",
61 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 int 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",
85 bat) < 0) {
86 return NULL;
87 }
88 if (pscanf(path, "%12s", state) != 1) {
89 return NULL;
90 }
91
92 if (!pick(bat, "/sys/class/power_supply/%s/charge_now",
93 "/sys/class/power_supply/%s/energy_now",
94 path, sizeof(path)) ||
95 pscanf(path, "%d", &charge_now) < 0) {
96 return NULL;
97 }
98
99 if (!strcmp(state, "Discharging")) {
100 if (!pick(bat, "/sys/class/power_supply/%s/current_now",
101 "/sys/class/power_supply/%s/power_now", path,
102 sizeof(path)) ||
103 pscanf(path, "%d", &current_now) < 0) {
104 return NULL;
105 }
106
107 if (current_now == 0) {
108 return NULL;
109 }
110
111 timeleft = (double)charge_now / (double)current_now;
112 h = timeleft;
113 m = (timeleft - (double)h) * 60;
114
115 return bprintf("%dh %dm", h, m);
116 }
117
118 return "";
119 }
120 #elif defined(__OpenBSD__)
121 #include <fcntl.h>
122 #include <machine/apmvar.h>
123 #include <sys/ioctl.h>
124 #include <unistd.h>
125
126 static int
127 load_apm_power_info(struct apm_power_info *apm_info)
128 {
129 int fd;
130
131 fd = open("/dev/apm", O_RDONLY);
132 if (fd < 0) {
133 warn("open '/dev/apm':");
134 return 0;
135 }
136
137 memset(apm_info, 0, sizeof(struct apm_power_info));
138 if (ioctl(fd, APM_IOC_GETPOWER, apm_info) < 0) {
139 warn("ioctl 'APM_IOC_GETPOWER':");
140 close(fd);
141 return 0;
142 }
143 return close(fd), 1;
144 }
145
146 const char *
147 battery_perc(const char *unused)
148 {
149 struct apm_power_info apm_info;
150
151 if (load_apm_power_info(&apm_info)) {
152 return bprintf("%d", apm_info.battery_life);
153 }
154
155 return NULL;
156 }
157
158 const char *
159 battery_state(const char *unused)
160 {
161 struct {
162 unsigned int state;
163 char *symbol;
164 } map[] = {
165 { APM_AC_ON, "+" },
166 { APM_AC_OFF, "-" },
167 };
168 struct apm_power_info apm_info;
169 size_t i;
170
171 if (load_apm_power_info(&apm_info)) {
172 for (i = 0; i < LEN(map); i++) {
173 if (map[i].state == apm_info.ac_state) {
174 break;
175 }
176 }
177 return (i == LEN(map)) ? "?" : map[i].symbol;
178 }
179
180 return NULL;
181 }
182
183 const char *
184 battery_remaining(const char *unused)
185 {
186 struct apm_power_info apm_info;
187
188 if (load_apm_power_info(&apm_info)) {
189 if (apm_info.ac_state != APM_AC_ON) {
190 return bprintf("%uh %02um",
191 apm_info.minutes_left / 60,
192 apm_info.minutes_left % 60);
193 } else {
194 return "";
195 }
196 }
197
198 return NULL;
199 }
200 #endif