#!/usr/bin/perl -w
# Toshiba Magnia SG20 controller v1.1 (lcd, buttons, fans)
# depends on: hw.o, stty, cat, perl(strict, Fcntl)
# (c) 2005-09-21, ariel/KotCzarny (szary (at) mail-mrrau-hyperreal-info)
# (hint for mail address: s/-/./g)
# (hint for hw.o: (works only for 2.4.x kernels though)
#   insmod -f hw.o; mknod /dev/hw c 126 0
# )
# (hint for shutdown: add this line:
#   echo -en "\x1b2q Power OFF\n" >/dev/ttyS0
# )

use strict;
use Fcntl;

my $delay=5;		# update this often (in seconds)
my $temp_hist_on=59;	# temp. to turn fans ON
my $temp_hist_off=40;	# temmp. to turn fans OFF
my $fan_ctrl_cpu=1;	# if negative, don't change CPU fan status
my $fan_ctrl_sys=-1;	# if negative, don't change SYS fan status
my $blight_timeout=600;	# if negative, don't turn OFF the backlight, timeout is blight seconds
my $net_dev="eth1";	# net device to monitor activity


my @days=("Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su");
my @months=("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec");

# --- configuration ends here ---

my $l1="l1"; my $l2="l2";
my $disp_mode=0; my @disp_modes=("General display", "Character table");
my $mode_shutdown=0; my $bank=0; my $tick=0;
my $ts=time; my $ots=0; my $dts=0;
my $blight=$blight_timeout;

`stty -F /dev/ttyS0 9600 cs8 cread -icanon -echo raw -crtscts`;
sysopen(F1, "/dev/hw", O_RDWR);
sysopen(F2, "/dev/ttyS0", O_RDWR);

sub u { u1(); u2(); }
sub u1 { syswrite F2, "\033H$l1"; }
sub u2 { syswrite F2, "\033H\n$l2"; }

sub pad { my $tmp=substr($_[0],0,16); $tmp.=substr("                ",0,16-length($tmp)); return $tmp; }
sub p { my $x=$_[1]; my $y=$_[2]; my $tmp="\033H"; my $i=0;
 if($y>0) { $tmp.="\n"; }
 if($x>=0) { for(; $i<$x; $i++) { $tmp.="\033M"; } }
 $tmp.=substr($_[0],0,16); $l2=$tmp;
}

sub fan { # fan(c1,c2,command): c1 cpu, c2 sys, command -1 off 0 don't change 1 on
 my $c1=$_[0]; my $c2=$_[1];
 if($fan_ctrl_cpu==1)
  { if($c1==0){ syswrite F1, "fan.cpu.off"; } elsif($c1==1){ syswrite F1, "fan.cpu.on"; } }
 if($fan_ctrl_sys==1)
  { if($c2==0){ syswrite F1, "fan.sys.off"; } elsif($c2==1){ syswrite F1, "fan.sys.on"; } }
}

sub backlight { # backlight(command): command 0 off 1 on
 my $c1=$_[0]; if($c1==0){ syswrite F2, "\x1bF"; } elsif($c1==1){ syswrite F2, "\x1bb"; }
}

sub makeclock {
 my $sec; my $min; my $hour; my $mday; my $mon; my $year; my $wday; my $yday; my $isdst; my $tmp;
 ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
 # $tmp=sprintf("\033H%s %s %2d %02d:%02d", $days[$wday], $months[$mon], $mday, $hour, $min);
 #$tmp=sprintf("%02d:%02d:%02d", $hour, $min, $sec);
 if($tick) { $tmp=sprintf(chr(205)."%02d:%02d", $hour, $min); }
 else      { $tmp=sprintf(" %02d:%02d", $hour, $min); }
 return $tmp;
}

sub max { if ($_[0] > $_[1]) { return $_[0]; } else { return $_[1]; } }

$l1="\x1bXMagnia-SG20 Ctrl";  $l2=chr(207)."ariel/KotCzarny"; u(); backlight(1);

my $nfound; my $rin = ""; vec($rin,fileno(F2),1) = 1; my $rout;
my $i=0; my $button=""; my @data; my @t1; my @t2; my @load; my @mem; my @fan1; my @fan2;
my @net; my $net_rx; my $net_tx; my $nnet_rx=0; my $nnet_tx=0; my $onet_rx; my $onet_tx;

while (1){ $tick++; $tick %= 2;
 if($nfound = select($rout=$rin, "", "", $delay))
 {
  if(sysread(F2, $button, 1))
  {

   # select button pressed
if($blight!=0)
{
   if($button eq "S") {
    if($mode_shutdown>0) { $l2=pad(""); u2(); $mode_shutdown=0; }
    else { $disp_mode++; $disp_mode %= @disp_modes; $l2=pad($disp_modes[$disp_mode]); u2(); }
   }

   # power button pressed
   if($button eq "A")
   {
    if($disp_mode=="0") {
     if($mode_shutdown==0) { $l1="Press [POWER] to"; $l2="confirm shutdown"; $mode_shutdown++; u(); }
     else { $l1="    SHUTDOWN    "; $l2="  in progress!  "; u(); `poweroff`; }
    }
    elsif($disp_mode=="1") {
     $bank++; if($bank>15) { $bank=0; }
     $l2=""; for($i=0;$i<16;$i++){ $l2.=chr($bank*16+$i); } u2();
    }
   }
}
$blight=$blight_timeout; backlight(1);

  }
 }

if($mode_shutdown==0)
{
 if ($blight>0) { $blight-=$delay; if($blight<=0) { $blight=0; backlight(0); } }
 $ots=$ts; $ts=time; $dts=$ts-$ots;


 @load=`cat /proc/loadavg`; $load[0] =~ s/ .*\n//;
 $l1=sprintf("\033H%d%s %s", $disp_mode, makeclock(), $load[0]);

 if($disp_mode=="0") {
  syswrite F1, "poll"; @data=`cat /dev/hw`;
  @t1=grep(/temp.cpu/, @data); $t1[0] =~ s/.*=//; chop($t1[0]);
  @t2=grep(/temp.sys/, @data); $t2[0] =~ s/.*=//; chop($t2[0]);

  @fan1=grep(/fan.cpu.rpm/, @data); $fan1[0] =~ s/.*=//; chop($fan1[0]);
  if($fan1[0]==99999) { $fan1[1]=chr(183); } else { $fan1[1]=sprintf("%1.0f", $fan1[0]/1000); }
  @fan2=grep(/fan.sys.rpm/, @data); $fan2[0] =~ s/.*=//; chop($fan2[0]);
  if($fan2[0]==99999) { $fan2[1]=chr(183); } else { $fan2[1]=sprintf("%1.0f", $fan2[0]/1000); }
  if($t1[0]>=$temp_hist_on && ($fan1[0]==99999 || $fan2[0]==99999)) { fan(1,1); }
  if($t1[0]<=$temp_hist_off
   && ($fan1[0]<99999 && $fan1[0]>0)
   && ($fan2[0]<99999 && $fan2[0]>0)
  ) { fan(0,0); }

  #@mem=`cat /proc/meminfo`; @mem=grep(/^Mem:/, @mem); $mem[0] =~ s/.*=//;

  @net=`cat /proc/net/dev`; @net=grep(/$net_dev/, @net); $net[0] =~ s/ *$net_dev: *//;
  @net=split(/\s+/, $net[0]);
  $onet_rx=$nnet_rx; $onet_tx=$nnet_tx;
  $nnet_rx=$net[0]; $nnet_tx=$net[8];
  $net_rx=sprintf("%3.1f", ($nnet_rx-$onet_rx)/max($dts,0.00000001)/1024*0.95 ); # 0.95
  $net_tx=sprintf("%3.1f", ($nnet_tx-$onet_tx)/max($dts,0.00000001)/1024*0.95 ); # for tcp overhead
  #print "$dts [$onet_rx | $onet_tx] [$nnet_rx | $nnet_tx] [$net_rx | $net_tx]\n";

  $l2=substr(pad("$fan1[1]$fan2[1] ".chr(198)."$net_rx".chr(197)."$net_tx"),0,12)." $t2[0]".chr(178)." ";
  u2(); # print "$l2\n";

  $l1.=" $t1[0]".chr(178)."   ";
  
 }
 elsif($disp_mode=="1") { $l1.=" ".($bank*16)."   "; }
 u1();
} #if $mode_shutdown==0

}
