30
30
package builder
31
31
32
32
import (
33
+ "io/ioutil"
34
+ "os"
35
+ "path/filepath"
36
+ "strings"
37
+
33
38
"github.com/arduino/arduino-builder/constants"
34
39
"github.com/arduino/arduino-builder/i18n"
35
40
"github.com/arduino/arduino-builder/types"
36
41
"github.com/arduino/arduino-builder/utils"
37
- "os"
38
- "path/filepath"
39
- "strings"
40
42
)
41
43
42
44
type MergeSketchWithBootloader struct {}
@@ -52,15 +54,25 @@ func (s *MergeSketchWithBootloader) Run(ctx *types.Context) error {
52
54
sketchFileName := filepath .Base (sketch .MainFile .Name )
53
55
logger := ctx .GetLogger ()
54
56
55
- sketchInBuildPath := filepath .Join (buildPath , sketchFileName + ".hex" )
56
- sketchInSubfolder := filepath .Join (buildPath , constants .FOLDER_SKETCH , sketchFileName + ".hex" )
57
+ sketchInBuildPath := filepath .Join (buildPath , sketchFileName )
58
+ sketchInSubfolder := filepath .Join (buildPath , constants .FOLDER_SKETCH , sketchFileName )
57
59
60
+ availableExtensions := []string {".hex" , ".bin" }
58
61
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 {
62
+
63
+ extension := ""
64
+
65
+ for _ , extension = range availableExtensions {
66
+ if _ , err := os .Stat (sketchInBuildPath + extension ); err == nil {
67
+ builtSketchPath = sketchInBuildPath + extension
68
+ break
69
+ } else if _ , err := os .Stat (sketchInSubfolder + extension ); err == nil {
70
+ builtSketchPath = sketchInSubfolder + extension
71
+ break
72
+ }
73
+ }
74
+
75
+ if builtSketchPath == constants .EMPTY_STRING {
64
76
return nil
65
77
}
66
78
@@ -78,9 +90,17 @@ func (s *MergeSketchWithBootloader) Run(ctx *types.Context) error {
78
90
return nil
79
91
}
80
92
81
- mergedSketchPath := filepath .Join (filepath .Dir (builtSketchPath ), sketchFileName + ".with_bootloader.hex" )
93
+ mergedSketchPath := filepath .Join (filepath .Dir (builtSketchPath ), sketchFileName + ".with_bootloader" + extension )
82
94
83
- err := merge (builtSketchPath , bootloaderPath , mergedSketchPath )
95
+ var err error
96
+ if extension == ".hex" {
97
+ err = mergeHex (builtSketchPath , bootloaderPath , mergedSketchPath )
98
+ } else {
99
+ ldscript := buildProperties [constants .BUILD_PROPERTIES_BUILD_LDSCRIPT ]
100
+ variantFolder := buildProperties [constants .BUILD_PROPERTIES_BUILD_VARIANT_PATH ]
101
+ ldscriptPath := filepath .Join (variantFolder , ldscript )
102
+ err = mergeBin (builtSketchPath , ldscriptPath , bootloaderPath , mergedSketchPath )
103
+ }
84
104
85
105
return err
86
106
}
@@ -127,7 +147,7 @@ func extractActualBootloader(bootloader []string) []string {
127
147
return realBootloader
128
148
}
129
149
130
- func merge (builtSketchPath , bootloaderPath , mergedSketchPath string ) error {
150
+ func mergeHex (builtSketchPath , bootloaderPath , mergedSketchPath string ) error {
131
151
sketch , err := utils .ReadFileToRows (builtSketchPath )
132
152
if err != nil {
133
153
return i18n .WrapError (err )
@@ -147,3 +167,46 @@ func merge(builtSketchPath, bootloaderPath, mergedSketchPath string) error {
147
167
148
168
return utils .WriteFile (mergedSketchPath , strings .Join (sketch , "\n " ))
149
169
}
170
+
171
+ func mergeBin (builtSketchPath , ldscriptPath , bootloaderPath , mergedSketchPath string ) error {
172
+ // 0xFF means empty
173
+ // only works if the bootloader is at the beginning of the flash
174
+ // only works if the flash address space is mapped at 0x00
175
+
176
+ // METHOD 1: (non appliable to most architectures)
177
+ // remove all comments from linkerscript
178
+ // find NAMESPACE of .text section -> FLASH
179
+ // find ORIGIN of FLASH section
180
+
181
+ // METHOD 2:
182
+ // Round the bootloader to the next "power of 2" bytes boundary
183
+
184
+ // generate a byte[FLASH] full of 0xFF and bitwise OR with bootloader BIN
185
+ // merge this slice with sketch BIN
186
+
187
+ bootloader , _ := ioutil .ReadFile (bootloaderPath )
188
+ sketch , _ := ioutil .ReadFile (builtSketchPath )
189
+
190
+ paddedBootloaderLen := nextPowerOf2 (len (bootloader ))
191
+
192
+ padding := make ([]byte , paddedBootloaderLen - len (bootloader ))
193
+ for i , _ := range padding {
194
+ padding [i ] = 0xFF
195
+ }
196
+
197
+ bootloader = append (bootloader , padding ... )
198
+ sketch = append (bootloader , sketch ... )
199
+
200
+ return ioutil .WriteFile (mergedSketchPath , sketch , 0644 )
201
+ }
202
+
203
+ func nextPowerOf2 (v int ) int {
204
+ v --
205
+ v |= v >> 1
206
+ v |= v >> 2
207
+ v |= v >> 4
208
+ v |= v >> 8
209
+ v |= v >> 16
210
+ v ++
211
+ return v
212
+ }
0 commit comments