status-bat/bat.c
author Stiletto <blasux@blasux.ru>
Fri, 24 Oct 2014 17:07:07 +0400
changeset 11 ad3d40f11f6d
parent 9 96b47c0505b5
child 16 e08bdbec1843
permissions -rw-r--r--
status-bat: flashing bullshit support

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <assert.h>
#include <string.h>
#include <limits.h>
#include <unistd.h>
#include <errno.h>

#include "config.h"
#ifdef USE_UDEV
#include <poll.h>
#include <libudev.h>
#endif

char *eights[] = { "ø", "▁", "▂", "▃", "▄", "▅", "▆","▇", "█" };

char *catfile(char *name) {
    struct stat buffer;
    int         status;
    int         f;
    char*       resbuf;
    f = open(name, O_RDONLY);
    if (f == -1) return NULL;
    status = fstat(f, &buffer);
    if (status != 0) return NULL;
    resbuf = malloc(buffer.st_size+1);
    if (resbuf == NULL) return NULL;
    status = read(f,resbuf,buffer.st_size);
    if (status == -1) {
        free(resbuf);
        return NULL;
    }
    if ((status>0)&&(resbuf[status-1]=='\n'))
        resbuf[status-1]='\0';
    resbuf[status]='\0';
    return resbuf;
}

int catint(char *name) {
    char *cont = catfile(name);
    assert (cont != NULL);
    int res = atoi(cont);
    free(cont);
    return res;
}

char *color_stop;
char *color_red;
char *color_orange;
char *color_green;
char *color_none;
static char *down_arrow = "↓";

char *color(int low,int mid,int rev,int value) {
    if (value>mid) {
        return rev ? color_red : color_green;
    } else if (value>low) {
        return color_orange;
    }
    return rev ? color_green : color_red;
}

int main(int argc, char *argv[]) {
    if (argc<=1) {
        fprintf(stderr, "Usage: %s <BAT1> [term|pango]\n", argv[0]);
        fflush(stderr);
        return 1;
    }

    char *arrow_color;
    char *eights_color;
    char *percent_color;
    char *remtimes_color;
    if (argc>2 && !strcmp(argv[2],"term")) {
        color_stop = "\x1b[0m";
        color_red = "\x1b[1;31m";
        color_green = "\x1b[1;32m";
        color_orange = "\x1b[1;33m";
        color_none = color_stop;
    } else if (argc>2 && !strcmp(argv[2],"pango")) {
        color_stop = "</span>";
        color_red = "<span color='#f33'>";
        color_green = "<span color='#0f0'>";
        color_orange = "<span color='#fa0'>";
        color_none = "<span>";
    } else {
        color_stop = color_red = color_green = color_orange = color_none = "";
    }

#ifdef USE_UDEV
    struct udev *udev;
    struct udev_device *dev;

    struct udev_monitor *mon;
    int mon_fd;

    udev = udev_new();
    if (!udev) {
        printf("Can't create udev\n");
        exit(1);
    }
    mon = udev_monitor_new_from_netlink(udev, "udev");
    udev_monitor_filter_add_match_subsystem_devtype(mon, "power_supply", NULL);
    udev_monitor_enable_receiving(mon);
    mon_fd = udev_monitor_get_fd(mon);
    static struct pollfd fds[1];
    fds[0].fd = mon_fd;
    fds[0].events = POLLIN;
#endif
    char filename[PATH_MAX+1];
    snprintf(filename,PATH_MAX,"/sys/class/power_supply/%s/energy_now",argv[1]);
    struct stat st;
    int energy = 0==stat(filename, &st);
    int sleeptime = UPDATE_PERIOD;
#ifdef DRAIN_THE_FUCK
    int alertflash = 1;
#endif
    while (1) {

        snprintf(filename,PATH_MAX,"/sys/class/power_supply/%s/%s_now",argv[1], energy ? "energy" : "charge");
        int charge_now = catint(filename);

        snprintf(filename,PATH_MAX,"/sys/class/power_supply/%s/%s_now",argv[1], energy ? "power" : "current");
        int current_now = catint(filename);

        snprintf(filename,PATH_MAX,"/sys/class/power_supply/%s/%s_full",argv[1], energy ? "energy" : "charge");
        int charge_full = catint(filename);

        snprintf(filename,PATH_MAX,"/sys/class/power_supply/%s/status",argv[1]);
        char *status = catfile(filename);

        int remtime = 0;
        char *arrow;

        remtimes_color = color_none;
        if (!strcmp(status,"Charging")) {
            if (current_now != 0)
                remtime = (charge_full-charge_now) / (current_now/60);
            arrow = "↑";
            arrow_color = color_orange;
        }
        else if (!strcmp(status,"Discharging")) {
            if (current_now != 0)
                remtime = charge_now / (current_now/60);
            arrow = down_arrow;
            arrow_color = color_none;
            remtimes_color = color(20,120,0,remtime);
        } else {
            arrow = "—";
            arrow_color = color_green;
        }
        free(status);

        int percent = charge_now/(charge_full/100);
        eights_color = percent_color = color(15,40,0,percent);
        printf("%s%s%s ",eights_color,eights[charge_now*8/charge_full],color_stop);
        printf("%s%d%%%s ",percent_color,percent,color_stop);
        printf("%s%s%s ",arrow_color,arrow,color_stop);
#ifdef DRAIN_THE_FUCK
        if ((remtime < 20)&&(arrow == down_arrow)) {
            sleeptime = 1;
            alertflash = !alertflash;
        } else {
            sleeptime = UPDATE_PERIOD;
            alertflash = 1;
        }
        if (alertflash) {
#endif
            printf("%s%d:%02d%s\n",remtimes_color, remtime/60, remtime%60, color_stop);
#ifdef DRAIN_THE_FUCK
        } else {
            printf("%s·:··%s\n",remtimes_color, color_stop);
        }
#endif
        fflush(stdout);
#ifdef USE_UDEV
        int poll_status = poll(fds,1, sleeptime*1000);
        if (poll_status < 0) {
            if (poll_status != EINTR) {
                perror("poll");
                exit(12);
            }
        }
        if (fds[0].revents & POLLIN) {
            dev = udev_monitor_receive_device(mon);
            if (dev) {
                udev_device_unref(dev);
            } else {
                printf("UDEV DC\n");
                exit(13);
            }
        }
#else
        sleep(sleeptime);
#endif
    }
}