]> mj.ucw.cz Git - osdd.git/commitdiff
osd-batt: Rewritten to use sysfs instead of /proc/acpi/
authorMartin Mares <mj@ucw.cz>
Sun, 15 Apr 2012 12:36:06 +0000 (14:36 +0200)
committerMartin Mares <mj@ucw.cz>
Sun, 15 Apr 2012 12:36:06 +0000 (14:36 +0200)
/proc/acpi/battery is no longer present on modern kernels.

osd-batt.c

index ace3a87f79d6e3248f88f7a3d00c809bf6d7cbc2..86ec6d38f30dc65ff0fba4272d2eb83c1f1dcc1b 100644 (file)
@@ -1,15 +1,18 @@
 /*
  *     A Simple Battery Status Display via OSD
  *
- *     (c) 2007--2010 Martin Mares <mj@ucw.cz>
+ *     (c) 2007--2012 Martin Mares <mj@ucw.cz>
  */
 
+#undef DEBUG
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 #include <dirent.h>
 #include <getopt.h>
+#include <fcntl.h>
 
 #include "osd.h"
 
@@ -17,7 +20,7 @@ static int check_mode;
 static int check_every;
 static int warn_threshold = 600;
 
-static int total_full, total_capa, discharge_rate;
+static int total_now, total_full, discharge_rate;
 static int charge_time, discharge_time;
 static int ac_online;
 static unsigned int present_mask, charge_mask, discharge_mask;
@@ -25,61 +28,103 @@ static unsigned int present_mask, charge_mask, discharge_mask;
 static unsigned int last_charge_mask, last_discharge_mask;
 static int last_ac_online = -1;
 
-static char *parse_line(char *line)
+#define MAX_BATTS 4
+#define BATT_NAME_LEN 32
+static char batt_names[MAX_BATTS][BATT_NAME_LEN];
+
+static char sys_dir[256];
+#define BUFSIZE 256
+
+static int sys_read(char *buf, char *attribute)
 {
-  char *t = strchr(line, '\n');
-  if (t)
-    *t = 0;
-  char *val = strchr(line, ':');
-  if (!val)
-    return NULL;
-  *val++ = 0;
-  while (*val == ' ' || *val == '\t')
-    *val++ = 0;
-  return val;
+  char name[256];
+  snprintf(name, sizeof(name), "%s/%s", sys_dir, attribute);
+
+  int fd = open(name, O_RDONLY);
+  if (fd < 0)
+    return 0;
+
+  int n = read(fd, buf, BUFSIZE);
+  close(fd);
+  if (n < 0)
+    return 0;
+
+  buf[BUFSIZE-1] = 0;
+  char *nl = strchr(buf, '\n');
+  if (nl)
+    *nl = 0;
+  DBG("\t%s=%s\n", attribute, buf);
+  return 1;
 }
 
-static void scan_ac(void)
+static int sys_read_int(char *attribute, int default_value)
 {
-  ac_online = 0;
+  char buf[BUFSIZE];
+  if (!sys_read(buf, attribute) || !buf[0])
+    return default_value;
+  else
+    return atoi(buf);
+}
 
-  const char dir[] = "/proc/acpi/ac_adapter";
-  DIR *d = opendir(dir);
-  if (!d)
-    return;
+static void parse_ac(void)
+{
+  ac_online = sys_read_int("online", 0);
+}
 
-  struct dirent *e;
-  while (e = readdir(d))
+static int get_batt_id(char *batt_name)
+{
+  for (int i=0; i<MAX_BATTS; i++)
     {
-      if (e->d_name[0] == '.')
-        continue;
-      char n[sizeof(dir) + 1 + strlen(e->d_name) + 6];
-      sprintf(n, "%s/%s/state", dir, e->d_name);
-      FILE *f = fopen(n, "r");
-      if (!f)
-       continue;
-      char line[1024];
-      while (fgets(line, sizeof(line)-1, f))
+      if (!strcmp(batt_names[i], batt_name))
+       return i;
+      if (!batt_names[i][0])
        {
-         char *val = parse_line(line);
-         if (!val)
-           continue;
-         if (!strcmp(line, "state") && !strcmp(val, "on-line"))
-           ac_online = 1;
+         snprintf(batt_names[i], BATT_NAME_LEN, "%s", batt_name);
+         return i;
        }
-      fclose(f);
     }
-  closedir(d);
+  return MAX_BATTS;
 }
 
-static void scan_batt(void)
+static void parse_batt(char *batt_name)
 {
+  int batt_id = get_batt_id(batt_name);
+  DBG("\t-> id %d\n", batt_id);
+
+  if (!sys_read_int("present", 1))
+    return;
+
+  int charging = sys_read_int("charging", 0);
+  int charge_full = sys_read_int("charge_full", 0);
+  int charge_now = sys_read_int("charge_now", 0);
+  int current_now = sys_read_int("current_now", 0);
+
+  present_mask |= 1 << batt_id;
+  total_now += charge_now;
+  total_full += charge_full;
+  if (charging && current_now > 0)
+    {
+      charge_mask |= 1 << batt_id;
+      int ch = (long long)(charge_full - charge_now)*3600 / current_now;
+      if (ch > charge_time)
+       charge_time = ch;
+    }
+  else if (current_now > 0)
+    {
+      discharge_mask |= 1 << batt_id;
+      discharge_rate += current_now;
+    }
+}
+
+static void scan(void)
+{
+  ac_online = 0;
   charge_time = discharge_time = 0;
-  total_full = total_capa = 0;
+  total_now = total_full = 0;
   discharge_rate = 0;
   present_mask = charge_mask = discharge_mask = 0;
 
-  const char dir[] = "/proc/acpi/battery";
+  const char dir[] = "/sys/class/power_supply";
   DIR *d = opendir(dir);
   if (!d)
     return;
@@ -88,76 +133,28 @@ static void scan_batt(void)
   while (e = readdir(d))
     {
       if (e->d_name[0] == '.')
-        continue;
-      char n[sizeof(dir) + 1 + strlen(e->d_name) + 6];
-      const char * const names[] = { "state", "info" };
-      int present = 0;
-      int rate = 0;
-      int charging = 0;
-      int remains = 0;
-      int last_full = 0;
-      int batt_id = -1;
-      for (int i=0; i<2; i++)
-        {
-         sprintf(n, "%s/%s/%s", dir, e->d_name, names[i]);
-         FILE *f = fopen(n, "r");
-         if (!f)
-           continue;
-         char line[1024];
-         while (fgets(line, sizeof(line)-1, f))
-           {
-             char *val = parse_line(line);
-             if (!val)
-               continue;
-             // printf("<%s> <%s>\n", line, val);
-             if (!strcmp(line, "present"))
-               present = !strcmp(val, "yes");
-             else if (!strcmp(line, "charging state"))
-               charging = !strcmp(val, "charging");
-             else if (!strcmp(line, "present rate"))
-               rate = atol(val);
-             else if (!strcmp(line, "remaining capacity"))
-               remains = atol(val);
-             else if (!strcmp(line, "last full capacity"))
-               last_full = atol(val);
-             else if (!strcmp(line, "serial number"))
-               batt_id = atol(val);
-           }
-         fclose(f);
-       }
-      if (present)
-        {
-         if (batt_id < 0 || batt_id > 31)
-           batt_id = 0;
-         present_mask |= 1 << batt_id;
-         total_full += remains;
-         total_capa += last_full;
-         if (charging)
-           {
-             charge_mask |= 1 << batt_id;
-             int ch = (last_full - remains)*3600 / rate;
-             if (ch > charge_time)
-               charge_time = ch;
-           }
-         else if (rate > 0)
-           {
-             discharge_mask |= 1 << batt_id;
-             discharge_rate += rate;
-           }
-       }
+       continue;
+      snprintf(sys_dir, sizeof(sys_dir), "%s/%s", dir, e->d_name);
+      DBG("%s\n", sys_dir);
+
+      char type[BUFSIZE];
+      if (!sys_read(type, "type"))
+       continue;
+
+      if (!strcmp(type, "Mains"))
+       parse_ac();
+      else if (!strcmp(type, "Battery"))
+       parse_batt(e->d_name);
     }
   if (discharge_rate)
-    discharge_time = total_full*3600 / discharge_rate;
+    discharge_time = (long long) total_now*3600 / discharge_rate;
   else
     discharge_time = 1000000;
 
   closedir(d);
-}
-
-static void scan(void)
-{
-  scan_ac();
-  scan_batt();
+  DBG("=> Capacity: now=%d full=%d\n", total_now, total_full);
+  DBG("=> Charge: mask=%d time=%d\n", charge_mask, charge_time);
+  DBG("=> Discharge: mask=%d rate=%d time=%d\n", discharge_mask, discharge_rate, discharge_time);
 }
 
 static char *batt_mask(char *p, unsigned int mask)
@@ -181,8 +178,8 @@ static void show(void)
 {
   char status[256];
   char *p = status;
-  if (total_capa)
-    p += sprintf(p, "%d%%", 100*total_full/total_capa);
+  if (total_full)
+    p += sprintf(p, "%d%%", (int)((long long)100*total_now/total_full));
   else
     p += sprintf(p, "??%%");
   if (discharge_mask && discharge_time < 1000000)