summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--status.c162
1 files changed, 162 insertions, 0 deletions
diff --git a/status.c b/status.c
new file mode 100644
index 0000000..e3a5c44
--- /dev/null
+++ b/status.c
@@ -0,0 +1,162 @@
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include <time.h>
+#include <sys/time.h>
+#include <errno.h>
+
+#define ELEMENT_SEPERATOR " "
+
+#define STATUS_STRBUF_SZ 512
+#define ELEMENT_STRBUF_SZ 64
+
+typedef void (*element_function)(char*);
+
+struct element {
+ const element_function f;
+ const struct timeval fire_interval;
+ struct timeval fire_previous;
+ char buf[ELEMENT_STRBUF_SZ];
+};
+
+
+void date(char* buf) {
+ time_t now = time(NULL);
+ struct tm tm;
+ localtime_r(&now, &tm);
+
+ strftime(buf, ELEMENT_STRBUF_SZ, "%F %R", &tm);
+}
+
+enum battery_status_charge {
+ bat_unknown,
+ bat_not_charging,
+ bat_charging,
+ bat_discharging
+};
+
+struct battery_status {
+ enum battery_status_charge status;
+ float charge;
+};
+
+struct battery_status get_battery_status(const char* buf) {
+ const char path_prefix[] = "/sys/class/power_supply/";
+
+ char charge_path[128];
+ char capacity_path[128];
+
+ memset(charge_path, 0, 128);
+ memset(capacity_path, 0, 128);
+
+ int charge = 0;
+ int capacity = 0;
+
+ char charge_str[512];
+ char capacity_str[512];
+
+ strcat(charge_path, path_prefix);
+ strcat(charge_path, buf);
+ strcat(charge_path, "/energy_now");
+
+ strcat(capacity_path, path_prefix);
+ strcat(capacity_path, buf);
+ strcat(capacity_path, "/energy_full");
+
+ FILE* bat_charge = fopen(charge_path, "r");
+ FILE* bat_capacity = fopen(capacity_path, "r");
+
+ if (!bat_charge) {
+ printf("%d: \"%s\" %s\n", errno, charge_path, strerror(errno));
+ return (struct battery_status){.status = bat_unknown, .charge = -1};
+ }
+ if (!bat_capacity) {
+ printf("%d: \"%s\" %s\n", errno, capacity_path, strerror(errno));
+ return (struct battery_status){.status = bat_unknown, .charge = -1};
+ }
+
+ fread(charge_str, sizeof(char), 512, bat_charge);
+ fread(capacity_str, sizeof(char), 512, bat_capacity);
+
+ fclose(bat_charge);
+ fclose(bat_capacity);
+
+ charge = atoi(charge_str);
+ capacity = atoi(capacity_str);
+
+ return (struct battery_status){.status = bat_unknown, .charge = (float)charge / capacity};
+}
+
+void get_battery0_status(char* buf) {
+ struct battery_status s = get_battery_status("BAT0");
+
+ snprintf(buf, ELEMENT_STRBUF_SZ, "\uf581 %.1f%%", 100.f * s.charge);
+}
+
+static struct element statusbar[] = {
+ {get_battery0_status, {5,0}, 0},
+ {date, {1,500000}, 0},
+};
+
+int main() {
+ const int num_elems = sizeof(statusbar)/sizeof(statusbar[0]);
+ struct timeval now;
+ const struct timeval one_minute = {.tv_sec = 60, .tv_usec = 0};
+
+
+ while (true) {
+ gettimeofday(&now, NULL);
+
+ // Stall updating for at most 1 minute
+ struct timeval next_update;
+ timeradd(&now, &one_minute, &next_update);
+
+ for (unsigned i = 0; i < num_elems; i++) {
+ struct timeval next_fire;
+ timeradd(&statusbar[i].fire_previous, &statusbar[i].fire_interval, &next_fire);
+
+ if (timercmp(&next_fire, &now, >)) {
+ // Check if this is the next to-be-updated element
+ if (timercmp(&next_fire, &next_update, <)) {
+ next_update = next_fire;
+ }
+ continue;
+ }
+
+ memset(statusbar[i].buf, 0, ELEMENT_STRBUF_SZ);
+
+ statusbar[i].f(statusbar[i].buf);
+ statusbar[i].fire_previous = now;
+
+ // Check if this element needs to be refreshed next, again
+ timeradd(&statusbar[i].fire_previous, &statusbar[i].fire_interval, &next_fire);
+ if (timercmp(&next_fire, &next_update, <)) {
+ next_update = next_fire;
+ }
+
+ printf("[%ld.%ld] %s\n", statusbar[i].fire_interval.tv_sec, statusbar[i].fire_interval.tv_usec, (char*)statusbar[i].buf);
+
+ }
+
+ unsigned c = 0;
+ char buf[STATUS_STRBUF_SZ];
+ memset(buf, 0, STATUS_STRBUF_SZ);
+
+ for (unsigned i = 0; i < num_elems; i++) {
+ strcat(buf, statusbar[i].buf);
+ if (i != num_elems - 1) strcat(buf, ELEMENT_SEPERATOR);
+ }
+
+ strcat(buf, "%");
+
+ puts(buf);
+
+ timersub(&next_update, &now, &next_update);
+ usleep(next_update.tv_sec*1000*1000+next_update.tv_usec);
+ }
+
+ return 0;
+}