#!/bin/bash

# this is a modified version of the fan control program found on 
# http://thinkwiki.org/ usable for macbooks.
#
# This file is placed in the public domain and may be freely distributed.

LEVELS=(  2000 2500 3000 3500 4000 4500 5000 5500)  # Fan speed levels
UP_TEMPS=(       52   60   64   68   72   74   76)  # Speed increase trip points
DOWN_TEMPS=(50   54   58   62   66   70   73)

FAN0=`find /sys/devices/platform/applesmc/ -name "*target*" | grep 0`
FAN1=`find /sys/devices/platform/applesmc/ -name "*target*" | grep 1`
FAN0_MANUAL=`find /sys/devices/platform/applesmc/ -name "*manual*" | grep 0`
FAN1_MANUAL=`find /sys/devices/platform/applesmc/ -name "*manual*" | grep 1`
ONLINE=`cat /sys/devices/system/cpu/cpu1/online | grep 1`

INTERVAL=3
VERBOSE=true
DRY_RUN=false

[[ "$1" == "-t" ]] && { DRY_RUN=true; echo "$0: Dry run, will not change fan state."; }

# Enable the fan in default mode if anything goes wrong:
set -e -E -u
$DRY_RUN || trap "manual_off; exit 0" EXIT HUP INT ABRT QUIT SEGV TERM

thermometer() { # output list of temperatures
  if [ ! -z $ONLINE ];then
    CPU0=`coretemp | grep "CPU 0" | grep -o "[[:digit:]]\{2\}"`
    CPU1=`coretemp | grep "CPU 1" | grep -o "[[:digit:]]\{2\}"`
    TEMP=$((($CPU0 + $CPU1) / 2 + 5 ))
  else
    CPU0=`sudo coretemp | sed "s/CPU 0: //" | tr -d " °C"`
    TEMP=$(( $CPU0 + 5))
  fi
  echo $TEMP
 #cat /tmp/a
}

speedometer() { # output fan speed
  if [ $1 -eq 0 ];then
    cat $FAN0
  else
    cat $FAN1
  fi
}

setspeed() {
  echo $1 > $FAN0
  echo $1 > $FAN1
}

manual_on() {
  echo "setting to manual"
  echo 1 > $FAN0_MANUAL
  echo 1 > $FAN1_MANUAL
}

manual_off() {
  echo 0 > $FAN0_MANUAL
  echo 0 > $FAN1_MANUAL
}

IDX=0
MAX_IDX=$(( ${#LEVELS[@]} - 1 ))
SETTLE=0

if ! lsmod | grep applesmc > /dev/null; then
  modprobe applesmc
fi

$DRY_RUN || manual_on
while true; do
    TEMP=`thermometer`
    $VERBOSE && SPEED0=`speedometer 0`
    $VERBOSE && SPEED1=`speedometer 1`

    # Calculate new level
    NEWIDX=$IDX
    DOWN=$(( IDX > 0 ))

        # Increase speed as much as needed
        while [[ $NEWIDX -lt $MAX_IDX ]] && 
              [[ $TEMP -ge ${UP_TEMPS[$NEWIDX]} ]]; do
            (( NEWIDX ++ ))
            DOWN=0
        done
        # Allow decrease (by one index)?
        if [[ $DOWN == 1 ]] && 
           [[ $TEMP -gt ${DOWN_TEMPS[$(( IDX - 1 ))]} ]]; then
            DOWN=0
        fi
      
    if [[ $DOWN == 1 ]]; then
        NEWIDX=$(( IDX - 1 ))
    fi

    # Transition
    OLDLEVEL=${LEVELS[$IDX]}
    NEWLEVEL=${LEVELS[$NEWIDX]}
    $VERBOSE && echo "fan.sh: Temps: $(( $TEMP -5 ))   Fan0: $SPEED0   Fan1: $SPEED1   Level: $OLDLEVEL->$NEWLEVEL"
    $DRY_RUN || setspeed $NEWLEVEL

    sleep $INTERVAL

    IDX=$NEWIDX
done
