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