#!/usr/bin/perl -w

###################################################
# I2C über I2C-RS232 Koppler von horter.de
# Jörg Brune joergbrune.de
################################################### 

use constant false=>0;
use constant true=>1;

$PortName="COM1"; # verwendete serielle Schnittstelle
$t_bps=1000;      # Bits pro Sekunde 
$debug=false;     # true/false true: Busverkehr anzeigen

print "Content-Type: text/html\n\n";
print "<htm><head><title>i2c test</title></head><body bgcolor=cornsilk>";

use Time::HiRes qw(usleep);
use Win32::SerialPort;  # Linux  Device::SerialPort  
# SerialPort gibts hier: http://www.bribes.org/perl/ppm/

$t_bt=1000000/$t_bps/4; 

$startdelay=20;   

## port öffnen
$quiet=0;
$PortObj = new Win32::SerialPort ($PortName, $quiet)
|| die "kann $PortName: $^E nicht öffnen\n";

sub i2cout
{ $cl=shift;$dt=shift;
  $PortObj->dtr_active($dt);$PortObj->rts_active($cl);
  usleep $t_bt; }

sub i2cstart
{ if($debug){print "<br><font size=2><> 76543120 ack dez<br>";}  ##
  for($i = 1; $i <= $startdelay; $i++) { i2cout(1,1); }
  i2cout(1,1);i2cout(1,0);i2cout(1,0);i2cout(0,0);  }

sub i2cstop   ##stopbit schreiben
{ i2cout(0,0);i2cout(1,0);i2cout(1,0);i2cout(1,1);
  for($i = 1; $i <= $startdelay; $i++) { i2cout(1,1); } }  

sub i2cwt    ## bit schreiben
{ $bit=shift;
  i2cout(0,$bit);i2cout(1,$bit);i2cout(1,$bit);i2cout(0,$bit); }

sub i2crb
{ i2cout(0,1);i2cout(1,1);
  $r = $PortObj->modemlines & 32;     ## ist 32 richtig? oder 16?
  if($r>0){$r=1;}
  i2cout(1,1);i2cout(0,1);
  return($r);}

sub ic2_wb    ## byte schreiben
{ $by=shift; $by0=$by;
  if($debug){print "-> ";}  ##
  for($i=1;$i<=8;$i++)
  { $bt=0;if(($by & 128)>0){$bt=1;}
    $by=($by << 1);
    i2cwt($bt);
    if($debug){print "$bt";}  ##
    }
  $ack=i2crb();
  if($debug){print " $ack $by0<br>"}; ##
  return($ack); }

sub ic2_rb    ## byte lesen
{ $by=0;
  if($debug){print "<- ";}  ##
  for($i=1;$i<=8;$i++)
  { $bt=i2crb();
    $by=($by << 1)+$bt;
    if($debug){print "$bt";}  ##
    }
  $ack=i2crb();
  if($debug){print " $ack $by<br>";} ##
  return($by); }

##############################
# Funktionen für I2C Bausteine

sub pcf8574wt
{ $adr=shift;$dat=shift;
  i2cstart();
  $err=-ic2_wb(64+$adr+$adr);
  $err=-ic2_wb($dat)+2*$err;  
  i2cstop();
  return($err);} 

sub pcf8574rd
{ $adr=shift;
  i2cstart();
  ic2_wb(64+$adr+$adr);
  ic2_wb(255);  
  ic2_wb(65+$adr+$adr); 
  $dat=ic2_rb();   
  i2cstop();
  return($dat); }

sub pcf8591rd
{ $adr=shift;$ain=shift;
  i2cstart();
  ic2_wb(144+$adr+$adr);
  ic2_wb($ain);  
  i2cstop();
  i2cstart();
  ic2_wb(144+$adr+$adr+1);
  $dat=ic2_rb();   
  i2cstop();
  i2cstart();
  ic2_wb(144+$adr+$adr+1);
  $dat=ic2_rb();   
  i2cstop();
  return($dat); }

sub pcf8591wt
{ $adr=shift;$dat=shift;
  i2cstart();
  ic2_wb(144+$adr+$adr);
  $err=-ic2_wb(64);  
  $err=-ic2_wb($dat)+2*$err;  
  i2cstop();
  return($err); }


############################################


## beispiel für pcf8574

# schreiben
$res=pcf8574wt(0,254);   # a:0-7, out:0-255

# lesen
$res=pcf8574rd(0);   # a:0-7
print " ....$res<br><br>";

## beispiel für pcf8591

# lesen
$res=pcf8591rd(0,0);   # a:0-7, in:0-3
print " ....$res<br><br>";

# schreiben
$res=pcf8591wt(0,20);   # a:0-7, out:0-255
print " ....$res<br><br>";


print "</body></html>\n";