-
-
Save minimum-necessary-change/e12b8553a9723dad3a37bf92488e373f to your computer and use it in GitHub Desktop.
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
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
| /* | |
| A Project of Andrea Cioni | |
| Title: Fan Daemon (FanD) | |
| Author: Andrea Cioni (andreacioni) | |
| [email protected] | |
| Copyright: | |
| Copyright (c) 2017 Andrea Cioni <[email protected]> | |
| 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 <frequency of the PWM signal> <sleep seconds between temperature checks> <min temp in Celsius> <max temp in Celsius> <min dc percent> <max dc percent> | |
| Example usage: | |
| ./fand 2 3 20 30 10 100 | |
| */ | |
| #include<stdio.h> | |
| #include<stdbool.h> | |
| #include<stdlib.h> | |
| #include<unistd.h> | |
| #include<signal.h> | |
| #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 <frequency> <sleep seconds> <min temp> <max temp> <min dc percent> <max dc percent> \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; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment