#include #include #include #include #include #include #include #include #include // from ds1620.c or therm.h #define CMD_SET_THERMOSTATE 0x53 #define CMD_GET_THERMOSTATE 0x54 #define CMD_GET_STATUS 0x56 #define CMD_GET_TEMPERATURE 0x57 #define CMD_SET_THERMOSTATE2 0x58 #define CMD_GET_THERMOSTATE2 0x59 #define CMD_GET_TEMPERATURE2 0x5a #define CMD_GET_FAN 0x5b #define CMD_SET_FAN 0x5c struct therm { int hi; int lo; }; // from ds1620.c /* * To keep the fan from continuously cycling on/off, we turn the fan * on at the lo speed setting, but turn it off at lo speed - a * delta. This define controls the delta. For example HI = 50, LO = * 48, DELTA = 2. Fan will go ON at 48 and OFF at 45 (lo - delta - 1). */ #define OFF_DELTA 4 // "Wed Jun 30 21:49:08 1993\n" => "Jun 30 21:49:08" char *timestamp(void) { static char str[30]; time_t now = time(NULL); strcpy(str, ctime(&now)); str[19] = '\0'; return &str[4]; } void fan_ctrl(int fd, int on) { syslog(LOG_INFO, "%s fan %s\n", timestamp(), on ? "on" : "off"); ioctl(fd, CMD_SET_FAN, &on); // Force the fan on if(on) { struct therm old, new = { 1, 0 }; ioctl(fd, CMD_GET_THERMOSTATE2, &old); ioctl(fd, CMD_SET_THERMOSTATE2, &new); sleep(2); ioctl(fd, CMD_SET_THERMOSTATE2, &old); } } void turnon(int signum) { // Always leave fan on! syslog(LOG_INFO, "Exiting %s signal %d\n", timestamp(), signum); // fan_ctrl function does not work here (sleep?) system("fan_ctrl on"); closelog(); exit(signum); } void fan(int fd, int verbose); int main(int argc, char *argv[]) { int fd; int verbose; if((fd = open("/dev/temperature", O_RDONLY)) == 0) { perror("/dev/temperature"); exit(1); } verbose = argc > 1 && strcmp(argv[1], "-v") == 0; if(verbose) { char host[20]; int len; strcpy(host, "/tmp/temp-"); len = strlen(host); if(gethostname(host + len, sizeof(host) - len)) { perror("gethostname"); exit(1); } if((verbose = open(host, O_RDWR | O_CREAT, 0644)) == -1) { perror(host); exit(1); } } if(fork() == 0) { // this is the daemon fan(fd, verbose); } if(verbose) close(verbose); exit(0); // kill the parent } void fan(int fd, int verbose) { int temp, lasttemp = 0, fan; int offdelta = 0; struct therm therm; signal(SIGINT, turnon); signal(SIGHUP, turnon); signal(SIGTERM, turnon); openlog("fan", LOG_CONS, LOG_DAEMON); syslog(LOG_NOTICE, "Started %s PID %d\n", timestamp(), getpid()); /* * If you reset the system during a fan start, the hi/lo will * be left at 1/0. Reset it to a sane value. */ ioctl(fd, CMD_GET_THERMOSTATE2, &therm); if(therm.hi == 1) { syslog(LOG_ERR, "Invalid hi/lo %d/%d. Reseting to defaults.\n", therm.hi, therm.lo); therm.hi = 50; therm.lo = 48; ioctl(fd, CMD_SET_THERMOSTATE2, &therm); } /* * We read the hi/lo and fan states every iteration in case someone * has called `set_therm' or `fan_ctrl'. */ while(1) { ioctl(fd, CMD_GET_TEMPERATURE, &temp); ioctl(fd, CMD_GET_THERMOSTATE2, &therm); ioctl(fd, CMD_GET_FAN, &fan); if(temp != lasttemp) { lasttemp = temp; if(verbose) { lseek(verbose, 0, SEEK_SET); write(verbose, &temp, sizeof(temp)); syslog(LOG_NOTICE, "%s lo %2d fan %d temp %d\n", timestamp(), therm.lo, fan, temp); } } if(fan) { if(temp < (therm.lo - offdelta)) fan_ctrl(fd, 0); offdelta = OFF_DELTA; } else if(temp >= therm.lo) fan_ctrl(fd, 1); sleep(15); } } /* * Local Variables: * compile-command: "cc -O3 -Wall fan.c -o fan" * End: */