2 * A Simple Battery Status Display via OSD
4 * (c) 2007--2012 Martin Mares <mj@ucw.cz>
19 static int check_mode;
20 static int check_every;
21 static int warn_threshold = 600;
23 static int total_now, total_full, discharge_rate;
24 static int charge_time, discharge_time;
26 static unsigned int present_mask, charge_mask, discharge_mask;
28 static unsigned int last_charge_mask, last_discharge_mask;
29 static int last_ac_online = -1;
32 #define BATT_NAME_LEN 32
33 static char batt_names[MAX_BATTS][BATT_NAME_LEN];
35 static char sys_dir[256];
38 static int sys_read(char *buf, char *attribute)
41 snprintf(name, sizeof(name), "%s/%s", sys_dir, attribute);
43 int fd = open(name, O_RDONLY);
47 int n = read(fd, buf, BUFSIZE);
53 char *nl = strchr(buf, '\n');
56 DBG("\t%s=%s\n", attribute, buf);
60 static int sys_read_int(char *attribute, int default_value)
63 if (!sys_read(buf, attribute) || !buf[0])
69 static void parse_ac(void)
71 ac_online = sys_read_int("online", 0);
74 static int get_batt_id(char *batt_name)
76 for (int i=0; i<MAX_BATTS; i++)
78 if (!strcmp(batt_names[i], batt_name))
80 if (!batt_names[i][0])
82 snprintf(batt_names[i], BATT_NAME_LEN, "%s", batt_name);
89 static void parse_batt(char *batt_name)
91 int batt_id = get_batt_id(batt_name);
92 DBG("\t-> id %d\n", batt_id);
94 if (!sys_read_int("present", 1))
98 int charging = sys_read(status, "status") && !strcmp(status, "Charging");
99 int charge_full = sys_read_int("charge_full", 0);
100 int charge_now = sys_read_int("charge_now", 0);
101 int current_now = sys_read_int("current_now", 0);
103 present_mask |= 1 << batt_id;
104 total_now += charge_now;
105 total_full += charge_full;
106 if (charging && current_now > 0)
108 charge_mask |= 1 << batt_id;
109 int ch = (long long)(charge_full - charge_now)*3600 / current_now;
110 if (ch > charge_time)
113 else if (current_now > 0)
115 discharge_mask |= 1 << batt_id;
116 discharge_rate += current_now;
120 static void scan(void)
123 charge_time = discharge_time = 0;
124 total_now = total_full = 0;
126 present_mask = charge_mask = discharge_mask = 0;
128 const char dir[] = "/sys/class/power_supply";
129 DIR *d = opendir(dir);
134 while (e = readdir(d))
136 if (e->d_name[0] == '.')
138 snprintf(sys_dir, sizeof(sys_dir), "%s/%s", dir, e->d_name);
139 DBG("%s\n", sys_dir);
142 if (!sys_read(type, "type"))
145 if (!strcmp(type, "Mains"))
147 else if (!strcmp(type, "Battery"))
148 parse_batt(e->d_name);
151 discharge_time = (long long) total_now*3600 / discharge_rate;
153 discharge_time = 1000000;
156 DBG("=> Capacity: now=%d full=%d\n", total_now, total_full);
157 DBG("=> Charge: mask=%d time=%d\n", charge_mask, charge_time);
158 DBG("=> Discharge: mask=%d rate=%d time=%d\n", discharge_mask, discharge_rate, discharge_time);
161 static char *batt_mask(char *p, unsigned int mask)
163 if (present_mask & (present_mask-1))
166 for (int i=0; mask; i++)
169 *p = (p == p0) ? ' ' : '+';
171 p += sprintf(p, "B%d", i);
178 static void show(void)
183 p += sprintf(p, "%d%%", (int)((long long)100*total_now/total_full));
185 p += sprintf(p, "??%%");
186 if (discharge_mask && discharge_time < 1000000)
188 p += sprintf(p, " %d:%02d remains", discharge_time/3600, (discharge_time/60)%60);
189 batt_mask(p, discharge_mask);
191 else if (charge_mask)
193 p += sprintf(p, " %d:%02d charging", charge_time/3600, (charge_time/60)%60);
194 batt_mask(p, charge_mask);
197 p += sprintf(p, " AC");
199 p += sprintf(p, " BATT");
201 struct osd_msg *msg = osd_new_msg();
202 osd_add_line(msg, NULL, status);
206 static void show_if_warn(void)
208 if (discharge_mask && discharge_time < warn_threshold ||
209 last_ac_online >= 0 && (
210 charge_mask != last_charge_mask ||
211 discharge_mask != last_discharge_mask ||
212 ac_online != last_ac_online))
215 last_charge_mask = charge_mask;
216 last_discharge_mask = discharge_mask;
217 last_ac_online = ac_online;
224 Usage: osd-batt <options>\n\
227 -c, --check\t\tDisplay status only if battery is low\n\
228 -e, --check-every=<sec>\tRun on background and check every <sec> seconds\n\
229 -w, --warn=<sec>\tBattery is low if less than <sec> seconds remain (default: 600)\n\
234 static const char short_opts[] = "ce:w:";
236 static const struct option long_opts[] = {
237 { "check", no_argument, NULL, 'c' },
238 { "check-every", required_argument, NULL, 'e' },
239 { "warn", required_argument, NULL, 'w' },
240 { NULL, 0, NULL, 0 },
243 int main(int argc, char **argv)
246 while ((opt = getopt_long(argc, argv, short_opts, long_opts, NULL)) >= 0)
253 check_every = atoi(optarg);
256 warn_threshold = atoi(optarg);
271 osd_wait(check_every);