summaryrefslogtreecommitdiffstats
path: root/reverse_engineering
diff options
context:
space:
mode:
authorroot <root@lamia.panaceas.james.local>2015-09-07 11:52:14 +0100
committerroot <root@lamia.panaceas.james.local>2015-09-07 11:52:14 +0100
commit472ebcbfaccd62adc0c4ab1c59a967c1d7034385 (patch)
tree9bbe8aee2f19d19e4b68e1ef4049349fcffbf1ed /reverse_engineering
downloadbracelet-472ebcbfaccd62adc0c4ab1c59a967c1d7034385.tar.gz
bracelet-472ebcbfaccd62adc0c4ab1c59a967c1d7034385.tar.bz2
bracelet-472ebcbfaccd62adc0c4ab1c59a967c1d7034385.zip
fish
Diffstat (limited to 'reverse_engineering')
-rw-r--r--reverse_engineering/Makefile37
-rwxr-xr-xreverse_engineering/accel.pl372
-rwxr-xr-xreverse_engineering/bits.pl150
-rwxr-xr-xreverse_engineering/eeprom.pl304
-rw-r--r--reverse_engineering/fish.pngbin0 -> 1622 bytes
-rw-r--r--reverse_engineering/gdb.script2
-rw-r--r--reverse_engineering/main0
-rw-r--r--reverse_engineering/openocd.cfg13
-rwxr-xr-xreverse_engineering/scani2c-1.pl301
-rwxr-xr-xreverse_engineering/scani2c-2.pl363
-rwxr-xr-xreverse_engineering/scani2c-3.pl367
-rwxr-xr-xreverse_engineering/screen.pl429
12 files changed, 2338 insertions, 0 deletions
diff --git a/reverse_engineering/Makefile b/reverse_engineering/Makefile
new file mode 100644
index 0000000..4bcb255
--- /dev/null
+++ b/reverse_engineering/Makefile
@@ -0,0 +1,37 @@
+PROG=main
+
+BDADDR=CF:5F:D0:0C:8D:FC
+
+
+OOCD=openocd
+OOCD_CFG=openocd.cfg
+
+
+CROSS=arm-none-eabi-
+CC := $(CROSS)gcc
+AS := $(CROSS)as
+AR := $(CROSS)ar
+LD := $(CROSS)ld
+NM := $(CROSS)nm
+OBJDUMP := $(CROSS)objdump
+OBJCOPY := $(CROSS)objcopy
+SIZE := $(CROSS)size
+GDB := $(CROSS)gdb
+NRFUTIL := nrfutil
+
+ds:
+ $(OOCD) -f $(OOCD_CFG)
+
+debug: ${PROG}
+ ${GDB} -x gdb.script ${PROG}
+
+reset:
+ ${OOCD} -f ${OOCD_CFG} \
+ -c "init" \
+ -c "reset init" \
+ -c "reset" \
+ -c "shutdown"
+
+scani2c:
+ perl scani2c.pl
+
diff --git a/reverse_engineering/accel.pl b/reverse_engineering/accel.pl
new file mode 100755
index 0000000..ac17a0e
--- /dev/null
+++ b/reverse_engineering/accel.pl
@@ -0,0 +1,372 @@
+#!/usr/bin/env perl
+use strict;
+
+use IO::Socket::INET;
+use Data::Dumper;
+
+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 << 12;
+my $SCLBIT = 1 << 13;
+
+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_recvbyte($) {
+ my ($ocd) = @_;
+
+ my $byte = 0;
+
+ for ( my $c = 0x80 ; $c ; $c >>= 1 ) {
+ my $v;
+
+ i2c_set( $ocd, 0, 1 );
+ i2c_set( $ocd, 1, 1 );
+ $v = i2c_get($ocd);
+
+ #print $v;
+
+ $byte |= $c if $v;
+
+ i2c_set( $ocd, 0, 1 );
+ }
+
+ return $byte;
+
+}
+
+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 $LIS_ADDR = 0x32;
+
+sub lis_write($$$) {
+ my ( $ocd, $reg, $v ) = @_;
+
+ my $ret;
+
+ i2c_startaddr( $ocd, $LIS_ADDR );
+
+ i2c_sendbyte( $ocd, $reg );
+
+ i2c_set( $ocd, 0, 1 );
+ i2c_set( $ocd, 1, 1 );
+ $ret = i2c_get($ocd);
+ i2c_set( $ocd, 0, 1 );
+
+ i2c_sendbyte( $ocd, $v );
+
+ i2c_set( $ocd, 0, 1 );
+ i2c_set( $ocd, 1, 1 );
+ i2c_set( $ocd, 0, 1 );
+
+ i2c_stop($ocd);
+}
+
+sub lis_read($$) {
+ my ( $ocd, $reg ) = @_;
+
+ my $ret;
+
+ i2c_startaddr( $ocd, $LIS_ADDR );
+
+ i2c_sendbyte( $ocd, $reg );
+
+ i2c_set( $ocd, 0, 1 );
+ i2c_set( $ocd, 1, 1 );
+ $ret = i2c_get($ocd);
+ i2c_set( $ocd, 0, 1 );
+
+ # mad repeated start
+ i2c_set( $ocd, 0, 1 );
+ i2c_set( $ocd, 1, 1 );
+
+ i2c_startaddr( $ocd, $LIS_ADDR | 1 );
+
+ $ret = i2c_recvbyte($ocd);
+
+ i2c_set( $ocd, 0, 1 );
+ i2c_set( $ocd, 1, 1 );
+ i2c_set( $ocd, 0, 1 );
+
+ i2c_stop($ocd);
+
+ return $ret;
+}
+
+sub lis_read16($$) {
+ my ( $ocd, $reg ) = @_;
+
+ my $ret;
+
+ i2c_startaddr( $ocd, $LIS_ADDR );
+
+ i2c_sendbyte( $ocd, $reg | 0x80 );
+
+ i2c_set( $ocd, 0, 1 );
+ i2c_set( $ocd, 1, 1 );
+ $ret = i2c_get($ocd);
+ i2c_set( $ocd, 0, 1 );
+
+ # mad repeated start
+ i2c_set( $ocd, 0, 1 );
+ i2c_set( $ocd, 1, 1 );
+
+ i2c_startaddr( $ocd, $LIS_ADDR | 1 );
+
+ $a = i2c_recvbyte($ocd);
+
+ i2c_set( $ocd, 0, 0 );
+ i2c_set( $ocd, 1, 0 );
+ i2c_set( $ocd, 0, 0 );
+
+ $b = i2c_recvbyte($ocd);
+
+ i2c_set( $ocd, 0, 1 );
+ i2c_set( $ocd, 1, 1 );
+ i2c_set( $ocd, 0, 1 );
+
+ i2c_stop($ocd);
+
+ $ret = $a | ( $b << 8 );
+
+ return $ret;
+}
+
+my $ocd = open_ocd('127.0.0.1:4444');
+
+io_clr( $ocd, $SCLBIT | $SDABIT );
+
+i2c_start($ocd);
+i2c_stop($ocd);
+
+
+lis_write($ocd,0x20,0x27);
+lis_write($ocd,0x22,0x0);
+printf "%02x\n",lis_read($ocd,0x22);
+my $a=io_get($ocd);
+lis_write($ocd,0x22,0xfe);
+printf "%02x\n",lis_read($ocd,0x22);
+my $b=io_get($ocd);
+
+my $v=$a;
+printf "%04b %04b %04b %04b %04b %04b %04b %04b\n",
+ ($v >>28) &0xf,
+ ($v >>24) &0xf,
+
+ ($v >>20) &0xf,
+ ($v >>16) &0xf,
+
+ ($v >>12) &0xf,
+ ($v >>8) &0xf,
+
+ ($v >>4) &0xf,
+ ($v) &0xf;
+$v=$b;
+
+
+printf "%04b %04b %04b %04b %04b %04b %04b %04b\n",
+ ($v >>28) &0xf,
+ ($v >>24) &0xf,
+
+ ($v >>20) &0xf,
+ ($v >>16) &0xf,
+
+ ($v >>12) &0xf,
+ ($v >>8) &0xf,
+
+ ($v >>4) &0xf,
+ ($v) &0xf;
+
+
+lis_write($ocd,0x22,0x0);
+
+
+while (1) {
+ printf "%04x %04x %04x\n", lis_read16( $ocd, 0x28 ),
+ lis_read16( $ocd, 0x2a ), lis_read16( $ocd, 0x2c );
+
+}
+
+die;
+
diff --git a/reverse_engineering/bits.pl b/reverse_engineering/bits.pl
new file mode 100755
index 0000000..c6b3c7f
--- /dev/null
+++ b/reverse_engineering/bits.pl
@@ -0,0 +1,150 @@
+#!/usr/bin/env perl
+use strict;
+
+use IO::Socket::INET;
+use Data::Dumper;
+#use IO::Socket::Timeout;
+#
+#
+
+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_get($) {
+my $ocd=shift;
+return read_reg($ocd,0x50000514);
+}
+
+
+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 $ocd=open_ocd('127.0.0.1:4444' );
+
+
+my $ov=-1;
+while (1) {
+my $v=dir_get($ocd);
+
+next if $v == $ov;
+
+$ov=$v;
+
+
+printf "%04b %04b %04b %04b %04b %04b %04b %04b\n",
+ ($v >>28) &0xf,
+ ($v >>24) &0xf,
+
+ ($v >>20) &0xf,
+ ($v >>16) &0xf,
+
+ ($v >>12) &0xf,
+ ($v >>8) &0xf,
+
+ ($v >>4) &0xf,
+ ($v) &0xf;
+
+}
+
diff --git a/reverse_engineering/eeprom.pl b/reverse_engineering/eeprom.pl
new file mode 100755
index 0000000..695ef48
--- /dev/null
+++ b/reverse_engineering/eeprom.pl
@@ -0,0 +1,304 @@
+#!/usr/bin/env perl
+use strict;
+
+use IO::Socket::INET;
+use Data::Dumper;
+
+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 << 9;
+my $SCLBIT = 1 << 8;
+
+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_recvbyte($) {
+ my ($ocd) = @_;
+
+ my $byte = 0;
+
+ for ( my $c = 0x80 ; $c ; $c >>= 1 ) {
+ my $v;
+
+ i2c_set( $ocd, 0, 1 );
+ i2c_set( $ocd, 1, 1 );
+ $v = i2c_get($ocd);
+
+ #print $v;
+
+ $byte |= $c if $v;
+
+ i2c_set( $ocd, 0, 1 );
+ }
+
+ return $byte;
+
+}
+
+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 $EE_ADDR = 0xa0;
+
+#sub lis_write($$$) {
+# my ( $ocd, $reg, $v ) = @_;
+#
+# my $ret;
+#
+# i2c_startaddr( $ocd, $LIS_ADDR );
+#
+# i2c_sendbyte( $ocd, $reg );
+#
+# i2c_set( $ocd, 0, 1 );
+# i2c_set( $ocd, 1, 1 );
+# $ret = i2c_get($ocd);
+# i2c_set( $ocd, 0, 1 );
+#
+# i2c_sendbyte( $ocd, $v );
+#
+# i2c_set( $ocd, 0, 1 );
+# i2c_set( $ocd, 1, 1 );
+# i2c_set( $ocd, 0, 1 );
+#
+# i2c_stop($ocd);
+#}
+#
+
+sub ee_read($$) {
+ my ( $ocd, $a ) = @_;
+
+ my $ret;
+
+ i2c_startaddr( $ocd, $EE_ADDR );
+
+ i2c_sendbyte( $ocd, ($a >> 8 ) & 0xff );
+
+ i2c_set( $ocd, 0, 1 );
+ i2c_set( $ocd, 1, 1 );
+ i2c_set( $ocd, 0, 1 );
+
+ i2c_sendbyte( $ocd, $a & 0xff );
+
+
+ i2c_set( $ocd, 0, 1 );
+ i2c_set( $ocd, 1, 1 );
+ i2c_set( $ocd, 0, 1 );
+
+
+ # mad repeated start
+ i2c_set( $ocd, 0, 1 );
+ i2c_set( $ocd, 1, 1 );
+
+ i2c_startaddr( $ocd, $EE_ADDR | 1 );
+
+ $ret = i2c_recvbyte($ocd);
+
+ i2c_set( $ocd, 0, 1 );
+ i2c_set( $ocd, 1, 1 );
+ i2c_set( $ocd, 0, 1 );
+
+ i2c_stop($ocd);
+
+ return $ret;
+}
+
+my $ocd = open_ocd('127.0.0.1:4444');
+
+io_clr( $ocd, $SCLBIT | $SDABIT );
+
+i2c_start($ocd);
+i2c_stop($ocd);
+
+
+$|=1;
+
+for (my $i=0;$i<0x100;$i+=0x10) {
+printf "%04x ",$i;
+for (my $j=0;$j<0x10;$j++) {
+printf " %02x",ee_read($ocd,$i+$j);
+}
+printf "\n";
+}
+
+die;
+
diff --git a/reverse_engineering/fish.png b/reverse_engineering/fish.png
new file mode 100644
index 0000000..5eb87c8
--- /dev/null
+++ b/reverse_engineering/fish.png
Binary files differ
diff --git a/reverse_engineering/gdb.script b/reverse_engineering/gdb.script
new file mode 100644
index 0000000..7cf9d09
--- /dev/null
+++ b/reverse_engineering/gdb.script
@@ -0,0 +1,2 @@
+target remote localhost:3333
+cont
diff --git a/reverse_engineering/main b/reverse_engineering/main
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/reverse_engineering/main
diff --git a/reverse_engineering/openocd.cfg b/reverse_engineering/openocd.cfg
new file mode 100644
index 0000000..b8d024a
--- /dev/null
+++ b/reverse_engineering/openocd.cfg
@@ -0,0 +1,13 @@
+# nF51822 Target
+source [find interface/stlink-v2.cfg]
+
+#source [find interface/jlink.cfg]
+#transport select swd
+
+
+#set WORKAREASIZE 0x4000
+set WORKAREASIZE 0x0
+source [find target/nrf51.cfg]
+
+# use hardware reset, connect under reset
+#reset_config srst_only srst_nogate
diff --git a/reverse_engineering/scani2c-1.pl b/reverse_engineering/scani2c-1.pl
new file mode 100755
index 0000000..5897492
--- /dev/null
+++ b/reverse_engineering/scani2c-1.pl
@@ -0,0 +1,301 @@
+#!/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);
+}
+
+
+
+
+
+
+
diff --git a/reverse_engineering/scani2c-2.pl b/reverse_engineering/scani2c-2.pl
new file mode 100755
index 0000000..0b0cdcf
--- /dev/null
+++ b/reverse_engineering/scani2c-2.pl
@@ -0,0 +1,363 @@
+#!/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<<9;
+my $SCLBIT=1<<8;
+
+
+
+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,$$;
+}
+
+
+
+#dir_set($ocd,$LED | $SCREEN_PWR);
+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);
+}
+
+
+die;
+
+
+
+#Power cycle screen
+io_clr($ocd,$SCREEN_PWR);
+io_set($ocd,$SCREEN_PWR);
+
+# 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);
+
+while (1) {
+sd_cmd($ocd,0xa7);
+sleep(1);
+sd_cmd($ocd,0xa6);
+sleep(1);
+}
+
+
+
+
diff --git a/reverse_engineering/scani2c-3.pl b/reverse_engineering/scani2c-3.pl
new file mode 100755
index 0000000..5898ac1
--- /dev/null
+++ b/reverse_engineering/scani2c-3.pl
@@ -0,0 +1,367 @@
+#!/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<<12;
+my $SCLBIT=1<<13;
+
+
+
+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,$$;
+}
+
+
+
+#dir_set($ocd,$LED | $SCREEN_PWR);
+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);
+i2c_start($ocd);
+i2c_stop($ocd);
+i2c_start($ocd);
+i2c_stop($ocd);
+}
+
+
+die;
+
+
+
+#Power cycle screen
+io_clr($ocd,$SCREEN_PWR);
+io_set($ocd,$SCREEN_PWR);
+
+# 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);
+
+while (1) {
+sd_cmd($ocd,0xa7);
+sleep(1);
+sd_cmd($ocd,0xa6);
+sleep(1);
+}
+
+
+
+
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);
+}
+