#!/usr/bin/env tclsh

# Generate a C include file from one or more Intel HEX files (avr-gcc output)
# jcw, 2010-04-18

# Examples:
#   ./hex2c.tcl Blink.cpp.hex ATmegaBOOT_168_atmega328.hex >data_blink.h
#   ./hex2c.tcl RF12demo.cpp.hex ATmegaBOOT_168_atmega328.hex >data_rf12demo.h
#   ./hex2c.tcl Blink.cpp.hex optiboot_atmega328.hex >opti_blink.h
#   ./hex2c.tcl RF12demo.cpp.hex optiboot_atmega328.hex >opti_rf12demo.h

if {$argv eq ""} {
  puts stderr "Usage: [info script] infile.hex ?...? >outfile.h"
  exit 1
}

set bytes {}

foreach a $argv {
  set start [llength $bytes]
  set mtime [clock format [file mtime $a] -format "%Y-%m-%d"]
  puts stderr $a:
  set fd [open $a]
  while {[gets $fd line] > 0} {
    if {[scan $line {:%2x%4x%2x%s} count addr type data]} {
      if {$type == 0} {
        if {![info exists next]} {
          set first [format 0x%04X $addr]
          set next $addr
        }
        while {$next < $addr} {
          lappend bytes 255 ;# pad with unset bytes if there is a gap
          incr next
        }
        if {$next != $addr} {
          puts stderr "non-contiguous data ($next vs $addr)"
        }
        incr next $count
        foreach {x y} [split [string range $data 0 end-2] ""] {
          lappend bytes [scan $x$y %x]
        }
      }
    }
  }
  incr next -$first
  set f [format %-30s [file tail $a]]
  lappend sections "\"$mtime $f ${next}b @ $first\",$first,$start,$next"
  unset next
  close $fd
}

puts "// This file was generated by hex2c.tcl on [clock format [clock seconds]]"
puts ""
puts "struct { const char* title; unsigned start, off, count; } sections\[] = {"

foreach x $sections {
  puts " {$x},"
}

puts "};"
puts ""
puts "const unsigned char progdata\[] PROGMEM = {"

set out " "
foreach x $bytes {
  if {[string length $out$x,] > 80} {
    puts $out
    set out " "
  }
  append out $x ,
}
puts $out

puts "};"
