From: Martin Mares Date: Sat, 17 Jul 2010 17:54:50 +0000 (+0200) Subject: Added a battery checking client X-Git-Tag: v1.0~8 X-Git-Url: http://mj.ucw.cz/gitweb/?a=commitdiff_plain;h=d3ef70d2dd6e98426a63e2cbcfc35d0bafbf998d;p=osdd.git Added a battery checking client --- diff --git a/Makefile b/Makefile index 5acc1db..a4492c5 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,16 @@ CFLAGS=-O2 -Wall -W -Wno-parentheses -Wstrict-prototypes -Wmissing-prototypes -Wundef -Wredundant-decls -std=gnu99 -all: osdd osdc +all: osdd osdc osd-batt osdd: osdd.o util.o osdc: osdc.o util.o send.o +osd-batt: osd-batt.o util.o send.o osdd.o: CFLAGS+=$(shell xosd-config --cflags) osdd: LDFLAGS+=$(shell xosd-config --libs) osdc: LDFLAGS+=-lX11 +osd-batt: LDFLAGS+=-lX11 clean: rm -f *~ *.o TAGS core osdd osdc diff --git a/osd-batt.c b/osd-batt.c new file mode 100644 index 0000000..9d7a6ca --- /dev/null +++ b/osd-batt.c @@ -0,0 +1,249 @@ +/* + * A Simple Battery Status Display via OSD + * + * (c) 2007--2010 Martin Mares + */ + +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "send.h" + +static int check_mode; +static int warn_threshold = 600; + +static int total_full, total_capa, discharge_rate; +static int charge_time, discharge_time; +static int ac_online; +static unsigned int present_mask, charge_mask, discharge_mask; + +static char *parse_line(char *line) +{ + 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; +} + +static void scan_ac(void) +{ + ac_online = 0; + + const char dir[] = "/proc/acpi/ac_adapter"; + DIR *d = opendir(dir); + if (!d) + return; + + struct dirent *e; + while (e = readdir(d)) + { + 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)) + { + char *val = parse_line(line); + if (!val) + continue; + if (!strcmp(line, "state") && !strcmp(val, "on-line")) + ac_online = 1; + } + fclose(f); + } + closedir(d); +} + +static void scan_batt(void) +{ + charge_time = discharge_time = 0; + total_full = total_capa = 0; + discharge_rate = 0; + present_mask = charge_mask = discharge_mask = 0; + + const char dir[] = "/proc/acpi/battery"; + DIR *d = opendir(dir); + if (!d) + return; + + struct dirent *e; + 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; + } + } + } + if (discharge_rate) + discharge_time = total_full*3600 / discharge_rate; + else + discharge_time = 1000000; + + closedir(d); +} + +static void scan(void) +{ + scan_ac(); + scan_batt(); +} + +static char *batt_mask(char *p, unsigned int mask) +{ + if (present_mask & (present_mask-1)) + { + char *p0 = p; + for (int i=0; mask; i++) + if (mask & (1 << i)) + { + *p = (p == p0) ? ' ' : '+'; + p++; + p += sprintf(p, "B%d", i); + mask &= ~(1 << i); + } + } + return p; +} + +static void show(void) +{ + char status[256]; + char *p = status; + if (total_capa) + p += sprintf(p, "%d%%", 100*total_full/total_capa); + else + p += sprintf(p, "??%%"); + if (discharge_mask && discharge_time < 1000000) + { + p += sprintf(p, " %d:%02d remains", discharge_time/3600, (discharge_time/60)%60); + batt_mask(p, discharge_mask); + } + else if (charge_mask) + { + p += sprintf(p, " %d:%02d charging", charge_time/3600, (charge_time/60)%60); + batt_mask(p, charge_mask); + } + else if (ac_online) + p += sprintf(p, " AC"); + else + p += sprintf(p, " BATT"); + + struct osd_msg *msg = osd_new_msg(); + osd_add_line(msg, NULL, status); + osd_send(msg); +} + +static void NONRET +usage(void) +{ + fprintf(stderr, "\ +Usage: osd-batt \n\ +\n\ +Options:\n\ +-c, --check\t\tDisplay status only if battery is low\n\ +-w, --warn=\tBattery is low if less than seconds remain\n\ +"); + exit(1); +} + +static const char short_opts[] = "cw:"; + +static const struct option long_opts[] = { + { "check", no_argument, NULL, 'c' }, + { "warn", required_argument, NULL, 'w' }, + { NULL, 0, NULL, 0 }, +}; + +int main(int argc, char **argv) +{ + int opt; + while ((opt = getopt_long(argc, argv, short_opts, long_opts, NULL)) >= 0) + switch (opt) + { + case 'c': + check_mode++; + break; + case 'w': + warn_threshold = atoi(optarg); + break; + default: + usage(); + } + if (optind < argc) + usage(); + + scan(); + if (!check_mode || (discharge_mask && discharge_time < warn_threshold)) + show(); + + return 0; +}