Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added external programmer support #720

Merged
merged 14 commits into from
Jun 15, 2020
Merged
18 changes: 9 additions & 9 deletions arduino/cores/cores.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,14 @@ type PlatformRelease struct {
Resource *resources.DownloadResource
Version *semver.Version
BoardsManifest []*BoardManifest
Dependencies ToolDependencies // The Dependency entries to load tools.
Platform *Platform `json:"-"`
Properties *properties.Map `json:"-"`
Boards map[string]*Board `json:"-"`
Programmers map[string]*properties.Map `json:"-"`
Menus *properties.Map `json:"-"`
InstallDir *paths.Path `json:"-"`
IsIDEBundled bool `json:"-"`
Dependencies ToolDependencies // The Dependency entries to load tools.
Platform *Platform `json:"-"`
Properties *properties.Map `json:"-"`
Boards map[string]*Board `json:"-"`
Programmers map[string]*Programmer `json:"-"`
Menus *properties.Map `json:"-"`
InstallDir *paths.Path `json:"-"`
IsIDEBundled bool `json:"-"`
}

// BoardManifest contains information about a board. These metadata are usually
Expand Down Expand Up @@ -117,7 +117,7 @@ func (platform *Platform) GetOrCreateRelease(version *semver.Version) (*Platform
Version: version,
Boards: map[string]*Board{},
Properties: properties.NewMap(),
Programmers: map[string]*properties.Map{},
Programmers: map[string]*Programmer{},
Platform: platform,
}
platform.Releases[tag] = release
Expand Down
15 changes: 11 additions & 4 deletions arduino/cores/packagemanager/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -284,10 +284,10 @@ func (pm *PackageManager) loadPlatformRelease(platform *cores.PlatformRelease, p

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

func (pm *PackageManager) loadProgrammer(programmerProperties *properties.Map) *cores.Programmer {
return &cores.Programmer{
Name: programmerProperties.Get("name"),
Properties: programmerProperties,
}
}

func (pm *PackageManager) loadBoards(platform *cores.PlatformRelease) error {
if platform.InstallDir == nil {
return fmt.Errorf("platform not installed")
Expand Down
25 changes: 25 additions & 0 deletions arduino/cores/programmers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// This file is part of arduino-cli.
//
// Copyright 2020 ARDUINO SA (http://www.arduino.cc/)
//
// This software is released under the GNU General Public License version 3,
// which covers the main part of arduino-cli.
// The terms of this license can be found at:
// https://www.gnu.org/licenses/gpl-3.0.en.html
//
// You can be released from the requirements of the above licenses by purchasing
// a commercial license. Buying such a license is mandatory if you want to
// modify or otherwise use the software for commercial activities involving the
// Arduino software without disclosing the source code of your own applications.
// To purchase a commercial license, send an email to [email protected].

package cores

import "github.com/arduino/go-properties-orderedmap"

// Programmer represents an external programmer
type Programmer struct {
Name string
Properties *properties.Map
PlatformRelease *PlatformRelease
}
129 changes: 129 additions & 0 deletions cli/burnbootloader/burnbootloader.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
// This file is part of arduino-cli.
//
// Copyright 2020 ARDUINO SA (http://www.arduino.cc/)
//
// This software is released under the GNU General Public License version 3,
// which covers the main part of arduino-cli.
// The terms of this license can be found at:
// https://www.gnu.org/licenses/gpl-3.0.en.html
//
// You can be released from the requirements of the above licenses by purchasing
// a commercial license. Buying such a license is mandatory if you want to
// modify or otherwise use the software for commercial activities involving the
// Arduino software without disclosing the source code of your own applications.
// To purchase a commercial license, send an email to [email protected].

package burnbootloader

import (
"context"
"os"

"github.com/arduino/arduino-cli/cli/errorcodes"
"github.com/arduino/arduino-cli/cli/feedback"
"github.com/arduino/arduino-cli/cli/instance"
"github.com/arduino/arduino-cli/commands/upload"
rpc "github.com/arduino/arduino-cli/rpc/commands"
"github.com/arduino/arduino-cli/table"
"github.com/arduino/go-paths-helper"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)

var (
fqbn string
port string
verbose bool
verify bool
importDir string
programmer string
burnBootloader bool
)

// NewCommand created a new `burn-bootloader` command
func NewCommand() *cobra.Command {
burnBootloaderCommand := &cobra.Command{
Use: "burn-bootloader",
Short: "Upload the bootloader.",
Long: "Upload the bootloader on the board using an external programmer.",
Example: " " + os.Args[0] + " burn-bootloader -b arduino:avr:uno -P atmel-ice",
Args: cobra.MaximumNArgs(1),
Run: run,
}

burnBootloaderCommand.Flags().StringVarP(&fqbn, "fqbn", "b", "", "Fully Qualified Board Name, e.g.: arduino:avr:uno")
burnBootloaderCommand.Flags().StringVarP(&port, "port", "p", "", "Upload port, e.g.: COM10 or /dev/ttyACM0")
burnBootloaderCommand.Flags().BoolVarP(&verify, "verify", "t", false, "Verify uploaded binary after the upload.")
burnBootloaderCommand.Flags().BoolVarP(&verbose, "verbose", "v", false, "Turns on verbose mode.")
burnBootloaderCommand.Flags().StringVarP(&programmer, "programmer", "P", "", "Use the specified programmer to upload or 'list' to list supported programmers.")

return burnBootloaderCommand
}

func run(command *cobra.Command, args []string) {
instance, err := instance.CreateInstance()
if err != nil {
feedback.Errorf("Error during Upload: %v", err)
os.Exit(errorcodes.ErrGeneric)
}

if programmer == "list" {
resp, err := upload.ListProgrammersAvailableForUpload(context.Background(), &rpc.ListProgrammersAvailableForUploadReq{
Instance: instance,
Fqbn: fqbn,
})
if err != nil {
feedback.Errorf("Error listing programmers: %v", err)
os.Exit(errorcodes.ErrGeneric)
}
feedback.PrintResult(&programmersList{
Programmers: resp.GetProgrammers(),
})
os.Exit(0)
}

if _, err := upload.BurnBootloader(context.Background(), &rpc.BurnBootloaderReq{
Instance: instance,
Fqbn: fqbn,
Port: port,
Verbose: verbose,
Verify: verify,
Programmer: programmer,
}, os.Stdout, os.Stderr); err != nil {
feedback.Errorf("Error during Upload: %v", err)
os.Exit(errorcodes.ErrGeneric)
}
os.Exit(0)
}

// initSketchPath returns the current working directory
func initSketchPath(sketchPath *paths.Path) *paths.Path {
if sketchPath != nil {
return sketchPath
}

wd, err := paths.Getwd()
if err != nil {
feedback.Errorf("Couldn't get current working directory: %v", err)
os.Exit(errorcodes.ErrGeneric)
}
logrus.Infof("Reading sketch from dir: %s", wd)
return wd
}

type programmersList struct {
Programmers []*rpc.Programmer
}

func (p *programmersList) Data() interface{} {
return p.Programmers
}

func (p *programmersList) String() string {
t := table.New()
t.SetHeader("ID", "Programmer Name", "Platform")
for _, prog := range p.Programmers {
t.AddRow(prog.GetId(), prog.GetName(), prog.GetPlatform())
}
return t.Render()
}
2 changes: 2 additions & 0 deletions cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"strings"

"github.com/arduino/arduino-cli/cli/board"
"github.com/arduino/arduino-cli/cli/burnbootloader"
"github.com/arduino/arduino-cli/cli/cache"
"github.com/arduino/arduino-cli/cli/compile"
"github.com/arduino/arduino-cli/cli/completion"
Expand Down Expand Up @@ -87,6 +88,7 @@ func createCliCommandTree(cmd *cobra.Command) {
cmd.AddCommand(sketch.NewCommand())
cmd.AddCommand(upload.NewCommand())
cmd.AddCommand(debug.NewCommand())
cmd.AddCommand(burnbootloader.NewCommand())
cmd.AddCommand(version.NewCommand())

cmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "Print the logs on the standard output.")
Expand Down
3 changes: 3 additions & 0 deletions cli/compile/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ var (
dryRun bool // Use this flag to now write the output file
libraries []string // List of custom libraries paths separated by commas. Or can be used multiple times for multiple libraries paths.
optimizeForDebug bool // Optimize compile output for debug, not for release
programmer string // Use the specified programmer to upload
)

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

return command
}
Expand Down Expand Up @@ -135,6 +137,7 @@ func run(cmd *cobra.Command, args []string) {
Verbose: verbose,
Verify: verify,
ImportDir: exportDir,
Programmer: programmer,
}, os.Stdout, os.Stderr)

if err != nil {
Expand Down
64 changes: 59 additions & 5 deletions cli/upload/upload.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,20 @@ import (
"github.com/arduino/arduino-cli/cli/instance"
"github.com/arduino/arduino-cli/commands/upload"
rpc "github.com/arduino/arduino-cli/rpc/commands"
"github.com/arduino/arduino-cli/table"
"github.com/arduino/go-paths-helper"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)

var (
fqbn string
port string
verbose bool
verify bool
importDir string
fqbn string
port string
verbose bool
verify bool
importDir string
programmer string
burnBootloader bool
)

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

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

if programmer == "list" {
resp, err := upload.ListProgrammersAvailableForUpload(context.Background(), &rpc.ListProgrammersAvailableForUploadReq{
Instance: instance,
Fqbn: fqbn,
})
if err != nil {
feedback.Errorf("Error listing programmers: %v", err)
os.Exit(errorcodes.ErrGeneric)
}
feedback.PrintResult(&programmersList{
Programmers: resp.GetProgrammers(),
})
os.Exit(0)
}

var path *paths.Path
if len(args) > 0 {
path = paths.New(args[0])
}
sketchPath := initSketchPath(path)

if burnBootloader {
if _, err := upload.Upload(context.Background(), &rpc.UploadReq{
Instance: instance,
Fqbn: fqbn,
SketchPath: sketchPath.String(),
Port: port,
Verbose: verbose,
Verify: verify,
ImportDir: importDir,
Programmer: programmer,
}, os.Stdout, os.Stderr); err != nil {
feedback.Errorf("Error during Upload: %v", err)
os.Exit(errorcodes.ErrGeneric)
}
os.Exit(0)
}

if _, err := upload.Upload(context.Background(), &rpc.UploadReq{
Instance: instance,
Fqbn: fqbn,
Expand All @@ -78,6 +114,7 @@ func run(command *cobra.Command, args []string) {
Verbose: verbose,
Verify: verify,
ImportDir: importDir,
Programmer: programmer,
}, os.Stdout, os.Stderr); err != nil {
feedback.Errorf("Error during Upload: %v", err)
os.Exit(errorcodes.ErrGeneric)
Expand All @@ -98,3 +135,20 @@ func initSketchPath(sketchPath *paths.Path) *paths.Path {
logrus.Infof("Reading sketch from dir: %s", wd)
return wd
}

type programmersList struct {
Programmers []*rpc.Programmer
}

func (p *programmersList) Data() interface{} {
return p.Programmers
}

func (p *programmersList) String() string {
t := table.New()
t.SetHeader("ID", "Programmer Name", "Platform")
for _, prog := range p.Programmers {
t.AddRow(prog.GetId(), prog.GetName(), prog.GetPlatform())
}
return t.Render()
}
18 changes: 18 additions & 0 deletions commands/daemon/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,24 @@ func (s *ArduinoCoreServerImpl) Upload(req *rpc.UploadReq, stream rpc.ArduinoCor
return stream.Send(resp)
}

// BurnBootloader FIXMEDOC
func (s *ArduinoCoreServerImpl) BurnBootloader(req *rpc.BurnBootloaderReq, stream rpc.ArduinoCore_BurnBootloaderServer) error {
resp, err := upload.BurnBootloader(
stream.Context(), req,
utils.FeedStreamTo(func(data []byte) { stream.Send(&rpc.BurnBootloaderResp{OutStream: data}) }),
utils.FeedStreamTo(func(data []byte) { stream.Send(&rpc.BurnBootloaderResp{ErrStream: data}) }),
)
if err != nil {
return err
}
return stream.Send(resp)
}

// ListProgrammersAvailableForUpload FIXMEDOC
func (s *ArduinoCoreServerImpl) ListProgrammersAvailableForUpload(ctx context.Context, req *rpc.ListProgrammersAvailableForUploadReq) (*rpc.ListProgrammersAvailableForUploadResp, error) {
return upload.ListProgrammersAvailableForUpload(ctx, req)
}

// LibraryDownload FIXMEDOC
func (s *ArduinoCoreServerImpl) LibraryDownload(req *rpc.LibraryDownloadReq, stream rpc.ArduinoCore_LibraryDownloadServer) error {
resp, err := lib.LibraryDownload(
Expand Down
Loading