diff options
Diffstat (limited to '')
-rw-r--r-- | bin/.gitignore | 1 | ||||
-rw-r--r-- | bin/Makefile | 2 | ||||
-rw-r--r-- | bin/README | 5 | ||||
-rw-r--r-- | bin/fbatt.c | 127 |
4 files changed, 134 insertions, 1 deletions
diff --git a/bin/.gitignore b/bin/.gitignore index a85824f1..c193de65 100644 --- a/bin/.gitignore +++ b/bin/.gitignore @@ -11,5 +11,6 @@ klon typo watch bri +fbatt fbclock gfxx diff --git a/bin/Makefile b/bin/Makefile index 6a4902cc..52bca4d4 100644 --- a/bin/Makefile +++ b/bin/Makefile @@ -1,6 +1,6 @@ ANY_BINS = atch dtch hnel pbcopy pbd pbpaste wake xx BSD_BINS = jrp klon typo watch -LIN_BINS = bri fbclock gfxx +LIN_BINS = bri fbatt fbclock gfxx ALL_BINS = $(ANY_BINS) $(BSD_BINS) $(LIN_BINS) CFLAGS += -Wall -Wextra -Wpedantic diff --git a/bin/README b/bin/README index b476d085..9a990d71 100644 --- a/bin/README +++ b/bin/README @@ -19,6 +19,11 @@ with ^Q. dtch a nvim & disown atch a + fbatt + +Battery charge indicator panel for the Linux Framebuffer through +/sys/class/power_supply. + fbclock Clock panel for the Linux framebuffer. Renders PSF2 bitmap fonts. diff --git a/bin/fbatt.c b/bin/fbatt.c new file mode 100644 index 00000000..a775ff49 --- /dev/null +++ b/bin/fbatt.c @@ -0,0 +1,127 @@ +/* Copyright (c) 2018, Curtis McEnroe <programble@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <dirent.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <linux/fb.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <sysexits.h> +#include <unistd.h> + +static const char *CLASS = "/sys/class/power_supply"; + +static const uint32_t RIGHT = 5 * 8 + 1; // fbclock width. +static const uint32_t WIDTH = 8; +static const uint32_t HEIGHT = 16; + +static const uint32_t BG = 0x1D2021; +static const uint32_t BORDER = 0xA99A84; +static const uint32_t GRAY = 0x938374; +static const uint32_t YELLOW = 0xD89A22; +static const uint32_t RED = 0xCC241D; + +int main() { + int error; + + DIR *dir = opendir(CLASS); + if (!dir) err(EX_OSFILE, "%s", CLASS); + + FILE *chargeFull = NULL; + FILE *chargeNow = NULL; + + const struct dirent *entry; + while (NULL != (errno = 0, entry = readdir(dir))) { + if (entry->d_name[0] == '.') continue; + + error = chdir(CLASS); + if (error) err(EX_IOERR, "%s", CLASS); + + error = chdir(entry->d_name); + if (error) err(EX_IOERR, "%s/%s", CLASS, entry->d_name); + + chargeFull = fopen("charge_full", "r"); + chargeNow = fopen("charge_now", "r"); + if (chargeFull && chargeNow) break; + } + if (!chargeFull || !chargeNow) { + if (errno) err(EX_IOERR, "%s", CLASS); + errx(EX_CONFIG, "empty %s", CLASS); + } + closedir(dir); + + const char *path = getenv("FRAMEBUFFER"); + if (!path) path = "/dev/fb0"; + + int fb = open(path, O_RDWR); + if (fb < 0) err(EX_OSFILE, "%s", path); + + struct fb_var_screeninfo info; + error = ioctl(fb, FBIOGET_VSCREENINFO, &info); + if (error) err(EX_IOERR, "%s", path); + + size_t size = 4 * info.xres * info.yres; + uint32_t *buf = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fb, 0); + if (buf == MAP_FAILED) err(EX_IOERR, "%s", path); + + for (;;) { + int match; + + rewind(chargeFull); + fflush(chargeFull); + uint32_t full; + match = fscanf(chargeFull, "%u", &full); + if (match == EOF) err(EX_IOERR, "charge_full"); + if (match < 1) errx(EX_DATAERR, "charge_full"); + + rewind(chargeNow); + fflush(chargeNow); + uint32_t now; + match = fscanf(chargeNow, "%u", &now); + if (match == EOF) err(EX_IOERR, "charge_now"); + if (match < 1) errx(EX_DATAERR, "charge_now"); + + uint32_t percent = 100 * now / full; + uint32_t height = 16 * now / full; + + for (int i = 0; i < 60; ++i, sleep(1)) { + uint32_t left = info.xres - RIGHT - WIDTH; + + for (uint32_t y = 0; y <= HEIGHT; ++y) { + buf[y * info.xres + left - 1] = BORDER; + buf[y * info.xres + left + WIDTH] = BORDER; + } + for (uint32_t x = left; x < left + WIDTH; ++x) { + buf[HEIGHT * info.xres + x] = BORDER; + } + + for (uint32_t y = 0; y < HEIGHT; ++y) { + for (uint32_t x = left; x < left + WIDTH; ++x) { + buf[y * info.xres + x] = + (HEIGHT - 1 - y > height) ? BG + : (percent <= 10) ? RED + : (percent <= 30) ? YELLOW + : GRAY; + } + } + } + } +} |