Skip to content
Snippets Groups Projects
firmwareprep.py 4 KiB
Newer Older
#!/usr/bin/env python
#
# Firmware prep utility for Fadecandy production.
#
# This tool bundles a bootloader and firmware image into a source
# file that can be included in the "production" firmware for the testjig.
#
########################### Configuration ###########################

# Paths for all .hex files to include in the installation image
SOURCE_FILES = [
    "../bin/fc-boot-v101.hex",
    "../firmware/fc-firmware.hex",
    ]

# ELF file corresponding to the firmware under test, for symbol lookups
ELF_FILE = "../firmware/fc-firmware.elf"

# Which GDB to use for the firmware image
GDB_COMMAND = "arm-none-eabi-gdb"

# Table of expressions to evaluate under GDB, and names to give them
DEFINITIONS = [
    ('fw_pFlags', '&buffers.flags'),
    ('fw_pFbPrev', '&buffers.fbPrev'),
    ('fw_pFbNext', '&buffers.fbNext'),
    ('fw_pLUT', '&buffers.lutCurrent[0]'),
    ('fw_usbPacketBufOffset', '&((usb_packet_t*)0)->buf'),
    ]

# Where to generate output
OUTPUT_FILE = "production/firmware_data.h"

#####################################################################

import intelhex, time, hashlib, struct, subprocess

# Flash memory sector size
SECTOR_SIZE = 1024

output = open(OUTPUT_FILE, 'w')
output.write("""/*
 * Firmware data for Fadecandy production.
 * AUTOMATICALLY GENERATED by firmwareprep.py
 * 
 * Date: %s
 *
 * Source files:
%s *
 * Copyright (c) 2013 Micah Elizabeth Scott
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

""" % (time.asctime(),
    ''.join([
        " *     %s (%s)\n" %
        (f, hashlib.sha1(open(f, 'rb').read()).hexdigest())
        for f in SOURCE_FILES
    ])))

# Load all .hex files into a flat memory image
loader = intelhex.IntelHex()
for path in SOURCE_FILES:
    loader.loadhex(path)
image = loader.tobinstr()

# Pad to a sector boundary
numSectors = (len(image) + SECTOR_SIZE - 1) // SECTOR_SIZE
numBytes = numSectors * SECTOR_SIZE
numWords = numBytes / 4
image += chr(loader.padding) * (numBytes - len(image))

# Use a GDB subprocess to evaluate symbols, and write those out to the file
gdbArgs = [GDB_COMMAND, '--batch', ELF_FILE]
for name, expression in DEFINITIONS:
    gdbArgs.append('-ex')
    gdbArgs.append('p (uint32_t)' + expression)
lines = subprocess.Popen(gdbArgs, stdin=subprocess.PIPE,
    stdout=subprocess.PIPE).communicate()[0].split('\n')
for i, (name, expression) in enumerate(DEFINITIONS):
    addr = int(lines[i].split('=', 2)[1])
    output.write("static const uint32_t %s = 0x%x;  // %s\n" % (name, addr, expression))

output.write("\n")

# Write the combined firmware image
output.write("static const unsigned fw_sectorCount = %d;\n" % numSectors)
output.write("static const uint32_t fw_data[%d] = {\n" % numWords)

wordsPerLine = 4
numLines = numWords / wordsPerLine

for line in range(numLines):
    addr = line * wordsPerLine * 4
    words = [
        "0x%08x, " % struct.unpack('<I',
            image[addr+4*x:addr+4*(x+1)]
        )[0]
        for x in range(wordsPerLine)
    ]
    output.write("    %s  // 0x%08x\n" % (''.join(words), addr))

output.write("};\n")