Skip to content

Commit cc1f62d

Browse files
committed
Produce merged sketch + bootloader on bin only platforms
1 parent a07ea16 commit cc1f62d

File tree

2 files changed

+73
-10
lines changed

2 files changed

+73
-10
lines changed

src/arduino.cc/builder/constants/constants.go

+1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ const BUILD_PROPERTIES_BUILD_PROJECT_NAME = "build.project_name"
4747
const BUILD_PROPERTIES_BUILD_SYSTEM_PATH = "build.system.path"
4848
const BUILD_PROPERTIES_BUILD_VARIANT = "build.variant"
4949
const BUILD_PROPERTIES_BUILD_VARIANT_PATH = "build.variant.path"
50+
const BUILD_PROPERTIES_BUILD_LDSCRIPT = "build.ldscript"
5051
const BUILD_PROPERTIES_COMPILER_C_ELF_FLAGS = "compiler.c.elf.flags"
5152
const BUILD_PROPERTIES_COMPILER_CPP_FLAGS = "compiler.cpp.flags"
5253
const BUILD_PROPERTIES_COMPILER_PATH = "compiler.path"

src/arduino.cc/builder/merge_sketch_with_bootloader.go

+72-10
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import (
3434
"arduino.cc/builder/i18n"
3535
"arduino.cc/builder/types"
3636
"arduino.cc/builder/utils"
37+
"io/ioutil"
3738
"os"
3839
"path/filepath"
3940
"strings"
@@ -52,15 +53,25 @@ func (s *MergeSketchWithBootloader) Run(ctx *types.Context) error {
5253
sketchFileName := filepath.Base(sketch.MainFile.Name)
5354
logger := ctx.GetLogger()
5455

55-
sketchInBuildPath := filepath.Join(buildPath, sketchFileName+".hex")
56-
sketchInSubfolder := filepath.Join(buildPath, constants.FOLDER_SKETCH, sketchFileName+".hex")
56+
sketchInBuildPath := filepath.Join(buildPath, sketchFileName)
57+
sketchInSubfolder := filepath.Join(buildPath, constants.FOLDER_SKETCH, sketchFileName)
5758

59+
availableExtensions := []string{".hex", ".bin"}
5860
builtSketchPath := constants.EMPTY_STRING
59-
if _, err := os.Stat(sketchInBuildPath); err == nil {
60-
builtSketchPath = sketchInBuildPath
61-
} else if _, err := os.Stat(sketchInSubfolder); err == nil {
62-
builtSketchPath = sketchInSubfolder
63-
} else {
61+
62+
extension := ""
63+
64+
for _, extension = range availableExtensions {
65+
if _, err := os.Stat(sketchInBuildPath + extension); err == nil {
66+
builtSketchPath = sketchInBuildPath + extension
67+
break
68+
} else if _, err := os.Stat(sketchInSubfolder + extension); err == nil {
69+
builtSketchPath = sketchInSubfolder + extension
70+
break
71+
}
72+
}
73+
74+
if builtSketchPath == constants.EMPTY_STRING {
6475
return nil
6576
}
6677

@@ -78,9 +89,17 @@ func (s *MergeSketchWithBootloader) Run(ctx *types.Context) error {
7889
return nil
7990
}
8091

81-
mergedSketchPath := filepath.Join(filepath.Dir(builtSketchPath), sketchFileName+".with_bootloader.hex")
92+
mergedSketchPath := filepath.Join(filepath.Dir(builtSketchPath), sketchFileName+".with_bootloader"+extension)
8293

83-
err := merge(builtSketchPath, bootloaderPath, mergedSketchPath)
94+
var err error
95+
if extension == ".hex" {
96+
err = mergeHex(builtSketchPath, bootloaderPath, mergedSketchPath)
97+
} else {
98+
ldscript := buildProperties[constants.BUILD_PROPERTIES_BUILD_LDSCRIPT]
99+
variantFolder := buildProperties[constants.BUILD_PROPERTIES_BUILD_VARIANT_PATH]
100+
ldscriptPath := filepath.Join(variantFolder, ldscript)
101+
err = mergeBin(builtSketchPath, ldscriptPath, bootloaderPath, mergedSketchPath)
102+
}
84103

85104
return err
86105
}
@@ -127,7 +146,7 @@ func extractActualBootloader(bootloader []string) []string {
127146
return realBootloader
128147
}
129148

130-
func merge(builtSketchPath, bootloaderPath, mergedSketchPath string) error {
149+
func mergeHex(builtSketchPath, bootloaderPath, mergedSketchPath string) error {
131150
sketch, err := utils.ReadFileToRows(builtSketchPath)
132151
if err != nil {
133152
return i18n.WrapError(err)
@@ -147,3 +166,46 @@ func merge(builtSketchPath, bootloaderPath, mergedSketchPath string) error {
147166

148167
return utils.WriteFile(mergedSketchPath, strings.Join(sketch, "\n"))
149168
}
169+
170+
func mergeBin(builtSketchPath, ldscriptPath, bootloaderPath, mergedSketchPath string) error {
171+
// 0xFF means empty
172+
// only works if the bootloader is at the beginning of the flash
173+
// only works if the flash address space is mapped at 0x00
174+
175+
// METHOD 1: (non appliable to most architectures)
176+
// remove all comments from linkerscript
177+
// find NAMESPACE of .text section -> FLASH
178+
// find ORIGIN of FLASH section
179+
180+
// METHOD 2:
181+
// Round the bootloader to the next "power of 2" bytes boundary
182+
183+
// generate a byte[FLASH] full of 0xFF and bitwise OR with bootloader BIN
184+
// merge this slice with sketch BIN
185+
186+
bootloader, _ := ioutil.ReadFile(bootloaderPath)
187+
sketch, _ := ioutil.ReadFile(builtSketchPath)
188+
189+
paddedBootloaderLen := nextPowerOf2(len(bootloader))
190+
191+
padding := make([]byte, paddedBootloaderLen-len(bootloader))
192+
for i, _ := range padding {
193+
padding[i] = 0xFF
194+
}
195+
196+
bootloader = append(bootloader, padding...)
197+
sketch = append(bootloader, sketch...)
198+
199+
return ioutil.WriteFile(mergedSketchPath, sketch, 0644)
200+
}
201+
202+
func nextPowerOf2(v int) int {
203+
v--
204+
v |= v >> 1
205+
v |= v >> 2
206+
v |= v >> 4
207+
v |= v >> 8
208+
v |= v >> 16
209+
v++
210+
return v
211+
}

0 commit comments

Comments
 (0)