feat: support generic bin and intel hex firmware
This commit is contained in:
1
go.mod
1
go.mod
@@ -16,6 +16,7 @@ require (
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/marcinbor85/gohex v0.0.0-20210308104911-55fb1c624d84
|
||||
github.com/mattn/go-tty v0.0.7
|
||||
github.com/sigurn/crc16 v0.0.0-20240131213347-83fcde1e29d1
|
||||
go.bug.st/serial v1.6.4
|
||||
|
||||
2
go.sum
2
go.sum
@@ -14,6 +14,8 @@ github.com/goplus/llvm v0.8.5 h1:DUnFeYC3Rco622tBEKGg8xkigRAV2fh5ZIfBCt7gOSs=
|
||||
github.com/goplus/llvm v0.8.5/go.mod h1:PeVK8GgzxwAYCiMiUAJb5wJR6xbhj989tu9oulKLLT4=
|
||||
github.com/goplus/mod v0.17.1 h1:ITovxDcc5zbURV/Wrp3/SBsYLgC1KrxY6pq1zMM2V94=
|
||||
github.com/goplus/mod v0.17.1/go.mod h1:iXEszBKqi38BAyQApBPyQeurLHmQN34YMgC2ZNdap50=
|
||||
github.com/marcinbor85/gohex v0.0.0-20210308104911-55fb1c624d84 h1:hyAgCuG5nqTMDeUD8KZs7HSPs6KprPgPP8QmGV8nyvk=
|
||||
github.com/marcinbor85/gohex v0.0.0-20210308104911-55fb1c624d84/go.mod h1:Pb6XcsXyropB9LNHhnqaknG/vEwYztLkQzVCHv8sQ3M=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-tty v0.0.7 h1:KJ486B6qI8+wBO7kQxYgmmEFDaFEE96JMBQ7h400N8Q=
|
||||
|
||||
@@ -2,7 +2,6 @@ package firmware
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
@@ -35,9 +34,14 @@ func ExtractFileFormatFromCommand(cmd string) string {
|
||||
|
||||
// ConvertFormats processes format conversions for embedded targets only
|
||||
func ConvertFormats(binFmt, fmtDetail string, envMap map[string]string) error {
|
||||
var err error
|
||||
// Convert to bin format first (needed for img)
|
||||
if envMap["bin"] != "" {
|
||||
err := makeFirmwareImage(envMap["out"], envMap["bin"], binFmt, fmtDetail)
|
||||
if strings.HasPrefix(binFmt, "esp") {
|
||||
err = makeFirmwareImage(envMap["out"], envMap["bin"], binFmt, fmtDetail)
|
||||
} else {
|
||||
err = objcopy(envMap["out"], envMap["bin"], "bin")
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to convert to bin format: %w", err)
|
||||
}
|
||||
@@ -45,7 +49,7 @@ func ConvertFormats(binFmt, fmtDetail string, envMap map[string]string) error {
|
||||
|
||||
// Convert to hex format
|
||||
if envMap["hex"] != "" {
|
||||
err := makeFirmwareImage(envMap["out"], envMap["hex"], binFmt, fmtDetail)
|
||||
err := objcopy(envMap["out"], envMap["hex"], "hex")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to convert to hex format: %w", err)
|
||||
}
|
||||
@@ -53,7 +57,7 @@ func ConvertFormats(binFmt, fmtDetail string, envMap map[string]string) error {
|
||||
|
||||
// Convert to img format
|
||||
if envMap["img"] != "" {
|
||||
err := makeFirmwareImage(envMap["out"], envMap["img"], binFmt+"-img", fmtDetail)
|
||||
err = makeFirmwareImage(envMap["out"], envMap["img"], binFmt+"-img", fmtDetail)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to convert to img format: %w", err)
|
||||
}
|
||||
@@ -77,38 +81,3 @@ func ConvertFormats(binFmt, fmtDetail string, envMap map[string]string) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// convertToHex converts binary file to hex format (each byte as two hex characters)
|
||||
func convertToHex(infile, outfile string) error {
|
||||
srcFile, err := os.Open(infile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer srcFile.Close()
|
||||
|
||||
dstFile, err := os.Create(outfile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer dstFile.Close()
|
||||
|
||||
// Read input file and convert each byte to two hex characters
|
||||
buf := make([]byte, 4096) // Read in chunks
|
||||
for {
|
||||
n, err := srcFile.Read(buf)
|
||||
if n > 0 {
|
||||
for i := 0; i < n; i++ {
|
||||
if _, writeErr := fmt.Fprintf(dstFile, "%02x", buf[i]); writeErr != nil {
|
||||
return writeErr
|
||||
}
|
||||
}
|
||||
}
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -4,8 +4,12 @@ package firmware
|
||||
|
||||
import (
|
||||
"debug/elf"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"sort"
|
||||
|
||||
"github.com/marcinbor85/gohex"
|
||||
)
|
||||
|
||||
// maxPadBytes is the maximum allowed bytes to be padded in a rom extraction
|
||||
@@ -103,3 +107,41 @@ func extractROM(path string) (uint64, []byte, error) {
|
||||
return progs[0].Paddr, rom, nil
|
||||
}
|
||||
}
|
||||
|
||||
// From tinygo/builder/builder/objcopy.go objcopy
|
||||
// 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, binaryFormat string) error {
|
||||
f, err := os.OpenFile(outfile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
// Read the .text segment.
|
||||
addr, data, err := extractROM(infile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Write to the file, in the correct format.
|
||||
switch binaryFormat {
|
||||
case "hex":
|
||||
fmt.Fprintf(os.Stderr, "Converting firmware format: %s -> %s (intel hex format: %s)\n", infile, outfile, binaryFormat)
|
||||
// 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":
|
||||
fmt.Fprintf(os.Stderr, "Converting firmware format: %s -> %s (format: %s)\n", infile, outfile, binaryFormat)
|
||||
// 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")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user