Skip to content
Snippets Groups Projects
Commit d3ef70d2 authored by Martin Mareš's avatar Martin Mareš
Browse files

Added a battery checking client

parent 845e5d4b
No related branches found
No related tags found
No related merge requests found
CFLAGS=-O2 -Wall -W -Wno-parentheses -Wstrict-prototypes -Wmissing-prototypes -Wundef -Wredundant-decls -std=gnu99 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 osdd: osdd.o util.o
osdc: osdc.o util.o send.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.o: CFLAGS+=$(shell xosd-config --cflags)
osdd: LDFLAGS+=$(shell xosd-config --libs) osdd: LDFLAGS+=$(shell xosd-config --libs)
osdc: LDFLAGS+=-lX11 osdc: LDFLAGS+=-lX11
osd-batt: LDFLAGS+=-lX11
clean: clean:
rm -f *~ *.o TAGS core osdd osdc rm -f *~ *.o TAGS core osdd osdc
/*
* A Simple Battery Status Display via OSD
*
* (c) 2007--2010 Martin Mares <mj@ucw.cz>
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <getopt.h>
#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 <options>\n\
\n\
Options:\n\
-c, --check\t\tDisplay status only if battery is low\n\
-w, --warn=<sec>\tBattery is low if less than <sec> 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;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment