@@ -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 p == port {
176- if req .GetVerbose () {
177- outStream .Write ([]byte (fmt .Sprintf ("Performing 1200-bps touch reset on serial port %s" , p )))
178- outStream .Write ([]byte (fmt .Sprintln ()))
179- }
180- if err := touchSerialPortAt1200bps (p ); err != nil {
181- return nil , fmt .Errorf ("cannot perform reset: %s" , err )
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 )
203+ }
204+ for _ , p := range ports {
205+ if p == port {
206+ if req .GetVerbose () {
207+ outStream .Write ([]byte (fmt .Sprintf ("Performing 1200-bps touch reset on serial port %s" , p )))
208+ outStream .Write ([]byte (fmt .Sprintln ()))
209+ }
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