diff --git a/builder/build.go b/builder/build.go index c02d2394..9e553c33 100644 --- a/builder/build.go +++ b/builder/build.go @@ -260,19 +260,27 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(stri } // Get an Intel .hex file or .bin file from the .elf file. - if outext == ".hex" || outext == ".bin" || outext == ".gba" { + outputBinaryFormat := config.BinaryFormat(outext) + switch outputBinaryFormat { + case "elf": + // do nothing, file is already in ELF format + case "hex", "bin": + // Extract raw binary, either encoding it as a hex file or as a raw + // firmware file. tmppath = filepath.Join(dir, "main"+outext) - err := objcopy(executable, tmppath) + err := objcopy(executable, tmppath, outputBinaryFormat) if err != nil { return err } - } else if outext == ".uf2" { + case "uf2": // Get UF2 from the .elf file. tmppath = filepath.Join(dir, "main"+outext) err := convertELFFileToUF2File(executable, tmppath, config.Target.UF2FamilyID) if err != nil { return err } + default: + return fmt.Errorf("unknown output binary format: %s", outputBinaryFormat) } return action(tmppath) } diff --git a/builder/objcopy.go b/builder/objcopy.go index e5b245c6..c2fefa04 100644 --- a/builder/objcopy.go +++ b/builder/objcopy.go @@ -4,7 +4,6 @@ import ( "debug/elf" "io/ioutil" "os" - "path/filepath" "sort" "github.com/marcinbor85/gohex" @@ -93,7 +92,7 @@ func extractROM(path string) (uint64, []byte, error) { // objcopy converts an ELF file to a different (simpler) output file format: // .bin or .hex. It extracts only the .text section. -func objcopy(infile, outfile string) error { +func objcopy(infile, outfile, binaryFormat string) error { f, err := os.OpenFile(outfile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666) if err != nil { return err @@ -107,23 +106,20 @@ func objcopy(infile, outfile string) error { } // Write to the file, in the correct format. - switch filepath.Ext(outfile) { - case ".gba": - // The address is not stored in a .gba file. - _, err := f.Write(data) - return err - case ".bin": - // The address is not stored in a .bin file (therefore you - // should use .hex files in most cases). - _, err := f.Write(data) - return err - case ".hex": + switch binaryFormat { + case "hex": + // Intel hex file, includes the firmware start address. mem := gohex.NewMemory() err := mem.AddBinary(uint32(addr), data) if err != nil { return objcopyError{"failed to create .hex file", err} } return mem.DumpIntelHex(f, 16) + case "bin": + // The start address is not stored in raw firmware files (therefore you + // should use .hex files in most cases). + _, err := f.Write(data) + return err default: panic("unreachable") } diff --git a/compileopts/config.go b/compileopts/config.go index fa82b72e..c2eb17d1 100644 --- a/compileopts/config.go +++ b/compileopts/config.go @@ -239,6 +239,31 @@ func (c *Config) Debug() bool { return c.Options.Debug } +// BinaryFormat returns an appropriate binary format, based on the file +// extension and the configured binary format in the target JSON file. +func (c *Config) BinaryFormat(ext string) string { + switch ext { + case ".bin", ".gba": + // The simplest format possible: dump everything in a raw binary file. + if c.Target.BinaryFormat != "" { + return c.Target.BinaryFormat + } + return "bin" + case ".hex": + // Similar to bin, but includes the start address and is thus usually a + // better format. + return "hex" + case ".uf2": + // Special purpose firmware format, mainly used on Adafruit boards. + // More information: + // https://github.com/Microsoft/uf2 + return "uf2" + default: + // Use the ELF format for unrecognized file formats. + return "elf" + } +} + // Programmer returns the flash method and OpenOCD interface name given a // particular configuration. It may either be all configured in the target JSON // file or be modified using the -programmmer command-line option. diff --git a/compileopts/target.go b/compileopts/target.go index 07625127..6547320a 100644 --- a/compileopts/target.go +++ b/compileopts/target.go @@ -47,6 +47,7 @@ type TargetSpec struct { FlashVolume string `json:"msd-volume-name"` FlashFilename string `json:"msd-firmware-name"` UF2FamilyID string `json:"uf2-family-id"` + BinaryFormat string `json:"binary-format"` OpenOCDInterface string `json:"openocd-interface"` OpenOCDTarget string `json:"openocd-target"` OpenOCDTransport string `json:"openocd-transport"` @@ -128,6 +129,9 @@ func (spec *TargetSpec) copyProperties(spec2 *TargetSpec) { if spec2.UF2FamilyID != "" { spec.UF2FamilyID = spec2.UF2FamilyID } + if spec2.BinaryFormat != "" { + spec.BinaryFormat = spec2.BinaryFormat + } if spec2.OpenOCDInterface != "" { spec.OpenOCDInterface = spec2.OpenOCDInterface }