URI: 
       battery.c - slstatus - status monitor
  HTML 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", &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 #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