#include <errno.h>
#include <unistd.h>
#include <ctype.h>
+#include <stdint.h>
#include <sys/poll.h>
#include <sys/types.h>
}
static void badusage(void) { fail("bad usage"); }
-#define CHGST_DISCHARGING 0 /* Reflects order in E(state,charging_state) */
-#define CHGST_CHARGING 1 /* in fields table. Also, much code assumes */
-#define CHGST_CHARGED 2 /* exactly these three possible states. */
-#define CHGST_ERROR 8 /* Except that this one is an extra bit. */
+typedef struct fileinfo fileinfo;
+struct fileinfo {
+ const char *filename;
+ void (*parse)(const fileinfo*);
+ const void *extra;
+};
-/*---------- structure of and results from /proc/acpi/battery/... ----------*/
+/*---------- structure of and results from /sys/class/power/... ----------*/
/* variables thisbat_... are the results from readbattery();
* if readbattery() succeeds they are all valid and not VAL_NOTFOUND
*/
typedef struct batinfo_field {
- const char *file;
const char *label;
- const char *acpi_label;
- double acpi_conversion_factor;
- unsigned long *valuep;
- const char *unit;
+ uint64_t *valuep;
const char *enumarray[10];
} batinfo_field;
-#define QUANTITY_FIELDS \
- QF(info, design_capacity, "mWh", energy_full_design, 1e-3) \
- QF(info, last_full_capacity, "mWh", energy_full, 1e-3) \
- QF(state, present_rate, "mW", power_now, 1e-3) \
- QF(state, remaining_capacity, "mWh", energy_now, 1e-3) \
- QF(alarm, alarm, "mWh", alarm, 1e-3)
-
-#define QF(f,l,u,a,ac) static unsigned long thisbat_##f##_##l;
- QUANTITY_FIELDS
-#undef QF
-
-static unsigned long thisbat_alarm_present, thisbat_info_present;
-static unsigned long thisbat_state_present, thisbat_state_charging_state;
+#define UEVENT_QUANTITY_FIELDS(q) \
+ q(design_capacity, CHARGE_FULL_DESIGN ) /* uAh */ \
+ q(last_full_capacity, CHARGE_FULL ) /* uAh */ \
+ q(present_rate, CURRENT_NOW ) /* uA */ \
+ q(remaining_capacity, CHARGE_NOW ) /* uAh */ \
+ q(present, PRESENT ) /* boolean */ \
+ q(online, ONLINE ) /* boolean */
+
+#define UEVENT_ENUM_FIELDS(e) \
+ e(type, TYPE, "Battery", "Mains" ) \
+ e(state, STATUS, "Discharging", "Charging", "Charged" )
+
+#define CHGST_DISCHARGING 0 /* Reflects order in e(state,...) above */
+#define CHGST_CHARGING 1 /* Also, much code assumes exadtly */
+#define CHGST_CHARGED 2 /* these three possible states. */
+#define CHGST_ERROR 8 /* Except that this one is an extra bit. */
+
+#define Q_FLD(f,l) { "POWER_SUPPLY_" #l, &thisbat_##f },
+#define E_FLD(f,l,vl...) { "POWER_SUPPLY_" #l, &thisbat_##f, { vl } },
+
+#define ALL_FIELDS(i) \
+ UEVENT_QUANTITY_FIELDS(i) \
+ UEVENT_ENUM_FIELDS(i) \
+ i(thisbat_alarm)
+
+#define F_VAR(f,...) static uint64_t thisbat_##f;
+ ALL_FIELDS(F_VAR)
+
+static const batinfo_field uevent_fields[]= {
+ UEVENT_QUANTITY_FIELDS(Q_FLD)
+ UEVENT_ENUM_FIELDS(E_FLD)
+ { 0 }
+};
#define VAL_NOTFOUND (~0UL)
-static const batinfo_field fields[]= {
-#define E(f,l) #f, #l, &thisbat_##f##_##l, 0
-#define QF(f,l,u) { #f, #l, &thisbat_##f##_##l, u },
- { E(alarm, present), 0,0, { "no", "yes" } },
- { E(info, present), 0,0, { "no", "yes" } },
- { E(state,present), 0,0, { "no", "yes" } },
- { E(state,charging_state), { "discharging", "charging", "charged" } },
- QUANTITY_FIELDS /* take care re charging_state values order - */
- { 0 } /* if you must change it, search for CHGST_... */
-#undef E
-#undef QF
+static const fileinfo files[]= {
+ { "uevent", parse_fields, uevent_fields },
+ { "alarm", parse_boolean, &thisbat_alarm },
+ { 0 }
};
-static const char *files[]= { "info", "state", "alarm" };
-
/*---------- parsing of one battery in /proc/acpi/battery/... ----------*/
/* variables private to the parser and its error handlers */
static void chdir_base(void) {
int r;
- r= chdir("/proc/acpi/battery");
- if (r) batfaile("chdir","/proc/acpi/battery");
+ r= chdir("/sys/class/power_supply");
+ if (r) batfaile("chdir","/sys/class/power_supply");
}
static void tidybattery(void) {
if (batdirname) { chdir_base(); batdirname=0; }
}
+static void parse_fields(const fileinfo *cfile, char *batlinebuf) {
+ equals= strchr(batlinebuf,'=');
+ if (!equals)
+ return batfailf("line without a equals");
+ *equals++= 0;
+
+ for (field=fields; field->file; field++) {
+ if (!strcmp(field->label,batlinebuf))
+ goto found;
+ }
+ return;
+
+ found:
+ if (!field->enumarray[0]) {
+
+ *field->valuep= strtoull(equals,&ep,10);
+ if (*ep)
+ batfailf("value number syntax incorrect");
+
+ } else {
+
+ for (*field->valuep=0, enumsearch=field->enumarray;
+ *enumsearch && strcmp(*enumsearch,equals);
+ (*field->valuep)++, enumsearch++);
+ if (!*enumsearch)
+ batfailf("unknown enum value");
+
+ }
+}
+
static int readbattery(void) { /* 0=>ok, -1=>couldn't */
const batinfo_field *field;
- const char *const *cfilename, *const *enumsearch;
+ const fileinfo *cfile;
+ const char *const *enumsearch;
char *colon, *ep, *sr, *p;
int r, l, missing;
r= chdir(batdirname);
if (r) return batfaile("chdir",batdirname);
+#define V_NOTFOUND(f,...) thisbat_##f = VAL_NOTFOUND;
+ ALL_FIELDS(V_NOTFOUND)
+
for (field=fields; field->file; field++)
*field->valuep= VAL_NOTFOUND;
- for (cfilename=files;
- (batfilename= *cfilename);
- cfilename++) {
+ for (cfile=files;
+ (batfilename= cfile->filename);
+ cfile++++) {
batfile= fopen(batfilename,"r");
if (!batfile) return batfaile("open",batfilename);
if (batlinebuf[l-1] != '\n')
return batfailf("line too long");
batlinebuf[l-1]= 0;
- colon= strchr(batlinebuf,':');
- if (!colon)
- return batfailf("line without a colon");
- *colon= 0;
-
- for (batlinevalue= colon+1;
- *batlinevalue && isspace((unsigned char)*batlinevalue);
- batlinevalue++);
-
- if (!strcmp(batlinebuf,"ERROR"))
- return batfailf("kernel reports error");
-
- for (p=batlinebuf; p<colon; p++)
- if (*p == ' ')
- *p= '_';
-
- for (field=fields; field->file; field++) {
- if (!strcmp(field->file,batfilename) &&
- !strcmp(field->label,batlinebuf))
- goto label_interesting;
- }
- continue;
-
- label_interesting:
- if (field->unit) {
-
- *field->valuep= strtoul(batlinevalue,&ep,10);
- if (ep==batlinevalue || *ep!=' ')
- batfailf("value number syntax incorrect");
- if (strcmp(ep+1,field->unit)) batfailf("incorrect unit");
- } else {
-
- for (*field->valuep=0, enumsearch=field->enumarray;
- *enumsearch && strcmp(*enumsearch,batlinevalue);
- (*field->valuep)++, enumsearch++);
- if (!*enumsearch)
- batfailf("unknown enum value");
-
- }
+ cfile->parse(cfile, batlinebuf);
}
fclose(batfile);