#!/usr/bin/perl -w # # This program changes the mote ID of a TinyOS image. It is used to # install a program for a specific mote. use strict; # default to backward compatability mode my $G_compat = 1; while( @ARGV && $ARGV[0] =~ /^-/ ) { my $opt = shift @ARGV; if( $opt eq "--srec" ) { $G_compat = 1; } elsif( $opt eq "--exe" ) { $G_compat = 0; } else { die "Unknown command line option $opt\n"; } } # print usage if we have the wrong number of arguments if( @ARGV < 3 ) { if( $G_compat ) { print "usage: set-mote-id [srec_in] [srec_out] [TOS_LOCAL_ADDRESS] ...\n"; } else { print "usage: set-mote-id [exe_in] [exe_out] [TOS_LOCAL_ADDRESS] ...\n"; } exit 0; } # get the args and default variables set up my $exein = shift @ARGV; my $exeout = shift @ARGV; my %user_symbols = (); for my $value (@ARGV) { my $name = 'TOS_LOCAL_ADDRESS'; ($name,$value) = ($1,$2) if $value =~ /^([^=]+)=(.*)/; $value = hex $value if $value =~ /^0x/; $user_symbols{$name} = $value; } my $segment_vma = undef; my $segment_lma = undef; my $segment_off = undef; # if in compatability mode, derive the names of the exes from the srecs my $srecin = undef; my $srecout = undef; if( $G_compat ) { $srecin = $exein; $srecout = $exeout; $exein =~ s/srec/exe/; $exeout =~ s/srec/exe/; } # find the data section open( SECTS, "avr-objdump -h $exein |" ) or die "Cannot extract section information: $!\n"; while() { if( /^\s*\d+\s+\.data\s+\S+\s+(\S+)\s+(\S+)\s+(\S+)/ ) { $segment_vma = hex $1; $segment_lma = hex $2; $segment_off = hex $3; last; } } close(SECTS); die "Could not find data section in $exein, aborting.\n" unless defined $segment_vma && defined $segment_lma && defined $segment_off; # build a hash of all data segment symbols to their address and size my %exe_symbols = (); open( SYMBOL, "avr-objdump -t $exein |" ) or die "Cannot extract symbol information: $!\n"; while() { if( /^(\S+)\s+\S+\s+\S+\s+\.data\s+(\S+)\s+(\S+)\s*$/ ) { $exe_symbols{$3} = { addr => hex($1), size => hex($2) }; } } close(SYMBOL); # slurp the input exe open (FILE_IN, "<$exein") or die "Could not open $exein: $!\n"; binmode FILE_IN; my $exe = join("",); close( FILE_IN ); # change the desired symbols at their file offsets for my $symbol (sort keys %user_symbols) { my $value = $user_symbols{$symbol}; if( defined $exe_symbols{$symbol} ) { my $addr = $exe_symbols{$symbol}->{addr}; my $size = $exe_symbols{$symbol}->{size}; my $filepos = $segment_off + ($addr - $segment_vma); my $bytes = substr( pack("V", $value) . ("\000" x $size), 0, $size ); substr( $exe, $filepos, $size ) = $bytes; } else { warn "Could not find symbol $symbol in $exein, ignoring symbol.\n"; } } # barf the output exe open (FILE_OUT, ">$exeout") or die "Could not open $exeout: $!\n"; binmode FILE_OUT; print FILE_OUT $exe; close( FILE_OUT ); # if in compatability mode, convert the output exe to the output srec if( $G_compat ) { my $cmd = "avr-objcopy --output-target=srec $exeout $srecout"; system( $cmd ) == 0 or die "Command \"$cmd\" failed"; }