#!/usr/bin/perl
#
# Programme d'affichage LCD sur 2 lignes x 20 caracteres  
# 
# This code is distributed under the terms of the GPL
#
# (c) 2003 Fisch Bob (bob@fesch.lu)
# http://www.fesch.lu
#
# Version 0.2 
# Designed initially for a CFAH2004AYYBJP 20x4 display
#

use strict;
use Fcntl;
use IO::Socket::INET;

#/\/\/\/\/\/\/\/\/\/\/\/\/\
# 
#  Config
#
#  NE PAS METTRE LE REFRESH
#  A MOINS DE 2 SI LE LCD
#  AFFICHE UP/DL !!!
#
#\/\/\/\/\/\/\/\/\/\/\/\/\/

my $BASEPORT 	= 0x378;
my $ROWS 	= 4;
my $COLS	= 20;	
my $REFRESH	= 2;

my $UPBITS 	= 160;
my $DOWNBITS	= 512;

#/\/\/\/\/\/\/\/\/\/\/\/\/\
# 
#  LCD respond times
#
#  A MODIFIER EN FONTION DE
#  LA VITESSE DE RACTION DE
#  VOTRE LCD ET DE VOTRE CPU !!!
#
#  L'unit est le temps ncessaire
#  au processeur de faire le calcul
#  de 1+1*1, choisi arbitrairement
#  car PERL ne possde pas de fonction
#  sleep de l'ordre de grandeur "ns" !!!
#
#\/\/\/\/\/\/\/\/\/\/\/\/\/

my $MEMORY_TIME	= 1;
my $DATA_TIME 	= 1;
my $INSTRUCTION_TIME	= 2000;

#/\/\/\/\/\/\/\/\/\/\/\/\/\
# 
#  Catch signals
#
#\/\/\/\/\/\/\/\/\/\/\/\/\/

$SIG{INT} = \&catch_sig;
$SIG{HUP} = \&catch_sig;
$SIG{TERM} = \&catch_sig;
$SIG{QUIT} = \&catch_sig;

#/\/\/\/\/\/\/\/\/\/\/\/\/\
# 
#  Global variables
#
#\/\/\/\/\/\/\/\/\/\/\/\/\/

my $dl=0;
my $ul=0;
my $itWas=-1;
my $scroll = '';
my $ixui = '';
my $ixuiTS = -1;


#/\/\/\/\/\/\/\/\/\/\/\/\/\
# 
#  Constants
#
#\/\/\/\/\/\/\/\/\/\/\/\/\/

my $base_port = $BASEPORT;
my $status_port = $BASEPORT + 1;
my $control_port = $BASEPORT + 2;


##### E and RW must be inverted because are attached to control pin 0 and 1
##### that are logically inverted by parallel port
my $E_HIGH	= 0;
my $E_LOW	= 1;
my $RW_HIGH	= 0;
my $RW_LOW	= 2;
my $RS_HIGH	= 4;
my $RS_LOW	= 0;


my $CLEARDISPLAY 	= 0x01;

my $RETURNHOME	= 0x02;

my $ENTRYMODE		= 0x04;
my $INCREMENT		= 0x02;
my $DECREMENT		= 0x00;
my $SHIFT_ON		= 0x01;
my $SHIFT_OFF		= 0x00;

my $DISPLAY		= 0x08;
my $DISPLAY_ON	= 0x04;
my $DISPLAY_OFF	= 0x00;
my $CURSOR_ON		= 0x02;
my $CURSOR_OFF	= 0x00;
my $BLINK_ON		= 0x01;
my $BLINK_OFF		= 0x00;

my $SHIFTMODE		= 0x10;
my $DISPLAY_SELECT	= 0x08;
my $CURSOR_SELECT	= 0x00;
my $RIGHT		= 0x01;
my $LEFT		= 0x00;

my $FUNCTIONSET	= 0x21;
my $EIGHTBITMODE	= 0x10;
my $FOURBITMODE	= 0x00;
my $TWOLINES		= 0x08;
my $ONELINE		= 0x00;
my $FONT5X11		= 0x01;
my $FONT5X8		= 0x00;

my $SETCGRAMADDRESS        		= 0x40;
my $CGRAM_ADDRESS_MASK     		= 0x3f;

my $SETDDRAMADDRESS			= 0x80;
my $DDRAM_ADDRESS_MASK     		= 0x7f;

my $READ_BF_AND_ADDRESS  		= 0x100;
my $BF_MASK     			= 0x80;
my $ADDRESS_MASK     		= 0x7f;

my $WRITE_TO_RAM         		= 0x200;
my $WRITE_TO_RAM_ADDRESS_MASK    	= 0xff;

my $READ_FROM_RAM                	= 0x300;
my $READ_FROM_RAM_ADDRESS_MASK   	= 0xff;


my $SECONDLINEOFFSET = 0x40;

my @MOIS;
$MOIS[0]="Jan";
$MOIS[1]="Feb";
$MOIS[2]="Mar";
$MOIS[3]="Apr";
$MOIS[4]="May";
$MOIS[5]="Jun";
$MOIS[6]="Jul";
$MOIS[7]="Aug";
$MOIS[8]="Sep";
$MOIS[9]="Oct";
$MOIS[10]="Nov";
$MOIS[11]="Dec";

#/\/\/\/\/\/\/\/\/\/\/\/\/\
# 
#  Initialisation
#
#\/\/\/\/\/\/\/\/\/\/\/\/\/

&lcd_init_8bit;

##### user 0-4
&generate_bars; 
##### user 5-6
&generate_heart;

#/\/\/\/\/\/\/\/\/\/\/\/\/\
# 
#  Main 
#
#\/\/\/\/\/\/\/\/\/\/\/\/\/

#&set_instruction($CLEARDISPLAY);

&set_data_at(0,0,0);
&set_data_at(1,0,1);
&set_data_at(2,0,2);
&set_data_at(3,0,3);
&set_data_at(4,0,4);


 my $start = time();

 ##### possible function calls
 #
 # set_scroll(text);
 # set_ixui				<--  appeller une fois par cycle!
 #
 #####
 #
 # fet_ixui				<-- net pas utiliser en mme temps que "get_scroll"
 # get_system_load
 # get_cpu_idle
 # get_scroll
 # get_name
 # get_uptime
 # get_swap
 # get_disk(mount_number) 		<-- 1,2,3 ...
 # get_downupload 
 # get_ipconnected 
 # get_number_of_connexions
 # get_connected_machines
 # get_time
 #
 # set_bars(initial_line)  		<-- this is drawn ower two lines!
 #
 ##### ATTENTION
 #
 #  NE PAS UTILISER get_downupload et set_bars
 #  EN MME TEMPS !
 #
 #####

while(1)
{
 #&set_ixui;
 &write_string_at(0,0,&get_ipconnected );
 &write_string_at(0,1,&get_system_load);
 &set_bars(2);
 &write_string_at(19,3,chr(5));
 sleep(1);

 &write_string_at(0,1,&get_system_load);
 &write_string_at(19,3,chr(6));
 sleep(1);

# sleep($REFRESH);
}

#/\/\/\/\/\/\/\/\/\/\/\/\/\
# 
#  Catch data
#
#\/\/\/\/\/\/\/\/\/\/\/\/\/

sub set_ixui
{
 # get time
 my $itIs = time();

 if(($itIs-$ixuiTS)>30)
 {
  $ixuiTS=$itIs;

  my $peer = 'www.ixus.net';
  my $peerport = 80;
  my $sock;
  unless($sock = new IO::Socket::INET (PeerAddr => $peer, PeerPort => $peerport, Proto => 'tcp', Timeout => 5))
  {
   print 'could not connect to www.ixus.net';
   return 0;
  }
  my $GET_CMD;
  $GET_CMD  = "GET http://www.ixus.net/ixui.html HTTP/1.1\r\n";
  $GET_CMD .= "Host: www.ixus.net\r\n";
  $GET_CMD .= "Cache-Control: no-cache\r\n";
  $GET_CMD .= "Connection: close\r\n\r\n";
  print $sock "$GET_CMD";
  my $ret = '';
  while (<$sock>) 
  {
   $ret .= $_; 
  }
  close($sock);
  my @lines = explode("\n",$ret);
  @lines = explode('<br>',$lines[10]);
  # 1 => time
  # 3 => title
  # 4 => forum
  # 5 => user
  my $title = $lines[1].': '.$lines[3].' ';
  if($ixui ne $title)
  {
   $ixui=$title;
   &set_scroll($ixui);
  }
 }
}

sub get_ixui
{
 return &get_scroll;
}

sub set_scroll
{
 $scroll = shift;
 while(length($scroll)<20)
 {
  $scroll.=' ';
 }
}

sub get_scroll
{
 my $title = substr($scroll,0,20);
 $scroll=substr($scroll,1,length($scroll)).substr($scroll,0,1);
 return $title;
}

sub get_connected_machines
{
 # affiche le nombre de machines accdantes 
 # internet via IpCOP (ou autre?). 
 # ATTENTION: Si une machine s'teind, son adresse
 # MAC reste encore un certain temps dans le cache,
 # donc la valeur n'est pas toujours tout  fait 
 # jour. Ce n'est qu'une indication!

 my $name = `arp -a|wc -l`;
 chop($name);
 my $title = sprintf("%-10s%10s","Online",$name);
 return "$title ";
}

sub get_name
{
 # by oxy750

 my $name = `/bin/uname -snr`;
 chop($name);
 return "$name";
}

sub get_uptime
{
 # by oxy750

 my ($title,$uptime,$time,$days,$other,$hours,$users,$ld);
 $uptime = `/usr/bin/uptime`;
 ($time,$other)=split(/,/,$uptime);
 ($other,$time,$other,$days,$other,$hours)=split(/ +/,$time);
 if ($hours eq "") 
 {
  $hours = $days;
  $days = 0;
 }
 my ($h,$m)=split(/:/,$hours);
 $title=sprintf("Uptime %3dd %02d:%02d:00",$days,$h,$m);
 return $title;
}

sub get_cpu_idle
{
 my($swp,$title,$total,$used,$free);
 $swp=`top -n 1 | head -n 3 | tail -n 1`;
 chop($swp);
 my @some=split(/ /,$swp);
 my $title=sprintf("%-12s%8s","CPU idle",$some[13]);
 return $title;
}

sub get_system_load
{
 my($swp,$title,$total,$used,$free);
 $swp=`/usr/bin/uptime`;
 chop($swp);
 my @some=split(/average/,$swp);
 #print $some[1]." -- ".substr($some[1],2,16)."\n";
 @some=split(/ /,substr($some[1],2,16));
 #substr($some[13].$some[14].$some[15],0,14)
 my $title=sprintf("%-6s%14s","Load",substr($some[0].$some[1].$some[2],0,14));
 return $title;
}


sub get_swap
{
 # by oxy750

 my($swp,$title,$total,$used,$free);
 $swp=`/usr/bin/free | tail -n 1`;
 chop($swp);
 my($title,$total,$used,$free)=split(/ +/,$swp);
 my $sizefree=sprintf("%.1fMo",$free/1024);
 my $pourcentuse=sprintf("%3d%%",int($used*100/$total));
 $title=sprintf("%-9s%4s %6s","Swap",$pourcentuse,$sizefree);

 return $title;
}

sub get_disk
{
 # by oxy750

 my ($fs,$size,$used,$avail,$pourcentuse,$mount);
 my $numdisk = shift;
 $numdisk++;
 my $disk=`/bin/df -h | head -n $numdisk | tail -n 1`;
 chop($disk);
 ($fs,$size,$used,$avail,$pourcentuse,$mount)=split(/ +/,$disk);
 $avail.="o";
 my $title=sprintf("%-9s%4s %6s",$mount,$pourcentuse,$avail);
 return $title;
}

sub set_bars 
{
 my $startLine = shift;
 
 my ($title);
 my ($DspeedByte,$DspeedBits,$DspeedKBits);
 my ($UspeedByte,$UspeedBits,$UspeedKBits);

 # get RX
 my $data = `ifconfig ppp0 | head -n 7 | tail -n 1`;
 $data = substr($data,19);
 my @pieces = split(/ /,$data);
 my $ds = $pieces[0];
 my $us = substr($pieces[5],6);

 # get time
 my $itIs = time();

 if($itWas!=-1 && ($itIs-$itWas)>0)
 {
   # calculate download speed
   $DspeedByte = ($ds-$dl)/($itIs-$itWas);
   $DspeedBits = int($DspeedByte * 8); 
   $DspeedKBits = ($DspeedBits / 1024);

   # calculate upload speed
   $UspeedByte = ($us-$ul)/($itIs-$itWas);
   $UspeedBits = int($UspeedByte * 8); 
   $UspeedKBits = ($UspeedBits / 1024);
 }

 my $UP=$UspeedKBits;
 my $DL=$DspeedKBits;

 my $UPs = "UP ";
 my $DLs = "DL ";

 $UP=($UP/$UPBITS)*(($COLS-3)*5);
 $DL=($DL/$DOWNBITS)*(($COLS-3)*5);
 
 $UP=sprintf("%i",$UP);
 $DL=sprintf("%i",$DL);

 my $ganzUP = sprintf("%i",$UP/5);
 my $ganzDL = sprintf("%i",$DL/5);

 #print "Casen: $ganzDL\n";

 for(my $i=0;$i<$ganzUP;$i++) {$UPs.=chr(4);}
 for(my $i=0;$i<$ganzDL;$i++) {$DLs.=chr(4);}

 $UPs.=chr($UP % 5);
 $DLs.=chr($DL % 5);

 while(length($UPs)<$COLS) {$UPs.=' ';}
 while(length($DLs)<$COLS) {$DLs.=' ';}

 $UPs=substr($UPs,0,$COLS-1);
 $DLs=substr($DLs,0,$COLS-1);

 &write_string_at(0,$startLine,$UPs);
 &write_string_at(0,$startLine+1,$DLs);

 $dl=$ds;
 $ul=$us;
 $itWas=$itIs;
}


sub get_downupload 
{
 # by oxy750
 # Calcul de la vitesse de UP et DL bas
 # sur speedDeamon de Fesch

 # remodified by myself ...

 my ($title);
 my ($DspeedByte,$DspeedBits,$DspeedKBits);
 my ($UspeedByte,$UspeedBits,$UspeedKBits);

 # get RX
 my $data = `ifconfig ppp0 | head -n 7 | tail -n 1`;
 $data = substr($data,19);
 my @pieces = split(/ /,$data);
 my $ds = $pieces[0];
 my $us = substr($pieces[5],6);

 # get time
 my $itIs = time();

 if($itWas!=-1 && ($itIs-$itWas)>0)
 {
   # calculate download speed
   $DspeedByte = ($ds-$dl)/($itIs-$itWas);
   $DspeedBits = int($DspeedByte * 1); # on laisse en octet
   $DspeedKBits = ($DspeedBits / 1024);

   # calculate upload speed
   $UspeedByte = ($us-$ul)/($itIs-$itWas);
   $UspeedBits = int($UspeedByte * 1); # on laisse en octet
   $UspeedKBits = ($UspeedBits / 1024);
 }

 $dl=$ds;
 $ul=$us;
 $itWas=$itIs;

 my $UP=0;
 my $DL=0;

 if($UspeedKBits<10) {$UP=sprintf("%.1f",$UspeedKBits);}
 else {$UP=sprintf("%i",$UspeedKBits);}

 if($DspeedKBits<10) {$DL=sprintf("%.1f",$DspeedKBits);}
 else {$DL=sprintf("%i",$DspeedKBits);}

 $title=sprintf("UP:%4s DL:%4s KB/s",$UP,$DL);
 return $title;
}

sub get_ipconnected 
{
 # by oxy750
 
 my $data = `ifconfig ppp0 | grep -i "inet addr"`;
 my($other,$inet,$addr,$ptp,$mask)=split(/ +/,$data);
 my($other,$ip)=split(/:/,$addr);
 my $title=sprintf("IP %17s",$ip);
 return "$title";
}

sub get_number_of_connexions
{
 # by oxy750

 # doesn't wark aat my IpCOP :(

 my ($sec,$min,$heure,$mjour,$mois,$annee,$sjour,$ajour,$isdst)=localtime(time);
 my $datelog=sprintf("%s %2s",$MOIS[$mois],$mjour);
 my $UP=`grep -i "$datelog" /var/log/messages | grep "up on ppp0" | wc -l`;
 chop($UP);
 my $DW=`grep -i "$datelog" /var/log/messages | grep "down on ppp0" | wc -l`;
 chop($DW);
 my $title=sprintf("ppp0 UP:%3d DOWN:%3d",$UP,$DW);
 return "$title";
}

sub get_time 
{
 # by oxy750

 my ($sec,$min,$heure,$mjour,$mois,$annee,$sjour,$ajour,$isdst)=localtime(time);
 $mois++;
 $annee += 1900;
 my $title=sprintf("%02d/%02d/%4d  %02d:%02d:%02d",$mjour,$mois,$annee,$heure,$min,$sec);
 return $title;
}


#/\/\/\/\/\/\/\/\/\/\/\/\/\
# 
#  Functions
#
#\/\/\/\/\/\/\/\/\/\/\/\/\/

sub generate_heart
{
 my $c = 5;

 &set_instruction($SETDDRAMADDRESS + $c);

 &set_instruction($SETCGRAMADDRESS + $c*8 + 0);
 &mem(0x08 | 0x02);
 &set_instruction($SETCGRAMADDRESS + $c*8 + 1);
 &mem(0x10 | 0x04 | 0x01);
 &set_instruction($SETCGRAMADDRESS + $c*8 + 2);
 &mem(0x10 | 0x04 | 0x01);
 &set_instruction($SETCGRAMADDRESS + $c*8 + 3);
 &mem(0x10 | 0x01);
 &set_instruction($SETCGRAMADDRESS + $c*8 + 4);
 &mem(0x10 | 0x01);
 &set_instruction($SETCGRAMADDRESS + $c*8 + 5);
 &mem(0x08 | 0x02);
 &set_instruction($SETCGRAMADDRESS + $c*8 + 6);
 &mem(0x08 | 0x02);
 &set_instruction($SETCGRAMADDRESS + $c*8 + 7);
 &mem(0x04);

 $c = 6;

 &set_instruction($SETDDRAMADDRESS + $c);

 &set_instruction($SETCGRAMADDRESS + $c*8 + 0);
 &mem(0x08 | 0x02);
 &set_instruction($SETCGRAMADDRESS + $c*8 + 1);
 &mem(0x10 | 0x08 | 0x04 | 0x02 | 0x01);
 &set_instruction($SETCGRAMADDRESS + $c*8 + 2);
 &mem(0x10 | 0x08 | 0x04 | 0x02 | 0x01);
 &set_instruction($SETCGRAMADDRESS + $c*8 + 3);
 &mem(0x10 | 0x08 | 0x04 | 0x02 | 0x01);
 &set_instruction($SETCGRAMADDRESS + $c*8 + 4);
 &mem(0x10 | 0x08 | 0x04 | 0x02 | 0x01);
 &set_instruction($SETCGRAMADDRESS + $c*8 + 5);
 &mem(0x08 | 0x04 | 0x02);
 &set_instruction($SETCGRAMADDRESS + $c*8 + 6);
 &mem(0x08 | 0x04 | 0x02);
 &set_instruction($SETCGRAMADDRESS + $c*8 + 7);
 &mem(0x04);

}

sub generate_bars
{
 for(my $c=0;$c <5;$c++)
 {
  &set_instruction($SETDDRAMADDRESS + $c);
 
  my $sim = 0;
  if($c==0) {$sim=0x10;}
  if($c==1) {$sim=0x18;}
  if($c==2) {$sim=0x1C;}
  if($c==3) {$sim=0x1E;}
  if($c==4) {$sim=0x1F;}
 
  for(my $l=0;$l<8;$l++)
  {
   &set_instruction($SETCGRAMADDRESS + $c*8 + $l);
   &mem($sim);
  }
 }
}

sub lcd_init_8bit
{
 &set_instruction($FUNCTIONSET | $EIGHTBITMODE);
 &set_instruction($FUNCTIONSET | $EIGHTBITMODE);
 &set_instruction($FUNCTIONSET | $EIGHTBITMODE);
 &set_instruction(
			$FUNCTIONSET | 
			$EIGHTBITMODE |  
			$TWOLINES | 
			$FONT5X8
			);
 ##### display off
 &set_instruction($DISPLAY | $DISPLAY_OFF);
 ##### display clear
 &set_instruction($CLEARDISPLAY);
 ##### entry mode
 &set_instruction(	$ENTRYMODE |
			$INCREMENT |
			$SHIFT_OFF
		);
 ##### end of initialization
 &set_instruction($RETURNHOME);
 ##### turn on display
 &set_instruction(	$DISPLAY | 
			$DISPLAY_ON |
			$CURSOR_OFF |
			$BLINK_OFF
		);
}

sub set_data_at
{
 my $offset = shift;
 my $line = shift;
 my $c = shift;

 my $lineIs = $line;

 if($line == 1) {$lineIs=1*$SECONDLINEOFFSET;}
 if($line == 2) {$lineIs=$COLS;}
 if($line == 3) {$lineIs=1*$SECONDLINEOFFSET + $COLS;}
 
 &set_instruction($SETDDRAMADDRESS + $offset + $lineIs);
 &set_data($c);
}

sub set_data
{
 my $data = shift;
 # print "Writing:\t$data => ".chr($data)."\n";
 write_byte($data,$base_port);
 write_byte($RS_HIGH | $RW_LOW | $E_HIGH,$control_port);
 mysleep($DATA_TIME);
 write_byte($RS_HIGH | $RW_LOW | $E_LOW,$control_port);
}

sub mem
{
 my $data = shift;
# if($data > 32) {print "Writing:\t$data => ".chr($data)."\n";}
# else {print "Writing:\t$data (<32)\n";}
 write_byte($data,$base_port);
 write_byte($RS_HIGH | $RW_LOW | $E_HIGH,$control_port);
 mysleep($MEMORY_TIME);
 write_byte($RS_HIGH | $RW_LOW | $E_LOW,$control_port);
}

sub set_instruction
{
 my $data = shift;
# if($data > 32) {print "Writing:\t$data => ".chr($data)."\n";}
# else {print "Writing:\t$data (<32)\n";}
 write_byte($data,$base_port);
 write_byte($RS_LOW | $RW_LOW | $E_HIGH,$control_port);
 mysleep($INSTRUCTION_TIME);
 write_byte($RS_LOW | $RW_LOW | $E_LOW,$control_port);
}

sub write_byte
{
 my $data = shift;
 my $show = chr($data);
 my $port = shift;

# open (PORT,">/dev/port");
# binmode (PORT);
# seek (PORT,$port,0)|| die "seek_err\n";
# print PORT $show ||die "write_err while writing $show\n";
# close (PORT);
#  | O_SYNC
 sysopen (PORT,"/dev/port",O_RDWR) || die "Datei: $!";
 binmode (PORT);
 sysseek (PORT,$port,0)|| die "seek_err\n";
 syswrite(PORT,$show)  || print "write_err while writing $data \n";
 close (PORT);
}

sub write_string
{
 my $str = shift;
 for(my $i=0;$i<length($str);$i++)
 {
  set_data(ord(substr($str,$i,1)));
 } 
}

sub write_string_at
{
 my $off = shift;
 my $line = shift;
 my $str = shift;

 #print "$str\n";

 for(my $i=0;$i<length($str);$i++)
 {
  set_data_at($off+$i,$line,ord(substr($str,$i,1)));
 } 
}

sub mysleep
{
 my $where = shift;
 my $some = 0;
 for(my $i=0;$i<$where;$i++)
 {
  $some=1+1*1;
 }
}

#/\/\/\/\/\/\/\/\/\/\/\/\/\
# 
#  General functions
#
#\/\/\/\/\/\/\/\/\/\/\/\/\/

sub catch_sig
{
 print "Shutdown ...\n";
 exit 0;
}

sub trim
{
  my $temp = shift;
  $temp =~ s/^\s*//;
  $temp =~ s/\s*$//;
  return $temp;
}

sub explode
{
 my $splitter = shift;
 my $who = shift;
 my $tmp;
 my @result;
 my $i = 0;
 my $count = 0;

 while($i<length($who))
 {
  if(substr($who,$i,length($splitter)) eq $splitter)
  {
   $result[$count]=$tmp;
   $tmp='';
   $count++;
   $i+=length($splitter);
  }
  else
  {
   $tmp=$tmp.substr($who,$i,1);
   $i++;
  }
 }
 $result[$count]=$tmp;
 return @result;
}


#/\/\/\/\/\/\/\/\/\/\/\/\/\
# 
#  Not used !!!
#
#\/\/\/\/\/\/\/\/\/\/\/\/\/

sub write_char_XXX
{
 my $show = shift;
 my $port = shift;

 ##### to modify !

 open (PORT,">/dev/port");
 binmode (PORT);
 seek (PORT,$port,0)|| die "seek_err\n";
 print PORT "$show" ||die "write_err while writing $show\n";
 close (PORT);
}

sub lcd_init_4bit
{
 &set_instruction($FUNCTIONSET | $EIGHTBITMODE);
 mysleep(10000);

 &set_instruction($FUNCTIONSET | $EIGHTBITMODE);
 mysleep(10000);

 &set_instruction($FUNCTIONSET | $EIGHTBITMODE);

 &set_instruction($FUNCTIONSET | $FOURBITMODE);
 &set_instruction(0x80 | 0x00);

 &set_instruction(0x00);
 &set_instruction(0x80 | 0x00);

 &set_instruction(0x00);
 &set_instruction(0x10);

 &set_instruction(0x00);
 &set_instruction(0x20 | 0x00);
}

__END__ 

