Skip to content

Commit 02b9a41

Browse files
committed
Fixed skethbook+bootloader hex merger.
Previous merger doesn't take into account .bin bootloaders and it may have problems if .hex data is not sorted by address.
1 parent ded057e commit 02b9a41

File tree

4 files changed

+172
-60
lines changed

4 files changed

+172
-60
lines changed

Diff for: go.mod

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ require (
66
bou.ke/monkey v1.0.1
77
github.com/GeertJohan/go.rice v1.0.0
88
github.com/arduino/board-discovery v0.0.0-20180823133458-1ba29327fb0c
9-
github.com/arduino/go-paths-helper v1.0.1
9+
github.com/arduino/go-paths-helper v1.2.0
1010
github.com/arduino/go-properties-orderedmap v1.0.0
1111
github.com/arduino/go-timeutils v0.0.0-20171220113728-d1dd9e313b1b
1212
github.com/arduino/go-win32-utils v0.0.0-20180330194947-ed041402e83b
@@ -25,6 +25,7 @@ require (
2525
github.com/juju/loggo v0.0.0-20190526231331-6e530bcce5d8 // indirect
2626
github.com/juju/testing v0.0.0-20190429233213-dfc56b8c09fc // indirect
2727
github.com/leonelquinteros/gotext v1.4.0
28+
github.com/marcinbor85/gohex v0.0.0-20200531163658-baab2527a9a2
2829
github.com/mattn/go-colorable v0.1.2
2930
github.com/mattn/go-runewidth v0.0.2 // indirect
3031
github.com/miekg/dns v1.0.5 // indirect

Diff for: go.sum

+4
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ github.com/arduino/board-discovery v0.0.0-20180823133458-1ba29327fb0c h1:agh2JT9
1616
github.com/arduino/board-discovery v0.0.0-20180823133458-1ba29327fb0c/go.mod h1:HK7SpkEax/3P+0w78iRQx1sz1vCDYYw9RXwHjQTB5i8=
1717
github.com/arduino/go-paths-helper v1.0.1 h1:utYXLM2RfFlc9qp/MJTIYp3t6ux/xM6mWjeEb/WLK4Q=
1818
github.com/arduino/go-paths-helper v1.0.1/go.mod h1:HpxtKph+g238EJHq4geEPv9p+gl3v5YYu35Yb+w31Ck=
19+
github.com/arduino/go-paths-helper v1.2.0 h1:qDW93PR5IZUN/jzO4rCtexiwF8P4OIcOmcSgAYLZfY4=
20+
github.com/arduino/go-paths-helper v1.2.0/go.mod h1:HpxtKph+g238EJHq4geEPv9p+gl3v5YYu35Yb+w31Ck=
1921
github.com/arduino/go-properties-orderedmap v1.0.0 h1:caaM25TQZKkytoKQUsgqtOVbrM5i8Gb427JmW0KL05s=
2022
github.com/arduino/go-properties-orderedmap v1.0.0/go.mod h1:DKjD2VXY/NZmlingh4lSFMEYCVubfeArCsGPGDwb2yk=
2123
github.com/arduino/go-timeutils v0.0.0-20171220113728-d1dd9e313b1b h1:9hDi4F2st6dbLC3y4i02zFT5quS4X6iioWifGlVwfy4=
@@ -125,6 +127,8 @@ github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDe
125127
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
126128
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
127129
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
130+
github.com/marcinbor85/gohex v0.0.0-20200531163658-baab2527a9a2 h1:n7R8fUwWZUB2XtyzBNsYNNm9/XgOBj6pvLi7GLMCHtM=
131+
github.com/marcinbor85/gohex v0.0.0-20200531163658-baab2527a9a2/go.mod h1:Pb6XcsXyropB9LNHhnqaknG/vEwYztLkQzVCHv8sQ3M=
128132
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
129133
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
130134
github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE=

Diff for: legacy/builder/merge_sketch_with_bootloader.go

+68-47
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,15 @@
1616
package builder
1717

1818
import (
19+
"math"
1920
"os"
21+
"strconv"
2022
"strings"
2123

2224
"github.com/arduino/arduino-cli/legacy/builder/constants"
2325
"github.com/arduino/arduino-cli/legacy/builder/types"
2426
"github.com/arduino/go-paths-helper"
27+
"github.com/marcinbor85/gohex"
2528
"github.com/pkg/errors"
2629
)
2730

@@ -66,68 +69,86 @@ func (s *MergeSketchWithBootloader) Run(ctx *types.Context) error {
6669

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

69-
return merge(builtSketchPath, bootloaderPath, mergedSketchPath)
70-
}
71-
72-
func hexLineOnlyContainsFF(line string) bool {
73-
//:206FE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB1
74-
if len(line) <= 11 {
75-
return false
72+
// Ignore merger errors for the first iteration
73+
maximumBinSize := 16000000
74+
if uploadMaxSize, ok := ctx.BuildProperties.GetOk(constants.PROPERTY_UPLOAD_MAX_SIZE); ok {
75+
maximumBinSize, _ = strconv.Atoi(uploadMaxSize)
76+
maximumBinSize *= 2
7677
}
77-
byteArray := []byte(line)
78-
for _, char := range byteArray[9:(len(byteArray) - 2)] {
79-
if char != 'F' {
80-
return false
81-
}
78+
err := merge(builtSketchPath, bootloaderPath, mergedSketchPath, maximumBinSize)
79+
if err != nil {
80+
logger.Fprintln(os.Stdout, constants.LOG_LEVEL_WARN, err.Error())
8281
}
83-
return true
84-
}
85-
86-
func extractActualBootloader(bootloader []string) []string {
8782

88-
var realBootloader []string
83+
return nil
84+
}
8985

90-
// skip until we find a line full of FFFFFF (except address and checksum)
91-
for i, row := range bootloader {
92-
if hexLineOnlyContainsFF(row) {
93-
realBootloader = bootloader[i:len(bootloader)]
94-
break
95-
}
86+
func merge(builtSketchPath, bootloaderPath, mergedSketchPath *paths.Path, maximumBinSize int) error {
87+
if bootloaderPath.Ext() == ".bin" {
88+
bootloaderPath = paths.New(strings.TrimSuffix(bootloaderPath.String(), ".bin") + ".hex")
9689
}
9790

98-
// drop all "empty" lines
99-
for i, row := range realBootloader {
100-
if !hexLineOnlyContainsFF(row) {
101-
realBootloader = realBootloader[i:len(realBootloader)]
102-
break
91+
memBoot := gohex.NewMemory()
92+
if bootFile, err := bootloaderPath.Open(); err == nil {
93+
defer bootFile.Close()
94+
if err := memBoot.ParseIntelHex(bootFile); err != nil {
95+
return errors.New(bootFile.Name() + " " + err.Error())
10396
}
97+
} else {
98+
return err
10499
}
105100

106-
if len(realBootloader) == 0 {
107-
// we didn't find any line full of FFFF, thus it's a standalone bootloader
108-
realBootloader = bootloader
101+
memSketch := gohex.NewMemory()
102+
if buildFile, err := builtSketchPath.Open(); err == nil {
103+
defer buildFile.Close()
104+
if err := memSketch.ParseIntelHex(buildFile); err != nil {
105+
return errors.New(buildFile.Name() + " " + err.Error())
106+
}
107+
} else {
108+
return err
109109
}
110110

111-
return realBootloader
112-
}
111+
memMerged := gohex.NewMemory()
112+
initialAddress := uint32(math.MaxUint32)
113+
lastAddress := uint32(0)
113114

114-
func merge(builtSketchPath, bootloaderPath, mergedSketchPath *paths.Path) error {
115-
sketch, err := builtSketchPath.ReadFileAsLines()
116-
if err != nil {
117-
return errors.WithStack(err)
115+
for _, segment := range memBoot.GetDataSegments() {
116+
if err := memMerged.AddBinary(segment.Address, segment.Data); err != nil {
117+
continue
118+
}
119+
if segment.Address < initialAddress {
120+
initialAddress = segment.Address
121+
}
122+
if segment.Address+uint32(len(segment.Data)) > lastAddress {
123+
lastAddress = segment.Address + uint32(len(segment.Data))
124+
}
118125
}
119-
sketch = sketch[:len(sketch)-2]
120-
121-
bootloader, err := bootloaderPath.ReadFileAsLines()
122-
if err != nil {
123-
return errors.WithStack(err)
126+
for _, segment := range memSketch.GetDataSegments() {
127+
if err := memMerged.AddBinary(segment.Address, segment.Data); err != nil {
128+
continue
129+
}
130+
if segment.Address < initialAddress {
131+
initialAddress = segment.Address
132+
}
133+
if segment.Address+uint32(len(segment.Data)) > lastAddress {
134+
lastAddress = segment.Address + uint32(len(segment.Data))
135+
}
124136
}
125137

126-
realBootloader := extractActualBootloader(bootloader)
127-
128-
for _, row := range realBootloader {
129-
sketch = append(sketch, row)
138+
if mergeFile, err := mergedSketchPath.Create(); err == nil {
139+
defer mergeFile.Close()
140+
memMerged.DumpIntelHex(mergeFile, 16)
141+
} else {
142+
return err
130143
}
131144

132-
return mergedSketchPath.WriteFile([]byte(strings.Join(sketch, "\n")))
145+
// size := lastAddress - initialAddress
146+
// if size > uint32(maximumBinSize) {
147+
// return nil
148+
// }
149+
// mergedSketchPathBin := paths.New(strings.TrimSuffix(mergedSketchPath.String(), ".hex") + ".bin")
150+
// data := memMerged.ToBinary(initialAddress, size, 0xFF)
151+
// return mergedSketchPathBin.WriteFile(data)
152+
153+
return nil
133154
}

Diff for: legacy/builder/test/merge_sketch_with_bootloader_test.go

+98-12
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package test
1717

1818
import (
19+
"fmt"
1920
"path/filepath"
2021
"strings"
2122
"testing"
@@ -46,8 +47,36 @@ func TestMergeSketchWithBootloader(t *testing.T) {
4647
err := buildPath.Join("sketch").MkdirAll()
4748
NoError(t, err)
4849

49-
fakeSketchHex := "row 1\n" +
50-
"row 2\n"
50+
fakeSketchHex := `:100000000C9434000C9446000C9446000C9446006A
51+
:100010000C9446000C9446000C9446000C94460048
52+
:100020000C9446000C9446000C9446000C94460038
53+
:100030000C9446000C9446000C9446000C94460028
54+
:100040000C9448000C9446000C9446000C94460016
55+
:100050000C9446000C9446000C9446000C94460008
56+
:100060000C9446000C94460011241FBECFEFD8E03C
57+
:10007000DEBFCDBF21E0A0E0B1E001C01D92A930FC
58+
:10008000B207E1F70E9492000C94DC000C9400008F
59+
:100090001F920F920FB60F9211242F933F938F93BD
60+
:1000A0009F93AF93BF938091050190910601A0911A
61+
:1000B0000701B09108013091040123E0230F2D378F
62+
:1000C00020F40196A11DB11D05C026E8230F02965C
63+
:1000D000A11DB11D20930401809305019093060199
64+
:1000E000A0930701B0930801809100019091010154
65+
:1000F000A0910201B09103010196A11DB11D809351
66+
:10010000000190930101A0930201B0930301BF91FC
67+
:10011000AF919F918F913F912F910F900FBE0F90B4
68+
:100120001F901895789484B5826084BD84B58160F1
69+
:1001300084BD85B5826085BD85B5816085BD8091B2
70+
:100140006E00816080936E0010928100809181002A
71+
:100150008260809381008091810081608093810022
72+
:10016000809180008160809380008091B1008460E4
73+
:100170008093B1008091B00081608093B000809145
74+
:100180007A00846080937A0080917A008260809304
75+
:100190007A0080917A00816080937A0080917A0061
76+
:1001A000806880937A001092C100C0E0D0E0209770
77+
:0C01B000F1F30E940000FBCFF894FFCF99
78+
:00000001FF
79+
`
5180
err = buildPath.Join("sketch", "sketch.ino.hex").WriteFile([]byte(fakeSketchHex))
5281
NoError(t, err)
5382

@@ -65,8 +94,8 @@ func TestMergeSketchWithBootloader(t *testing.T) {
6594
NoError(t, err)
6695
mergedSketchHex := string(bytes)
6796

68-
require.True(t, strings.HasPrefix(mergedSketchHex, "row 1\n:107E0000112484B714BE81FFF0D085E080938100F7\n"))
69-
require.True(t, strings.HasSuffix(mergedSketchHex, ":0400000300007E007B\n:00000001FF\n"))
97+
require.Contains(t, mergedSketchHex, ":100000000C9434000C9446000C9446000C9446006A\n")
98+
require.True(t, strings.HasSuffix(mergedSketchHex, ":00000001FF\n"))
7099
}
71100

72101
func TestMergeSketchWithBootloaderSketchInBuildPath(t *testing.T) {
@@ -88,8 +117,36 @@ func TestMergeSketchWithBootloaderSketchInBuildPath(t *testing.T) {
88117
err := buildPath.Join("sketch").MkdirAll()
89118
NoError(t, err)
90119

91-
fakeSketchHex := "row 1\n" +
92-
"row 2\n"
120+
fakeSketchHex := `:100000000C9434000C9446000C9446000C9446006A
121+
:100010000C9446000C9446000C9446000C94460048
122+
:100020000C9446000C9446000C9446000C94460038
123+
:100030000C9446000C9446000C9446000C94460028
124+
:100040000C9448000C9446000C9446000C94460016
125+
:100050000C9446000C9446000C9446000C94460008
126+
:100060000C9446000C94460011241FBECFEFD8E03C
127+
:10007000DEBFCDBF21E0A0E0B1E001C01D92A930FC
128+
:10008000B207E1F70E9492000C94DC000C9400008F
129+
:100090001F920F920FB60F9211242F933F938F93BD
130+
:1000A0009F93AF93BF938091050190910601A0911A
131+
:1000B0000701B09108013091040123E0230F2D378F
132+
:1000C00020F40196A11DB11D05C026E8230F02965C
133+
:1000D000A11DB11D20930401809305019093060199
134+
:1000E000A0930701B0930801809100019091010154
135+
:1000F000A0910201B09103010196A11DB11D809351
136+
:10010000000190930101A0930201B0930301BF91FC
137+
:10011000AF919F918F913F912F910F900FBE0F90B4
138+
:100120001F901895789484B5826084BD84B58160F1
139+
:1001300084BD85B5826085BD85B5816085BD8091B2
140+
:100140006E00816080936E0010928100809181002A
141+
:100150008260809381008091810081608093810022
142+
:10016000809180008160809380008091B1008460E4
143+
:100170008093B1008091B00081608093B000809145
144+
:100180007A00846080937A0080917A008260809304
145+
:100190007A0080917A00816080937A0080917A0061
146+
:1001A000806880937A001092C100C0E0D0E0209770
147+
:0C01B000F1F30E940000FBCFF894FFCF99
148+
:00000001FF
149+
`
93150
err = buildPath.Join("sketch.ino.hex").WriteFile([]byte(fakeSketchHex))
94151
NoError(t, err)
95152

@@ -107,8 +164,9 @@ func TestMergeSketchWithBootloaderSketchInBuildPath(t *testing.T) {
107164
NoError(t, err)
108165
mergedSketchHex := string(bytes)
109166

110-
require.True(t, strings.HasPrefix(mergedSketchHex, "row 1\n:107E0000112484B714BE81FFF0D085E080938100F7\n"))
111-
require.True(t, strings.HasSuffix(mergedSketchHex, ":0400000300007E007B\n:00000001FF\n"))
167+
fmt.Println(string(mergedSketchHex))
168+
require.Contains(t, mergedSketchHex, ":100000000C9434000C9446000C9446000C9446006A\n")
169+
require.True(t, strings.HasSuffix(mergedSketchHex, ":00000001FF\n"))
112170
}
113171

114172
func TestMergeSketchWithBootloaderWhenNoBootloaderAvailable(t *testing.T) {
@@ -168,8 +226,36 @@ func TestMergeSketchWithBootloaderPathIsParameterized(t *testing.T) {
168226
err := buildPath.Join("sketch").MkdirAll()
169227
NoError(t, err)
170228

171-
fakeSketchHex := "row 1\n" +
172-
"row 2\n"
229+
fakeSketchHex := `:100000000C9434000C9446000C9446000C9446006A
230+
:100010000C9446000C9446000C9446000C94460048
231+
:100020000C9446000C9446000C9446000C94460038
232+
:100030000C9446000C9446000C9446000C94460028
233+
:100040000C9448000C9446000C9446000C94460016
234+
:100050000C9446000C9446000C9446000C94460008
235+
:100060000C9446000C94460011241FBECFEFD8E03C
236+
:10007000DEBFCDBF21E0A0E0B1E001C01D92A930FC
237+
:10008000B207E1F70E9492000C94DC000C9400008F
238+
:100090001F920F920FB60F9211242F933F938F93BD
239+
:1000A0009F93AF93BF938091050190910601A0911A
240+
:1000B0000701B09108013091040123E0230F2D378F
241+
:1000C00020F40196A11DB11D05C026E8230F02965C
242+
:1000D000A11DB11D20930401809305019093060199
243+
:1000E000A0930701B0930801809100019091010154
244+
:1000F000A0910201B09103010196A11DB11D809351
245+
:10010000000190930101A0930201B0930301BF91FC
246+
:10011000AF919F918F913F912F910F900FBE0F90B4
247+
:100120001F901895789484B5826084BD84B58160F1
248+
:1001300084BD85B5826085BD85B5816085BD8091B2
249+
:100140006E00816080936E0010928100809181002A
250+
:100150008260809381008091810081608093810022
251+
:10016000809180008160809380008091B1008460E4
252+
:100170008093B1008091B00081608093B000809145
253+
:100180007A00846080937A0080917A008260809304
254+
:100190007A0080917A00816080937A0080917A0061
255+
:1001A000806880937A001092C100C0E0D0E0209770
256+
:0C01B000F1F30E940000FBCFF894FFCF99
257+
:00000001FF
258+
`
173259
err = buildPath.Join("sketch", "sketch.ino.hex").WriteFile([]byte(fakeSketchHex))
174260
NoError(t, err)
175261

@@ -187,6 +273,6 @@ func TestMergeSketchWithBootloaderPathIsParameterized(t *testing.T) {
187273
NoError(t, err)
188274
mergedSketchHex := string(bytes)
189275

190-
require.True(t, strings.HasPrefix(mergedSketchHex, "row 1\n:020000023000CC"))
191-
require.True(t, strings.HasSuffix(mergedSketchHex, ":040000033000E000E9\n:00000001FF\n"))
276+
require.Contains(t, mergedSketchHex, ":100000000C9434000C9446000C9446000C9446006A\n")
277+
require.True(t, strings.HasSuffix(mergedSketchHex, ":00000001FF\n"))
192278
}

0 commit comments

Comments
 (0)