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))
97 int charging = sys_read_int("charging", 0);
98 int charge_full = sys_read_int("charge_full", 0);
99 int charge_now = sys_read_int("charge_now", 0);
100 int current_now = sys_read_int("current_now", 0);
102 present_mask |= 1 << batt_id;
103 total_now += charge_now;
104 total_full += charge_full;
105 if (charging && current_now > 0)
107 charge_mask |= 1 << batt_id;
108 int ch = (long long)(charge_full - charge_now)*3600 / current_now;
109 if (ch > charge_time)
112 else if (current_now > 0)
114 discharge_mask |= 1 << batt_id;
115 discharge_rate += current_now;
119 static void scan(void)
122 charge_time = discharge_time = 0;
123 total_now = total_full = 0;
125 present_mask = charge_mask = discharge_mask = 0;
127 const char dir[] = "/sys/class/power_supply";
128 DIR *d = opendir(dir);
133 while (e = readdir(d))
135 if (e->d_name[0] == '.')
137 snprintf(sys_dir, sizeof(sys_dir), "%s/%s", dir, e->d_name);
138 DBG("%s\n", sys_dir);
141 if (!sys_read(type, "type"))
144 if (!strcmp(type, "Mains"))
146 else if (!strcmp(type, "Battery"))
147 parse_batt(e->d_name);
150 discharge_time = (long long) total_now*3600 / discharge_rate;
152 discharge_time = 1000000;
155 DBG("=> Capacity: now=%d full=%d\n", total_now, total_full);
156 DBG("=> Charge: mask=%d time=%d\n", charge_mask, charge_time);
157 DBG("=> Discharge: mask=%d rate=%d time=%d\n", discharge_mask, discharge_rate, discharge_time);
160 static char *batt_mask(char *p, unsigned int mask)
162 if (present_mask & (present_mask-1))
165 for (int i=0; mask; i++)
168 *p = (p == p0) ? ' ' : '+';
170 p += sprintf(p, "B%d", i);
177 static void show(void)
182 p += sprintf(p, "%d%%", (int)((long long)100*total_now/total_full));
184 p += sprintf(p, "??%%");
185 if (discharge_mask && discharge_time < 1000000)
187 p += sprintf(p, " %d:%02d remains", discharge_time/3600, (discharge_time/60)%60);
188 batt_mask(p, discharge_mask);
190 else if (charge_mask)
192 p += sprintf(p, " %d:%02d charging", charge_time/3600, (charge_time/60)%60);
193 batt_mask(p, charge_mask);
196 p += sprintf(p, " AC");
198 p += sprintf(p, " BATT");
200 struct osd_msg *msg = osd_new_msg();
201 osd_add_line(msg, NULL, status);
205 static void show_if_warn(void)
207 if (discharge_mask && discharge_time < warn_threshold ||
208 last_ac_online >= 0 && (
209 charge_mask != last_charge_mask ||
210 discharge_mask != last_discharge_mask ||
211 ac_online != last_ac_online))
214 last_charge_mask = charge_mask;
215 last_discharge_mask = discharge_mask;
216 last_ac_online = ac_online;
223 Usage: osd-batt <options>\n\
226 -c, --check\t\tDisplay status only if battery is low\n\
227 -e, --check-every=<sec>\tRun on background and check every <sec> seconds\n\
228 -w, --warn=<sec>\tBattery is low if less than <sec> seconds remain (default: 600)\n\
233 static const char short_opts[] = "ce:w:";
235 static const struct option long_opts[] = {
236 { "check", no_argument, NULL, 'c' },
237 { "check-every", required_argument, NULL, 'e' },
238 { "warn", required_argument, NULL, 'w' },
239 { NULL, 0, NULL, 0 },
242 int main(int argc, char **argv)
245 while ((opt = getopt_long(argc, argv, short_opts, long_opts, NULL)) >= 0)
252 check_every = atoi(optarg);
255 warn_threshold = atoi(optarg);
270 osd_wait(check_every);