#!/usr/bin/env perl 
use strict;

use IO::Socket::INET;
use Data::Dumper;
#use IO::Socket::Timeout;
#
#

$SIG{INT}=\&quit;
my $prompt= '> ';

sub my_readline_worker($)
{
my $sock=shift;
my $ret="";
my $d="";

while (1) {
return $ret if $sock->read($d,1)!=1;

next if $d eq "\n";

$ret.=$d;

return $ret if $d eq "\r";
return $ret if $ret =~ /> $/;

} 


}

sub my_readline($)
{
my $sock=shift;
my $ret=my_readline_worker($sock);
#print $ret."\n";
return $ret;
}




sub wait_for_prompt($)
{
my $ocd=shift;

1 while (my_readline($ocd) ne $prompt);
}


sub open_ocd($) {
my $addr=shift;
my $sock = IO::Socket::INET->new( $addr);
wait_for_prompt($sock);
    $sock->printf( "reset halt\n");
    wait_for_prompt($sock);
return $sock;
}


sub write_reg($$$)
{
my ($ocd,$r,$v)=@_;

$ocd->printf("mww 0x%08x 0x%08x\n",$r,$v);
wait_for_prompt($ocd);
}

sub read_reg($$)
{
my ($ocd,$r)=@_;
my $ret;

$ocd->printf("mdw 0x%08x\n",$r);

$ret=my_readline($ocd);
$ret=my_readline($ocd);

wait_for_prompt($ocd);


$ret =~ s/[\r\n\s]//g;


if ($ret =~ /0x[0-9A-Fa-f]+:([0-9a-fA-F]+)/) {
	return hex($1);
}

return undef;
}



sub dir_set($$) {
my ($ocd,$v)=@_;
write_reg($ocd,0x50000518,$v);
}


sub dir_clr($$) {
my ($ocd,$v)=@_;
write_reg($ocd,0x5000051c,$v);
}

sub io_set($$) {
my ($ocd,$v)=@_;
write_reg($ocd,0x50000508,$v);
}

sub io_clr($$) {
my ($ocd,$v)=@_;
write_reg($ocd,0x5000050c,$v);
}

sub io_get($) {
my $ocd=shift;
return read_reg($ocd,0x50000510);
}


sub io_cnf($$$) {
    my ( $ocd, $pin, $v ) = @_;
    write_reg( $ocd, 0x50000700 + ($pin * 4), $v );
}


my $SDABIT=1<<18;
my $SCLBIT=1<<17;



sub i2c_set($$$) {
my ($ocd,$scl,$sda) =@_;
my $clr=0;
my $set=0;


if ($scl) {
	$clr|=$SCLBIT;
} else {
	$set|=$SCLBIT;
}

if ($sda) {
	$clr|=$SDABIT;
} else {
	$set|=$SDABIT;
}

dir_set($ocd,$set);
dir_clr($ocd,$clr);
}


sub i2c_get($) {
my $ocd=shift;

return (io_get($ocd) & $SDABIT ) ? 1:0;
}

sub i2c_start($) {
my $ocd=shift;

i2c_set($ocd,1,1);
i2c_set($ocd,1,0);
i2c_set($ocd,0,0);
}

sub i2c_stop($) {
my $ocd=shift;

i2c_set($ocd,0,0);
i2c_set($ocd,1,0);
i2c_set($ocd,1,1);
}


sub i2c_sendbyte($$)
{
my ($ocd,$byte) =@_;

for ( my $c=0x80; $c; $c>>=1)
{
my $v=($c & $byte) ? 1:0;

print $v;

i2c_set($ocd,0,$v);
i2c_set($ocd,1,$v);
i2c_set($ocd,0,$v);
}

}

sub i2c_startaddr($$)
{
my ($ocd,$addr) =@_;
my $ret;

i2c_start($ocd);
i2c_sendbyte($ocd,$addr);
print " ";

i2c_set($ocd,0,1);
i2c_set($ocd,1,1);

$ret=i2c_get($ocd);
i2c_set($ocd,0,1);

print $ret;

return $ret;

}

sub i2c_ping($$)
{
my ($ocd,$addr) =@_;
my $ret;
$ret=i2c_startaddr($ocd,$addr);
i2c_stop($ocd);
return $ret;
}


my $ocd=open_ocd('127.0.0.1:4444' );


io_cnf($ocd,18,0x60c);
io_cnf($ocd,17,0x60c);
io_clr($ocd,$SCLBIT | $SDABIT);

i2c_start($ocd);
i2c_stop($ocd);

for (my $a=0;$a<0x100;$a++) {
printf "a=0x%02x ",$a;
i2c_ping($ocd,$a);
i2c_start($ocd);
i2c_stop($ocd);
i2c_start($ocd);
i2c_stop($ocd);

print "\n";
}