#!/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);
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);
}

my $SDABIT=1<<23;
my $SCLBIT=1<<24;



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);
print "S";
}

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

i2c_set($ocd,0,0);
i2c_set($ocd,1,0);
i2c_set($ocd,1,1);
print "T\n";
}


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 $SDADDR=0x78;

sub sd_write($$$) {
my ($ocd,$dnc,$v)=@_;

my $ack1;
my $ack2;

i2c_startaddr($ocd,$SDADDR);
i2c_sendbyte($ocd,0x80| ($dnc ? 0x40:0x00));

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

i2c_sendbyte($ocd,$v);

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

i2c_stop($ocd);

return $ack1 | $ack2;
}

sub sd_cmd($$)
{
my ($ocd,$c)=@_;

return sd_write($ocd,0,$c);
}

sub sd_dat($$)
{
my ($ocd,$d)=@_;

return sd_write($ocd,1,$d);
}





my $LED=1<<22;
my $SCREEN_PWR=1<<25;
my $SCREEN_NRESET=1<<30;

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


sub quit
{
    io_clr($ocd,$SCREEN_PWR);
    io_set($ocd,$LED);
    kill 9,$$;
}


io_clr($ocd,$SCLBIT | $SDABIT);

dir_set($ocd,$LED | $SCREEN_PWR);
io_clr($ocd,$LED);
io_clr($ocd,$SCREEN_PWR);

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

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