Last active
January 2, 2016 21:39
-
-
Save maxdeliso/8364440 to your computer and use it in GitHub Desktop.
battery checker C program vs bash script
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
asmBatt |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* asmBatt.c - stupid battery status printer | |
* Max DeLiso <[email protected]> | |
* license: don't pretend you wrote this or people will think you're friendless | |
* | |
* notes: this will only run on a 64 bit linux system, and only if ACPI | |
* is loaded and has populated the /sys/ entries listed below. | |
*/ | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
#include <sys/syscall.h> | |
#include <fcntl.h> | |
#include <asm/unistd_64.h> | |
#include <stdbool.h> | |
#include <stdint.h> | |
#define SYS_BLOCK_SIZE 16 | |
#define STDOUT_FILENO 1 | |
#define ENOW_PATH "/sys/class/power_supply/BAT0/energy_now" | |
#define EFULL_PATH "/sys/class/power_supply/BAT0/energy_full" | |
#define STATUS_PATH "/sys/class/power_supply/BAT0/status" | |
enum { | |
ERR_OPEN_FAILED = 1, | |
ERR_READ_FAILED, | |
ERR_WRITE_FAILED, | |
ERR_CLOSE_FAILED | |
}; | |
static void readFile(const char * const filePath, char * buf); | |
static inline bool isNum(const char ch); | |
static uint64_t parseInteger(const char * const intString); | |
static uint64_t tenPow(const uint64_t exp); | |
static void writeBatt(const int battRemaining, const bool charging); | |
/* inline assembly syscall functions */ | |
static void exit(const int errCode); | |
static int openRO(const char * const filePath); | |
static int close(const int fdHandle); | |
static int writeStdout(const char * const buf, const size_t len); | |
static ssize_t readSysBlock(const int fd, const char * buf); | |
extern void asmBatt() { | |
char enowStr[SYS_BLOCK_SIZE]; | |
char efullStr[SYS_BLOCK_SIZE]; | |
char statusStr[SYS_BLOCK_SIZE]; | |
readFile(ENOW_PATH, enowStr); | |
readFile(EFULL_PATH, efullStr); | |
readFile(STATUS_PATH, statusStr); | |
const uint64_t battNow = parseInteger(enowStr); | |
const uint64_t battFull = parseInteger(efullStr); | |
const int battRemaining = (int) (100.0f * battNow / battFull); | |
writeBatt(battRemaining, statusStr[0] == 'C'); | |
exit(0); | |
} | |
static void readFile(const char * const filePath, char * buf) { | |
int fd = openRO(filePath); | |
if(fd < 0) { | |
exit(ERR_OPEN_FAILED); | |
} | |
ssize_t bytesRead = readSysBlock(fd, buf); | |
if(bytesRead >= SYS_BLOCK_SIZE) { | |
exit(ERR_READ_FAILED); | |
} | |
buf[bytesRead] = '\0'; | |
if(close(fd) < 0) { | |
exit(ERR_CLOSE_FAILED); | |
} | |
} | |
static inline bool isNum(const char ch) { | |
switch(ch) { | |
case '0': case '1': case '2': case '3': case '4': | |
case '5': case '6': case '7': case '8': case '9': | |
return true; | |
default: | |
return false; | |
} | |
} | |
static uint64_t parseInteger(const char * const intString) { | |
uint64_t intValue = 0; | |
int intStringLen = 0; | |
while(isNum(intString[++intStringLen])); | |
for(int i = 0; i < intStringLen; ++i) { | |
intValue += (intString[i] - '0') * tenPow(intStringLen - i - 1); | |
} | |
return intValue; | |
} | |
static uint64_t tenPow(const uint64_t exp) { | |
if(exp == 0) return 1; | |
else return 10 * tenPow(exp - 1); | |
} | |
static void writeBatt(const int battRemaining, const bool charging) { | |
/* NOTE: this buffer is stored in global memory to prevent it from | |
* being bungled at high optimization levels */ | |
static char outBuffer[7] = "XX% (X)"; | |
/* |01 5 | */ | |
/* |charged| */ | |
if(battRemaining < 100) { | |
outBuffer[0] = '0' + (battRemaining / 10); | |
outBuffer[1] = '0' + (battRemaining % 10); | |
outBuffer[5] = (charging) ? ('+') : ('-'); | |
} else { | |
outBuffer[0] = 'c'; | |
outBuffer[1] = 'h'; | |
outBuffer[2] = 'a'; | |
outBuffer[3] = 'r'; | |
outBuffer[4] = 'g'; | |
outBuffer[5] = 'e'; | |
outBuffer[6] = 'd'; | |
} | |
if(writeStdout(outBuffer, 7) == -1) { | |
exit(ERR_WRITE_FAILED); | |
} | |
} | |
static void exit(const int errCode) { | |
__asm__("movq %0, %%rax\n\t" | |
"movq %1, %%rdi\n\t" | |
"syscall\n\t" | |
: /* no output */ | |
:"r" ((uint64_t) __NR_exit), | |
"r" ((uint64_t) errCode) | |
:"rax", "rdi", "rcx", "r11"); | |
} | |
static int openRO(const char * const filePath) { | |
uint64_t syscall_ret; | |
__asm__("movq %1, %%rax\n\t" | |
"movq %2, %%rdi\n\t" | |
"movq %3, %%rsi\n\t" | |
"movq %4, %%rdx\n\t" | |
"syscall\n\t" | |
"mov %%rax, %0\n\t" | |
:"=r" (syscall_ret) | |
:"r" ((uint64_t) __NR_open), | |
"r" (filePath), | |
"r" ((uint64_t) O_RDONLY), | |
"r" ((uint64_t) 0) | |
:"rax", "rdi", "rsi", "rdx", "rcx", "r11"); | |
return syscall_ret; | |
} | |
static int close(const int fdHandle) { | |
uint64_t syscall_ret; | |
__asm__("movq %1, %%rax\n\t" | |
"movq %2, %%rdi\n\t" | |
"syscall\n\t" | |
"mov %%rax, %0\n\t" | |
:"=r" (syscall_ret) | |
:"r" ((uint64_t) __NR_close), | |
"r" ((uint64_t) fdHandle) | |
:"rax", "rdi", "rcx", "r11"); | |
return syscall_ret; | |
} | |
static int writeStdout(const char * const buf, const size_t len) { | |
uint64_t syscall_ret; | |
__asm__("movq %1, %%rax\n\t" | |
"movq $1, %%rdi\n\t" | |
"movq %2, %%rsi\n\t" | |
"movq %3, %%rdx\n\t" | |
"syscall\n\t" | |
"mov %%rax, %0\n\t" | |
:"=r" (syscall_ret) | |
:"r" ((uint64_t) __NR_write), | |
"r" (buf), | |
"r" (len) | |
:"rax", "rdi", "rsi", "rdx", "rcx", "r11"); | |
return syscall_ret; | |
} | |
static ssize_t readSysBlock(const int fd, const char * buf) { | |
uint64_t syscall_ret; | |
__asm__("movq %1, %%rax\n\t" | |
"movq %2, %%rdi\n\t" | |
"movq %3, %%rsi\n\t" | |
"movq %4, %%rdx\n\t" | |
"syscall\n\t" | |
"mov %%rax, %0\n\t" | |
:"=r" (syscall_ret) | |
:"r" ((uint64_t) __NR_read), | |
"r" ((uint64_t) fd), | |
"r" (buf), | |
"r" ((uint64_t) SYS_BLOCK_SIZE) | |
:"rax", "rdi", "rsi", "rdx", "rcx", "r11"); | |
return syscall_ret; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
cat /sys/class/power_supply/BAT0/energy_now \ | |
/sys/class/power_supply/BAT0/energy_full \ | |
/sys/class/power_supply/BAT0/status | | |
tr "\n" " " | | |
awk '{printf("batt: %.2f%% %-13s", $1 / $2 * 100, $3)}' |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CC=gcc | |
CFLAGS=-O3 -std=c99 -fno-builtin-exit | |
LDFLAGS=-static -nostartfiles -nodefaultlibs \ | |
-Wl,--start-group -easmBatt -Wl,--end-group | |
STRIP=strip | |
OUT=asmBatt | |
$(OUT): $(OUT).c Makefile | |
$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ | |
$(STRIP) $(OUT) | |
clean: | |
$(RM) $(OUT) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
wuuuuuut !?? wut is dis?? what code?