root/lm-sensors/branches/lm-sensors-3.0.0/prog/pwm/fancontrol @ 5102

Revision 5102, 9.6 KB (checked in by khali, 7 years ago)

Detect improperly formatted FCTEMPS value (#2293).

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
Line 
1#!/bin/bash
2#
3# Simple script implementing a temperature dependent fan speed control
4#
5# Version 0.66
6#
7# Usage: fancontrol [CONFIGFILE]
8#
9# Dependencies:
10#   bash, egrep, sed, cut, sleep, lm_sensors :)
11#
12# Please send any questions, comments or success stories to
13# marius.reiner@hdev.de
14# Thanks!
15#
16# The latest version of this script is available at:
17# http://www.hdev.de/fancontrol/fancontrol.html
18# or in the SVN version of lm_sensors
19#
20# For configuration instructions and warnings please see fancontrol.txt, which
21# can be found in the doc/ directory or at the website mentioned above.
22#
23#
24#    Copyright 2003 Marius Reiner <marius.reiner@hdev.de>
25#    Copyright (C) 2007 Jean Delvare <khali@linux-fr.org>
26#
27#    This program is free software; you can redistribute it and/or modify
28#    it under the terms of the GNU General Public License as published by
29#    the Free Software Foundation; either version 2 of the License, or
30#    (at your option) any later version.
31#
32#    This program is distributed in the hope that it will be useful,
33#    but WITHOUT ANY WARRANTY; without even the implied warranty of
34#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
35#    GNU General Public License for more details.
36#
37#    You should have received a copy of the GNU General Public License
38#    along with this program; if not, write to the Free Software
39#    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
40#
41#
42
43#DEBUG=1
44MAX=255
45
46echo $$ > /var/run/fancontrol.pid
47
48declare -i pwmval
49
50function LoadConfig {
51        echo "Loading configuration from $1 ..."
52        # grep configuration from file
53        INTERVAL=`egrep '^INTERVAL=.*$' $1 | sed -e 's/INTERVAL=//g'`
54        FCTEMPS=`egrep '^FCTEMPS=.*$' $1 | sed -e 's/FCTEMPS=//g'`
55        MINTEMP=`egrep '^MINTEMP=.*$' $1 | sed -e 's/MINTEMP=//g'`
56        MAXTEMP=`egrep '^MAXTEMP=.*$' $1 | sed -e 's/MAXTEMP=//g'`
57        MINSTART=`egrep '^MINSTART=.*$' $1 | sed -e 's/MINSTART=//g'`
58        MINSTOP=`egrep '^MINSTOP=.*$' $1 | sed -e 's/MINSTOP=//g'`
59        # optional settings:
60        FCFANS=`egrep '^FCFANS=.*$' $1 | sed -e 's/FCFANS=//g'`
61        MINPWM=`egrep '^MINPWM=.*$' $1 | sed -e 's/MINPWM=//g'`
62        MAXPWM=`egrep '^MAXPWM=.*$' $1 | sed -e 's/MAXPWM=//g'`
63       
64        # Check whether all mandatory settings are set
65        if [[ -z ${INTERVAL} || -z ${FCTEMPS} || -z ${MINTEMP} || -z ${MAXTEMP} || -z ${MINSTART} || -z ${MINSTOP} ]]
66        then
67                echo "Some mandatory settings missing, please check your config file!"
68                exit 1
69        fi
70        if [ "$INTERVAL" -le 0 ]
71        then
72                echo "Error in configuration file:"
73                echo "INTERVAL must be at least 1"
74                exit 1
75        fi
76
77        # write settings to arrays for easier use and print them
78        echo
79        echo "Common settings:"
80        echo "  INTERVAL=$INTERVAL"
81                                               
82        let fcvcount=0
83        for fcv in $FCTEMPS
84        do
85                if ! echo $fcv | egrep -q '='
86                then
87                        echo "Error in configuration file:"
88                        echo "FCTEMPS value is improperly formatted"
89                        exit 1
90                fi
91
92                AFCPWM[$fcvcount]=`echo $fcv |cut -d'=' -f1`
93                AFCTEMP[$fcvcount]=`echo $fcv |cut -d'=' -f2`
94                AFCFAN[$fcvcount]=`echo $FCFANS |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
95                AFCMINTEMP[$fcvcount]=`echo $MINTEMP |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
96                AFCMAXTEMP[$fcvcount]=`echo $MAXTEMP |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
97                AFCMINSTART[$fcvcount]=`echo $MINSTART |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
98                AFCMINSTOP[$fcvcount]=`echo $MINSTOP |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
99                AFCMINPWM[$fcvcount]=`echo $MINPWM |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
100                [ -z "${AFCMINPWM[$fcvcount]}" ] && AFCMINPWM[$fcvcount]=0
101                AFCMAXPWM[$fcvcount]=`echo $MAXPWM |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
102                [ -z "${AFCMAXPWM[$fcvcount]}" ] && AFCMAXPWM[$fcvcount]=255
103
104                # verify the validity of the settings
105                if [ "${AFCMINTEMP[$fcvcount]}" -ge "${AFCMAXTEMP[$fcvcount]}" ]
106                then
107                        echo "Error in configuration file (${AFCPWM[$fcvcount]}):"
108                        echo "MINTEMP must be less than MAXTEMP"
109                        exit 1
110                fi
111                if [ "${AFCMAXPWM[$fcvcount]}" -gt 255 ]
112                then
113                        echo "Error in configuration file (${AFCPWM[$fcvcount]}):"
114                        echo "MAXPWM must be at most 255"
115                        exit 1
116                fi
117                if [ "${AFCMINSTOP[$fcvcount]}" -ge "${AFCMAXPWM[$fcvcount]}" ]
118                then
119                        echo "Error in configuration file (${AFCPWM[$fcvcount]}):"
120                        echo "MINSTOP must be less than MAXPWM"
121                        exit 1
122                fi
123                if [ "${AFCMINSTOP[$fcvcount]}" -lt "${AFCMINPWM[$fcvcount]}" ]
124                then
125                        echo "Error in configuration file (${AFCPWM[$fcvcount]}):"
126                        echo "MINSTOP must be greater than or equal to MINPWM"
127                        exit 1
128                fi
129                if [ "${AFCMINPWM[$fcvcount]}" -lt 0 ]
130                then
131                        echo "Error in configuration file (${AFCPWM[$fcvcount]}):"
132                        echo "MINPWM must be at least 0"
133                        exit 1
134                fi
135
136                echo
137                echo "Settings for ${AFCPWM[$fcvcount]}:"
138                echo "  Depends on ${AFCTEMP[$fcvcount]}"
139                echo "  Controls ${AFCFAN[$fcvcount]}"
140                echo "  MINTEMP=${AFCMINTEMP[$fcvcount]}"
141                echo "  MAXTEMP=${AFCMAXTEMP[$fcvcount]}"
142                echo "  MINSTART=${AFCMINSTART[$fcvcount]}"
143                echo "  MINSTOP=${AFCMINSTOP[$fcvcount]}"
144                echo "  MINPWM=${AFCMINPWM[$fcvcount]}"
145                echo "  MAXPWM=${AFCMAXPWM[$fcvcount]}"
146                let fcvcount=fcvcount+1
147        done
148        echo
149}
150
151if [ -f "$1" ]
152then
153        LoadConfig $1
154else
155        LoadConfig /etc/fancontrol
156fi
157
158DIR=/proc/sys/dev/sensors
159if [ ! -d $DIR ]
160then
161        # For Linux 2.6, detect if config file uses the hwmon class or not yet
162        if echo "${AFCPWM[0]}" | egrep -q '^hwmon[0-9]'
163        then
164                SDIR=/sys/class/hwmon
165        else
166                SDIR=/sys/bus/i2c/devices
167        fi
168
169        if [ ! -d $SDIR ]
170        then
171                echo $0: 'No sensors found! (did you load the necessary modules?)'
172                exit 1
173        else
174                SYSFS=1
175                DIR=$SDIR
176        fi     
177fi
178cd $DIR
179
180# $1 = pwm file name
181function pwmdisable()
182{
183        if [ -n "$SYSFS" ]
184        then
185                ENABLE=${1}_enable
186                # No enable file? Just set to max
187                if [ ! -f $ENABLE ]
188                then
189                        echo $MAX > $1
190                        return 0
191                fi
192
193                # Try pwmN_enable=0
194                echo 0 > $ENABLE 2> /dev/null
195                if [ `cat $ENABLE` -eq 0 ]
196                then
197                        # Success
198                        return 0
199                fi
200
201                # It didn't work, try pwmN_enable=1 pwmN=255
202                echo 1 > $ENABLE 2> /dev/null
203                echo $MAX > $1
204                if [ `cat $ENABLE` -eq 1 -a `cat $1` -ge 190 ]
205                then
206                        # Success
207                        return 0
208                fi
209
210                # Nothing worked
211                echo "$ENABLE stuck to" `cat $ENABLE` >&2
212                return 1
213        else
214                echo $MAX 0 > $1
215        fi
216}
217
218# $1 = pwm file name
219function pwmenable()
220{
221        if [ "$SYSFS" = "1" ]
222        then
223                ENABLE=${1}_enable
224                if [ -f $ENABLE ]
225                then
226                        echo 1 > $ENABLE 2> /dev/null
227                        if [ $? -ne 0 ]
228                        then
229                                return 1
230                        fi
231                fi
232                echo $MAX > $1
233        else
234                echo $MAX 1 > $1
235        fi
236}
237
238function restorefans()
239{
240        local status=$1
241        echo 'Aborting, restoring fans...'
242        let fcvcount=0
243        while (( $fcvcount < ${#AFCPWM[@]} )) # go through all pwm outputs
244        do
245                pwmo=${AFCPWM[$fcvcount]}
246                pwmdisable $pwmo
247                let fcvcount=$fcvcount+1
248        done
249        echo 'Verify fans have returned to full speed'
250        exit $status
251}
252
253trap 'restorefans 0' SIGQUIT SIGTERM
254trap 'restorefans 1' SIGHUP SIGINT
255
256# main function
257function UpdateFanSpeeds {
258        let fcvcount=0
259        while (( $fcvcount < ${#AFCPWM[@]} )) # go through all pwm outputs
260        do
261                #hopefully shorter vars will improve readability:
262                pwmo=${AFCPWM[$fcvcount]}
263                tsens=${AFCTEMP[$fcvcount]}
264                fan=${AFCFAN[$fcvcount]}
265                mint=${AFCMINTEMP[$fcvcount]}
266                maxt=${AFCMAXTEMP[$fcvcount]}
267                minsa=${AFCMINSTART[$fcvcount]}
268                minso=${AFCMINSTOP[$fcvcount]}
269                minpwm=${AFCMINPWM[$fcvcount]}
270                maxpwm=${AFCMAXPWM[$fcvcount]}
271               
272                read tval < ${tsens}
273                if [ $? -ne 0 ]
274                then
275                        echo "Error reading temperature from $DIR/$tsens"
276                        restorefans 1
277                fi
278                if [ "$SYSFS" = "1" ]
279                then
280                        let tval="($tval+500)/1000"
281                else
282                        tval=`echo ${tval} | cut -d' ' -f3 | cut -d'.' -f1`
283                fi
284
285                read pwmpval < ${pwmo}
286                if [ $? -ne 0 ]
287                then
288                        echo "Error reading PWM value from $DIR/$pwmo"
289                        restorefans 1
290                fi
291                if [ "$SYSFS" != "1" ]
292                then
293                        pwmpval=`echo ${pwmpval} | cut -d' ' -f1`
294                fi
295               
296                # If fanspeed-sensor output shall be used, do it
297                if [[ -n ${fan} ]]
298                then
299                        read fanval < ${fan}
300                        if [ $? -ne 0 ]
301                        then
302                                echo "Error reading Fan value from $DIR/$fan"
303                                restorefans 1
304                        fi
305                        if [ "$SYSFS" != "1" ]
306                        then
307                                fanval=`echo ${fanval} | cut -d' ' -f2`
308                        fi
309                else
310                        fanval=1  # set it to a non zero value, so the rest of the script still works
311                fi
312               
313                # debug info
314                if [ "$DEBUG" != "" ]
315                then
316                        echo "pwmo=$pwmo"
317                        echo "tsens=$tsens"
318                        echo "fan=$fan"
319                        echo "mint=$mint"
320                        echo "maxt=$maxt"
321                        echo "minsa=$minsa"
322                        echo "minso=$minso"
323                        echo "minpwm=$minpwm"
324                        echo "maxpwm=$maxpwm"
325                        echo "tval=$tval"
326                        echo "pwmpval=$pwmpval"
327                        echo "fanval=$fanval"
328                fi
329               
330                if (( $tval <= $mint ))
331                  then pwmval=$minpwm # below min temp, use defined min pwm
332                elif (( $tval >= $maxt ))
333                  then pwmval=$maxpwm # over max temp, use defined max pwm
334                else
335                  # calculate the new value from temperature and settings
336                  pwmval="(${tval}-${mint})*(${maxpwm}-${minso})/(${maxt}-${mint})+${minso}"
337                  if [ $pwmpval -eq 0 -o $fanval -eq 0 ]
338                  then # if fan was stopped start it using a safe value
339                        echo $minsa > $pwmo
340                        # Sleep while still handling signals
341                        read < <(exec sleep 1)
342                  fi
343                fi
344                echo $pwmval > $pwmo # write new value to pwm output
345                if [ $? -ne 0 ]
346                then
347                        echo "Error writing PWM value to $DIR/$pwmo"
348                        restorefans 1
349                fi
350                if [ "$DEBUG" != "" ]
351                then
352                        echo "new pwmval=$pwmval"
353                fi
354                let fcvcount=$fcvcount+1
355        done
356}
357
358echo 'Enabling PWM on fans...'
359let fcvcount=0
360while (( $fcvcount < ${#AFCPWM[@]} )) # go through all pwm outputs
361do
362        pwmo=${AFCPWM[$fcvcount]}
363        pwmenable $pwmo
364        if [ $? -ne 0 ]
365        then
366                echo "Error enabling PWM on $DIR/$pwmo"
367                restorefans 1
368        fi
369        let fcvcount=$fcvcount+1
370done
371
372echo 'Starting automatic fan control...'
373
374# main loop calling the main function at specified intervals
375while true
376do
377        UpdateFanSpeeds
378        # Sleep while still handling signals
379        read < <(exec sleep $INTERVAL)
380done
Note: See TracBrowser for help on using the browser.