Skip to content

Commit ec44ad1

Browse files
cmaglieumbynos
authored andcommitted
Added external programmer support (arduino#720)
* Added scaffolding for external programmer support * Added programmers extraction in arduino/cores module * Implemented programmers list command * Print upload command line in verbose mode * Added programmer option to compile command * External programmer implementation * Factored function runTool in upload This will turn out useful for burn-bootloader that requires to run two actions in a row ("erase" and "bootloader"). * Implemented burn-bootloader * Increased tracing log * Test fix * Added BurnBootloder action * Make the upload port parameter mandatory only when really needed * Fixed nil pointer exception when burning-bootloader * Added sanity check on upload parameters
1 parent 4a5330a commit ec44ad1

File tree

20 files changed

+1198
-268
lines changed

20 files changed

+1198
-268
lines changed

arduino/cores/cores.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,14 @@ type PlatformRelease struct {
4040
Resource *resources.DownloadResource
4141
Version *semver.Version
4242
BoardsManifest []*BoardManifest
43-
Dependencies ToolDependencies // The Dependency entries to load tools.
44-
Platform *Platform `json:"-"`
45-
Properties *properties.Map `json:"-"`
46-
Boards map[string]*Board `json:"-"`
47-
Programmers map[string]*properties.Map `json:"-"`
48-
Menus *properties.Map `json:"-"`
49-
InstallDir *paths.Path `json:"-"`
50-
IsIDEBundled bool `json:"-"`
43+
Dependencies ToolDependencies // The Dependency entries to load tools.
44+
Platform *Platform `json:"-"`
45+
Properties *properties.Map `json:"-"`
46+
Boards map[string]*Board `json:"-"`
47+
Programmers map[string]*Programmer `json:"-"`
48+
Menus *properties.Map `json:"-"`
49+
InstallDir *paths.Path `json:"-"`
50+
IsIDEBundled bool `json:"-"`
5151
}
5252

5353
// BoardManifest contains information about a board. These metadata are usually
@@ -117,7 +117,7 @@ func (platform *Platform) GetOrCreateRelease(version *semver.Version) (*Platform
117117
Version: version,
118118
Boards: map[string]*Board{},
119119
Properties: properties.NewMap(),
120-
Programmers: map[string]*properties.Map{},
120+
Programmers: map[string]*Programmer{},
121121
Platform: platform,
122122
}
123123
platform.Releases[tag] = release

arduino/cores/packagemanager/loader.go

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -284,10 +284,10 @@ func (pm *PackageManager) loadPlatformRelease(platform *cores.PlatformRelease, p
284284

285285
// Create programmers properties
286286
if programmersProperties, err := properties.SafeLoad(programmersTxtPath.String()); err == nil {
287-
platform.Programmers = properties.MergeMapsOfProperties(
288-
map[string]*properties.Map{},
289-
platform.Programmers, // TODO: Very weird, why not an empty one?
290-
programmersProperties.FirstLevelOf())
287+
for programmerID, programmerProperties := range programmersProperties.FirstLevelOf() {
288+
platform.Programmers[programmerID] = pm.loadProgrammer(programmerProperties)
289+
platform.Programmers[programmerID].PlatformRelease = platform
290+
}
291291
} else {
292292
return err
293293
}
@@ -299,6 +299,13 @@ func (pm *PackageManager) loadPlatformRelease(platform *cores.PlatformRelease, p
299299
return nil
300300
}
301301

302+
func (pm *PackageManager) loadProgrammer(programmerProperties *properties.Map) *cores.Programmer {
303+
return &cores.Programmer{
304+
Name: programmerProperties.Get("name"),
305+
Properties: programmerProperties,
306+
}
307+
}
308+
302309
func (pm *PackageManager) loadBoards(platform *cores.PlatformRelease) error {
303310
if platform.InstallDir == nil {
304311
return fmt.Errorf("platform not installed")

arduino/cores/programmers.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// This file is part of arduino-cli.
2+
//
3+
// Copyright 2020 ARDUINO SA (http://www.arduino.cc/)
4+
//
5+
// This software is released under the GNU General Public License version 3,
6+
// which covers the main part of arduino-cli.
7+
// The terms of this license can be found at:
8+
// https://www.gnu.org/licenses/gpl-3.0.en.html
9+
//
10+
// You can be released from the requirements of the above licenses by purchasing
11+
// a commercial license. Buying such a license is mandatory if you want to
12+
// modify or otherwise use the software for commercial activities involving the
13+
// Arduino software without disclosing the source code of your own applications.
14+
// To purchase a commercial license, send an email to license@arduino.cc.
15+
16+
package cores
17+
18+
import "github.com/arduino/go-properties-orderedmap"
19+
20+
// Programmer represents an external programmer
21+
type Programmer struct {
22+
Name string
23+
Properties *properties.Map
24+
PlatformRelease *PlatformRelease
25+
}

cli/burnbootloader/burnbootloader.go

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
// This file is part of arduino-cli.
2+
//
3+
// Copyright 2020 ARDUINO SA (http://www.arduino.cc/)
4+
//
5+
// This software is released under the GNU General Public License version 3,
6+
// which covers the main part of arduino-cli.
7+
// The terms of this license can be found at:
8+
// https://www.gnu.org/licenses/gpl-3.0.en.html
9+
//
10+
// You can be released from the requirements of the above licenses by purchasing
11+
// a commercial license. Buying such a license is mandatory if you want to
12+
// modify or otherwise use the software for commercial activities involving the
13+
// Arduino software without disclosing the source code of your own applications.
14+
// To purchase a commercial license, send an email to license@arduino.cc.
15+
16+
package burnbootloader
17+
18+
import (
19+
"context"
20+
"os"
21+
22+
"github.com/arduino/arduino-cli/cli/errorcodes"
23+
"github.com/arduino/arduino-cli/cli/feedback"
24+
"github.com/arduino/arduino-cli/cli/instance"
25+
"github.com/arduino/arduino-cli/commands/upload"
26+
rpc "github.com/arduino/arduino-cli/rpc/commands"
27+
"github.com/arduino/arduino-cli/table"
28+
"github.com/arduino/go-paths-helper"
29+
"github.com/sirupsen/logrus"
30+
"github.com/spf13/cobra"
31+
)
32+
33+
var (
34+
fqbn string
35+
port string
36+
verbose bool
37+
verify bool
38+
importDir string
39+
programmer string
40+
burnBootloader bool
41+
)
42+
43+
// NewCommand created a new `burn-bootloader` command
44+
func NewCommand() *cobra.Command {
45+
burnBootloaderCommand := &cobra.Command{
46+
Use: "burn-bootloader",
47+
Short: "Upload the bootloader.",
48+
Long: "Upload the bootloader on the board using an external programmer.",
49+
Example: " " + os.Args[0] + " burn-bootloader -b arduino:avr:uno -P atmel-ice",
50+
Args: cobra.MaximumNArgs(1),
51+
Run: run,
52+
}
53+
54+
burnBootloaderCommand.Flags().StringVarP(&fqbn, "fqbn", "b", "", "Fully Qualified Board Name, e.g.: arduino:avr:uno")
55+
burnBootloaderCommand.Flags().StringVarP(&port, "port", "p", "", "Upload port, e.g.: COM10 or /dev/ttyACM0")
56+
burnBootloaderCommand.Flags().BoolVarP(&verify, "verify", "t", false, "Verify uploaded binary after the upload.")
57+
burnBootloaderCommand.Flags().BoolVarP(&verbose, "verbose", "v", false, "Turns on verbose mode.")
58+
burnBootloaderCommand.Flags().StringVarP(&programmer, "programmer", "P", "", "Use the specified programmer to upload or 'list' to list supported programmers.")
59+
60+
return burnBootloaderCommand
61+
}
62+
63+
func run(command *cobra.Command, args []string) {
64+
instance, err := instance.CreateInstance()
65+
if err != nil {
66+
feedback.Errorf("Error during Upload: %v", err)
67+
os.Exit(errorcodes.ErrGeneric)
68+
}
69+
70+
if programmer == "list" {
71+
resp, err := upload.ListProgrammersAvailableForUpload(context.Background(), &rpc.ListProgrammersAvailableForUploadReq{
72+
Instance: instance,
73+
Fqbn: fqbn,
74+
})
75+
if err != nil {
76+
feedback.Errorf("Error listing programmers: %v", err)
77+
os.Exit(errorcodes.ErrGeneric)
78+
}
79+
feedback.PrintResult(&programmersList{
80+
Programmers: resp.GetProgrammers(),
81+
})
82+
os.Exit(0)
83+
}
84+
85+
if _, err := upload.BurnBootloader(context.Background(), &rpc.BurnBootloaderReq{
86+
Instance: instance,
87+
Fqbn: fqbn,
88+
Port: port,
89+
Verbose: verbose,
90+
Verify: verify,
91+
Programmer: programmer,
92+
}, os.Stdout, os.Stderr); err != nil {
93+
feedback.Errorf("Error during Upload: %v", err)
94+
os.Exit(errorcodes.ErrGeneric)
95+
}
96+
os.Exit(0)
97+
}
98+
99+
// initSketchPath returns the current working directory
100+
func initSketchPath(sketchPath *paths.Path) *paths.Path {
101+
if sketchPath != nil {
102+
return sketchPath
103+
}
104+
105+
wd, err := paths.Getwd()
106+
if err != nil {
107+
feedback.Errorf("Couldn't get current working directory: %v", err)
108+
os.Exit(errorcodes.ErrGeneric)
109+
}
110+
logrus.Infof("Reading sketch from dir: %s", wd)
111+
return wd
112+
}
113+
114+
type programmersList struct {
115+
Programmers []*rpc.Programmer
116+
}
117+
118+
func (p *programmersList) Data() interface{} {
119+
return p.Programmers
120+
}
121+
122+
func (p *programmersList) String() string {
123+
t := table.New()
124+
t.SetHeader("ID", "Programmer Name", "Platform")
125+
for _, prog := range p.Programmers {
126+
t.AddRow(prog.GetId(), prog.GetName(), prog.GetPlatform())
127+
}
128+
return t.Render()
129+
}

cli/cli.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"strings"
2323

2424
"github.com/arduino/arduino-cli/cli/board"
25+
"github.com/arduino/arduino-cli/cli/burnbootloader"
2526
"github.com/arduino/arduino-cli/cli/cache"
2627
"github.com/arduino/arduino-cli/cli/compile"
2728
"github.com/arduino/arduino-cli/cli/completion"
@@ -87,6 +88,7 @@ func createCliCommandTree(cmd *cobra.Command) {
8788
cmd.AddCommand(sketch.NewCommand())
8889
cmd.AddCommand(upload.NewCommand())
8990
cmd.AddCommand(debug.NewCommand())
91+
cmd.AddCommand(burnbootloader.NewCommand())
9092
cmd.AddCommand(version.NewCommand())
9193

9294
cmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "Print the logs on the standard output.")

cli/compile/compile.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ var (
5050
dryRun bool // Use this flag to now write the output file
5151
libraries []string // List of custom libraries paths separated by commas. Or can be used multiple times for multiple libraries paths.
5252
optimizeForDebug bool // Optimize compile output for debug, not for release
53+
programmer string // Use the specified programmer to upload
5354
)
5455

5556
// NewCommand created a new `compile` command
@@ -84,6 +85,7 @@ func NewCommand() *cobra.Command {
8485
command.Flags().StringSliceVar(&libraries, "libraries", []string{},
8586
"List of custom libraries paths separated by commas. Or can be used multiple times for multiple libraries paths.")
8687
command.Flags().BoolVar(&optimizeForDebug, "optimize-for-debug", false, "Optional, optimize compile output for debug, not for release.")
88+
command.Flags().StringVarP(&programmer, "programmer", "P", "", "Optional, use the specified programmer to upload.")
8789

8890
return command
8991
}
@@ -135,6 +137,7 @@ func run(cmd *cobra.Command, args []string) {
135137
Verbose: verbose,
136138
Verify: verify,
137139
ImportDir: exportDir,
140+
Programmer: programmer,
138141
}, os.Stdout, os.Stderr)
139142

140143
if err != nil {

cli/upload/upload.go

Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,20 @@ import (
2424
"github.com/arduino/arduino-cli/cli/instance"
2525
"github.com/arduino/arduino-cli/commands/upload"
2626
rpc "github.com/arduino/arduino-cli/rpc/commands"
27+
"github.com/arduino/arduino-cli/table"
2728
"github.com/arduino/go-paths-helper"
2829
"github.com/sirupsen/logrus"
2930
"github.com/spf13/cobra"
3031
)
3132

3233
var (
33-
fqbn string
34-
port string
35-
verbose bool
36-
verify bool
37-
importDir string
34+
fqbn string
35+
port string
36+
verbose bool
37+
verify bool
38+
importDir string
39+
programmer string
40+
burnBootloader bool
3841
)
3942

4043
// NewCommand created a new `upload` command
@@ -53,6 +56,7 @@ func NewCommand() *cobra.Command {
5356
uploadCommand.Flags().StringVarP(&importDir, "input-dir", "", "", "Direcory containing binaries to upload.")
5457
uploadCommand.Flags().BoolVarP(&verify, "verify", "t", false, "Verify uploaded binary after the upload.")
5558
uploadCommand.Flags().BoolVarP(&verbose, "verbose", "v", false, "Optional, turns on verbose mode.")
59+
uploadCommand.Flags().StringVarP(&programmer, "programmer", "P", "", "Optional, use the specified programmer to upload or 'list' to list supported programmers.")
5660

5761
return uploadCommand
5862
}
@@ -64,12 +68,44 @@ func run(command *cobra.Command, args []string) {
6468
os.Exit(errorcodes.ErrGeneric)
6569
}
6670

71+
if programmer == "list" {
72+
resp, err := upload.ListProgrammersAvailableForUpload(context.Background(), &rpc.ListProgrammersAvailableForUploadReq{
73+
Instance: instance,
74+
Fqbn: fqbn,
75+
})
76+
if err != nil {
77+
feedback.Errorf("Error listing programmers: %v", err)
78+
os.Exit(errorcodes.ErrGeneric)
79+
}
80+
feedback.PrintResult(&programmersList{
81+
Programmers: resp.GetProgrammers(),
82+
})
83+
os.Exit(0)
84+
}
85+
6786
var path *paths.Path
6887
if len(args) > 0 {
6988
path = paths.New(args[0])
7089
}
7190
sketchPath := initSketchPath(path)
7291

92+
if burnBootloader {
93+
if _, err := upload.Upload(context.Background(), &rpc.UploadReq{
94+
Instance: instance,
95+
Fqbn: fqbn,
96+
SketchPath: sketchPath.String(),
97+
Port: port,
98+
Verbose: verbose,
99+
Verify: verify,
100+
ImportDir: importDir,
101+
Programmer: programmer,
102+
}, os.Stdout, os.Stderr); err != nil {
103+
feedback.Errorf("Error during Upload: %v", err)
104+
os.Exit(errorcodes.ErrGeneric)
105+
}
106+
os.Exit(0)
107+
}
108+
73109
if _, err := upload.Upload(context.Background(), &rpc.UploadReq{
74110
Instance: instance,
75111
Fqbn: fqbn,
@@ -78,6 +114,7 @@ func run(command *cobra.Command, args []string) {
78114
Verbose: verbose,
79115
Verify: verify,
80116
ImportDir: importDir,
117+
Programmer: programmer,
81118
}, os.Stdout, os.Stderr); err != nil {
82119
feedback.Errorf("Error during Upload: %v", err)
83120
os.Exit(errorcodes.ErrGeneric)
@@ -98,3 +135,20 @@ func initSketchPath(sketchPath *paths.Path) *paths.Path {
98135
logrus.Infof("Reading sketch from dir: %s", wd)
99136
return wd
100137
}
138+
139+
type programmersList struct {
140+
Programmers []*rpc.Programmer
141+
}
142+
143+
func (p *programmersList) Data() interface{} {
144+
return p.Programmers
145+
}
146+
147+
func (p *programmersList) String() string {
148+
t := table.New()
149+
t.SetHeader("ID", "Programmer Name", "Platform")
150+
for _, prog := range p.Programmers {
151+
t.AddRow(prog.GetId(), prog.GetName(), prog.GetPlatform())
152+
}
153+
return t.Render()
154+
}

commands/daemon/daemon.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,24 @@ func (s *ArduinoCoreServerImpl) Upload(req *rpc.UploadReq, stream rpc.ArduinoCor
216216
return stream.Send(resp)
217217
}
218218

219+
// BurnBootloader FIXMEDOC
220+
func (s *ArduinoCoreServerImpl) BurnBootloader(req *rpc.BurnBootloaderReq, stream rpc.ArduinoCore_BurnBootloaderServer) error {
221+
resp, err := upload.BurnBootloader(
222+
stream.Context(), req,
223+
utils.FeedStreamTo(func(data []byte) { stream.Send(&rpc.BurnBootloaderResp{OutStream: data}) }),
224+
utils.FeedStreamTo(func(data []byte) { stream.Send(&rpc.BurnBootloaderResp{ErrStream: data}) }),
225+
)
226+
if err != nil {
227+
return err
228+
}
229+
return stream.Send(resp)
230+
}
231+
232+
// ListProgrammersAvailableForUpload FIXMEDOC
233+
func (s *ArduinoCoreServerImpl) ListProgrammersAvailableForUpload(ctx context.Context, req *rpc.ListProgrammersAvailableForUploadReq) (*rpc.ListProgrammersAvailableForUploadResp, error) {
234+
return upload.ListProgrammersAvailableForUpload(ctx, req)
235+
}
236+
219237
// LibraryDownload FIXMEDOC
220238
func (s *ArduinoCoreServerImpl) LibraryDownload(req *rpc.LibraryDownloadReq, stream rpc.ArduinoCore_LibraryDownloadServer) error {
221239
resp, err := lib.LibraryDownload(

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy