#!/bin/bash
#
# acerfand - Rudimentary automatic fan control for noisy Acer Aspire One models
#
# Author Rachel Greenham
#
# version 0.01

LOGGER=$(which logger)
if [ ! -x $LOGGER ] ; then
	LOGGER="/usr/bin/logger"
fi
if [ ! -x $LOGGER ] ; then
	echo "Warning, logger can't be found. Will log to stdout"
	unset LOGGER
fi

LOGLEVEL="info"

log() {
	if [ ! -z "$LOGGER" ] ; then
		$LOGGER -p daemon.$LOGLEVEL -t acerfand "$@"
	else
		echo "$@"
	fi
}

info() {
	LOGLEVEL="info"
	log "$@"
}

notice() {
	LOGLEVEL="notice"
#	log "$@"
}

err() {
	LOGLEVEL="err"
	log "$@"
}

if pgrep acerfand  | grep -v $$ > /dev/null; then
	info "acerfand already running"
	exit 0
fi

ME=$(readlink -f $0)

ACEREC=$(which acer_ec.pl)
if [ -z $ACEREC ] ; then
	ACEREC=$(dirname $ME)/acer_ec.pl
fi

if [ ! -r $ACEREC ] ; then
	err "acer_ec.pl can't be found"
	exit 1
fi

INTERVAL=5
FANOFF=60
FANAUTO=70

if [ -r "/etc/acerfand.conf" ] ; then
	source "/etc/acerfand.conf"
fi

R_FAN=55
R_TEMP=58

FAN_CMD_OFF=1f
FAN_CMD_AUTO=00

FAN_STATE_UNRECOGNIZED=0
FAN_STATE_AUTO=1
FAN_STATE_OFF=2
FAN_STATE_NAMES=("Unrecognized" "Auto" "Off")
FAN_STATE_CMDS=("$FAN_CMD_OFF" "$FAN_CMD_AUTO" "$FAN_CMD_OFF")

acer_ec() {
	perl $ACEREC $@
}

getTemp() {
	TEMP=$[$(acer_ec ?= $R_TEMP | cut -f 3 -d' ')]
	notice "temp: $TEMP"
}

getRawFanState() {
	RAW_FAN_STATE=$(acer_ec ?= $R_FAN | cut -f 3 -d' ')
}

getFanState() {
	FAN_STATE=$FAN_STATE_UNRECOGNIZED
	getRawFanState
	if [ "$RAW_FAN_STATE" == "0x1f" ]; then
		FAN_STATE=$FAN_STATE_OFF
	else
		let A="$RAW_FAN_STATE & 0x10" || true
		if [ "$A == 0" ] ; then
			# ASSUMPTION: All values with nybble 1==0 denote auto
			FAN_STATE=$FAN_STATE_AUTO
		fi
	fi
	notice "read fan state ${FAN_STATE_NAMES[$FAN_STATE]}"
}

setFan() {
	info "Set fan ${FAN_STATE_NAMES[$1]}"
	acer_ec := $R_FAN ${FAN_STATE_CMDS[$1]} > /dev/null
}

govern() {
trap "info exiting;setFan $FAN_STATE_AUTO; exit" INT TERM EXIT
info "Starting to govern acer fan speed. Interval: $INTERVAL, fan-off: $FANOFF, fan-auto: $FANAUTO"
while true; do
	getTemp
	getFanState
	case "$FAN_STATE" in
		$FAN_STATE_AUTO)
			if [ "$TEMP" -le "$FANOFF" ] ; then
				setFan $FAN_STATE_OFF
			fi
			;;
		$FAN_STATE_OFF)
			if [ "$TEMP" -ge "$FANAUTO" ] ; then
				setFan $FAN_STATE_AUTO
			fi
			;;
		*)
			# weird state. Let's turn it off,
			# then decide next time around
			setFan $FAN_STATE_OFF
			;;
	esac
	sleep $INTERVAL
done
}

set -e

govern &

