Xinqi Bao's Git

bcd42cda413aac9b09aa1c2daff26559c68418d3
[slstatus.git] / components / battery.c
1 /* See LICENSE file for copyright and license details. */
2 #include <errno.h>
3 #include <stdio.h>
4 #include <string.h>
5
6 #include "../util.h"
7
8 #if defined(__linux__)
9 #include <limits.h>
10
11 const char *
12 battery_perc(const char *bat)
13 {
14 int perc;
15 char path[PATH_MAX];
16
17 if (esnprintf(path, sizeof(path),
18 "/sys/class/power_supply/%s/capacity",
19 bat) < 0) {
20 return NULL;
21 }
22 if (pscanf(path, "%d", &perc) != 1) {
23 return NULL;
24 }
25
26 return bprintf("%d", perc);
27 }
28
29 const char *
30 battery_state(const char *bat)
31 {
32 static struct {
33 char *state;
34 char *symbol;
35 } map[] = {
36 { "Charging", "+" },
37 { "Discharging", "-" },
38 };
39 size_t i;
40 char path[PATH_MAX], state[12];
41
42 if (esnprintf(path, sizeof(path),
43 "/sys/class/power_supply/%s/status",
44 bat) < 0) {
45 return NULL;
46 }
47 if (pscanf(path, "%12s", state) != 1) {
48 return NULL;
49 }
50
51 for (i = 0; i < LEN(map); i++) {
52 if (!strcmp(map[i].state, state)) {
53 break;
54 }
55 }
56 return (i == LEN(map)) ? "?" : map[i].symbol;
57 }
58
59 const char *
60 battery_remaining(const char *bat)
61 {
62 int charge_now, current_now, m, h;
63 float timeleft;
64 char path[PATH_MAX], state[12];
65
66 if (esnprintf(path, sizeof(path),
67 "/sys/class/power_supply/%s/status",
68 bat) < 0) {
69 return NULL;
70 }
71 if (pscanf(path, "%12s", state) != 1) {
72 return NULL;
73 }
74
75 if (!strcmp(state, "Discharging")) {
76 if (esnprintf(path, sizeof(path),
77 "/sys/class/power_supply/%s/charge_now",
78 bat) < 0) {
79 return NULL;
80 }
81 if (pscanf(path, "%d", &charge_now) != 1) {
82 return NULL;
83 }
84 if (esnprintf(path, sizeof(path),
85 "/sys/class/power_supply/%s/current_now",
86 bat) < 0) {
87 return NULL;
88 }
89 if (pscanf(path, "%d", &current_now) != 1) {
90 return NULL;
91 }
92
93 timeleft = (float)charge_now / (float)current_now;
94 h = timeleft;
95 m = (timeleft - (float)h) * 60;
96
97 return bprintf("%dh %dm", h, m);
98 }
99
100 return "";
101 }
102 #elif defined(__OpenBSD__)
103 #include <fcntl.h>
104 #include <machine/apmvar.h>
105 #include <sys/ioctl.h>
106 #include <unistd.h>
107
108 static int
109 load_apm_power_info(struct apm_power_info *apm_info)
110 {
111 int fd;
112
113 fd = open("/dev/apm", O_RDONLY);
114 if (fd < 0) {
115 warn("open '/dev/apm':");
116 return 0;
117 }
118
119 memset(apm_info, 0, sizeof(struct apm_power_info));
120 if (ioctl(fd, APM_IOC_GETPOWER, apm_info) < 0) {
121 warn("ioctl 'APM_IOC_GETPOWER':");
122 close(fd);
123 return 0;
124 }
125 return close(fd), 1;
126 }
127
128 const char *
129 battery_perc(const char *unused)
130 {
131 struct apm_power_info apm_info;
132
133 if (load_apm_power_info(&apm_info)) {
134 return bprintf("%d", apm_info.battery_life);
135 }
136
137 return NULL;
138 }
139
140 const char *
141 battery_state(const char *unused)
142 {
143 struct {
144 unsigned int state;
145 char *symbol;
146 } map[] = {
147 { APM_AC_ON, "+" },
148 { APM_AC_OFF, "-" },
149 };
150 struct apm_power_info apm_info;
151 size_t i;
152
153 if (load_apm_power_info(&apm_info)) {
154 for (i = 0; i < LEN(map); i++) {
155 if (map[i].state == apm_info.ac_state) {
156 break;
157 }
158 }
159 return (i == LEN(map)) ? "?" : map[i].symbol;
160 }
161
162 return NULL;
163 }
164
165 const char *
166 battery_remaining(const char *unused)
167 {
168 struct apm_power_info apm_info;
169
170 if (load_apm_power_info(&apm_info)) {
171 if (apm_info.ac_state != APM_AC_ON) {
172 return bprintf("%uh %02um", apm_info.minutes_left / 60,
173 apm_info.minutes_left % 60);
174 } else {
175 return "";
176 }
177 }
178
179 return NULL;
180 }
181 #endif