2 * A Simple Battery Status Display via OSD
4 * (c) 2007--2010 Martin Mares <mj@ucw.cz>
16 static int check_mode;
17 static int check_every;
18 static int warn_threshold = 600;
20 static int total_full, total_capa, discharge_rate;
21 static int charge_time, discharge_time;
23 static unsigned int present_mask, charge_mask, discharge_mask;
25 static unsigned int last_charge_mask, last_discharge_mask;
26 static int last_ac_online = -1;
28 static char *parse_line(char *line)
30 char *t = strchr(line, '\n');
33 char *val = strchr(line, ':');
37 while (*val == ' ' || *val == '\t')
42 static void scan_ac(void)
46 const char dir[] = "/proc/acpi/ac_adapter";
47 DIR *d = opendir(dir);
52 while (e = readdir(d))
54 if (e->d_name[0] == '.')
56 char n[sizeof(dir) + 1 + strlen(e->d_name) + 6];
57 sprintf(n, "%s/%s/state", dir, e->d_name);
58 FILE *f = fopen(n, "r");
62 while (fgets(line, sizeof(line)-1, f))
64 char *val = parse_line(line);
67 if (!strcmp(line, "state") && !strcmp(val, "on-line"))
75 static void scan_batt(void)
77 charge_time = discharge_time = 0;
78 total_full = total_capa = 0;
80 present_mask = charge_mask = discharge_mask = 0;
82 const char dir[] = "/proc/acpi/battery";
83 DIR *d = opendir(dir);
88 while (e = readdir(d))
90 if (e->d_name[0] == '.')
92 char n[sizeof(dir) + 1 + strlen(e->d_name) + 6];
93 const char * const names[] = { "state", "info" };
100 for (int i=0; i<2; i++)
102 sprintf(n, "%s/%s/%s", dir, e->d_name, names[i]);
103 FILE *f = fopen(n, "r");
107 while (fgets(line, sizeof(line)-1, f))
109 char *val = parse_line(line);
112 // printf("<%s> <%s>\n", line, val);
113 if (!strcmp(line, "present"))
114 present = !strcmp(val, "yes");
115 else if (!strcmp(line, "charging state"))
116 charging = !strcmp(val, "charging");
117 else if (!strcmp(line, "present rate"))
119 else if (!strcmp(line, "remaining capacity"))
121 else if (!strcmp(line, "last full capacity"))
122 last_full = atol(val);
123 else if (!strcmp(line, "serial number"))
130 if (batt_id < 0 || batt_id > 31)
132 present_mask |= 1 << batt_id;
133 total_full += remains;
134 total_capa += last_full;
137 charge_mask |= 1 << batt_id;
138 int ch = (last_full - remains)*3600 / rate;
139 if (ch > charge_time)
144 discharge_mask |= 1 << batt_id;
145 discharge_rate += rate;
150 discharge_time = total_full*3600 / discharge_rate;
152 discharge_time = 1000000;
157 static void scan(void)
163 static char *batt_mask(char *p, unsigned int mask)
165 if (present_mask & (present_mask-1))
168 for (int i=0; mask; i++)
171 *p = (p == p0) ? ' ' : '+';
173 p += sprintf(p, "B%d", i);
180 static void show(void)
185 p += sprintf(p, "%d%%", 100*total_full/total_capa);
187 p += sprintf(p, "??%%");
188 if (discharge_mask && discharge_time < 1000000)
190 p += sprintf(p, " %d:%02d remains", discharge_time/3600, (discharge_time/60)%60);
191 batt_mask(p, discharge_mask);
193 else if (charge_mask)
195 p += sprintf(p, " %d:%02d charging", charge_time/3600, (charge_time/60)%60);
196 batt_mask(p, charge_mask);
199 p += sprintf(p, " AC");
201 p += sprintf(p, " BATT");
203 struct osd_msg *msg = osd_new_msg();
204 osd_add_line(msg, NULL, status);
208 static void show_if_warn(void)
210 if (discharge_mask && discharge_time < warn_threshold ||
211 last_ac_online >= 0 && (
212 charge_mask != last_charge_mask ||
213 discharge_mask != last_discharge_mask ||
214 ac_online != last_ac_online))
217 last_charge_mask = charge_mask;
218 last_discharge_mask = discharge_mask;
219 last_ac_online = ac_online;
226 Usage: osd-batt <options>\n\
229 -c, --check\t\tDisplay status only if battery is low\n\
230 -e, --check-every=<sec>\tRun on background and check every <sec> seconds\n\
231 -w, --warn=<sec>\tBattery is low if less than <sec> seconds remain (default: 600)\n\
236 static const char short_opts[] = "ce:w:";
238 static const struct option long_opts[] = {
239 { "check", no_argument, NULL, 'c' },
240 { "check-every", required_argument, NULL, 'e' },
241 { "warn", required_argument, NULL, 'w' },
242 { NULL, 0, NULL, 0 },
245 int main(int argc, char **argv)
248 while ((opt = getopt_long(argc, argv, short_opts, long_opts, NULL)) >= 0)
255 check_every = atoi(optarg);
258 warn_threshold = atoi(optarg);
273 osd_wait(check_every);