status

statusbar program for dwm
git clone anongit@rnpnr.xyz:status.git
Log | Files | Refs | Feed | README | LICENSE

battery_info.c (3174B)


      1 /* See LICENSE for license details. */
      2 struct bat_arg {
      3 	s8    bat;      /* BAT name (ex. s8("BAT0")) */
      4 	char *pre;      /* prefix for percentages less than thres */
      5 	char *suf;      /* suffix for percentages less than thres */
      6 	i32   thres;    /* % threshold to consider low (-1 to disable) */
      7 };
      8 
      9 struct linux_battery_data { Stream path_base; i64 energy_full; };
     10 
     11 static BLOCK_UPDATE_FN(battery_info_update)
     12 {
     13 	struct bat_arg *ba             = b->arg;
     14 	struct linux_battery_data *lbd = b->user_data;
     15 
     16 	char *pre = ba->pre ? ba->pre : "";
     17 	char *suf = ba->suf ? ba->suf : "";
     18 
     19 	i32 h, m;
     20 	i64 power_now, energy_now;
     21 	f64 timeleft;
     22 
     23 	size sidx = lbd->path_base.write_index;
     24 
     25 	stream_push_s8(&lbd->path_base, s8("/energy_now"));
     26 	energy_now = read_i64(stream_ensure_c_str(&lbd->path_base));
     27 	lbd->path_base.write_index = sidx;
     28 
     29 	f32 percent = 100 * (energy_now / (f64)lbd->energy_full) + 0.5;
     30 	b32 warn    = percent < ba->thres;
     31 
     32 	char state_buffer[16] = {0};
     33 	stream_push_s8(&lbd->path_base, s8("/status"));
     34 	s8 state = s8_trim_space(read_s8(stream_ensure_c_str(&lbd->path_base),
     35 	                                (s8){.len = sizeof(state_buffer),
     36 	                                     .data = (u8 *)state_buffer}));
     37 	if (state.len <= 0) state = s8("Unknown");
     38 	lbd->path_base.write_index = sidx;
     39 	state.data[state.len] = 0;
     40 
     41 	i64 len;
     42 	/* NOTE(rnp): proper devices use negative power to indicate discharging but that
     43 	 * is not always the case. The status string can mostly be trusted */
     44 	if (s8_equal(state, s8("Discharging"))) {
     45 		stream_push_s8(&lbd->path_base, s8("/power_now"));
     46 		power_now = read_i64(stream_ensure_c_str(&lbd->path_base));
     47 		if (!power_now) power_now = 1;
     48 		lbd->path_base.write_index = sidx;
     49 
     50 		timeleft = energy_now / (f64)ABS(power_now);
     51 		h = timeleft;
     52 		m = (timeleft - (f64)h) * 60;
     53 
     54 		len = snprintf(buffer, sizeof(buffer), "%s%d%% (%d:%02d)%s", warn? pre : "",
     55 		              (i32)percent, h, m, warn? suf : "");
     56 	} else {
     57 		len = snprintf(buffer, sizeof(buffer), "%s%d%% (%s)%s", warn? pre : "",
     58 		               (i32)percent, (char *)state.data, warn? suf : "");
     59 	}
     60 	buffer[len] = 0;
     61 	b->len = snprintf(b->data, sizeof(b->data), b->fmt, buffer);
     62 }
     63 
     64 #define LINUX_BAT_INFO_STRS \
     65 	X("/energy_full")    \
     66 	X("/energy_now")     \
     67 	X("/power_now")      \
     68 	X("/status")
     69 
     70 static BLOCK_INIT_FN(battery_info_init)
     71 {
     72 	struct bat_arg *ba = b->arg;
     73 	struct linux_battery_data *lbd;
     74 	b->user_data = lbd = push_struct(a, struct linux_battery_data);
     75 
     76 	size max_length = 0;
     77 	#define X(cstr) if ((sizeof(cstr) - 1) > max_length) max_length = sizeof(cstr) - 1;
     78 	LINUX_BAT_INFO_STRS
     79 	#undef X
     80 
     81 	size needed_length = max_length + ba->bat.len + sizeof("/sys/class/power_supply/");
     82 	lbd->path_base     = stream_alloc(a, needed_length);
     83 
     84 	stream_push_s8(&lbd->path_base, s8("/sys/class/power_supply/"));
     85 	stream_push_s8(&lbd->path_base, ba->bat);
     86 	size sidx = lbd->path_base.write_index;
     87 	stream_push_s8(&lbd->path_base, s8("/energy_full"));
     88 	lbd->energy_full = read_i64(stream_ensure_c_str(&lbd->path_base));
     89 	if (!lbd->energy_full)
     90 		die("battery_info_init: failed to read battery capacity\n");
     91 	lbd->path_base.write_index = sidx;
     92 
     93 	battery_info_update(b);
     94 }