Skip to content

Commit 9a17698

Browse files
aykevldeadprogram
authored andcommitted
compileopts: add support for custom binary formats
Some chips (like the ESP family) have a particular image format that is more complex than simply dumping everything in a raw image.
1 parent 3ee47a9 commit 9a17698

File tree

4 files changed

+49
-16
lines changed

4 files changed

+49
-16
lines changed

builder/build.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -260,19 +260,27 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(stri
260260
}
261261

262262
// Get an Intel .hex file or .bin file from the .elf file.
263-
if outext == ".hex" || outext == ".bin" || outext == ".gba" {
263+
outputBinaryFormat := config.BinaryFormat(outext)
264+
switch outputBinaryFormat {
265+
case "elf":
266+
// do nothing, file is already in ELF format
267+
case "hex", "bin":
268+
// Extract raw binary, either encoding it as a hex file or as a raw
269+
// firmware file.
264270
tmppath = filepath.Join(dir, "main"+outext)
265-
err := objcopy(executable, tmppath)
271+
err := objcopy(executable, tmppath, outputBinaryFormat)
266272
if err != nil {
267273
return err
268274
}
269-
} else if outext == ".uf2" {
275+
case "uf2":
270276
// Get UF2 from the .elf file.
271277
tmppath = filepath.Join(dir, "main"+outext)
272278
err := convertELFFileToUF2File(executable, tmppath, config.Target.UF2FamilyID)
273279
if err != nil {
274280
return err
275281
}
282+
default:
283+
return fmt.Errorf("unknown output binary format: %s", outputBinaryFormat)
276284
}
277285
return action(tmppath)
278286
}

builder/objcopy.go

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"debug/elf"
55
"io/ioutil"
66
"os"
7-
"path/filepath"
87
"sort"
98

109
"github.com/marcinbor85/gohex"
@@ -93,7 +92,7 @@ func extractROM(path string) (uint64, []byte, error) {
9392

9493
// objcopy converts an ELF file to a different (simpler) output file format:
9594
// .bin or .hex. It extracts only the .text section.
96-
func objcopy(infile, outfile string) error {
95+
func objcopy(infile, outfile, binaryFormat string) error {
9796
f, err := os.OpenFile(outfile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
9897
if err != nil {
9998
return err
@@ -107,23 +106,20 @@ func objcopy(infile, outfile string) error {
107106
}
108107

109108
// Write to the file, in the correct format.
110-
switch filepath.Ext(outfile) {
111-
case ".gba":
112-
// The address is not stored in a .gba file.
113-
_, err := f.Write(data)
114-
return err
115-
case ".bin":
116-
// The address is not stored in a .bin file (therefore you
117-
// should use .hex files in most cases).
118-
_, err := f.Write(data)
119-
return err
120-
case ".hex":
109+
switch binaryFormat {
110+
case "hex":
111+
// Intel hex file, includes the firmware start address.
121112
mem := gohex.NewMemory()
122113
err := mem.AddBinary(uint32(addr), data)
123114
if err != nil {
124115
return objcopyError{"failed to create .hex file", err}
125116
}
126117
return mem.DumpIntelHex(f, 16)
118+
case "bin":
119+
// The start address is not stored in raw firmware files (therefore you
120+
// should use .hex files in most cases).
121+
_, err := f.Write(data)
122+
return err
127123
default:
128124
panic("unreachable")
129125
}

compileopts/config.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,31 @@ func (c *Config) Debug() bool {
239239
return c.Options.Debug
240240
}
241241

242+
// BinaryFormat returns an appropriate binary format, based on the file
243+
// extension and the configured binary format in the target JSON file.
244+
func (c *Config) BinaryFormat(ext string) string {
245+
switch ext {
246+
case ".bin", ".gba":
247+
// The simplest format possible: dump everything in a raw binary file.
248+
if c.Target.BinaryFormat != "" {
249+
return c.Target.BinaryFormat
250+
}
251+
return "bin"
252+
case ".hex":
253+
// Similar to bin, but includes the start address and is thus usually a
254+
// better format.
255+
return "hex"
256+
case ".uf2":
257+
// Special purpose firmware format, mainly used on Adafruit boards.
258+
// More information:
259+
// https://github.com/Microsoft/uf2
260+
return "uf2"
261+
default:
262+
// Use the ELF format for unrecognized file formats.
263+
return "elf"
264+
}
265+
}
266+
242267
// Programmer returns the flash method and OpenOCD interface name given a
243268
// particular configuration. It may either be all configured in the target JSON
244269
// file or be modified using the -programmmer command-line option.

compileopts/target.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ type TargetSpec struct {
4747
FlashVolume string `json:"msd-volume-name"`
4848
FlashFilename string `json:"msd-firmware-name"`
4949
UF2FamilyID string `json:"uf2-family-id"`
50+
BinaryFormat string `json:"binary-format"`
5051
OpenOCDInterface string `json:"openocd-interface"`
5152
OpenOCDTarget string `json:"openocd-target"`
5253
OpenOCDTransport string `json:"openocd-transport"`
@@ -128,6 +129,9 @@ func (spec *TargetSpec) copyProperties(spec2 *TargetSpec) {
128129
if spec2.UF2FamilyID != "" {
129130
spec.UF2FamilyID = spec2.UF2FamilyID
130131
}
132+
if spec2.BinaryFormat != "" {
133+
spec.BinaryFormat = spec2.BinaryFormat
134+
}
131135
if spec2.OpenOCDInterface != "" {
132136
spec.OpenOCDInterface = spec2.OpenOCDInterface
133137
}

0 commit comments

Comments
 (0)