commit 50fdb142dd6fa27e402d1ed6d44597fa24d5813a Author: Sandy Mossgrave Date: Tue Mar 14 18:17:58 2023 +0000 Initial commit. Works. Makefile copied from pokemath project Reads two files from sysfs: charge_now and charge_full under BAT0, then divides them using float math. Output is guaranteed to be stable across major versions. Supported options: -v gives verbose output for debugging purposes -h shows help text and exits -t gives terse output Known issues: The path to charge_now and charge_full is hard-coded. This utility will not work with batteries that do not happen to be named BAT0. The float value given by this program is not actually a percentage. TODO: Move help text #defines into a header file Add support to traverse /sys/class/power_supply and locate batteries Possibly add support to store default battery paths in /etc/battery_percent.conf DISCLAIMER: This program is already too overcomplicated and shows no signs of slowing down. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e5ffdac --- /dev/null +++ b/Makefile @@ -0,0 +1,58 @@ +#NEWPROJECT requires refactor.sh main.c +# Taken from https://stackoverflow.com/questions/30573481/how-to-write-a-makefile-with-separate-source-and-header-directories + +SRCDIR := sources +MAINDIR := $(SRCDIR)/main +INCDIR := include +OBJDIR := objects +MAINOD := $(OBJDIR)/main +BINDIR := build + +REFACTOR := refactor.h + +HEADERS := $(wildcard $(INCDIR)/*.h) + +MAINS := $(wildcard $(MAINDIR)/*.c) +MAINOBJS := $(patsubst $(MAINDIR)/%.c, $(MAINOD)/%.o, $(MAINS)) + +TARGETS := $(patsubst $(MAINDIR)/%.c, $(BINDIR)/%, $(MAINS)) + +SOURCES := $(wildcard $(SRCDIR)/*.c) + +OBJECTS := $(patsubst $(SRCDIR)/%.c, $(OBJDIR)/%.o, $(SOURCES)) + +CPPFLAGS := -Iinclude -MMD -MP +CFLAGS := -Wall -Werror -Wpedantic +LDFLAGS := #-Lmath or whatever +LDLIBS := #-lm or whatever + +.PHONY: all clean + +all: $(TARGETS) + @echo $(TARGETS) + +refactor: + ./refactor.sh + +$(TARGETS): $(OBJECTS) $(MAINOBJS) | $(BINDIR) $(OBJDIR) $(MAINOD) + $(CC) $(LDFLAGS) $(OBJECTS) $(patsubst $(BINDIR)/%, $(MAINOD)/%.o, $@) $(LDLIBS) -o $@ + +$(BINDIR) $(OBJDIR) $(MAINOD): + mkdir --parents $@ + +$(OBJDIR)/%.o: $(SRCDIR)/%.c $(HEADERS) | $(OBJDIR) + $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ + +$(MAINOD)/%.o: $(MAINDIR)/%.c $(HEADERS) | $(MAINOD) + $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ + +clean: + $(RM) -rv $(BINDIR) $(OBJDIR) + +# Honestly still not sure what this directive does. +# It's an include directive, which processes all .d files that correspond to members of $(OBJ), +# with the hyphen in front meaning that it suppresses/ignores errors (from nonexistent .d files) +# Seems to be included under the stipulation that GNU make will auto-generate .d files based on +# a given file's #include directives? +# https://stackoverflow.com/questions/19114410/what-is-d-file-after-building-with-make +-include $(OBJ:.o=.d) diff --git a/sources/main/battery.c b/sources/main/battery.c new file mode 100644 index 0000000..9cde435 --- /dev/null +++ b/sources/main/battery.c @@ -0,0 +1,86 @@ +#include +#include +#include + +#define CHARGE_NOW_PATH "/sys/class/power_supply/BAT0/charge_now" +#define CHARGE_FULL_PATH "/sys/class/power_supply/BAT0/charge_full" +#define VERSION "v0.0" +#define TITLE "Battery Percentage, by Catluck Kettlemerry" +#define PROGNAME "battery_percentage" +#define USAGE0 "Usage: " +#define USAGE1 "[option]" +#define OPTIONS0 "Options:" +#define OPTIONS1 "\t-v run verbosely" +#define OPTIONS2 "\t-h show help and exit" +#define OPTIONS3 "\t-t provide terse output" + +int run_verbose = 0; +int run_terse = 0; + +void print_help(void){ + printf("%s %s\n", TITLE, VERSION); + printf("%s %s %s\n", USAGE0, PROGNAME, USAGE1); + printf("%s\n%s\n%s\n%s\n", OPTIONS0, OPTIONS1, OPTIONS2, OPTIONS3); +} + +int main(int argc, char *const argv[]){ + + int opt; + while((opt = getopt(argc, argv, "vht")) != -1) { + switch(opt){ + case 'v': + run_verbose = 1; + break; + case 'h': + print_help(); + return 0; + case 't': + run_terse = 1; + break; + default: + printf("Literally how could you pass an unspecified argument to this program"); + } + } + + FILE * fd_now = fopen(CHARGE_NOW_PATH, "r"); + FILE * fd_full = fopen(CHARGE_FULL_PATH, "r"); + + int c_now; + int c_full; + + int vals_read = fscanf(fd_now, "%d", &c_now); + if(vals_read != 1){ + if(errno != 0){ + perror("Error reading full battery charge: "); + } else if(vals_read == EOF){ + printf("End-of-file reached while reading current battery charge(?)"); + } else { + printf("Invalid number of arguments (%d) returned while reading full battery charge", vals_read); + } + return 1; + } + vals_read = fscanf(fd_full, "%d", &c_full); + if(vals_read != 1){ + if(errno != 0){ + perror("Error reading full battery charge: "); + } else if(vals_read == EOF){ + printf("End-of-file reached while reading full battery charge(?)"); + } else { + printf("Invalid number of arguments (%d) returned while reading full battery charge", vals_read); + } + return 1; + } + + if(run_verbose){ + printf("Current charge: %d\n", c_now); + printf("Full charge: %d\n", c_full); + } + + if(!run_terse) { + printf("Battery percentage: "); + } + float pct = ((float)c_now) / ((float)c_full); + printf("%f\n", pct); + + return 0; +}