Skip to content

Commit

Permalink
make MergeSketchWithBootloader a method recevier of arduino/builder
Browse files Browse the repository at this point in the history
  • Loading branch information
alessio-perugini committed Sep 12, 2023
1 parent 9cf492b commit 352362d
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 191 deletions.
129 changes: 129 additions & 0 deletions arduino/builder/sketch.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ package builder
import (
"bytes"
"fmt"
"math"
"regexp"
"strconv"
"strings"

"github.com/arduino/arduino-cli/arduino/builder/compilation"
"github.com/arduino/arduino-cli/arduino/builder/cpp"
Expand All @@ -29,6 +32,7 @@ import (
f "github.com/arduino/arduino-cli/internal/algorithms"
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
"github.com/arduino/go-paths-helper"
"github.com/marcinbor85/gohex"

"github.com/pkg/errors"
)
Expand Down Expand Up @@ -221,3 +225,128 @@ func (b *Builder) BuildSketch(

return sketchObjectFiles, nil
}

// MergeSketchWithBootloader fixdoc
func (b *Builder) MergeSketchWithBootloader(onlyUpdateCompilationDatabase bool) error {
if onlyUpdateCompilationDatabase {
return nil
}

if !b.buildProperties.ContainsKey("bootloader.noblink") && !b.buildProperties.ContainsKey("bootloader.file") {
return nil
}

sketchFileName := b.sketch.MainFile.Base()
sketchInBuildPath := b.buildPath.Join(sketchFileName + ".hex")
sketchInSubfolder := b.buildPath.Join("sketch", sketchFileName+".hex")

var builtSketchPath *paths.Path
if sketchInBuildPath.Exist() {
builtSketchPath = sketchInBuildPath
} else if sketchInSubfolder.Exist() {
builtSketchPath = sketchInSubfolder
} else {
return nil
}

bootloader := ""
if bootloaderNoBlink, ok := b.buildProperties.GetOk("bootloader.noblink"); ok {
bootloader = bootloaderNoBlink
} else {
bootloader = b.buildProperties.Get("bootloader.file")
}
bootloader = b.buildProperties.ExpandPropsInString(bootloader)

bootloaderPath := b.buildProperties.GetPath("runtime.platform.path").Join("bootloaders", bootloader)
if bootloaderPath.NotExist() {
if b.logger.Verbose() {
b.logger.Warn(tr("Bootloader file specified but missing: %[1]s", bootloaderPath))
}
return nil
}

mergedSketchPath := builtSketchPath.Parent().Join(sketchFileName + ".with_bootloader.hex")

// Ignore merger errors for the first iteration
maximumBinSize := 16000000
if uploadMaxSize, ok := b.buildProperties.GetOk("upload.maximum_size"); ok {
maximumBinSize, _ = strconv.Atoi(uploadMaxSize)
maximumBinSize *= 2
}
err := merge(builtSketchPath, bootloaderPath, mergedSketchPath, maximumBinSize)
if err != nil && b.logger.Verbose() {
b.logger.Info(err.Error())
}

return nil
}

func merge(builtSketchPath, bootloaderPath, mergedSketchPath *paths.Path, maximumBinSize int) error {
if bootloaderPath.Ext() == ".bin" {
bootloaderPath = paths.New(strings.TrimSuffix(bootloaderPath.String(), ".bin") + ".hex")
}

memBoot := gohex.NewMemory()
if bootFile, err := bootloaderPath.Open(); err == nil {
defer bootFile.Close()
if err := memBoot.ParseIntelHex(bootFile); err != nil {
return errors.New(bootFile.Name() + " " + err.Error())
}
} else {
return err
}

memSketch := gohex.NewMemory()
if buildFile, err := builtSketchPath.Open(); err == nil {
defer buildFile.Close()
if err := memSketch.ParseIntelHex(buildFile); err != nil {
return errors.New(buildFile.Name() + " " + err.Error())
}
} else {
return err
}

memMerged := gohex.NewMemory()
initialAddress := uint32(math.MaxUint32)
lastAddress := uint32(0)

for _, segment := range memBoot.GetDataSegments() {
if err := memMerged.AddBinary(segment.Address, segment.Data); err != nil {
continue
}
if segment.Address < initialAddress {
initialAddress = segment.Address
}
if segment.Address+uint32(len(segment.Data)) > lastAddress {
lastAddress = segment.Address + uint32(len(segment.Data))
}
}
for _, segment := range memSketch.GetDataSegments() {
if err := memMerged.AddBinary(segment.Address, segment.Data); err != nil {
continue
}
if segment.Address < initialAddress {
initialAddress = segment.Address
}
if segment.Address+uint32(len(segment.Data)) > lastAddress {
lastAddress = segment.Address + uint32(len(segment.Data))
}
}

if mergeFile, err := mergedSketchPath.Create(); err == nil {
defer mergeFile.Close()
memMerged.DumpIntelHex(mergeFile, 16)
} else {
return err
}

// Write out a .bin if the addresses doesn't go too far away from origin
// (and consequently produce a very large bin)
size := lastAddress - initialAddress
if size > uint32(maximumBinSize) {
return nil
}
mergedSketchPathBin := paths.New(strings.TrimSuffix(mergedSketchPath.String(), ".hex") + ".bin")
data := memMerged.ToBinary(initialAddress, size, 0xFF)
return mergedSketchPathBin.WriteFile(data)
}
6 changes: 1 addition & 5 deletions legacy/builder/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,11 +177,7 @@ func (s *Builder) Run(ctx *types.Context) error {
}),

types.BareCommand(func(ctx *types.Context) error {
return MergeSketchWithBootloader(
ctx.OnlyUpdateCompilationDatabase,
ctx.Builder.GetBuildPath(), ctx.Builder.Sketch(), ctx.Builder.GetBuildProperties(),
ctx.BuilderLogger,
)
return ctx.Builder.MergeSketchWithBootloader(ctx.OnlyUpdateCompilationDatabase)
}),

types.BareCommand(func(ctx *types.Context) error {
Expand Down
160 changes: 0 additions & 160 deletions legacy/builder/merge_sketch_with_bootloader.go

This file was deleted.

30 changes: 4 additions & 26 deletions legacy/builder/test/merge_sketch_with_bootloader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ import (
"strings"
"testing"

"github.com/arduino/arduino-cli/arduino/builder/logger"
"github.com/arduino/arduino-cli/legacy/builder"
"github.com/arduino/arduino-cli/legacy/builder/constants"
"github.com/arduino/arduino-cli/legacy/builder/types"
paths "github.com/arduino/go-paths-helper"
Expand Down Expand Up @@ -70,12 +68,7 @@ func TestMergeSketchWithBootloader(t *testing.T) {
err = buildPath.Join("sketch", "sketch1.ino.hex").WriteFile([]byte(fakeSketchHex))
require.NoError(t, err)

builderLogger := logger.New(nil, nil, false, "")
err = builder.MergeSketchWithBootloader(
ctx.OnlyUpdateCompilationDatabase,
ctx.Builder.GetBuildPath(), ctx.Builder.Sketch(), ctx.Builder.GetBuildProperties(),
builderLogger,
)
err = ctx.Builder.MergeSketchWithBootloader(ctx.OnlyUpdateCompilationDatabase)
require.NoError(t, err)

bytes, err := buildPath.Join("sketch", "sketch1.ino.with_bootloader.hex").ReadFile()
Expand Down Expand Up @@ -127,12 +120,7 @@ func TestMergeSketchWithBootloaderSketchInBuildPath(t *testing.T) {
err = buildPath.Join("sketch1.ino.hex").WriteFile([]byte(fakeSketchHex))
require.NoError(t, err)

builderLogger := logger.New(nil, nil, false, "")
err = builder.MergeSketchWithBootloader(
ctx.OnlyUpdateCompilationDatabase,
ctx.Builder.GetBuildPath(), ctx.Builder.Sketch(), ctx.Builder.GetBuildProperties(),
builderLogger,
)
err = ctx.Builder.MergeSketchWithBootloader(ctx.OnlyUpdateCompilationDatabase)
require.NoError(t, err)

bytes, err := buildPath.Join("sketch1.ino.with_bootloader.hex").ReadFile()
Expand All @@ -153,12 +141,7 @@ func TestMergeSketchWithBootloaderWhenNoBootloaderAvailable(t *testing.T) {
buildProperties.Remove(constants.BUILD_PROPERTIES_BOOTLOADER_NOBLINK)
buildProperties.Remove(constants.BUILD_PROPERTIES_BOOTLOADER_FILE)

builderLogger := logger.New(nil, nil, false, "")
err := builder.MergeSketchWithBootloader(
ctx.OnlyUpdateCompilationDatabase,
ctx.Builder.GetBuildPath(), ctx.Builder.Sketch(), ctx.Builder.GetBuildProperties(),
builderLogger,
)
err := ctx.Builder.MergeSketchWithBootloader(ctx.OnlyUpdateCompilationDatabase)
require.NoError(t, err)

exist, err := buildPath.Join("sketch.ino.with_bootloader.hex").ExistCheck()
Expand Down Expand Up @@ -213,12 +196,7 @@ func TestMergeSketchWithBootloaderPathIsParameterized(t *testing.T) {
err = buildPath.Join("sketch", "sketch1.ino.hex").WriteFile([]byte(fakeSketchHex))
require.NoError(t, err)

builderLogger := logger.New(nil, nil, false, "")
err = builder.MergeSketchWithBootloader(
ctx.OnlyUpdateCompilationDatabase,
ctx.Builder.GetBuildPath(), ctx.Builder.Sketch(), ctx.Builder.GetBuildProperties(),
builderLogger,
)
err = ctx.Builder.MergeSketchWithBootloader(ctx.OnlyUpdateCompilationDatabase)
require.NoError(t, err)

bytes, err := buildPath.Join("sketch", "sketch1.ino.with_bootloader.hex").ReadFile()
Expand Down

0 comments on commit 352362d

Please sign in to comment.