/*
 * Xbox Fan Control
 * Copyright (C) Thomas "ShALLaX" Pedley (gentoox@shallax.com)
 *
 * Daemonisation and syslog assistance by
 * David "dmp" Pye (dmp@davidmpye.dyndns.org)
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

#include <fcntl.h>
#include "i2c-dev.h"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "xbox.h"
#include <getopt.h>
#include <syslog.h>
#include <signal.h>

int verbosity, loopCount, cpuBoost, boardBoost, maxBoost, cpuLock, boardLock;
int cpuLastTemp, boardLastTemp, lastpoll, pid, fd, cpuShutdown, boardShutdown;
int lock, mode, cpuTemp, boardTemp, Xcalibur, quiet;
char *scale, *progname, *sensor;
char *devfsname = "/dev/i2c/0";
char *nondevfsname = "/dev/i2c-0";
char *fname;

void XcaliburTest() {
	unsigned char byte;
	fd = open(fname, O_RDWR);
	if (ioctl(fd,I2C_SLAVE_FORCE,XCALIBUR_ADDRESS) < 0) {
			fprintf(stderr,"Error: Could not set address to %d: %s\n",XCALIBUR_ADDRESS,strerror(errno));
			exit(1);
	}

	byte = i2c_smbus_read_byte_data(fd,0x00);
	if (byte != 255) {
		Xcalibur = 1;
	}
}

/* Help screen shown when programme is started with --help */
void help() {
	printf("Fanctl by ShALLaX (c)\nThis tool allows you to set the Xbox's fan speed.\n");
	printf("\nSimple usage:\n");
	printf(" -f, --setspeed X  Set fan to X%% speed\n");
	printf(" -r, --read        Read back the fan speed in percent\n");
	printf(" -q, --quiet       Enable quiet mode (allows setting the speed to as low as 10%%\n");
	printf("                   Quiet mode applies to one-shot and daemon modes.\n");
	if(Xcalibur != 1) {
	   printf(" -h, --help        This screen\n");
		printf("\nDaemon usage:\n");
		printf(" Switch           Description                       Values       Defaults\n");
		printf(" --------------------------------------------------------------------------\n");
		printf(" -i, --idle       Set the idle temp              (1 -> 211)      40°C/104°F\n");
		printf(" -c, --cpushut    Set the cpu shutdown temp      (2 -> 212)      70°C/158°F\n");
		printf(" -a, --ambshut    Set the board shutdown temp    (2 -> 212)      60°C/140°F\n");
		printf(" -t, --scale      Set the scale                  C, F            C\n");
		printf(" -v, --verbose    Output results                 (0 -> 2)        0\n");
		printf(" -p, --poll       Poll interval (seconds)        (5 -> 300)      60\n");
		printf(" -b, --resetboost Reset boost interval (Seconds) (6000 -> 86400) Off\n");
		printf("\nRules:\n");
		printf(" If your chosen fan speed is '<= 10' or '> 100' the setting is autolocked at 10.\n");
		printf("\nVerbosity\n");
		printf(" 0 = No logging\n");
		printf(" 1 = Initial settings output on run.\n");
		printf(" 2 = As above + syslog entries each time the fan speed changes by + 3%% from last\n     poll.\n");
		printf("\nInfo:\n");
		printf(" Numbers may be floored (i.e. 85%% will go to 84%%) because of the way the\n Xbox's i2c works.\n");
		printf(" SIGTERM = Kill daemon and return fan settings to normal\n SIGQUIT = Kill daemon and set fan to 100%%\n SIGUSR1 resets the boostlocks.\n");
	}
	exit(0);
}

void resetBoostLocks() {
	boardLock = cpuLock = cpuBoost = boardBoost = 0;
	loopCount = 0;
	if (verbosity >= 2) {
		openlog(progname,LOG_NDELAY,LOG_LOCAL0);
		syslog(LOG_INFO,"fanctl[%i]: Boostlocks reset.", pid);
		closelog();
	}
}

/* Calculate the new speed to be set. */
int calcSpeed(int idleLimit,int currentTemp,int shutdownLimit) {
	float gradient, range, newSpeed;
	range = (shutdownLimit - idleLimit);

	if(quiet == 1) {
		/* 10%->100% [5->50] = 45 */
		gradient = 45/range;
		newSpeed = (((currentTemp - idleLimit) * gradient) + 5);
	} else {
		/* 20%->100% [10->50] = 40 */
		gradient = 40/range;
		newSpeed = (((currentTemp - idleLimit) * gradient) + 10);
	}


	if (boardTemp >= idleLimit) {
		if (boardLastTemp <= boardTemp) {
			if (strcasecmp(sensor, "b") == 0) {
				if ((boardBoost < maxBoost) && (boardLock == 0)) {
					boardBoost = boardBoost + 1;
				}
				/* If the boardBoost reaches maxboost, then you
				   may as well lock it. */
				if ((boardBoost == maxBoost) && (boardLock == 0)) {
					boardLock = 1;
				}
			}
		} else {
			/* If the temperature drops, then clear the boost */
			boardLock = 1;
		}
	}

	/* Obviously, if the temperature drops below the idle limit rapidly
	   then the above boardLock wont be activated, for this reason this
	   if statement needs to be executed too.  */
	if ((boardLastTemp >= idleLimit) && (boardTemp < idleLimit)) {
		boardLock = 1;
	}


	/* All the same, but this time for the CPU sensor. */
	if (cpuTemp >= idleLimit) {
		if (cpuLastTemp <= cpuTemp) {
			if (strcasecmp(sensor, "c") == 0) {
				if ((cpuBoost < maxBoost) && (cpuLock == 0)) {
					cpuBoost = cpuBoost + 1;
				}
				if ((cpuBoost == maxBoost) && (cpuLock == 0)) {
					cpuLock = 1;
				}
			}
		} else {
			cpuLock = 1;
		}
	}

	if ((cpuLastTemp >= idleLimit) && (cpuTemp < idleLimit)) {
		cpuLock = 1;
	}

	/* Which speed value should be sent back to the programme? */
	if (strcasecmp(sensor, "b") == 0) {
		if (boardTemp >= idleLimit) {
			newSpeed = newSpeed + boardBoost;
		}
	} else {
		if (cpuTemp >= idleLimit) {
			newSpeed = newSpeed + cpuBoost;
		}
	}

	/* Some safeguards here to ensure that the speed never gets set
	   lower than 10%, and never higher than 100%. */
	if(quiet == 1) {
		if (newSpeed <= 5) {
			newSpeed = 5;
		}
	} else {
		if (newSpeed <= 10) {
			newSpeed = 10;
		}
	}
	/* If set to 20%, give back control to the Xbox's PIC.  */
	if (newSpeed == 10) {
		lock = 1;
	}

	if (newSpeed > 50) {
		newSpeed = 50;
	}

	if (newSpeed > 10) {
		lock = 0;
	}
	return newSpeed;
}

/* Return the current fan speed. */
int getFanSpeed() {
	int speed;
	fd = open(fname, O_RDWR);
	ioctl(fd,I2C_SLAVE_FORCE,PIC_ADDRESS);
	speed = i2c_smbus_read_byte_data(fd,FAN_READBACK);
	close(fd);
	return speed; 
}

/* Return the current temperature. */
void getTemperature() {
	fd = open(fname, O_RDWR);
	ioctl(fd,I2C_SLAVE_FORCE,PIC_ADDRESS);
	cpuTemp = i2c_smbus_read_byte_data(fd,0x09);
	boardTemp = i2c_smbus_read_byte_data(fd,0x0A);
	close(fd);
}

void setFanSpeed(int speed) {
	/* If the speed is 20%, lock the fan setting. */
	fd = open(fname, O_RDWR);
 	ioctl(fd,I2C_SLAVE_FORCE,PIC_ADDRESS);
 	i2c_smbus_write_byte_data(fd,FAN_MODE,1);
 	i2c_smbus_write_byte_data(fd,FAN_REGISTER,speed);
	if ( lock == 1 && Xcalibur != 1 ) {
		sleep(1);
		i2c_smbus_write_byte_data(fd,FAN_MODE,0);
	}
	close(fd);
}

/* Poweroff after writing an error to syslog and the console and pausing 5 seconds
   to enable the log to write and be saved. */
void poweroff() {
	int i;
	openlog(progname,LOG_CONS||LOG_NDELAY||LOG_PERROR,LOG_LOCAL0);
	/* What caused the shutdown?  CPU or Board? */
	if ((boardTemp >= boardShutdown) && (cpuTemp >= cpuShutdown)) {
		syslog(LOG_EMERG,"fanctl[%i]: DUAL OVERHEAT! SHUTDOWN! - CPU: %i°%s, Board: %i°%s", pid, cpuTemp, scale, boardTemp, scale);
	} else if (cpuTemp >= cpuShutdown) {
		syslog(LOG_EMERG,"fanctl[%i]: CPU OVERHEAT! SHUTDOWN! - CPU: %i°%s, Board: %i°%s", pid, cpuTemp, scale, boardTemp, scale);
	} else if (boardTemp >= boardShutdown) {
		syslog(LOG_EMERG,"fanctl[%i]: Board OVERHEAT! SHUTDOWN! - CPU: %i°%s, Board: %i°%s", pid, cpuTemp, scale, boardTemp, scale);
	}
	closelog();
	/* Audio feedback of an overheat!  Maybe a controversial way of doing it, but
	   setting the fan speed to 10 (default) shouldnt cause any problems for such 
	   a short period of time. */
	for (i=0; i<3; i++) {
		setFanSpeed(10);
		sleep(1);
		setFanSpeed(50);
		sync();
		sleep(1);
	}

	fd = open(fname, O_RDWR);
	ioctl(fd,I2C_SLAVE_FORCE,PIC_ADDRESS);
	i2c_smbus_write_byte_data(fd,0x1A,0x01);
	sleep(1);
	i2c_smbus_write_byte_data(fd,0x02,0x80);
	close(fd);
	exit(0);
}

void signalHandler(int sig) {
	switch (sig) {
		/* SIGTERM returns the fan to normal settings, then quits the daemon. */
		case SIGTERM: 
			lock = 1;
			setFanSpeed(10);
			openlog(progname,LOG_NDELAY,LOG_LOCAL0);
			syslog(LOG_INFO,"fanctl[%i]: Terminated - Fan speed returned to 20%% and locked.", pid);
			closelog();
			/* Remove lockfile */
			remove("/var/lock/fanctl.lock");
			exit(0);
			break;
		/* SIGUSR1 resets the boostlocks */
		case SIGUSR1: 
			resetBoostLocks();
			break;
		/* SIGQUIT sets the fan to 100% and locks the setting, then quits the daemon. */
		case SIGQUIT:
			lock = 1;
			setFanSpeed(50);
			openlog(progname,LOG_NDELAY,LOG_LOCAL0);
			syslog(LOG_INFO,"fanctl[%i]: Terminated - Fan speed set to 100%% and locked.", pid);
			closelog();
			/* Delete lockfile */
			remove("/var/lock/fanctl.lock");
			exit(0);
			break;
		default:
			/* Should never get here. */
			break;
	}
}

/* Check to see if a lockfile is in place, if it is, quit. */
void lockCheck() {
	FILE *fp;
	if ((fp = fopen("/var/lock/fanctl.lock", "r")) != NULL) {
		fprintf(stderr, "fanctl is already running in daemon mode or was killed.\nPlease kill the process (if it isnt dead already) and delete\n'/var/lock/fanctl.lock'\n\nIf you want to simply set the speed, run fanctl with the -f flag\nSee --help for more details.\n");
		exit(1);
	}
}

/* Create the lockfile. */
void lockCreate() {
	FILE *fp;
	if ((fp = fopen("/var/lock/fanctl.lock", "w")) == NULL) {
		fprintf(stderr, "Cant open lockfile to write, are you root?\nDoes the directory '/var/lock' exist?\n");
		exit(1);
	} else {
		fclose(fp);
	}
}

/* Check to see if the PIC device is reachable and can be written to. */
void checkPIC() {
	if ((fd = open(devfsname, O_RDWR)) < 0) {
		if ((fd=open(nondevfsname,O_RDWR))<0) {
			fprintf(stderr, "Error - failed to open EITHER /dev/i2c/0 or /dev/i2c-0\n	  - you must be root and have the correct i2c modules loaded.\n");
			remove("/var/lock/fanctl.lock");
			exit(1);
		} else {
			fname = malloc (strlen(nondevfsname));
			strncpy (fname, nondevfsname, strlen(nondevfsname));
		}
	} else {
		fname = malloc (strlen(devfsname));
		strncpy (fname, devfsname, strlen(devfsname));
	}

	if (ioctl(fd,I2C_SLAVE_FORCE,PIC_ADDRESS) < 0) {
		fprintf(stderr, "Error: Could not set address to %d: %s\n",PIC_ADDRESS,strerror(errno));
	remove("/var/lock/fanctl.lock");
		exit(1);
	}
	close(fd);
}


int main(int argc, char *argv[]) {
	/* Declarations and initialisations */
	int resetBoostInterval, resetBoostLoop, resetBoostLock, deflection, newspeed, pollinterval, defidle, reg, daemon, c, x, cs, idle;
	deflection = 3; /* Used for syslogging */
	mode = 1;
	quiet = 0;

	/* Set the maximum boost levels for boardBoost and cpuBoost
	   Remember, the percentage value is actually double what we set, 
	   so "20" = "40%" */
	maxBoost = 20;

	/* Hardcoded default shutdown temperatures */
	cpuShutdown = 70;
	boardShutdown = 60;

	/* Default pollinterval */
	pollinterval = 60;

	progname = argv[0];
	resetBoostInterval = resetBoostLock = loopCount = boardBoost = cpuBoost = cpuLastTemp = boardLastTemp = lastpoll = verbosity = lock = 0;

	/* Default is to start as a daemon.  */
	daemon = 1;

	/* Predefined default idle temperature. */
	defidle = 40;

	/* Initial value used later to check if the user has specified
	   a value or not. */
	idle = -1337;

	/* Default to °C */
	scale = malloc (strlen("C"));
	sensor = malloc (strlen("b"));
	strncpy (scale, "C", strlen("C"));

	/* Check to see if we can write to the i2c device */
	checkPIC();

	/* Do we have an Xcalibur? */
	XcaliburTest();

	/* SIG handlers. */
	signal(SIGTERM, signalHandler);
	signal(SIGUSR1, signalHandler);
	signal(SIGQUIT, signalHandler);

	while (1) {
		/* Arguments for the programme. */
		int option_index = 0;
		static struct option long_options[] = {
	 		{"idle", 1, 0, 'i'},
			{"cpushut", 1, 0, 'c'},
			{"ambshut", 1, 0, 'a'},
			{"poll", 1, 0, 'p'},
	  		{"scale", 1, 0, 's'},
			{"help", 0, 0, 'h'},
			{"verbose", 1, 0, 'v'},
			{"setspeed", 1, 0, 'f'},
			{"resetboost", 1, 0, 'b'},
			{"read", 0, 0, 'r'},
			{"quiet", 0, 0, 'q'},
   		{0, 0, 0, 0}
	 	};

	 	c = getopt_long(argc, argv, "i:c:a:p:s:f:v:b:?::h::r::q", long_options, &option_index);

	 	if (c == -1) {
			break;
		}
	
	 	switch (c) {
			case 'q':
				quiet = 1;
				break;
			case 'b':
				resetBoostLock = 1;
				resetBoostInterval = atoi(optarg);
				break;
			case 'h':
				help();
				break;
			case 'i':
			  	idle = atoi(optarg);
				break;
			case 'c':
			  	cpuShutdown = atoi(optarg);
				break;
			case 'a':
			  	boardShutdown = atoi(optarg);
				break;
	   	case 's':
				if ((strcmp(optarg,"C") == 0) || (strcmp(optarg,"F") == 0)) {
					strncpy (scale, optarg, strlen(optarg));
				} else {
					fprintf(stderr, "Invalid scale: '%s'\n", optarg);
					fprintf(stderr, "Please select either C or F (case sensitive)\n");
					remove("/var/lock/fanctl.lock");
					exit(1);
				}
				break;
			case 'f':
				x = atoi(optarg);
				daemon = 0;
				break;
			case 'p':
				pollinterval = atoi(optarg);
				break;
			case 'v':
				verbosity = atoi(optarg);
				break;
			case 'r':
				cs = getFanSpeed();
				cs = cs * 2;
				printf("Fanctl by ShALLaX (c).  Run: '%s --help' for usage\nStarted in one-shot mode.\n\n", argv[0]);
				printf("Current speed: %i%%\n", cs);
				exit(0);
				break;
			case '?':
				fprintf(stderr, "See %s --help for details\n", argv[0]);
				exit(0);
				break;
			/* Should never occur */
			default:
				break;
		}
	}

	if (daemon == 1 && Xcalibur != 1) {
		/* Check and create lockfile. */
		lockCheck();
		lockCreate();

		if (resetBoostLock == 1) {
			if ((resetBoostInterval < 6000) || (resetBoostInterval > 86400)) {
				printf("Invalid reset boost interval, please see --help for details\n");
				remove("/var/lock/fanctl.lock");
				exit(1);
			}
			resetBoostLoop = (resetBoostInterval / pollinterval);
		} 
	
		/* Check to see if idle temp has been specified,
		   if not then set it to the defidle value.  And of course,
		   take °F into account. */
		if ( idle == -1337 ) { 
			if (strcasecmp(scale, "F") == 0) {
				idle = ((9.0 / 5.0) * defidle) + 32.0;
			} else {
				idle = defidle;
			}
		}

		/* Convert the recorded temperatures to °F if necessary. */
		if (strcasecmp(scale, "F") == 0) {
			cpuShutdown = ((9.0 / 5.0) * cpuShutdown) + 32.0;
			boardShutdown = ((9.0 / 5.0) * boardShutdown) + 32.0;
		}

		/* Dont allow cpuShutdown to be less or equal to 1. */
		if ( cpuShutdown <= 1 ) {
			fprintf(stderr, "Sorry, your cpuShutdown setting must be greater than 1°%s\n", scale);
			remove("/var/lock/fanctl.lock");
			exit(1);
		}

		/* Dont allow cpuShutdown to be greater than 212. */
		if ( cpuShutdown > 212 ) {
			fprintf(stderr, "Sorry, your cpuShutdown setting must be less than 213°%s\n", scale);
			remove("/var/lock/fanctl.lock");
			exit(1);
		}

		/* Dont allow boardShutdown to be less or equal to 1. */
		if ( boardShutdown <= 1 ) {
			fprintf(stderr, "Sorry, your boardShutdown setting must be greater than 1°%s\n", scale);
			remove("/var/lock/fanctl.lock");
			exit(1);
		}

		/* Dont allow boardShutdown to be greater than 212. */
		if ( boardShutdown > 212 ) {
			fprintf(stderr, "Sorry, your boardShutdown setting must be less than 213°%s\n", scale);
			remove("/var/lock/fanctl.lock");
			exit(1);
		}

		if ( boardShutdown <= cpuShutdown ) {
			/* Dont allow the idle temperature to be greater than the board shutdown temperature */
			if ( idle >= boardShutdown ) {
				fprintf(stderr, "Sorry, your idle setting must be lower than %i°%s\n",boardShutdown, scale);
				remove("/var/lock/fanctl.lock");
				exit(1);
			}
		} else {
			/* Dont allow the idle temperature to be greater than the CPU shutdown temperature */
			if ( idle >= cpuShutdown ) {
				fprintf(stderr, "Sorry, your idle setting must be lower than %i°%s\n",cpuShutdown, scale);
				remove("/var/lock/fanctl.lock");
				exit(1);
			}
		}

		/* Dont allow it to be less or equal to 0. */
		if ( idle <= 0 ) {
			fprintf(stderr, "Sorry, your idle setting must be greater than 0°%s\n", scale);
			remove("/var/lock/fanctl.lock");
			exit(1);
		}

		if ((pollinterval < 5) || ( pollinterval > 300 )) {
			fprintf(stderr, "Invalid poll interval\nSee %s --help for details\n", progname);
			remove("/var/lock/fanctl.lock");
			exit(1);
		}

		/* The welcome message (and verbosity if selected).  This is the last 
		   output before going daemon! */
		printf("Fanctl by ShALLaX (c).  Run: '%s --help' for usage\nStarted in daemon mode.\n", argv[0]);
		if(quiet == 1) {
			printf("!!Quiet mode enabled - use with caution!!\n");
		}
		if (verbosity >= 1) {
			/* Get the fan speed and double it for percent output. */
			cs = getFanSpeed();
			cs = cs * 2;

			/* Initialise the global temperature variables, and look out for °F */
			getTemperature();

			if (strcasecmp(scale,"F") == 0) { 
				cpuTemp = ((9.0 / 5.0) * cpuTemp) + 32.0;
				boardTemp = ((9.0 / 5.0) * boardTemp) + 32.0;
			}
			printf("\nCPU temperature:		  %i", cpuTemp);
			if (strcasecmp(scale,"c") == 0) { printf(" °C\n"); } else { printf(" °F\n"); }
			printf("Board temperature:		%i", boardTemp);
			if (strcasecmp(scale,"c") == 0) { printf(" °C\n"); } else { printf(" °F\n"); }
			printf("CPU shutdown:			 %i", cpuShutdown);
			if (strcasecmp(scale,"c") == 0) { printf(" °C\n"); } else { printf(" °F\n"); }
			printf("Board shutdown:		   %i", boardShutdown);
			if (strcasecmp(scale,"c") == 0) { printf(" °C\n"); } else { printf(" °F\n"); }
			printf("Idle temperature:		 %i", idle);
			if (strcasecmp(scale,"c") == 0) { printf(" °C\n"); } else { printf(" °F\n"); }
			printf("Poll Interval			 %i seconds\n", pollinterval);
			if (resetBoostLock == 1) { printf("Reset boost interval:	 %i seconds\n", resetBoostInterval); }
		}

		/* Begin forking. */
		switch(fork()) {
			case -1: /* Error occurred */
				fprintf(stderr,"%s: error forking off daemon process - %s",progname, strerror(errno));	
				remove("/var/lock/fanctl.lock");
				exit(1);
			case 0: /* Forked child */
				pid = getpid();
				openlog(progname,LOG_NDELAY,LOG_LOCAL0);
				syslog(LOG_INFO,"fanctl[%i]: Daemon started - idleTemp: %i°%s, pollInterval: %i seconds, boostReset %i seconds, verbosity: %i, cpuShutdown: %i°%s, boardShutdown: %i°%s", pid, idle, scale, pollinterval, resetBoostInterval, verbosity, cpuShutdown, scale, boardShutdown, scale);
				closelog();
				chdir("/");
				close (STDIN_FILENO);
				close (STDOUT_FILENO);
	   		close (STDERR_FILENO);
				break;
			default: /* Parent process */
				return 0;
		}

		/* Repeat this untill killed at the poll interval. */
		while (1) {
			/* Get the fan speed. */
			cs = getFanSpeed();
			cs = cs * 2;

			/* And get the temperatures + take care of conversions. */
			getTemperature();
			if (strcasecmp(scale,"F") == 0) { 
				cpuTemp = ((9.0 / 5.0) * cpuTemp) + 32.0; 
				boardTemp = ((9.0 / 5.0) * boardTemp) + 32.0; 
			}

			/* If the CPU temperature or board temperatures are above the 
			   hardcoded defaults, then run the poweroff function. */
			if (( cpuTemp >= cpuShutdown ) || (boardTemp >= boardShutdown)) {
				poweroff();
			}

			/* Use the highest temperature, if the temperatures are 
			   equal, go with the CPU temperature. */
			if (cpuTemp > boardTemp) {
				strncpy (sensor, "c", strlen("c"));
			}
			if (cpuTemp < boardTemp) {
				strncpy (sensor, "b", strlen("b"));
			}
			if (cpuTemp == boardTemp) {
				strncpy (sensor, "c", strlen("c"));
			}

			/* Set the speed depending on which temperature is higher. */
			if (cpuTemp > boardTemp) {
				reg = calcSpeed(idle, cpuTemp, cpuShutdown);
			} else {
				reg = calcSpeed(idle, boardTemp, boardShutdown);
			}		

			if (reg > 50) {
				reg = 50;
			}

			newspeed = reg * 2;
			
			/* Call the fan speed function */
			setFanSpeed(reg);

			/* If the temperature change between polls is greater than [deflection]%, 
			   and verbosity is enabled, then log the event */
			if ((abs(lastpoll - cs) >= deflection) && (verbosity >= 2)) {
				openlog(progname,LOG_NDELAY,LOG_LOCAL0);
				if ( lock == 1 ) {
					if ((cpuTemp < idle) && (boardTemp < idle)) {
						syslog(LOG_INFO,"fanctl[%i]: Below idle temperature (%i°%s) - CPU: %i°%s, Board: %i°%s - cpuBoost %i%% (Lock = %i), boardBoost %i%% (Lock = %i) - Setting speed (%i%%) and locking fan control.", pid, idle, scale, cpuTemp, scale, boardTemp, scale, cpuBoost*2, cpuLock, boardBoost*2, boardLock, newspeed);
					} else {
						/* If the speed is 20%, state the controls have been locked. */
						if ((cpuTemp > boardTemp) || (cpuTemp == boardTemp)) {
							syslog(LOG_INFO,"fanctl[%i]: Using CPU boost - CPU: %i°%s, Board: %i°%s - cpuBoost %i%% (Lock = %i), boardBoost %i%% (Lock = %i) - Setting speed (%i%%) and locking fan control.", pid, cpuTemp, scale, boardTemp, scale, cpuBoost*2, cpuLock, boardBoost*2, boardLock, newspeed);
						} else {
							syslog(LOG_INFO,"fanctl[%i]: Using Board boost - CPU: %i°%s, Board: %i°%s - cpuBoost %i%% (Lock = %i), boardBoost %i%% (Lock = %i) - Setting speed (%i%%) and locking fan control.", pid, cpuTemp, scale, boardTemp, scale, cpuBoost*2, cpuLock, boardBoost*2, boardLock, newspeed);
						}
					}
				} else {
					if ((cpuTemp < idle) && (boardTemp < idle)) {
						syslog(LOG_INFO,"fanctl[%i]: Below idle temperature (%i°%s) - CPU: %i°%s, Board: %i°%s - cpuBoost %i%% (Lock = %i), boardBoost %i%% (Lock = %i) - Setting speed (%i%%) and locking fan control.", pid, idle, scale, cpuTemp, scale, boardTemp, scale, cpuBoost*2, cpuLock, boardBoost*2, boardLock, newspeed);
					} else {
						if ((cpuTemp > boardTemp) || (cpuTemp == boardTemp)) {
							syslog(LOG_INFO,"fanctl[%i]: Using CPU boost - CPU: %i°%s, Board: %i°%s - cpuBoost %i%% (Lock = %i), boardBoost %i%% (Lock = %i) - Setting speed (%i%%).", pid, cpuTemp, scale, boardTemp, scale, cpuBoost*2, cpuLock, boardBoost*2, boardLock, newspeed);
						} else {
							syslog(LOG_INFO,"fanctl[%i]: Using Board boost - CPU: %i°%s, Board: %i°%s - cpuBoost %i%% (Lock = %i), boardBoost %i%% (Lock = %i) - Setting speed (%i%%).", pid, cpuTemp, scale, boardTemp, scale, cpuBoost*2, cpuLock, boardBoost*2, boardLock, newspeed);
						}
					}
				}
				closelog();
			}

			/* Use lastpoll as a memory so the programme knows how much
			   the fan speed has changed since the last poll so it can 
			   decide whether to log into syslog. */
			lastpoll = cs;

			/* Used to check if the temperature has dropped - if it has dropped,
			   then the appropriate boostlock is enabled. */
			cpuLastTemp = cpuTemp;
			boardLastTemp = boardTemp;

			loopCount = loopCount + 1;
			/* If the loop count has reached the lock reset count
			   then reset the locks and boosts.  Log if verbose. */
			if (loopCount == resetBoostLoop) {
				resetBoostLocks();
			}

			/* Sleep before repeating the loop. */
			sleep(pollinterval);
		}
	} else if (daemon == 0) {
		if(quiet == 1) {
			if ( x <= 10 ) { 
				x = 10;
				lock = 0;
			}
		} else {
			if ( x <= 20 ) { 
				x = 20;
			}
		}

		if ( x == 20 ) {
			lock = 1;
		}

		if ( x > 100 ) { 
			x = 100;
			lock = 0;
		}

		/* Yes, there is a point to this, it floors the value of x ;) */
		x = ((x / 2) * 2) / 2;

		/* This is for the non-daemon element, basically, this is a one-shot 
		   speed set function (and it displays some output).
		   Get the "old speed". */
		cs = getFanSpeed();
		cs = cs * 2;
		printf("Fanctl by ShALLaX (c).  Run: '%s --help' for usage\nStarted in one-shot mode.\n", argv[0]);
		if(quiet == 1) {
			printf("!!Quiet mode enabled - use with caution!!\n\n");
		} else {
			printf("\n");
		}
		printf("Old speed: %i%%\n", cs);
		/* Specify the "new speed" */
		printf("New speed: %i%%", x*2);
		if ( lock == 1 && Xcalibur != 1 ) {
			printf(" and locked\n"); 
		} else { 
			printf("\n");
		}
		/* And set it (lock if the speed is == 20%.  syslog it!) */
		pid = getpid();
		openlog(progname,LOG_NDELAY,LOG_LOCAL0);
		if (x == 10) {
			if (Xcalibur != 1) {
				syslog(LOG_INFO,"fanctl[%i]: Speed manually set to %i%% and locked.", pid, x*2);
			} else {
				syslog(LOG_INFO,"fanctl[%i]: Speed manually set to %i%%.", pid, x*2);
			}
		} else {
			syslog(LOG_INFO,"fanctl[%i]: Speed manually set to %i%%.", pid, x*2);
		}
		closelog();
		setFanSpeed(x);
	} else if (Xcalibur == 1) {
		help();
	}
	exit (0);
}
