summaryrefslogtreecommitdiffstats
path: root/reverse_engineering/screen.pl
diff options
context:
space:
mode:
Diffstat (limited to 'reverse_engineering/screen.pl')
-rwxr-xr-xreverse_engineering/screen.pl429
1 files changed, 429 insertions, 0 deletions
diff --git a/reverse_engineering/screen.pl b/reverse_engineering/screen.pl
new file mode 100755
index 0000000..f78bbdf
--- /dev/null
+++ b/reverse_engineering/screen.pl
@@ -0,0 +1,429 @@
+#!/usr/bin/env perl
+use strict;
+
+use GD::Image;
+
+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 );
+}
+
+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 );
+}
+
+sub sd_address_mode($$) {
+ my ( $ocd, $m ) = @_;
+
+ sd_cmd( $ocd, 0x20 );
+ sd_cmd( $ocd, $m );
+}
+
+sub sd_cols($$$) {
+ my ( $ocd, $s, $e ) = @_;
+
+ sd_cmd( $ocd, 0x21 );
+ sd_cmd( $ocd, $s );
+ sd_cmd( $ocd, $e );
+}
+
+sub sd_rows($$$) {
+ my ( $ocd, $s, $e ) = @_;
+
+ sd_cmd( $ocd, 0x22 );
+ sd_cmd( $ocd, $s );
+ sd_cmd( $ocd, $e );
+}
+
+sub sd_init($) {
+ my $ocd = shift;
+
+ # off
+ sd_cmd( $ocd, 0xae );
+
+ # set clock freq
+ sd_cmd( $ocd, 0xd5 );
+ sd_cmd( $ocd, 0xa0 );
+
+ #set multiplex ratio
+ sd_cmd( $ocd, 0xa8 );
+ sd_cmd( $ocd, 0x1f );
+
+ #set display offset
+ sd_cmd( $ocd, 0xd3 );
+ sd_cmd( $ocd, 0x00 );
+
+ #set display start
+ sd_cmd( $ocd, 0x40 );
+
+ #set charge pump using DC/DC
+ sd_cmd( $ocd, 0x8d );
+ sd_cmd( $ocd, 0x14 );
+
+ #set segment remap
+ sd_cmd( $ocd, 0xa1 );
+
+ #set com scan direction
+ sd_cmd( $ocd, 0xc8 );
+
+ # set com pins hardware config.
+ sd_cmd( $ocd, 0xda );
+ sd_cmd( $ocd, 0x02 );
+
+ #set contrast
+ sd_cmd( $ocd, 0x81 );
+ sd_cmd( $ocd, 0x8f );
+
+ #set precharge period using DC/DC
+ sd_cmd( $ocd, 0xd9 );
+ sd_cmd( $ocd, 0xf1 );
+
+ #set deselect voltage
+ sd_cmd( $ocd, 0xdb );
+ sd_cmd( $ocd, 0x40 );
+
+ #set display on/off
+ sd_cmd( $ocd, 0xa4 );
+
+ #set display on
+ sd_cmd( $ocd, 0xaf );
+}
+
+sub sd_display($$) {
+ my ( $ocd, $fn ) = @_;
+
+my $ack;
+
+ my $file=GD::Image->new($fn);
+
+ my $img=GD::Image->new(128,32,1);
+
+ $img->copy($file,0,0,0,0,128,32);
+
+ sd_cols($ocd,0,127);
+ sd_rows($ocd,0,63);
+
+
+ for (my $y=0;$y<32;$y+=8) {
+
+ print "y=$y\n";
+ i2c_startaddr( $ocd, $SDADDR );
+ i2c_sendbyte( $ocd, 0x40 );
+
+ i2c_set( $ocd, 0, 1 );
+ i2c_set( $ocd, 1, 1 );
+
+ $ack = i2c_get($ocd);
+ i2c_set( $ocd, 0, 1 );
+ print " ";
+
+
+ for (my $x=0;$x<128;++$x) {
+
+ my $v=0;
+ my $c=0x1;
+
+ for (my $i=0;$i<8;++$i) {
+ my $w=$img->getPixel($x,$i+$y);
+
+# print "r=$r,g=$g,b=$b\n";
+
+ $v|=$c if $w>8388607;
+
+ $c<<=1;
+ }
+
+
+ i2c_sendbyte( $ocd, $v );
+
+ i2c_set( $ocd, 0, 1 );
+ i2c_set( $ocd, 1, 1 );
+
+ $ack = i2c_get($ocd);
+ i2c_set( $ocd, 0, 1 );
+
+ print " ";
+
+
+ }
+ i2c_stop($ocd);
+ }
+
+
+
+}
+
+my $ocd = open_ocd('127.0.0.1:4444');
+
+my $LED = 1 << 22;
+my $SCREEN_PWR = 1 << 25;
+my $SCREEN_BRIGHT = 1 << 30;
+
+sub quit
+{
+ io_clr( $ocd, $SCREEN_PWR );
+ io_clr( $ocd, $SCREEN_BRIGHT );
+ io_set( $ocd, $LED );
+ kill 9, $$;
+}
+
+dir_set( $ocd, $LED | $SCREEN_PWR | $SCREEN_BRIGHT );
+io_clr( $ocd, $SCLBIT | $SDABIT );
+io_clr( $ocd, $LED );
+
+i2c_start($ocd);
+i2c_stop($ocd);
+
+#for (my $a=0;$a<0x100;$a++) {
+#printf "a=0x%02x ",$a;
+#i2c_ping($ocd,$a);
+#}
+#
+
+#Power down screen
+io_clr( $ocd, $SCREEN_PWR | $SCREEN_BRIGHT );
+
+#power up screen
+io_set( $ocd, $SCREEN_PWR | $SCREEN_BRIGHT );
+sd_init($ocd);
+
+sd_address_mode( $ocd, 0x0 );
+
+sd_display($ocd,"fish.png");
+
+while (1) {
+ sd_cmd( $ocd, 0xa7 );
+ sleep(1);
+ sd_cmd( $ocd, 0xa6 );
+ sleep(1);
+}
+