#!/usr/local/bin/perl -w # Quick & dirty perl hack to pack an Intel Hex format output file. # Will consolidate lines up to $outChunk bytes per line. use integer; # 16 bytes per line is default. $outChunk = 16; $nextOffset = 0; $pendingData = ""; $pendingDataStart = 0; $pendingDataCount = 0; $lastExtendedOffset = 0; while (<>) { if (/:([\dABCDEFabcdef]{2})([\dABCDEFabcdef]{4})(\d\d)(.*)([\dABCDEFabcdef]{2})/) { # $1 = record len; $2 = offset; $3 = record type; $4 = data; $5 = checksum. $recordLen = hex $1; $recordOffset = hex $2; # Sanity checks... if ((length $4) % 2 == 1) { print STDERR "packihx: odd data length $4 in line $.\n"; exit -1; } if ((length $4) / 2 != $recordLen) { print STDERR "packihx: data len mismatch in line $.: $1 != len $4\n"; exit -1; } if (checksum("$1$2$3$4") != hex $5) { print STDERR "packihx: bad checksum in line $.: "; printf STDERR "wanted %02X, got %s\n", checksum("$1$2$3$4"), $5; exit -1; } if ($3 != 0) { # If this is an extended data offset record, and it # matches the expected extended data offset, then # we can simply discard it. if (($3 == 4) && ($recordLen == 2)) { my $extendedOffset = hex $4; if ($extendedOffset == $lastExtendedOffset) { next; } $lastExtendedOffset = $extendedOffset; } # Not a data record. Flush anything pending, then write this # line as is. &flush_pending_data; $pendingDataStart = 0; $nextOffset = 0; print; } else { # If this isn't contigous with the last record, # flush anything pending and start collecting anew. if ($recordOffset != $nextOffset) { &flush_pending_data; $pendingDataStart = $recordOffset; $nextOffset = $pendingDataStart; } # Append this data onto the pending data. $pendingData .= $4; $pendingDataCount += $recordLen; $nextOffset += $recordLen; # If we'va accumulated at least an outChunk # worth of data, write it out. while ($pendingDataCount >= $outChunk) { &write_pending_line($outChunk); } } } else { print STDERR "packihx: don't recognize line $.: $_"; exit -1; } } &flush_pending_data; exit 0; # Write all buffered data. sub flush_pending_data { while ($pendingDataCount > $outChunk) { &write_pending_line($outChunk); } if ($pendingDataCount) { &write_pending_line($pendingDataCount); } } # Write a given number of bytes of buffered output. sub write_pending_line { my $lineLen = shift(@_); if ($lineLen > $pendingDataCount) { print STDERR "packihx: internal error: asked to write $lineLen bytes "; print STDERR "with only $pendingDataCount bytes buffered.\n"; exit -1; } my $data = substr $pendingData, 0, $lineLen * 2; my $toWrite = sprintf "%02X%04X00%s", $lineLen, $pendingDataStart, $data; my $cks = checksum($toWrite); printf ":%s%02X\n", $toWrite, $cks; $pendingDataStart += $lineLen; $pendingDataCount -= $lineLen; $pendingData = substr $pendingData, $lineLen * 2; } # Generate a IHX checksum. sub checksum { my $line = shift(@_); my $offset = 0; my $cks = 0; while ($offset < length $line) { my $byte = substr $line, $offset, 2; $cks += hex $byte; $offset += 2; } if ($offset != length $line) { print STDERR "packihx: checksum: got odd number of bytes... I hate that"; exit -1; } $cks &= 0xff; if ($cks) { $cks = 0x100 - $cks; } return $cks; }