Advertisement
Guest User

Untitled

a guest
Nov 3rd, 2022
92
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 5.94 KB | None | 0 0
  1. // control charging of battery on apple M1
  2. // tested on macbook pro 2021 model
  3. // works on linux
  4.  
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <sys/types.h>
  8. #include <sys/stat.h>
  9. #include <sys/wait.h>
  10. #include <fcntl.h>
  11. #include <unistd.h>
  12. #include <string.h>
  13. #include <errno.h>
  14. #include <syslog.h>
  15. #include <time.h>
  16.  
  17. // util
  18. #define NTRIM(s) s[strlen(s)-1]='\0'
  19.  
  20. // sys fp
  21. static const char MACSMC_BATTERY_FP[] =
  22.     "/sys/class/power_supply/macsmc-battery/";
  23.  
  24. // modes
  25. static const char AUT[] = "auto";
  26. static const char DIS[] = "force-discharge";
  27. static const char INH[] = "inhibit-charge";
  28.  
  29. char get_last_battery_mode()
  30. {
  31.     FILE *battery_file;
  32.  
  33.     // no idea what all modes
  34.     char mode[40];
  35.  
  36.     char path[sizeof(MACSMC_BATTERY_FP) + 30];
  37.  
  38.     strcpy(path, MACSMC_BATTERY_FP);
  39.  
  40.     battery_file = fopen(strcat(path, "charge_behaviour"), "r");
  41.  
  42.     if (battery_file == NULL) {
  43.     syslog(LOG_USER | LOG_ERR,
  44.            "Could not open charge_behaviour file.\n");
  45.     return -1;
  46.     }
  47.  
  48.     fgets(mode, 40, battery_file);
  49.  
  50.     fclose(battery_file);
  51.  
  52.     mode[strcspn(mode, "\n")] = '\0';
  53.  
  54.     if (strncmp(mode, AUT, sizeof(AUT)) == 0)
  55.     return 'a';
  56.     else if (strncmp(mode, DIS, sizeof(DIS)) == 0)
  57.     return 'd';
  58.     else if (strncmp(mode, INH, sizeof(INH)) == 0)
  59.     return 'i';
  60.  
  61.     syslog(LOG_USER | LOG_ERR,
  62.        "Something went wrong with getting battery mode");
  63.     exit(EXIT_FAILURE);
  64. }
  65.  
  66. int set_battery_to(char mode)
  67. {
  68.     FILE *battery_file;
  69.  
  70.     char path[sizeof(MACSMC_BATTERY_FP) + 30];
  71.  
  72.     const char *mode_p;
  73.  
  74.     strcpy(path, MACSMC_BATTERY_FP);
  75.  
  76.     battery_file = fopen(strcat(path, "charge_behaviour"), "w");
  77.  
  78.     if (battery_file == NULL) {
  79.     syslog(LOG_USER | LOG_ERR,
  80.            "Could not open charge_behaviour file.\n");
  81.     return -1;
  82.     }
  83.  
  84.     switch (mode) {
  85.     case 'a':
  86.     mode_p = AUT;
  87.     break;
  88.     case 'd':
  89.     mode_p = DIS;
  90.     break;
  91.     case 'i':
  92.     mode_p = INH;
  93.     break;
  94.     default:
  95.     fclose(battery_file);
  96.     syslog(LOG_USER | LOG_ERR, "Mode does not exist.\n");
  97.     return -1;
  98.     }
  99.  
  100.     fprintf(battery_file, "%s", mode_p);
  101.  
  102.     fclose(battery_file);
  103.  
  104.     syslog(LOG_USER | LOG_INFO,
  105.        strcat(strcpy(path, "Set battery mode "), mode_p));
  106.  
  107.     return 0;
  108. }
  109.  
  110. int get_battery_state(char st_fn, char *value)
  111. {
  112.     FILE *battery_file;
  113.  
  114.     char path[sizeof(MACSMC_BATTERY_FP) + 30];
  115.  
  116.     strcpy(path, MACSMC_BATTERY_FP);
  117.  
  118.     switch (st_fn) {
  119.     case 'c':
  120.     battery_file = fopen(strcat(path, "capacity"), "r");
  121.     break;
  122.     case 't':
  123.     battery_file = fopen(strcat(path, "temp"), "r");
  124.     break;
  125.     default:
  126.     syslog(LOG_USER | LOG_ERR, "No such state or none selected.\n");
  127.     return -1;
  128.     }
  129.  
  130.     if (battery_file == NULL) {
  131.     syslog(LOG_USER | LOG_ERR, st_fn == 'c' ?
  132.            "Could not open capacity file" :
  133.            "Could not open temperature file");
  134.     return -1;
  135.     }
  136.  
  137.     fgets(value, 5, battery_file);
  138.  
  139.     fclose(battery_file);
  140.  
  141.     return atoi(value);
  142. }
  143.  
  144. int main(int argc, char **argv)
  145. {
  146.     int option;
  147.     int limit = 75;
  148.     int temp_limit = 335;
  149.  
  150.     // script
  151.  
  152.     while ((option = getopt(argc, argv, "l:uh")) != -1) {
  153.     switch (option) {
  154.     case 'h':
  155.         puts("help");
  156.         puts("-l limit capacity");
  157.         break;
  158.     case 'l':
  159.         limit = atoi(optarg);
  160.         printf("limit: %d\n", limit);
  161.         break;
  162.     default:        /* '?' */
  163.         puts("unknown option");
  164.     }
  165.     }
  166.  
  167.     // process
  168.  
  169.     pid_t pid, sid;
  170.  
  171.     pid = fork();
  172.  
  173.     if (pid < 0) {
  174.     printf("charge-ctl exiting - failure.\n");
  175.     exit(EXIT_FAILURE);
  176.     }
  177.  
  178.     if (0 < pid) {
  179.     printf("Child pid = %i\n", pid);
  180.  
  181.     int wstatus;
  182.     int endid = waitpid(pid, &wstatus, 0);
  183.  
  184.     printf("Child end id = %i\n", endid);
  185.     printf("EXIT?: %d\n", WIFEXITED(wstatus));
  186.     printf("STOPPED?: %d\n", WIFSTOPPED(wstatus));
  187.     psignal(WTERMSIG(wstatus), "EXIT SIGNAL");
  188.  
  189.     printf("charge-ctl exiting - success.\n");
  190.     exit(EXIT_SUCCESS);
  191.     }
  192.  
  193.     umask(0);
  194.  
  195.     sid = setsid();
  196.  
  197.     if (sid < 0) {
  198.     exit(EXIT_FAILURE);
  199.     }
  200.  
  201.     if ((chdir("/")) < 0) {
  202.     exit(EXIT_FAILURE);
  203.     }
  204.  
  205.     close(STDIN_FILENO);
  206.     close(STDOUT_FILENO);
  207.     close(STDERR_FILENO);
  208.  
  209.     // logs
  210.     char LOGNAME[] = "charge-ctl";
  211.  
  212.     openlog(LOGNAME, LOG_PID | LOG_CONS, LOG_USER);
  213.  
  214.     // vars
  215.     char cap[40];
  216.     char temp[40];
  217.     int icap;
  218.     int itemp;
  219.     int last_cap = 0;
  220.     int last_temp = 0;
  221.     char last_mode = get_last_battery_mode();
  222.     time_t time_info;
  223.  
  224.     // run
  225.  
  226.     while (1) {
  227.  
  228.     // battery cap
  229.  
  230.     icap = get_battery_state('c', cap);
  231.  
  232.     // battery temp
  233.  
  234.     itemp = get_battery_state('t', temp);
  235.  
  236.     if (icap < 0 || itemp < 0) {
  237.         if (icap < 0)
  238.         syslog(LOG_USER | LOG_ERR,
  239.                strcat(strcpy
  240.                   (cap, "Failed retrieving battery state "),
  241.                   "capacity\n"));
  242.         else
  243.         syslog(LOG_USER | LOG_ERR,
  244.                strcat(strcpy
  245.                   (temp, "Failed retrieving battery state "),
  246.                   "temperature\n"));
  247.  
  248.         exit(EXIT_FAILURE);
  249.     }
  250.     // time
  251.  
  252.     time(&time_info);
  253.  
  254.     char *curr_time = ctime(&time_info);
  255.  
  256.     // trim
  257.  
  258.     NTRIM(cap);
  259.     NTRIM(temp);
  260.     NTRIM(curr_time);
  261.  
  262.     // log state
  263.  
  264.     if ((icap != last_cap) || (itemp != last_temp)) {
  265.         syslog(LOG_USER | LOG_INFO,
  266.            "%s: Battery Capacity = %s Battery Temperature = %s\n",
  267.            curr_time, cap, temp);
  268.         last_cap = icap;
  269.         last_temp = itemp;
  270.     }
  271.     // then new mode
  272.  
  273.     int res = 0;
  274.     char mode_msg[40];
  275.  
  276.     if (icap < limit - 2 && last_mode != 'a') {
  277.         if (temp_limit < itemp) {
  278.         res = set_battery_to('a');
  279.         last_mode = 'a';
  280.         }
  281.     } else if (limit < icap && last_mode != 'd') {
  282.         res = set_battery_to('d');
  283.         last_mode = 'd';
  284.     } else if (last_mode != 'i') {
  285.         res = set_battery_to('i');
  286.         last_mode = 'i';
  287.     }
  288.  
  289.     if (res < 0) {
  290.         syslog(LOG_USER | LOG_ERR,
  291.            strcat(strcpy(mode_msg, "Failed setting mode "),
  292.               last_mode == 'a' ? AUT : last_mode ==
  293.               'd' ? DIS : INH));
  294.         exit(EXIT_FAILURE);
  295.     }
  296.  
  297.     sleep(20);
  298.     }
  299.  
  300.     closelog();
  301.  
  302.     exit(EXIT_SUCCESS);
  303. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement