Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // control charging of battery on apple M1
- // tested on macbook pro 2021 model
- // works on linux
- #include <stdio.h>
- #include <stdlib.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <sys/wait.h>
- #include <fcntl.h>
- #include <unistd.h>
- #include <string.h>
- #include <errno.h>
- #include <syslog.h>
- #include <time.h>
- // util
- #define NTRIM(s) s[strlen(s)-1]='\0'
- // sys fp
- static const char MACSMC_BATTERY_FP[] =
- "/sys/class/power_supply/macsmc-battery/";
- // modes
- static const char AUT[] = "auto";
- static const char DIS[] = "force-discharge";
- static const char INH[] = "inhibit-charge";
- char get_last_battery_mode()
- {
- FILE *battery_file;
- // no idea what all modes
- char mode[40];
- char path[sizeof(MACSMC_BATTERY_FP) + 30];
- strcpy(path, MACSMC_BATTERY_FP);
- battery_file = fopen(strcat(path, "charge_behaviour"), "r");
- if (battery_file == NULL) {
- syslog(LOG_USER | LOG_ERR,
- "Could not open charge_behaviour file.\n");
- return -1;
- }
- fgets(mode, 40, battery_file);
- fclose(battery_file);
- mode[strcspn(mode, "\n")] = '\0';
- if (strncmp(mode, AUT, sizeof(AUT)) == 0)
- return 'a';
- else if (strncmp(mode, DIS, sizeof(DIS)) == 0)
- return 'd';
- else if (strncmp(mode, INH, sizeof(INH)) == 0)
- return 'i';
- syslog(LOG_USER | LOG_ERR,
- "Something went wrong with getting battery mode");
- exit(EXIT_FAILURE);
- }
- int set_battery_to(char mode)
- {
- FILE *battery_file;
- char path[sizeof(MACSMC_BATTERY_FP) + 30];
- const char *mode_p;
- strcpy(path, MACSMC_BATTERY_FP);
- battery_file = fopen(strcat(path, "charge_behaviour"), "w");
- if (battery_file == NULL) {
- syslog(LOG_USER | LOG_ERR,
- "Could not open charge_behaviour file.\n");
- return -1;
- }
- switch (mode) {
- case 'a':
- mode_p = AUT;
- break;
- case 'd':
- mode_p = DIS;
- break;
- case 'i':
- mode_p = INH;
- break;
- default:
- fclose(battery_file);
- syslog(LOG_USER | LOG_ERR, "Mode does not exist.\n");
- return -1;
- }
- fprintf(battery_file, "%s", mode_p);
- fclose(battery_file);
- syslog(LOG_USER | LOG_INFO,
- strcat(strcpy(path, "Set battery mode "), mode_p));
- return 0;
- }
- int get_battery_state(char st_fn, char *value)
- {
- FILE *battery_file;
- char path[sizeof(MACSMC_BATTERY_FP) + 30];
- strcpy(path, MACSMC_BATTERY_FP);
- switch (st_fn) {
- case 'c':
- battery_file = fopen(strcat(path, "capacity"), "r");
- break;
- case 't':
- battery_file = fopen(strcat(path, "temp"), "r");
- break;
- default:
- syslog(LOG_USER | LOG_ERR, "No such state or none selected.\n");
- return -1;
- }
- if (battery_file == NULL) {
- syslog(LOG_USER | LOG_ERR, st_fn == 'c' ?
- "Could not open capacity file" :
- "Could not open temperature file");
- return -1;
- }
- fgets(value, 5, battery_file);
- fclose(battery_file);
- return atoi(value);
- }
- int main(int argc, char **argv)
- {
- int option;
- int limit = 75;
- int temp_limit = 335;
- // script
- while ((option = getopt(argc, argv, "l:uh")) != -1) {
- switch (option) {
- case 'h':
- puts("help");
- puts("-l limit capacity");
- break;
- case 'l':
- limit = atoi(optarg);
- printf("limit: %d\n", limit);
- break;
- default: /* '?' */
- puts("unknown option");
- }
- }
- // process
- pid_t pid, sid;
- pid = fork();
- if (pid < 0) {
- printf("charge-ctl exiting - failure.\n");
- exit(EXIT_FAILURE);
- }
- if (0 < pid) {
- printf("Child pid = %i\n", pid);
- int wstatus;
- int endid = waitpid(pid, &wstatus, 0);
- printf("Child end id = %i\n", endid);
- printf("EXIT?: %d\n", WIFEXITED(wstatus));
- printf("STOPPED?: %d\n", WIFSTOPPED(wstatus));
- psignal(WTERMSIG(wstatus), "EXIT SIGNAL");
- printf("charge-ctl exiting - success.\n");
- exit(EXIT_SUCCESS);
- }
- umask(0);
- sid = setsid();
- if (sid < 0) {
- exit(EXIT_FAILURE);
- }
- if ((chdir("/")) < 0) {
- exit(EXIT_FAILURE);
- }
- close(STDIN_FILENO);
- close(STDOUT_FILENO);
- close(STDERR_FILENO);
- // logs
- char LOGNAME[] = "charge-ctl";
- openlog(LOGNAME, LOG_PID | LOG_CONS, LOG_USER);
- // vars
- char cap[40];
- char temp[40];
- int icap;
- int itemp;
- int last_cap = 0;
- int last_temp = 0;
- char last_mode = get_last_battery_mode();
- time_t time_info;
- // run
- while (1) {
- // battery cap
- icap = get_battery_state('c', cap);
- // battery temp
- itemp = get_battery_state('t', temp);
- if (icap < 0 || itemp < 0) {
- if (icap < 0)
- syslog(LOG_USER | LOG_ERR,
- strcat(strcpy
- (cap, "Failed retrieving battery state "),
- "capacity\n"));
- else
- syslog(LOG_USER | LOG_ERR,
- strcat(strcpy
- (temp, "Failed retrieving battery state "),
- "temperature\n"));
- exit(EXIT_FAILURE);
- }
- // time
- time(&time_info);
- char *curr_time = ctime(&time_info);
- // trim
- NTRIM(cap);
- NTRIM(temp);
- NTRIM(curr_time);
- // log state
- if ((icap != last_cap) || (itemp != last_temp)) {
- syslog(LOG_USER | LOG_INFO,
- "%s: Battery Capacity = %s Battery Temperature = %s\n",
- curr_time, cap, temp);
- last_cap = icap;
- last_temp = itemp;
- }
- // then new mode
- int res = 0;
- char mode_msg[40];
- if (icap < limit - 2 && last_mode != 'a') {
- if (temp_limit < itemp) {
- res = set_battery_to('a');
- last_mode = 'a';
- }
- } else if (limit < icap && last_mode != 'd') {
- res = set_battery_to('d');
- last_mode = 'd';
- } else if (last_mode != 'i') {
- res = set_battery_to('i');
- last_mode = 'i';
- }
- if (res < 0) {
- syslog(LOG_USER | LOG_ERR,
- strcat(strcpy(mode_msg, "Failed setting mode "),
- last_mode == 'a' ? AUT : last_mode ==
- 'd' ? DIS : INH));
- exit(EXIT_FAILURE);
- }
- sleep(20);
- }
- closelog();
- exit(EXIT_SUCCESS);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement