Skip to content

Commit e251045

Browse files
committed
External programmer implementation
1 parent 8d2e4a7 commit e251045

File tree

1 file changed

+99
-64
lines changed

1 file changed

+99
-64
lines changed

commands/upload/upload.go

Lines changed: 99 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"time"
2525

2626
"github.com/arduino/arduino-cli/arduino/cores"
27+
"github.com/arduino/arduino-cli/arduino/cores/packagemanager"
2728
"github.com/arduino/arduino-cli/arduino/sketches"
2829
"github.com/arduino/arduino-cli/cli/feedback"
2930
"github.com/arduino/arduino-cli/commands"
@@ -80,45 +81,62 @@ func Upload(ctx context.Context, req *rpc.UploadReq, outStream io.Writer, errStr
8081
pm := commands.GetPackageManager(req.GetInstance().GetId())
8182

8283
// Find target board and board properties
83-
_, _, board, boardProperties, _, err := pm.ResolveFQBN(fqbn)
84+
_, boardPlatform, board, boardProperties, buildPlatform, err := pm.ResolveFQBN(fqbn)
8485
if err != nil {
8586
return nil, fmt.Errorf("incorrect FQBN: %s", err)
8687
}
8788

88-
// Load programmer tool
89-
uploadToolPattern, have := boardProperties.GetOk("upload.tool")
90-
if !have || uploadToolPattern == "" {
91-
return nil, fmt.Errorf("cannot get programmer tool: undefined 'upload.tool' property")
92-
}
93-
94-
var referencedPlatformRelease *cores.PlatformRelease
95-
if split := strings.Split(uploadToolPattern, ":"); len(split) > 2 {
96-
return nil, fmt.Errorf("invalid 'upload.tool' property: %s", uploadToolPattern)
97-
} else if len(split) == 2 {
98-
referencedPackageName := split[0]
99-
uploadToolPattern = split[1]
100-
architecture := board.PlatformRelease.Platform.Architecture
101-
102-
if referencedPackage := pm.Packages[referencedPackageName]; referencedPackage == nil {
103-
return nil, fmt.Errorf("required platform %s:%s not installed", referencedPackageName, architecture)
104-
} else if referencedPlatform := referencedPackage.Platforms[architecture]; referencedPlatform == nil {
105-
return nil, fmt.Errorf("required platform %s:%s not installed", referencedPackageName, architecture)
106-
} else {
107-
referencedPlatformRelease = pm.GetInstalledPlatformRelease(referencedPlatform)
89+
// Load upload tool definitions
90+
var uploadToolName string
91+
var uploadToolPlatform *cores.PlatformRelease
92+
var programmer *cores.Programmer
93+
if programmerID := req.GetProgrammer(); programmerID != "" {
94+
programmer = boardPlatform.Programmers[programmerID]
95+
if programmer == nil {
96+
// Try to find the programmer in the referenced build platform
97+
programmer = buildPlatform.Programmers[programmerID]
98+
}
99+
if programmer == nil {
100+
return nil, fmt.Errorf("programmer '%s' not available", programmerID)
101+
}
102+
uploadToolName = programmer.Properties.Get("program.tool")
103+
uploadToolPlatform = programmer.PlatformRelease
104+
if uploadToolName == "" {
105+
return nil, fmt.Errorf("cannot get programmer tool: undefined 'program.tool' property")
106+
}
107+
} else {
108+
uploadToolName = boardProperties.Get("upload.tool")
109+
uploadToolPlatform = boardPlatform
110+
if uploadToolName == "" {
111+
return nil, fmt.Errorf("cannot get upload tool: undefined 'upload.tool' property")
112+
}
113+
if split := strings.Split(uploadToolName, ":"); len(split) > 2 {
114+
return nil, fmt.Errorf("invalid 'upload.tool' property: %s", uploadToolName)
115+
} else if len(split) == 2 {
116+
uploadToolName = split[1]
117+
uploadToolPlatform = pm.GetInstalledPlatformRelease(
118+
pm.FindPlatform(&packagemanager.PlatformReference{
119+
Package: split[0],
120+
PlatformArchitecture: boardPlatform.Platform.Architecture,
121+
}),
122+
)
108123
}
109124
}
110125

111126
// Build configuration for upload
112127
uploadProperties := properties.NewMap()
113-
if referencedPlatformRelease != nil {
114-
uploadProperties.Merge(referencedPlatformRelease.Properties)
128+
if uploadToolPlatform != nil {
129+
uploadProperties.Merge(uploadToolPlatform.Properties)
115130
}
116-
uploadProperties.Merge(board.PlatformRelease.Properties)
117-
uploadProperties.Merge(board.PlatformRelease.RuntimeProperties())
131+
uploadProperties.Merge(boardPlatform.Properties)
132+
uploadProperties.Merge(boardPlatform.RuntimeProperties())
118133
uploadProperties.Merge(boardProperties)
119134

120-
uploadToolProperties := uploadProperties.SubTree("tools." + uploadToolPattern)
135+
uploadToolProperties := uploadProperties.SubTree("tools." + uploadToolName)
121136
uploadProperties.Merge(uploadToolProperties)
137+
if programmer != nil {
138+
uploadProperties.Merge(programmer.Properties)
139+
}
122140

123141
if requiredTools, err := pm.FindToolsRequiredForBoard(board); err == nil {
124142
for _, requiredTool := range requiredTools {
@@ -132,17 +150,25 @@ func Upload(ctx context.Context, req *rpc.UploadReq, outStream io.Writer, errStr
132150
if v, ok := uploadProperties.GetOk("upload.params.verbose"); ok {
133151
uploadProperties.Set("upload.verbose", v)
134152
}
153+
if v, ok := uploadProperties.GetOk("program.params.verbose"); ok {
154+
uploadProperties.Set("program.verbose", v)
155+
}
135156
} else {
136157
if v, ok := uploadProperties.GetOk("upload.params.quiet"); ok {
137158
uploadProperties.Set("upload.verbose", v)
138159
}
160+
if v, ok := uploadProperties.GetOk("program.params.quiet"); ok {
161+
uploadProperties.Set("program.verbose", v)
162+
}
139163
}
140164

141165
// Set properties for verify
142166
if req.GetVerify() {
143167
uploadProperties.Set("upload.verify", uploadProperties.Get("upload.params.verify"))
168+
uploadProperties.Set("program.verify", uploadProperties.Get("program.params.verify"))
144169
} else {
145170
uploadProperties.Set("upload.verify", uploadProperties.Get("upload.params.noverify"))
171+
uploadProperties.Set("program.verify", uploadProperties.Get("program.params.noverify"))
146172
}
147173

148174
var importPath *paths.Path
@@ -165,50 +191,54 @@ func Upload(ctx context.Context, req *rpc.UploadReq, outStream io.Writer, errStr
165191
uploadProperties.SetPath("build.path", importPath)
166192
uploadProperties.Set("build.project_name", sketch.Name+".ino")
167193

168-
// Perform reset via 1200bps touch if requested
169-
if uploadProperties.GetBoolean("upload.use_1200bps_touch") {
170-
ports, err := serial.GetPortsList()
171-
if err != nil {
172-
return nil, fmt.Errorf("cannot get serial port list: %s", err)
173-
}
174-
for _, p := range ports {
175-
if req.GetVerbose() {
176-
outStream.Write([]byte(fmt.Sprintf("Performing 1200-bps touch reset on serial port %s", p)))
177-
outStream.Write([]byte(fmt.Sprintln()))
194+
// If not using programmer perform some action required
195+
// to set the board in bootloader mode
196+
actualPort := port
197+
if programmer == nil {
198+
// Perform reset via 1200bps touch if requested
199+
if uploadProperties.GetBoolean("upload.use_1200bps_touch") {
200+
ports, err := serial.GetPortsList()
201+
if err != nil {
202+
return nil, fmt.Errorf("cannot get serial port list: %s", err)
178203
}
179-
if p == port {
180-
if err := touchSerialPortAt1200bps(p); err != nil {
181-
return nil, fmt.Errorf("cannot perform reset: %s", err)
204+
for _, p := range ports {
205+
if req.GetVerbose() {
206+
outStream.Write([]byte(fmt.Sprintf("Performing 1200-bps touch reset on serial port %s", p)))
207+
outStream.Write([]byte(fmt.Sprintln()))
208+
}
209+
if p == port {
210+
if err := touchSerialPortAt1200bps(p); err != nil {
211+
return nil, fmt.Errorf("cannot perform reset: %s", err)
212+
}
213+
break
182214
}
183-
break
184215
}
216+
217+
// Scanning for available ports seems to open the port or
218+
// otherwise assert DTR, which would cancel the WDT reset if
219+
// it happened within 250 ms. So we wait until the reset should
220+
// have already occurred before we start scanning.
221+
time.Sleep(500 * time.Millisecond)
185222
}
186223

187-
// Scanning for available ports seems to open the port or
188-
// otherwise assert DTR, which would cancel the WDT reset if
189-
// it happened within 250 ms. So we wait until the reset should
190-
// have already occurred before we start scanning.
191-
time.Sleep(500 * time.Millisecond)
192-
}
224+
// Wait for upload port if requested
225+
if uploadProperties.GetBoolean("upload.wait_for_upload_port") {
226+
if req.GetVerbose() {
227+
outStream.Write([]byte(fmt.Sprintln("Waiting for upload port...")))
228+
}
229+
if p, err := waitForNewSerialPort(); err != nil {
230+
return nil, fmt.Errorf("cannot detect serial ports: %s", err)
231+
} else if p == "" {
232+
feedback.Print("No new serial port detected.")
233+
} else {
234+
actualPort = p
235+
}
193236

194-
// Wait for upload port if requested
195-
actualPort := port // default
196-
if uploadProperties.GetBoolean("upload.wait_for_upload_port") {
197-
if req.GetVerbose() {
198-
outStream.Write([]byte(fmt.Sprintln("Waiting for upload port...")))
199-
}
200-
if p, err := waitForNewSerialPort(); err != nil {
201-
return nil, fmt.Errorf("cannot detect serial ports: %s", err)
202-
} else if p == "" {
203-
feedback.Print("No new serial port detected.")
204-
} else {
205-
actualPort = p
237+
// on OS X, if the port is opened too quickly after it is detected,
238+
// a "Resource busy" error occurs, add a delay to workaround.
239+
// This apply to other platforms as well.
240+
time.Sleep(500 * time.Millisecond)
206241
}
207-
208-
// on OS X, if the port is opened too quickly after it is detected,
209-
// a "Resource busy" error occurs, add a delay to workaround.
210-
// This apply to other platforms as well.
211-
time.Sleep(500 * time.Millisecond)
212242
}
213243

214244
// Set serial port property
@@ -220,7 +250,12 @@ func Upload(ctx context.Context, req *rpc.UploadReq, outStream io.Writer, errStr
220250
}
221251

222252
// Build recipe for upload
223-
recipe := uploadProperties.Get("upload.pattern")
253+
var recipe string
254+
if programmer != nil {
255+
recipe = uploadProperties.Get("program.pattern")
256+
} else {
257+
recipe = uploadProperties.Get("upload.pattern")
258+
}
224259
cmdLine := uploadProperties.ExpandPropsInString(recipe)
225260
if req.GetVerbose() {
226261
outStream.Write([]byte(fmt.Sprintln(cmdLine)))

0 commit comments

Comments
 (0)