/* A Project of Andrea Cioni Title: Fan Daemon (FanD) Author: Andrea Cioni (andreacioni) cioni95@gmail.com Copyright: Copyright (c) 2017 Andrea Cioni https://github.com/dweeber/WiFi_Check Purpose: Simple utility program for GNU/Linux systems to control a fan motor of your miniPC (UDOO,Raspberry Pi,Orange Pi,etc) through a PWM signal. Compile: gcc -std=gnu99 fand.c -o fand Launch: fand Example usage: ./fand 2 3 20 30 10 100 */ #include #include #include #include #include #define HELLO_BANNER "Fan Daemon" #define VERSION "(0.2v)" #define BASE_PATH "/sys/class/pwm/pwmchip0/" #define EXPORT_PATH BASE_PATH "pwm0/" static volatile bool go = true; struct console_args { unsigned long period; unsigned long sleep_timeout; unsigned long min_temp; unsigned long max_temp; unsigned short min_percent_dc; unsigned short max_percent_dc; }; bool export() { return system("echo 0 > " BASE_PATH "export") == 0; } bool unexport() { return system("echo 0 > " BASE_PATH "unexport") == 0; } bool enable(bool enable) { if(enable) return system("echo 1 > " EXPORT_PATH "enable") == 0; else return system("echo 0 > " EXPORT_PATH "enable") == 0; } bool setup(unsigned long period) { char buf[1024]; return (sprintf(buf,"echo %lu > " EXPORT_PATH "period",period) != 0) && (system(buf) == 0); } bool set_dc(float percent,unsigned long period) { char buf[1024]; percent = (percent>100.0f) ? 100.0f : percent; unsigned long dc_ns = (percent/100)*period; dc_ns = (dc_ns >= period) ? (period-1) : dc_ns; printf("Percent: %0.1f %%, DC: %lu/%lu\n",percent,dc_ns,period); return (sprintf(buf,"echo %lu > " EXPORT_PATH "duty_cycle",dc_ns) != 0) && (system(buf) == 0); } float read_cpu_temp() { float ret = -1.0f; FILE *fp = popen("/bin/cat /sys/devices/virtual/thermal/thermal_zone0/temp", "r"); char buf[1024] = {0}; if(fp != NULL) { if(fgets(buf,1023,fp) != NULL) { printf("Temperature read: %s",buf); if((ret=strtoul(buf,NULL,10)) != 0) { ret=ret/1000; } else { printf("Cannot convert output string\n"); } } else { printf("Cannot read CPU temperature from output\n"); } pclose(fp); } else { printf("Cannot read CPU temperature\n"); } return ret; } void kill_handler(int sig) { printf("Terminating...\n"); go=false; } int run(struct console_args _args) { int ret=0; signal(SIGINT,kill_handler); while(go) { float cpu_temp = read_cpu_temp(),percentdc=0; if(cpu_temp > _args.min_temp) { float ratio = (cpu_temp-_args.min_temp)/(_args.max_temp - _args.min_temp); percentdc = (ratio*(_args.max_percent_dc - _args.min_percent_dc))+_args.min_percent_dc; } if(!set_dc(percentdc,_args.period)) printf("There was an error setting the duty cicle"); sleep(_args.sleep_timeout); printf("\n"); } return ret; } bool parse_arguments(int argv, char **argc,struct console_args *_args) { bool ret=true; if(argv == 7) { unsigned long ul = strtoul(argc[1],NULL,10); if(ul != 0) { _args->period = (1.0f/ul)*100000000L; printf("Frequency: %lu Hz, Period: %lu s\n",ul,_args->period); } else ret &= false; ul = strtoul(argc[2],NULL,10); if(ul != 0) { _args->sleep_timeout = ul; printf("Sleep timeout: %lu s\n",_args->sleep_timeout); } else ret &= false; ul = strtoul(argc[3],NULL,10); if(ul != 0) { _args->min_temp = ul; printf("Min temperature: %lu *C\n",_args->min_temp); } else ret &= false; ul = strtoul(argc[4],NULL,10); if(ul != 0) { _args->max_temp = ul; printf("Max temperature: %lu *C\n",_args->max_temp); } else ret &= false; ul = strtoul(argc[5],NULL,10); if(ul != 0) { _args->min_percent_dc = (unsigned short) ul; printf("Min duty cycle: %i %%\n",_args->min_percent_dc); } else ret &= false; ul = strtoul(argc[6],NULL,10); if(ul != 0) { _args->max_percent_dc = (unsigned short) ul; printf("Max duty cycle: %i %%\n",_args->max_percent_dc); } else ret &= false; } else ret=false; return ret; } int main(int argv, char **argc) { int ret = 0; struct console_args _args; printf("%s %s\n",HELLO_BANNER,VERSION); if(!parse_arguments(argv,argc,&_args)) { printf("fand \n"); ret = 100; } else { printf("Exporting..."); if(export()) { printf("OK!\n"); printf("Setupping (f=%lu)...",_args.period); if(setup(_args.period)) { printf("OK!\n"); printf("Enabling..."); if(enable(true)) { printf("OK!\n"); ret = run(_args); printf("Disabling..."); if(enable(false)) { printf("OK!\n"); } else { printf("FAIL!\n"); ret = 4; } } else { printf("FAIL!\n"); ret=3; } } else { printf("FAIL!\n"); ret=2; } } else { printf("FAIL!\n"); ret=1; } printf("Unexporting..."); if(unexport()) { printf("OK!\n"); } else { printf("FAIL!\n"); } } return ret; }