commit 9277f37fbd9ab2abf0a46c4c294f322c7b2c70be from: Benjamin Stürz date: Fri Jun 14 14:31:11 2024 UTC make bedstatus more portable commit - 41845009e0bf65a06ac9a5cb667e62cdfe939dfc commit + 9277f37fbd9ab2abf0a46c4c294f322c7b2c70be blob - 6503128fa94d82c7b7bf817f2407056390a81c09 blob + 1fdcb99d4bf543892bcd66104fe535fb027405f3 --- Makefile +++ Makefile @@ -6,6 +6,11 @@ HDR_DWM = dwm/drw.h dwm/util.h dwm/config.h master.h SRC_ST = st/st.c st/x.c HDR_ST = st/arg.h st/st.h st/win.h st/config.h master.h +SRC_BS = bedstatus/bedstatus.c +HDR_BS = bedstatus/bedstatus.h \ + bedstatus/unsupported.c \ + bedstatus/openbsd.c + SRC_DMENU = dmenu/dmenu.c dmenu/drw.c dmenu/util.c HDR_DMENU = dmenu/arg.h dmenu/config.h dmenu/drw.h dmenu/util.h master.h @@ -76,7 +81,7 @@ bin/st: ${SRC_ST} ${HDR_ST} @mkdir -p bin ${CC} -o $@ ${SRC_ST} ${CFLAGS} `pkg-config --cflags --libs fontconfig freetype2 x11 xft xrender` -lm -lutil -bin/bedstatus: bedstatus/bedstatus.c +bin/bedstatus: ${SRC_BS} ${HDR_BS} @mkdir -p bin ${CC} -o $@ bedstatus/bedstatus.c ${CFLAGS} `pkg-config --cflags --libs x11` blob - 3acfb46c3c44b48560b003bf074c13bbcb708694 blob + fedc672f5da002f3fd3467776189563f404e5df7 --- bedstatus/bedstatus.c +++ bedstatus/bedstatus.c @@ -1,137 +1,80 @@ -#include -#include -#include -#include -#include -#include -#include #include #include -#include -#include +#include #include #include -#include #include #include -#define MAXSENSORS 16 -#define CPUSPEEDHISTLEN 3 +#ifdef __OpenBSD__ +# include "openbsd.c" +#else +# include "unsupported.c" +#endif -static int power_sensors[MAXSENSORS]; -static int cputemp_sensor = -1; -static int num_power_sensors = 0; +#define SYM_CPU "\uf2db " +#define SYM_RAM "\uf538 " +#define SYM_BAT_CHARGING "\uf5e7 " +#define SYM_BAT_EMPTY "\uf244 " +#define SYM_BAT_LOW "\uf243 " +#define SYM_BAT_HALF "\uf242 " +#define SYM_BAT_HIGH "\uf241 " +#define SYM_BAT_FULL "\uf240 " -struct cpu_usage { - struct cpustats new; - struct cpustats old; - struct cpustats diffs; -}; +static size_t pos; +static char buf[256]; -static int num_cpu (void) +static void append (const char *fmt, ...) { - const int mib[] = { CTL_HW, HW_NCPU }; - int ncpu = 0; - size_t size = sizeof ncpu; + va_list ap; + int n; + + if (pos >= sizeof (buf)) + return; - if (sysctl (mib, 2, &ncpu, &size, NULL, 0) < 0) - return 1; + va_start (ap, fmt); + n = vsnprintf (buf + pos, sizeof (buf) - pos, fmt, ap); + va_end (ap); - return ncpu; + if (n > 0) + pos += n; } -static int64_t percentages (struct cpustats *out, struct cpu_usage *cpu) +static void format_cpu (const struct status *st) { - int64_t total_change = 0; + if (!st->has_cpu_usage && !st->has_cpu_speed && !st->has_cpu_temp) + return; - for (int i = 0; i < 6; ++i) { - int64_t change = cpu->new.cs_time[i] - cpu->old.cs_time[i]; - if (change < 0) - change = INT64_MAX - cpu->old.cs_time[i] - cpu->new.cs_time[i]; - - cpu->diffs.cs_time[i] = change; - total_change += change; - cpu->old.cs_time[i] = cpu->new.cs_time[i]; - } - - if (total_change == 0) - total_change = 1; + append ("[CPU " SYM_CPU); - for (int i = 0; i < 6; ++i) { - out->cs_time[i] = (cpu->diffs.cs_time[i] * 1000 + total_change / 2) / total_change; + if (st->has_cpu_usage) { + append ("%d%%", st->cpu_usage); + if (st->has_cpu_speed || st->has_cpu_temp) + append (" ("); } - return total_change; -} + if (st->has_cpu_speed) { + append ("%d MHz", st->cpu_speed); -static int cpuspeed (void) -{ - static int history[CPUSPEEDHISTLEN]; - const int mib[2] = { CTL_HW, HW_CPUSPEED }; - int speed, sum = 0; - size_t len = sizeof speed; + if (st->has_cpu_temp) + append ("/"); + } - if (sysctl (mib, 2, &speed, &len, NULL, 0) == -1) - return -1; + if (st->has_cpu_temp) + append ("%d°C", st->cpu_temp); - memmove (history + 1, history, (CPUSPEEDHISTLEN - 1) * sizeof *history); - history[0] = speed; + if (st->has_cpu_usage && (st->has_cpu_speed || st->has_cpu_temp)) + append (")"); - for (int i = 0; i < CPUSPEEDHISTLEN; ++i) - sum += history[i]; - - return sum / CPUSPEEDHISTLEN; + append ("] "); } -static int64_t read_sensor (int id, int type, int n) +static void format_ram (const struct status *st) { - const int mib[5] = { CTL_HW, HW_SENSORS, id, type, n }; - struct sensor sensor; - size_t len = sizeof sensor; - int ret; - - ret = sysctl (mib, 5, &sensor, &len, NULL, 0); - - return (ret == -1 || sensor.status & SENSOR_FINVALID) ? -1 : sensor.value; -} - -static const char *cpu (int ncpu, struct cpu_usage *cpus) -{ - static char buffer[64]; - uint64_t sum = 0; - int64_t temp; - int usage, speed; - - for (int i = 0; i < ncpu; ++i) { - const int mib[] = { CTL_KERN, KERN_CPUSTATS, i }; - struct cpustats tmp; - size_t size = sizeof tmp; - - if (sysctl (mib, 3, &cpus[i].new, &size, NULL, 0) < 0) - continue; - - percentages (&tmp, &cpus[i]); - sum += 1000 - tmp.cs_time[5]; - } - - usage = sum / ncpu / 10; - speed = cpuspeed (); - temp = cputemp_sensor != -1 ? read_sensor (cputemp_sensor, SENSOR_TEMP, 0) : -1; - - if (temp != -1) { - temp = (temp - 273150000) / 1000000; - snprintf (buffer, sizeof buffer, "%d%% (%d MHz/%d°C)", (int)usage, speed, (int)temp); - } else { - snprintf (buffer, sizeof buffer, "%d%% (%d MHz)", (int)usage, speed); - } - return buffer; -} - -static const char *ram (void) -{ + uint64_t bytes; struct unit { const char *s; - unsigned long long u; + uint64_t u; } units[] = { { "PiB", 1ull << 50 }, { "TiB", 1ull << 40 }, @@ -140,158 +83,132 @@ static const char *ram (void) { "KiB", 1ull << 10 }, { NULL, 0 }, }; - const int mib[] = { CTL_VM, VM_UVMEXP }; - struct uvmexp uvmexp; - size_t size = sizeof uvmexp; - uint64_t bytes; - static char buffer[10]; - if (sysctl (mib, 2, &uvmexp, &size, NULL, 0) < 0) - return "N/A"; + if (!st->has_mem_usage) + return; - bytes = ((uint64_t)uvmexp.active << (uvmexp.pageshift - 10)) * 1024; + append ("[RAM " SYM_RAM); - for (const struct unit *u = units; u->s != NULL; ++u) { + bytes = st->mem_usage; + + for (const struct unit *u = units; u-> s != NULL; ++u) { if (bytes < u->u) continue; const unsigned raw = bytes * 100 / u->u; if (raw >= 10000) { - snprintf (buffer, sizeof buffer, "%u %s", raw / 100, u->s); + append ("%u", raw / 100); } else if (raw >= 1000) { - snprintf (buffer, sizeof buffer, "%u.%u %s", raw / 100, raw / 10 % 10, u->s); + append ("%u.%u", raw / 100, raw / 10 % 10); } else { - snprintf (buffer, sizeof buffer, "%u.%02u %s", raw / 100, raw % 100, u->s); + append ("%u.%02u", raw / 100, raw % 100); } - return buffer; + + append (" %s", u->s); + goto done; } - snprintf (buffer, sizeof buffer, "%u B", (unsigned)bytes); - return buffer; + + append ("%u B", (unsigned)bytes); + +done: + append ("] "); } -static void bat (int fd, const char **bat_sym, unsigned *bat_perc, const char **bat_time) +static void format_bat (const struct status *st) { - static char buffer[32]; - struct apm_power_info info; - - if (fd < 0 || ioctl (fd, APM_IOC_GETPOWER, &info) != 0) { - *bat_sym = "N/A"; - *bat_perc = 0; - *bat_time = "N/A"; + if (!st->has_bat_charging && !st->has_bat_perc && !st->has_bat_rem && !st->has_power) return; - } - *bat_perc = info.battery_life; + append ("[BAT "); - if (info.minutes_left != (u_int)-1) { - size_t pos = 0; - unsigned minutes = info.minutes_left; - const static struct unit { + if (!st->has_bat_charging && st->has_bat_perc) { + if (st->bat_perc < 25) { + append (SYM_BAT_EMPTY); + } else if (st->bat_perc < 50) { + append (SYM_BAT_LOW); + } else if (st->bat_perc < 75) { + append (SYM_BAT_HALF); + } else if (st->bat_perc < 99) { + append (SYM_BAT_HIGH); + } else { + append (SYM_BAT_FULL); + } + } else { + append (SYM_BAT_CHARGING); + } + + if (st->has_bat_perc) { + append ("%d%%", st->bat_perc); + + if (st->has_bat_rem || st->has_power) + append (" ("); + } + + if (st->has_bat_rem) { + unsigned rem = st->bat_rem; + struct unit { char c; unsigned v; } units[] = { - { .c = 'd', 24 * 60 }, - { .c = 'h', 60 }, - { .c = 'm', 1 }, - { .c = '\0', 0 }, + { 'd', 24 * 60 }, + { 'h', 60 }, + { 'm', 1 }, + { '\0', 0 }, }; for (size_t i = 0; units[i].v != 0; ++i) { const struct unit u = units[i]; - if (minutes >= u.v) { - pos += snprintf (buffer + pos, sizeof buffer - pos, "%u%c", minutes / u.v, u.c); - minutes %= u.v; - } - } - buffer[pos] = '\0'; - *bat_time = buffer; - } else { - *bat_time = "N/A"; - } - switch (info.ac_state) { - case APM_AC_OFF: - case APM_AC_UNKNOWN: - case APM_AC_BACKUP: - if (info.battery_life < 25) { - *bat_sym = "\uf244"; - } else if (info.battery_life < 50) { - *bat_sym = "\uf243"; - } else if (info.battery_life < 75) { - *bat_sym = "\uf242"; - } else if (info.battery_life < 99) { - *bat_sym = "\uf241"; - } else { - *bat_sym = "\uf240"; + if (rem < u.v) + continue; + + append ("%u%c", rem / u.v, u.c); + rem %= u.v; } - break; - case APM_AC_ON: - *bat_sym = "\uf5e7"; - break; + + if (st->has_power) + append ("/"); } -} -static void find_sensors (void) -{ - for (int i = 0; i < MAXSENSORS; ++i) { - const int mib[3] = { CTL_HW, HW_SENSORS, i }; - struct sensordev dev; - size_t sdlen = sizeof dev; + if (st->has_power) { + unsigned pwr = st->power; - if (sysctl (mib, 3, &dev, &sdlen, NULL, 0) == -1) - continue; + append ("%u.%02uW", pwr / 1000, pwr % 1000 / 10); + } - if (dev.maxnumt[SENSOR_WATTS] > 0) { - power_sensors[num_power_sensors++] = i; - } + if (st->has_bat_perc && (st->has_bat_rem || st->has_power)) + append (")"); - if (dev.maxnumt[SENSOR_TEMP] > 0 - && memcmp (dev.xname, "cpu", 3) == 0 - && cputemp_sensor == -1) { - cputemp_sensor = i; - } - } + append ("] "); } -static const char *power (void) +static void format_time (void) { - static char power[32]; - int64_t total = 0; + struct tm *tm; + time_t t; - if (num_power_sensors == 0) - return ""; + t = time (NULL); + tm = localtime (&t); + strftime (buf + pos, sizeof (buf) - pos, "%a %F %T", tm); +} - for (int i = 0; i < num_power_sensors; ++i) { - const int mib[5] = { CTL_HW, HW_SENSORS, power_sensors[i], SENSOR_WATTS, 0 }; - struct sensor sensor; - size_t slen = sizeof sensor; +static void format_status (const struct status *st) +{ + format_cpu (st); + format_ram (st); + format_bat (st); + format_time (); +} - if (sysctl (mib, 5, &sensor, &slen, NULL, 0) == -1) - continue; - - if (sensor.flags & SENSOR_FINVALID) - continue; - - total += sensor.value; - } - - const int sub = total / 10000; - snprintf (power, sizeof power, "/%d.%02uW", sub / 100, sub % 100); - return power; -} - int main (int argc, char *argv[]) { - int ncpu; - struct cpu_usage *cpus; - unsigned long root; - char status[256]; Display *dpy; - int fd_apm, screen; + int screen; + unsigned long root; (void)argv; - + if (argc != 1) { puts ("bedstatus-" VERSION); return 1; @@ -304,37 +221,16 @@ int main (int argc, char *argv[]) screen = XDefaultScreen (dpy); root = XRootWindow (dpy, screen); - ncpu = num_cpu (); - cpus = calloc (ncpu, sizeof (struct cpu_usage)); - fd_apm = open ("/dev/apm", O_RDONLY); - find_sensors (); + init_backend (); while (1) { - const char *bat_sym, *bat_time; - unsigned bat_perc; - time_t t; - struct tm *tm; + struct status st; - bat (fd_apm, &bat_sym, &bat_perc, &bat_time); + update_status (&st); + pos = 0; + format_status (&st); - const int num = snprintf ( - status, - sizeof status, - "[CPU \uf2db %s] [RAM \uf538 %s] [BAT %s %u%% (%s%s)] ", - cpu (ncpu, cpus), - ram (), - bat_sym, - bat_perc, - bat_time, - power () - ); - - t = time (NULL); - tm = localtime (&t); - strftime (status + num, sizeof status - num, "%a %F %T", tm); - status[sizeof status - 1] = '\0'; - - XStoreName (dpy, root, status); + XStoreName (dpy, root, buf); XFlush (dpy); sleep (1); } blob - /dev/null blob + 6891c83045156ca5af5caae2655d2e91d4de622b (mode 644) --- /dev/null +++ bedstatus/bedstatus.h @@ -0,0 +1,22 @@ +#ifndef FILE_BEDSTATUS_H +#define FILE_BEDSTATUS_H +#include +#include + +#define E(t, n) t n; bool has_##n +struct status { + E(int, cpu_usage); // CPU Usage in % + E(int, cpu_speed); // CPU Frequency in MHz + E(int, cpu_temp); // CPU Temperature in DegC + E(uint64_t, mem_usage); // RAM Usage in Bytes + E(int, bat_perc); // Battery Level in % + E(int, bat_rem); // Remaining Battery Life in Minutes + E(bool, bat_charging); // Is the AC connected? + E(int, power); // Power Drain in Milli-Watts +}; +#undef E + +void init_backend (void); +void update_status (struct status *); + +#endif // FILE_BEDSTATUS_H blob - /dev/null blob + 96977840c0c93594325c70eef65b19dac5605338 (mode 644) --- /dev/null +++ bedstatus/openbsd.c @@ -0,0 +1,200 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bedstatus.h" + +#define MAXSENSORS 16 + +struct cpu_usage { + struct cpustats new, old, diffs; +}; + +static int ncpu = 1; +static struct cpu_usage *cpus; +static int apm_fd = -1; +static int cputemp_sensor = -1; +static int num_power_sensors = 0; +static int power_sensors[MAXSENSORS]; + +static bool read_sensor (struct sensor *sen, int which, int what) +{ + const int mib[5] = { CTL_HW, HW_SENSORS, which, what, 0 }; + size_t len = sizeof (*sen); + + return sysctl (mib, 5, sen, &len, NULL, 0) != -1; +} + +static int64_t percentages (struct cpustats *out, struct cpu_usage *cpu) +{ + int64_t total_change = 0; + + for (int i = 0; i < 6; ++i) { + int64_t change = cpu->new.cs_time[i] - cpu->old.cs_time[i]; + if (change < 0) + change = INT64_MAX - cpu->old.cs_time[i] - cpu->new.cs_time[i]; + + cpu->diffs.cs_time[i] = change; + total_change += change; + cpu->old.cs_time[i] = cpu->new.cs_time[i]; + } + + if (total_change == 0) + total_change = 1; + + for (int i = 0; i < 6; ++i) { + out->cs_time[i] = (cpu->diffs.cs_time[i] * 1000 + total_change / 2) / total_change; + } + + return total_change; +} + + +static bool cpu_usage (int *usage) +{ + uint64_t sum = 0; + + for (int i = 0; i < ncpu; ++i) { + const int mib[3] = { CTL_KERN, KERN_CPUSTATS, i }; + struct cpustats tmp; + size_t len = sizeof (tmp); + + if (sysctl (mib, 3, &cpus[i].new, &len, NULL, 0) < 0) + continue; + + percentages (&tmp, &cpus[i]); + sum += 1000 - tmp.cs_time[5]; + } + + *usage = sum / ncpu / 10; + return true; +} + +static bool cpu_speed (int *speed) +{ + const int mib[2] = { CTL_HW, HW_CPUSPEED }; + size_t len = sizeof (*speed); + + return sysctl (mib, 2, speed, &len, NULL, 0) != -1; +} + +static bool cpu_temp (int *temp) +{ + struct sensor sen; + + if (!read_sensor (&sen, cputemp_sensor, SENSOR_TEMP) || sen.status & SENSOR_FINVALID) + return false; + + *temp = (sen.value - 273150000) / 1000000;; + + return true; +} + +static bool mem_usage (uint64_t *usage) +{ + const int mib[2] = { CTL_VM, VM_UVMEXP }; + struct uvmexp uvm; + size_t len = sizeof (uvm); + + if (sysctl (mib, 2, &uvm, &len, NULL, 0) == -1) + return false; + + *usage = (uint64_t)uvm.active << uvm.pageshift; + + return true; +} + +static void bat (struct status *st) +{ + struct apm_power_info info; + + if (apm_fd < 0 || ioctl (apm_fd, APM_IOC_GETPOWER, &info) != 0) + return; + + st->has_bat_perc = true; + st->bat_perc = info.battery_life; + + if (info.minutes_left != (u_int)-1) { + st->has_bat_rem = true; + st->bat_rem = info.minutes_left; + } + + switch (info.ac_state) { + case APM_AC_ON: + st->has_bat_charging = true; + st->bat_charging = true; + break; + case APM_AC_OFF: + case APM_AC_BACKUP: + st->has_bat_charging = true; + st->bat_charging = false; + break; + } +} + +static bool power (int *milliwatts) +{ + struct sensor sen; + int64_t total = 0; + + if (num_power_sensors == 0) + return false; + + for (int i = 0; i < num_power_sensors; ++i) { + if (!read_sensor (&sen, power_sensors[i], SENSOR_WATTS)) + continue; + + total += sen.value; + } + + *milliwatts = total / 1000; + return true; +} + +void init_backend (void) +{ + const int mib_ncpu[2] = { CTL_HW, HW_NCPU }; + size_t len = sizeof (ncpu); + + sysctl (mib_ncpu, 2, &ncpu, &len, NULL, 0); + cpus = calloc (ncpu, sizeof (struct cpu_usage)); + + apm_fd = open ("/dev/apm", O_RDONLY); + + for (int i = 0; i < MAXSENSORS; ++i) { + const int mib[3] = { CTL_HW, HW_SENSORS, i}; + struct sensordev dev; + + len = sizeof (dev); + + if (sysctl (mib, 3, &dev, &len, NULL, 0) == -1) + continue; + + if (dev.maxnumt[SENSOR_WATTS] > 0) { + power_sensors[num_power_sensors++] = i; + } + + if (dev.maxnumt[SENSOR_TEMP] > 0 && memcmp (dev.xname, "cpu", 3) == 0 && cputemp_sensor == -1) { + cputemp_sensor = i; + } + } +} + +void update_status (struct status *st) +{ + memset (st, 0, sizeof (*st)); + st->has_cpu_usage = cpu_usage (&st->cpu_usage); + st->has_cpu_temp = cpu_temp (&st->cpu_temp); + st->has_cpu_speed = cpu_speed (&st->cpu_speed); + st->has_mem_usage = mem_usage (&st->mem_usage); + bat (st); + st->has_power = power (&st->power); +} blob - /dev/null blob + a359db9cc9fa1311553b9e6c1cc80688acbc4d3f (mode 644) --- /dev/null +++ bedstatus/unsupported.c @@ -0,0 +1,11 @@ +#include +#include "bedstatus.h" + +void init_backend (void) +{ +} + +void update_status (struct status *st) +{ + memset (st, 0, sizeof (&st)); +}