2 * A Simple Battery Status Display via OSD
4 * (c) 2007--2012 Martin Mares <mj@ucw.cz>
20 static int check_mode;
21 static int check_every;
22 static int warn_threshold = 600;
24 static int total_now, total_full, discharge_rate;
25 static int charge_time, discharge_time;
27 static unsigned int present_mask, charge_mask, discharge_mask;
29 static unsigned int last_charge_mask, last_discharge_mask;
30 static int last_ac_online = -1;
33 #define BATT_NAME_LEN 32
34 static char batt_names[MAX_BATTS][BATT_NAME_LEN];
36 static char sys_dir[256];
39 static int sys_read(char *buf, char *attribute)
42 snprintf(name, sizeof(name), "%s/%s", sys_dir, attribute);
44 int fd = open(name, O_RDONLY);
48 int n = read(fd, buf, BUFSIZE);
54 char *nl = strchr(buf, '\n');
57 DBG("\t%s=%s\n", attribute, buf);
61 static int sys_read_int(char *attribute, int default_value)
64 if (!sys_read(buf, attribute) || !buf[0])
70 static void parse_ac(void)
72 ac_online = sys_read_int("online", 0);
75 static int get_batt_id(char *batt_name)
77 for (int i=0; i<MAX_BATTS; i++)
79 if (!strcmp(batt_names[i], batt_name))
81 if (!batt_names[i][0])
83 snprintf(batt_names[i], BATT_NAME_LEN, "%s", batt_name);
90 static void parse_batt(char *batt_name)
92 int batt_id = get_batt_id(batt_name);
93 DBG("\t-> id %d\n", batt_id);
95 if (!sys_read_int("present", 1))
99 int charging = sys_read(status, "status") && !strcmp(status, "Charging");
100 int charge_full = sys_read_int("charge_full", 0);
101 int charge_now = sys_read_int("charge_now", 0);
102 int current_now = sys_read_int("current_now", 0);
104 present_mask |= 1 << batt_id;
105 total_now += charge_now;
106 total_full += charge_full;
107 if (charging && current_now > 0)
109 charge_mask |= 1 << batt_id;
110 int ch = (long long)(charge_full - charge_now)*3600 / current_now;
111 if (ch > charge_time)
114 else if (current_now > 0)
116 discharge_mask |= 1 << batt_id;
117 discharge_rate += current_now;
121 static void scan(void)
124 charge_time = discharge_time = 0;
125 total_now = total_full = 0;
127 present_mask = charge_mask = discharge_mask = 0;
129 const char dir[] = "/sys/class/power_supply";
130 DIR *d = opendir(dir);
135 while (e = readdir(d))
137 if (e->d_name[0] == '.')
139 snprintf(sys_dir, sizeof(sys_dir), "%s/%s", dir, e->d_name);
140 DBG("%s\n", sys_dir);
143 if (!sys_read(type, "type"))
146 if (!strcmp(type, "Mains"))
148 else if (!strcmp(type, "Battery"))
149 parse_batt(e->d_name);
152 discharge_time = (long long) total_now*3600 / discharge_rate;
154 discharge_time = 1000000;
157 DBG("=> Capacity: now=%d full=%d\n", total_now, total_full);
158 DBG("=> Charge: mask=%d time=%d\n", charge_mask, charge_time);
159 DBG("=> Discharge: mask=%d rate=%d time=%d\n", discharge_mask, discharge_rate, discharge_time);
162 static char *batt_mask(char *p, unsigned int mask)
164 if (present_mask & (present_mask-1))
167 for (int i=0; mask; i++)
170 *p = (p == p0) ? ' ' : '+';
172 p += sprintf(p, "B%d", i);
179 static void show(void)
184 p += sprintf(p, "%d%%", (int)((long long)100*total_now/total_full));
186 p += sprintf(p, "??%%");
187 if (discharge_mask && discharge_time < 1000000)
189 p += sprintf(p, " %d:%02d remains", discharge_time/3600, (discharge_time/60)%60);
190 batt_mask(p, discharge_mask);
192 else if (charge_mask)
194 p += sprintf(p, " %d:%02d charging", charge_time/3600, (charge_time/60)%60);
195 batt_mask(p, charge_mask);
198 p += sprintf(p, " AC");
200 p += sprintf(p, " BATT");
202 struct osd_msg *msg = osd_new_msg();
203 osd_add_line(msg, NULL, status);
207 static void show_if_warn(void)
209 if (discharge_mask && discharge_time < warn_threshold ||
210 last_ac_online >= 0 && (
211 charge_mask != last_charge_mask ||
212 discharge_mask != last_discharge_mask ||
213 ac_online != last_ac_online))
216 last_charge_mask = charge_mask;
217 last_discharge_mask = discharge_mask;
218 last_ac_online = ac_online;
225 Usage: osd-batt <options>\n\
228 -c, --check\t\tDisplay status only if battery is low\n\
229 -e, --check-every=<sec>\tRun on background and check every <sec> seconds\n\
230 -w, --warn=<sec>\tBattery is low if less than <sec> seconds remain (default: 600)\n\
235 static const char short_opts[] = "ce:w:";
237 static const struct option long_opts[] = {
238 { "check", no_argument, NULL, 'c' },
239 { "check-every", required_argument, NULL, 'e' },
240 { "warn", required_argument, NULL, 'w' },
241 { NULL, 0, NULL, 0 },
244 int main(int argc, char **argv)
247 while ((opt = getopt_long(argc, argv, short_opts, long_opts, NULL)) >= 0)
254 check_every = atoi(optarg);
257 warn_threshold = atoi(optarg);
272 osd_wait(check_every);