From: Tramm "Foo" Hudson <hudson@eecs.tulane.edu>
To: lego-robotics@crynwr.com
Subject: Firmware loading.  It works!
Date: Thu, 1 Oct 1998 04:14:08 -0500 (CDT)

Fellow hackers,

I am -so- close to getting this working!  Arrgh!  Ok, I've hacked
up talkrcx to work on my Linux box with Perl 5.004_4 (Paul, do you
want my fixes?), written a program to take a binary file produced by
gcc and ld, convert it to an appropriate format and then use talkrcx to
send it.

Everything goes great -- the rcx responds with 'b2 00', which means
message received, checksum ok.  I then send the magic 'ad 4c 45 47 3f ae'
and it croaks with a long, low beep and no response on the IR.  The
code then sends a 10 and sees the proper response.

ARRGH!

Ok, while this was sitting in the background, I have gotten it to
work!  The problem is making sure that the overall checksum is
correct.  I had missed that part of the protocol.  I'm not sure how
key the "Do you byte, when I knock?\0" string is, but I have it in
there just in case.  As a correction, it is required.  Sigh...

So, my first native code program doesn't do anything.  It beeps the
speaker with system call 327c on start up and then hangs.  Well, it
doesn't do anything yet (the unit doesn't appear to turn on), but I
was able to download the firmware sucessfully.

Who else has had any luck doing this?  And how do I hack gcc to use
the proper calling sequence (r6 for arg 1, the rest on the stack)?


Anyway, here is my mk-dl program that takes a raw binary image and
interacts with talkrcx (my hacked version, may work with others).

#!/usr/bin/perl -w
#########################################
#
# mk-dl
# Version 1e-9
#
# Converts a raw binary file into a format ready to be downloaded
# to a LEGO(r) RCX control unit.  Works with Paul Haas' talkrcx program
# to coordinate the I/O to the control box.
#
# VERY BETA!  Be prepared for problems.  Let me know if things
# work for you.  YMMV.  As-is.  No warrenties.  All of that stuff.
#
# Tramm Hudson (hudson@cs.tulane.edu)
# 1 Oct '98
#
use strict;

# Print the preload stuff
print <<"";
10                      # Ping!
10                      # Ping! (Sync sequence numbers)
18                      # Check for life
10                      # Ping!
1d 01 03 05 07 0b       # Get versions
15 01 03 05 07 0b       # Get versions again?
6d 01 03 05 07 0b       # Erase firmware


# Slurp entire files
undef $/;

my @chars = (qw(0 1 2 3 4 5 6 7 8 9 a b c d e f));

sub hex2str {
  my $arg = ord(shift);
  $chars[$arg >> 4] . $chars[$arg & 0xF];
}


my @code;

# Read in all files provided on the command line
# Skip initial nulls incase the linker padded the files
while( <> )
{
  # Kill initial nulls
  s/^\0*//;

  # Map it to the hex value
  push @code, map { (hex2str $_) } split //;
}


# Now compute the checksums
my $packet_checksum = 0;
my $total_checksum = 0;
map { $total_checksum = ($total_checksum + hex($_)) & 0xFFFF; } @code;

# This command begins to write a new firmware image at 0x8000 with
# checksum $total_checksum
printf "75 00 80 %02x %02x 00\n",
        ($total_checksum & 0xFF), ($total_checksum >> 8);

#
# Ok, let's write out the packets
#
my $packet_num = 1;
while( @code )
{
  my @packet = splice(@code,0,255);
  my $length = @packet;
  my $packet_checksum = 0;

  printf "4d %02x 00 %02x 00 ", $packet_num++, $length;
  for( @packet ) {
    $packet_checksum = ($packet_checksum + hex($_)) & 0xFF;
    print "$_ ";
  }

  printf "%02x\n", $packet_checksum;
}

#
# Bogus empty packet
#
print "45 00 00 00 00 00\n";



#
# Now clean up and switch to the new firmware image
#
print <<"";
ad 4c 45 47 4f ae       # Unlock the firmware with LEGO(R)
10
18

__END__


-- 
  o   hudson@cs.tulane.edu            tbhudso@cs.sandia.gov   O___|   
 /|\  http://www.cs.tulane.edu/~hudson/     H 505.266.59.96   /\  \_  
 <<   KC5RNF @ N5YYF.NM.AMPR.ORG            W 505.284.24.32   \ \/\_\  
  0                                                            U \_  | 
