root/lm-sensors/trunk/prog/pwm/fancontrol.pl @ 3025

Revision 3025, 10.1 KB (checked in by khali, 8 years ago)

Strip useless whitespace before new line at end of string.

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
Line 
1#!/usr/bin/perl -wT
2# $Id$
3#
4# Perl script for temperature dependent fan speed control.
5#
6# Copyright 2004 dean takemori <deant@hawaii.rr.com>
7#
8# This is a reimplementation in perl of Marius Reiner's bash script for
9# fan speed control.  It has advantages in that it can daemonize itself
10# and needn't spawn subprocesses for grep, sleep etc.  Much of the structure
11# of the bash script is preserved to make mirroring changes easier, so
12# this is seriously non-idiomatic perl but at the same time it should not
13# be considered a a direct bash to perl translation.
14#
15# Usage: fancontrol [CONFIGFILE]
16#
17# For configuration instructions and warnings please see fancontrol.txt,
18# which can be found in the doc/ directory or at the website mentioned
19# elsewhere.
20#
21# This script is derived from Marius Reiner's bash version, so it is
22# hereby placed under the GPL.
23#
24#    Copyright 2003 Marius Reiner <marius.reiner@hdev.de>
25#
26#    This program is free software; you can redistribute it and/or modify
27#    it under the terms of the GNU General Public License as published by
28#    the Free Software Foundation; either version 2 of the License, or
29#    (at your option) any later version.
30#
31#    This program is distributed in the hope that it will be useful,
32#    but WITHOUT ANY WARRANTY; without even the implied warranty of
33#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
34#    GNU General Public License for more details.
35#
36#    You should have received a copy of the GNU General Public License
37#    along with this program; if not, write to the Free Software
38#    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
39#
40
41use warnings;
42use strict;
43use IO::Handle;
44use Getopt::Std;
45use POSIX;
46
47$ENV{PATH} = "/bin:/usr/bin";
48
49##### Configuration #####
50use constant DEBUG => 1;
51use constant MAX   => 255;
52
53use constant PIDFILE  => '/var/run/fancontrol.pid';
54use constant CONFFILE => '/etc/fancontrol';
55use constant LOGFILE  => '/var/log/fancontrol/fancontrol.log';
56use constant ERRFILE  => '/var/log/fancontrol/fancontrol.err';
57
58use constant SDIR => '/sys/bus/i2c/devices';
59### End Configuration ###
60
61our $interval;
62our $pwmo;
63our @afcpwm;
64our @afctemp;
65our @afcfan;
66our @afcmaxtemp;
67our @afcmintemp;
68our @afcminstart;
69our @afcminstop;
70
71sub loadconfig($);
72sub pwmdisable($);
73sub pwmenable($);
74sub restorefans();
75sub calc(@);
76sub UpdateFanSpeeds();
77END { restorefans(); }
78
79our $opt_d;
80getopts('d');
81
82my $config = shift;
83if (defined($config))
84   { loadconfig($config); }
85else
86   { loadconfig(CONFFILE); }
87
88### Daemonize
89if ( defined($opt_d) && ($opt_d == 1) )
90   {
91     my $pid = fork;
92     POSIX::_exit(0) if $pid;
93
94     unless (defined($pid))
95       { die("Couldn't fork: $!"); }
96
97     open(*STDERR, '>', ERRFILE);
98     IO::Handle::autoflush(*STDERR);
99     open(*STDOUT, '>>', LOGFILE);
100     IO::Handle::autoflush(*STDOUT);
101
102     unless (POSIX::setsid())
103       { die("Couldn't open new session: $!"); }
104
105   }
106
107### Pidfile
108if (open(FILE, ">" . PIDFILE))
109   {
110     print(FILE "$$\n");
111     close(FILE);
112   }
113else
114   { print(PIDFILE . ": $!\n"); }
115
116
117### What kind of interface?
118our $sysfs = 0;
119our $dir = '/proc/sys/dev/sensors';
120if (!(-d $dir))
121   {
122     if (!(-d SDIR))
123       { die("No sensors found! (are the necessary modules loaded?) :
124$!\n"); }
125     else
126       {
127         $sysfs = 1;
128         $dir = SDIR;
129       }
130   }
131
132### Trap signals
133$SIG{TERM} = \&restorefans;
134$SIG{HUP}  = \&restorefans;
135$SIG{INT}  = \&restorefans;
136$SIG{QUIT} = \&restorefans;
137
138### Enable PWM
139print("Enabling PWM on fans...\n");
140my $fcvcount = 0;
141while ($fcvcount < $#afcpwm+1)
142   {
143     $pwmo = $afcpwm[$fcvcount];
144     unless (pwmenable($pwmo))
145       { die("Error enabling PWM on $dir/$pwmo : $!\n"); }
146     $fcvcount++;
147   }
148
149print("Starting automatic fan control...\n");
150
151while(1)
152   {
153     UpdateFanSpeeds();
154     sleep($interval);
155   }
156
1571;
158
159################################################################
160sub loadconfig($)
161{
162   my $file = shift;
163
164   print("Loading configuration from $file ...\n");
165
166   unless ( (-e $file) && (-r $file) )
167     { die("Unable to read config file $file: $!"); }
168
169   open(F, $file);
170
171   our ($interval, $fctemps, $fcfans, $mintemp, $maxtemp, $minstart, 
172$minstop);
173   while($_ = <F>)
174     {
175       if ($_ =~ /^\s+$/)                { next; }
176       elsif ($_ =~ /^INTERVAL=(.*)$/) { $interval = $1; next; }
177       elsif ($_ =~ /^FCTEMPS=(.*)$/)  { $fctemps = $1;  next; }
178       elsif ($_ =~ /^FCFANS=(.*)$/)   { $fcfans = $1;   next; }
179       elsif ($_ =~ /^MINTEMP=(.*)$/)  { $mintemp = $1;  next; }
180       elsif ($_ =~ /^MAXTEMP=(.*)$/)  { $maxtemp = $1;  next; }
181       elsif ($_ =~ /^MINSTART=(.*)$/) { $minstart = $1; next; }
182       elsif ($_ =~ /^MINSTOP=(.*)$/)  { $minstop = $1;  next; }
183     }
184   close(F);
185
186   unless (defined($interval))
187     { die("Some settings missing ..."); }
188
189   print("\nCommon settings:\n");
190   print("  INTERVAL=$interval\n");
191
192   my $fcvcount = 0;
193   foreach my $fcv (split(/\s+/, $fctemps))
194     {
195       ($afcpwm[$fcvcount], $afctemp[$fcvcount]) = split(/=/, $fcv);
196
197       $fcfans   =~ s/^\S*=(\S+)\s*//;  $afcfan[$fcvcount]      = $1;
198       $mintemp  =~ s/^\S*=(\S+)\s*//;  $afcmintemp[$fcvcount]  = $1;
199       $maxtemp  =~ s/^\S*=(\S+)\s*//;  $afcmaxtemp[$fcvcount]  = $1;
200       $minstart =~ s/^\S*=(\S+)\s*//;  $afcminstart[$fcvcount] = $1;
201       $minstop  =~ s/^\S*=(\S+)\s*//;  $afcminstop[$fcvcount]  = $1;
202
203       print("\nSettings for $afcpwm[$fcvcount]:\n");
204       print("  Depends on $afctemp[$fcvcount]\n");
205       print("  Controls $afcfan[$fcvcount]\n");
206       print("  MINTEMP  = $afcmintemp[$fcvcount]\n");
207       print("  MAXTEMP  = $afcmaxtemp[$fcvcount]\n");
208       print("  MINSTART = $afcminstart[$fcvcount]\n");
209       print("  MINSTOP  = $afcminstop[$fcvcount]\n");
210
211       $fcvcount++;
212     }
213}
214
215
216################################################################
217sub pwmdisable($)
218{
219   my $p = shift;
220
221   if ($sysfs == 1)
222     {
223       if (open(F, ">$dir/$p"))
224         {
225           print(F MAX . '\n');
226           close(F);
227         }
228       else
229         { die("$dir/$p : $!"); }
230
231       my $enable = "$dir/$p/pwm/pwm_enable";
232       if (-f $enable)
233         {
234           if (open(F, ">$enable"))
235             {
236               print(F '0');
237               close(F);
238             }
239           else
240             { die("$dir/$p/pwm/pwm_enable : $!"); }
241         }
242     }
243   else
244     {
245       if (open(F, ">$dir/$p"))
246         {
247           print(F MAX . ' 0');
248           close(F);
249         }
250       else
251         { die("$dir/$p : $!"); }
252     }
253   return(1);
254}
255
256
257#################################################################
258sub pwmenable($)
259{
260   my $p = shift;
261
262   if ($sysfs == 1)
263     {
264       my $enable = "$dir/$p/pwm/pwm_enable";
265       if (-f $enable)
266         {
267           if (open(F, ">$enable"))
268             {
269               print(F "1\n");
270               close(F);
271             }
272           else
273             { die("$dir/$p : $!\n"); }
274         }
275     }
276   else
277     {
278       if (open(F, ">$dir/$p"))
279         {
280           print(F MAX . " 1\n");
281           close(F);
282         }
283       else
284         { die("$dir/$p : $!\n"); }
285     }
286   return(1);
287}
288
289
290################################################################
291sub restorefans()
292{
293   $SIG{TERM} = 'IGNORE';
294   $SIG{HUP}  = 'IGNORE';
295   $SIG{INT}  = 'IGNORE';
296   $SIG{QUIT} = 'IGNORE';
297
298   print("Aborting, restoring fans...\n");
299   my $fcvcount = 0;
300
301   while ( $fcvcount < $#afcpwm+1)
302     {
303       my $pwmo = $afcpwm[$fcvcount];
304       &pwmdisable($afcpwm[$fcvcount]);
305       $fcvcount++;
306     }
307   print("Verify fans have returned to full speed\n");
308   POSIX:_exit(-1);
309}
310
311
312############################################################
313sub UpdateFanSpeeds()
314{
315   my $fcvcount = 0;
316
317   while ($fcvcount < $#afcpwm+1)
318     {
319       my $pwmo  = $afcpwm[$fcvcount];
320       my $tsens = $afctemp[$fcvcount];
321       my $fan   = $afcfan[$fcvcount];
322       my $mint  = $afcmintemp[$fcvcount];
323       my $maxt  = $afcmaxtemp[$fcvcount];
324       my $minsa = $afcminstart[$fcvcount];
325       my $minso = $afcminstop[$fcvcount];
326
327       ### tval
328       my $tval = 0;
329       if (open(F, "$dir/$tsens"))
330         {
331           $tval = <F>;
332           close(F);
333         }
334       else
335         { die("Error reading temperature from $dir/$tsens"); }
336       $tval =~ /([.\d]+)\s*$/;
337       $tval = int($1);
338       if ($sysfs == 1)
339         { $tval /= 1000; }
340
341       ### pwmpval
342       my $pwmpval = 0;
343       if (open(F, "$dir/$pwmo"))
344         {
345           $pwmpval = <F>;
346           close(F);
347         }
348       else
349         { die("Error reading PWM value from $dir/$pwmo"); }
350       ($pwmpval) = split(/\s/, $pwmpval);
351
352       ### fanval
353       my $fanval = 0;
354       if (open(F, "$dir/$fan"))
355         {
356           $fanval = <F>;
357           close(F);
358         }
359       else
360         { die("Error reading Fan value from $dir/$fan"); }
361       $fanval =~ /(\d+)\s$/;
362       $fanval = $1;
363
364       ### DEBUG
365       if (DEBUG == 1)
366         {
367           print("pwmo=$pwmo\n");
368           print("tsens=$tsens\n");
369           print("fan=$fan\n");
370           print("mint=$mint\n");
371           print("maxt=$maxt\n");
372           print("minsa=$minsa\n");
373           print("minso=$minso\n");
374           print("tval=$tval\n");
375           print("pwmpval=$pwmpval\n");
376           print("fanval=$fanval\n");
377           print("\n");
378         }
379
380       my $pwmval;
381       if ($tval <= $mint)
382         { $pwmval = 0; }
383       elsif ($tval >= $maxt)
384         { $pwmval = MAX; }
385       else
386         {
387           $pwmval = eval ( ($tval - $mint) / ($maxt - $mint) )**2 ;
388           $pwmval *= (255 - $minso);
389           $pwmval += $minso;
390           $pwmval = int($pwmval);
391           if ( ($pwmval == 0) || ($fanval == 0) )
392             {
393               if (open(F, ">$dir/$pwmo"))
394                 {
395                   print(F "$minsa\n");
396                   close(F);
397                 }
398               else
399                 { die("Error writing PWM value to $dir/$pwmo : $!\n"); }
400               sleep 1;
401             }
402         }
403
404       if (open(F, ">$dir/$pwmo"))
405         {
406           print(F "$pwmval\n");
407           close(F);
408         }
409       else
410         { die("Error writing PWM value to $dir/$pwmo : $!\n"); }
411
412       if (DEBUG == 1)
413         { print("new pwmval = $pwmval\n"); }
414
415       $fcvcount++;
416     }
417
418}
419
4201;
421
422
Note: See TracBrowser for help on using the browser.