Motorola S-Record

This is a format used to contain binary images for embedded devices that is produced by some compiler packages. It is quite similar to the Intel HEX format files which perform a similar task.

An S-Record file consists of a number of lines of ASCII data. Each line is a single record typically holding a chunk of data to be placed at a certain address. Each line has a checksum just like the intel format.

 +-------------------//------------------//-----------------------+
 | type | count | address  |            data           | checksum |
 +-------------------//------------------//-----------------------+

See http://en.wikipedia.org/wiki/SREC_(file_format%29 as well.

See bin2srec in this wiki as well.


Package to decode S-Record files

 # srec.tcl - Copyright (c) 2008 Pat Thoyts <[email protected]>
 #
 #        Parse a Motorola S-record file and write a binary image
 
 namespace eval ::srecord {}
 
 # s-record checksum (2-complement 8 bit sum)
 proc ::srecord::cksum {data {seed 0}} {
     set t $seed
     binary scan $data c* bytes
     foreach byte $bytes { incr t [expr {$byte & 0xff}] }
     return [expr {(~$t) & 0xff}]
 }
 
 # decode one s-record. Returns a list of type, address, binary data
 proc ::srecord::decode_line {line} {
     set type [string range $line 0 1]
     switch -exact -- $type {
         S0 {set addrlen 4}
         S1 {set addrlen 4}
         S2 {set addrlen 6}
         S3 {set addrlen 8}
         S5 {set addrlen 4}
         S7 {set addrlen 8}
         S8 {set addrlen 6}
         S9 {set addrlen 4}
         default {
             return -code error "invalid data format: \"$type\" invalid type"
         }
     }
     if {[scan [string range $line 2 3] %02x count] != 1} {
         return -code error "invalid data format: count field incorrect"
     }
     if {[scan [string range $line 4 end] %0${addrlen}x addr] != 1} {
         return -code error "invalid data format: address field incorrect"
     }
     if {[scan [string range $line end-1 end] %02x cksum] != 1} {
         return -code error "invalid data format: checksum field incorrect"
     }
     set data [binary format H* [string range $line 2 end-2]]
     if {$count != [string length $data]} {
         return -code error "invalid data format: line count incorrect"
     }
     if {[cksum $data] != $cksum} {
         return -code error "invalid checksum: data corruption detected"
     }
 
     return [list $type $addr [string range $data [expr {$addrlen/2 + 1}] end]]
 }
 
 # Decode an entire file - the result is a block of binary data.
 # NB: we only handle S0 and S3 records
 proc ::srecord::decode_image {filename imagevar {progresscmd {}}} {
     upvar $imagevar image
     set size [file size $filename]
     set f [open $filename r]
     fconfigure $f -buffering line -translation auto
     set done 0
     while {[gets $f line] > 0} {
         foreach {type addr data} [decode_line $line] break
         switch -exact -- $type {
             S0 {
                 # module information
                 set mname [string range $data 0 19]
                 foreach {mver mrev} {0 0} break
                 scan [string range $data 20 21] %02x mver
                 scan [string range $data 22 23] %02x mrev
                 set mdesc [string range $data 24 end]
                 #puts [list $mname $mver $mrev $mdesc]
             }
             S3 {
                 set a0 [expr {$addr}]
                 set aend [expr {$a0 + [string length $data] - 1}]
                 set image [string replace $image $addr $aend $data]
             }
             default {
                 return -code error "unhandled record type \"$type\""
             }
         }
         incr done [string length $line]
         if {$progresscmd ne {}} {
             uplevel #0 [list $progresscmd] [expr {($done * 100) / $size}]
         }
     }
     close $f
     return
 }
 
 proc ::srecord::decode_file {filename size {progresscmd {}}} {
     # create a zero-filled binary object of the right size
     set image [binary format @[expr {$size}]]
     # decode the s-record file into the binary object
     decode_image $filename $size image $progresscmd
     return $image
 }
 
 package provide srecord 1.0.0

And a test program using the above package:

 # Test the srecord package by converting a file into a binary image
 # The output is to stdout or a named file or to inputfile.bin if no name.
 #
 # usage: srec flash.srec flash.bin
 
 package require srecord
 
 proc Main {filename {binfile {}}} {
     if {$binfile eq {}} {
         set binfile [file rootname $filename].bin
     }
     set data [::srecord::decode_file $filename 0x40000]
     if {$binfile eq "-"} {
         set oldenc [fconfigure stdout -encoding]
         set oldtrn [fconfigure stdout -translation]
         set oldeof [fconfigure stdout -eofchar]
         fconfigure stdout -encoding binary -translation binary -eofchar {}
         puts -nonewline stdout $data
         fconfigure stdout -encoding $oldenc -translation $oldtrn -eofchar $oldeof
     } else {
         set f [open $binfile w]
         fconfigure $f -encoding binary -translation binary -eofchar {}
         puts -nonewline $f $data
         close $f
     }
     return 0
 }
 
 if {!$tcl_interactive} {
     set r [catch [linsert $argv 0 Main] err]
     if {$r} {puts $::errorInfo} elseif {$err ne ""} {puts $err}
     exit $r
 }