diff --git a/Taskfile.yml b/Taskfile.yml index 780f80f0b9b..5dc842fb9b9 100755 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -7,6 +7,7 @@ tasks: - '{{ default "protoc" .PROTOC_BINARY }} --proto_path=rpc --go_out=plugins=grpc,paths=source_relative:rpc ./rpc/commands/*.proto' - '{{ default "protoc" .PROTOC_BINARY }} --proto_path=rpc --go_out=plugins=grpc,paths=source_relative:rpc ./rpc/monitor/*.proto' - '{{ default "protoc" .PROTOC_BINARY }} --proto_path=rpc --go_out=plugins=grpc,paths=source_relative:rpc ./rpc/settings/*.proto' + - '{{ default "protoc" .PROTOC_BINARY }} --proto_path=rpc --go_out=plugins=grpc,paths=source_relative:rpc ./rpc/debug/*.proto' build: desc: Build the project diff --git a/arduino/cores/packagemanager/package_manager.go b/arduino/cores/packagemanager/package_manager.go index 3d4a2b33d55..d7016566ef4 100644 --- a/arduino/cores/packagemanager/package_manager.go +++ b/arduino/cores/packagemanager/package_manager.go @@ -323,7 +323,6 @@ func (tr *ToolReleaseActions) Get() (*cores.ToolRelease, error) { // GetInstalledPlatformRelease returns the PlatformRelease installed (it is chosen) func (pm *PackageManager) GetInstalledPlatformRelease(platform *cores.Platform) *cores.PlatformRelease { - pm.Log.Infof("Selecting installed platform release for %s", platform) releases := platform.GetAllInstalled() if len(releases) == 0 { return nil diff --git a/arduino/utils/stream.go b/arduino/utils/stream.go new file mode 100644 index 00000000000..c8894a6403b --- /dev/null +++ b/arduino/utils/stream.go @@ -0,0 +1,58 @@ +// 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 license@arduino.cc. + +package utils + +import "io" + +// FeedStreamTo creates a pipe to pass data to the writer function. +// FeedStreamTo returns the io.Writer side of the pipe, on which the user can write data +func FeedStreamTo(writer func(data []byte)) io.Writer { + r, w := io.Pipe() + go func() { + data := make([]byte, 1024) + for { + if n, err := r.Read(data); err == nil { + writer(data[:n]) + } else { + r.Close() + return + } + } + }() + return w +} + +// ConsumeStreamFrom creates a pipe to consume data from the reader function. +// ConsumeStreamFrom returns the io.Reader side of the pipe, which the user can use to consume the data +func ConsumeStreamFrom(reader func() ([]byte, error)) io.Reader { + r, w := io.Pipe() + go func() { + for { + if data, err := reader(); err != nil { + if err == io.EOF { + w.Close() + } else { + w.CloseWithError(err) + } + return + } else if _, err := w.Write(data); err != nil { + w.Close() + return + } + } + }() + return r +} diff --git a/cli/cli.go b/cli/cli.go index f1c81d7a697..c5a061d085b 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -28,6 +28,7 @@ import ( "github.com/arduino/arduino-cli/cli/config" "github.com/arduino/arduino-cli/cli/core" "github.com/arduino/arduino-cli/cli/daemon" + "github.com/arduino/arduino-cli/cli/debug" "github.com/arduino/arduino-cli/cli/errorcodes" "github.com/arduino/arduino-cli/cli/feedback" "github.com/arduino/arduino-cli/cli/generatedocs" @@ -77,6 +78,7 @@ func createCliCommandTree(cmd *cobra.Command) { cmd.AddCommand(lib.NewCommand()) cmd.AddCommand(sketch.NewCommand()) cmd.AddCommand(upload.NewCommand()) + cmd.AddCommand(debug.NewCommand()) cmd.AddCommand(version.NewCommand()) cmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "Print the logs on the standard output.") diff --git a/cli/daemon/daemon.go b/cli/daemon/daemon.go index e3ea2811d9a..fc38dd11d38 100644 --- a/cli/daemon/daemon.go +++ b/cli/daemon/daemon.go @@ -31,6 +31,7 @@ import ( "github.com/arduino/arduino-cli/cli/globals" "github.com/arduino/arduino-cli/commands/daemon" srv_commands "github.com/arduino/arduino-cli/rpc/commands" + srv_debug "github.com/arduino/arduino-cli/rpc/debug" srv_monitor "github.com/arduino/arduino-cli/rpc/monitor" srv_settings "github.com/arduino/arduino-cli/rpc/settings" "github.com/sirupsen/logrus" @@ -73,16 +74,19 @@ func runDaemonCommand(cmd *cobra.Command, args []string) { VersionString: globals.VersionInfo.VersionString, }) - // register the monitors service + // Register the monitors service srv_monitor.RegisterMonitorServer(s, &daemon.MonitorService{}) - // register the settings service + // Register the settings service srv_settings.RegisterSettingsServer(s, &daemon.SettingsService{}) + // Register the debug session service + srv_debug.RegisterDebugServer(s, &daemon.DebugService{}) + if !daemonize { // When parent process ends terminate also the daemon go func() { - // stdin is closed when the controlling parent process ends + // Stdin is closed when the controlling parent process ends _, _ = io.Copy(ioutil.Discard, os.Stdin) os.Exit(0) }() @@ -115,6 +119,6 @@ func runDaemonCommand(cmd *cobra.Command, args []string) { // This message will show up on the stdout of the daemon process so that gRPC clients know it is time to connect. logrus.Infof("Daemon is listening on TCP port %s...", port) if err := s.Serve(lis); err != nil { - logrus.Fatalf("failed to serve: %v", err) + logrus.Fatalf("Failed to serve: %v", err) } } diff --git a/cli/debug/debug.go b/cli/debug/debug.go new file mode 100644 index 00000000000..64e8e7150a9 --- /dev/null +++ b/cli/debug/debug.go @@ -0,0 +1,96 @@ +// 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 license@arduino.cc. + +package debug + +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/debug" + dbg "github.com/arduino/arduino-cli/rpc/debug" + "github.com/arduino/go-paths-helper" + "github.com/sirupsen/logrus" + "github.com/spf13/cobra" +) + +var ( + fqbn string + port string + verbose bool + verify bool + importFile string +) + +// NewCommand created a new `upload` command +func NewCommand() *cobra.Command { + debugCommand := &cobra.Command{ + Use: "debug", + Short: "Debug Arduino sketches.", + Long: "Debug Arduino sketches. (this command opens an interactive gdb session)", + Example: " " + os.Args[0] + " debug -b arduino:samd:mkr1000 /home/user/Arduino/MySketch", + Args: cobra.MaximumNArgs(1), + Run: run, + } + + debugCommand.Flags().StringVarP(&fqbn, "fqbn", "b", "", "Fully Qualified Board Name, e.g.: arduino:avr:uno") + debugCommand.Flags().StringVarP(&port, "port", "p", "", "Upload port, e.g.: COM10 or /dev/ttyACM0") + debugCommand.Flags().StringVarP(&importFile, "input", "i", "", "Input file to be uploaded for debug.") + + return debugCommand +} + +func run(command *cobra.Command, args []string) { + instance, err := instance.CreateInstance() + if err != nil { + feedback.Errorf("Error during Debug: %v", err) + os.Exit(errorcodes.ErrGeneric) + } + + var path *paths.Path + if len(args) > 0 { + path = paths.New(args[0]) + } + sketchPath := initSketchPath(path) + + if _, err := debug.Debug(context.Background(), &dbg.DebugConfigReq{ + Instance: &dbg.Instance{Id: instance.GetId()}, + Fqbn: fqbn, + SketchPath: sketchPath.String(), + Port: port, + ImportFile: importFile, + }, os.Stdin, os.Stdout); err != nil { + feedback.Errorf("Error during Debug: %v", err) + os.Exit(errorcodes.ErrGeneric) + } +} + +// 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 +} diff --git a/client_example/go.mod b/client_example/go.mod index 91cc576487c..7bce3c37a40 100644 --- a/client_example/go.mod +++ b/client_example/go.mod @@ -2,8 +2,9 @@ module github.com/arduino/arduino-cli/client_example go 1.13 +replace github.com/arduino/arduino-cli => ../ + require ( github.com/arduino/arduino-cli v0.0.0-20200109150215-ffa84fdaab21 - github.com/gosuri/uitable v0.0.0-20160404203958-36ee7e946282 // indirect - google.golang.org/grpc v1.23.0 -) \ No newline at end of file + google.golang.org/grpc v1.27.0 +) diff --git a/client_example/go.sum b/client_example/go.sum index 8e07356509d..b101220d43c 100644 --- a/client_example/go.sum +++ b/client_example/go.sum @@ -1,18 +1,13 @@ bou.ke/monkey v1.0.1/go.mod h1:FgHuK96Rv2Nlf+0u1OOVDpCMdsWyOFmeeketDHE7LIg= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/arduino/arduino-cli v0.0.0-20190826141027-35722fda467d h1:1Rwlmz0+4ofl3wKC29IlgAwb/66f2afOTUWsGgh5NLk= -github.com/arduino/arduino-cli v0.0.0-20190826141027-35722fda467d/go.mod h1:XFDg7LwMgVGiJAkVLQ0AM3Gei5LjfuDIKwOcrU9rnsI= -github.com/arduino/arduino-cli v0.0.0-20200109150215-ffa84fdaab21 h1:KEQLrEwD+3UG3wS5vPFcudrMFzvjJHq5xOoIgvjFPaQ= -github.com/arduino/arduino-cli v0.0.0-20200109150215-ffa84fdaab21/go.mod h1:Jtn7ZeNH70MG8bW0MZRVeGGxmAf1FQ3BgnFgLZmBOTc= github.com/arduino/board-discovery v0.0.0-20180823133458-1ba29327fb0c/go.mod h1:HK7SpkEax/3P+0w78iRQx1sz1vCDYYw9RXwHjQTB5i8= -github.com/arduino/go-paths-helper v0.0.0-20190214132331-c3c98d1bf2e1/go.mod h1:OGL+FS3aTrS01YsBAJJhkGuxtEGsFRSgZYo8b3vefdc= github.com/arduino/go-paths-helper v1.0.1/go.mod h1:HpxtKph+g238EJHq4geEPv9p+gl3v5YYu35Yb+w31Ck= -github.com/arduino/go-properties-orderedmap v0.0.0-20181003091528-89278049acd3/go.mod h1:kiSuHm7yz3chiy8rb2MphC7ECn3MlkQFAIe4SXmQg6o= github.com/arduino/go-properties-orderedmap v0.0.0-20190828172252-05018b28ff6c/go.mod h1:kiSuHm7yz3chiy8rb2MphC7ECn3MlkQFAIe4SXmQg6o= github.com/arduino/go-timeutils v0.0.0-20171220113728-d1dd9e313b1b/go.mod h1:uwGy5PpN4lqW97FiLnbcx+xx8jly5YuPMJWfVwwjJiQ= github.com/arduino/go-win32-utils v0.0.0-20180330194947-ed041402e83b/go.mod h1:iIPnclBMYm1g32Q5kXoqng4jLhMStReIP7ZxaoUC2y8= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cmaglie/pb v1.0.27 h1:ynGj8vBXR+dtj4B7Q/W/qGt31771Ux5iFfRQBnwdQiA= github.com/cmaglie/pb v1.0.27/go.mod h1:GilkKZMXYjBA4NxItWFfO+lwkp59PLHQ+IOW/b/kmZI= @@ -22,23 +17,27 @@ github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= -github.com/creack/goselect v0.0.0-20180328191401-176c667f75aa/go.mod h1:gHrIcH/9UZDn2qgeTUeW5K9eZsVYCH6/60J/FHysWyE= github.com/creack/goselect v0.1.1/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fluxio/iohelpers v0.0.0-20160419043813-3a4dd67a94d2/go.mod h1:c7sGIpDbBo0JZZ1tKyC1p5smWf8QcUjK4bFtZjHAecg= github.com/fluxio/multierror v0.0.0-20160419044231-9c68d39025e5/go.mod h1:BEUDl7FG1cc76sM0J0x8dqr6RhiL4uqvk6oFkwuNyuM= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gosuri/uitable v0.0.0-20160404203958-36ee7e946282/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo= github.com/h2non/filetype v1.0.8/go.mod h1:isekKqOuhMj+s/7r3rIeTErIRy4Rub5uBWHfvMusLMU= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= @@ -63,10 +62,10 @@ github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/9 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmylund/sortutil v0.0.0-20120526081524-abeda66eb583/go.mod h1:sFPiU/UgDcsQVu3vkqpZLCXWFwUoQRpHGu9ATihPAl0= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5/go.mod h1:GEXHk5HgEKCvEIIrSpFI3ozzG5xOKA2DVlEX/gGnewM= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g= -github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= @@ -79,7 +78,6 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -88,7 +86,6 @@ github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1: go.bug.st/cleanup v1.0.0/go.mod h1:EqVmTg2IBk4znLbPD28xne3abjsJftMdqqJEjhn70bk= go.bug.st/downloader v1.1.0 h1:LipC9rqRCe8kwa+ah3ZDfCqneVaf34cB/TKjXZiZt54= go.bug.st/downloader v1.1.0/go.mod h1:l+RPbNbrTB+MoAIp8nrZsP22nRPDy26XJZQqmm4gNT4= -go.bug.st/relaxed-semver v0.0.0-20181022103824-0265409c5852/go.mod h1:WWVH9tve4kargu9fsX18qW/UHxE37QcgPXRtE/xSvxY= go.bug.st/relaxed-semver v0.0.0-20190922224835-391e10178d18/go.mod h1:Cx1VqMtEhE9pIkEyUj3LVVVPkv89dgW8aCKrRPDR/uE= go.bug.st/serial v1.0.0/go.mod h1:rpXPISGjuNjPTRTcMlxi9lN6LoIPxd1ixVjBd8aSk/Q= go.bug.st/serial.v1 v0.0.0-20180827123349-5f7892a7bb45/go.mod h1:dRSl/CVCTf56CkXgJMDOdSwNfo2g1orOGE/gBGdvjZw= @@ -103,10 +100,11 @@ golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -114,9 +112,15 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9 h1:ZBzSG/7F4eNKz2L3GE9o300RX0Az1Bw5HF7PDraD+qU= golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5 h1:LfCXLvNmTYH9kEmVgqbnsWfruoXZIrh4YBgqVHtDvw0= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -125,12 +129,14 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190327125643-d831d65fe17d h1:XB2jc5XQ9uhizGTS2vWcN01bc4dI6z3C4KY5MQm8SS8= -google.golang.org/genproto v0.0.0-20190327125643-d831d65fe17d/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90 h1:7THRSvPuzF1bql5kyFzX0JM0vpGhwuhskgJrJsbZ80Y= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0 h1:AzbTB6ux+okLTzP8Ru1Xs41C303zdcfEht7MQnYJt5A= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.27.0 h1:rRYRFMVgRv6E0D70Skyfsr28tDXIuuPZyWGMPdMcnXg= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= diff --git a/client_example/hello.ino b/client_example/hello/hello.ino similarity index 100% rename from client_example/hello.ino rename to client_example/hello/hello.ino diff --git a/client_example/main.go b/client_example/main.go index b67e3f5de55..314c4b44edd 100644 --- a/client_example/main.go +++ b/client_example/main.go @@ -16,16 +16,19 @@ package main import ( + "bytes" "context" + "fmt" "io" "io/ioutil" "log" "os" "path" "path/filepath" - "time" + "strings" rpc "github.com/arduino/arduino-cli/rpc/commands" + dbg "github.com/arduino/arduino-cli/rpc/debug" "github.com/arduino/arduino-cli/rpc/settings" "google.golang.org/grpc" ) @@ -40,7 +43,7 @@ func main() { // Establish a connection with the gRPC server, started with the command: // arduino-cli daemon - conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure(), grpc.WithBlock(), grpc.WithTimeout(100*time.Millisecond)) + conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure(), grpc.WithBlock()) if err != nil { log.Fatal("error connecting to arduino-cli rpc server, you can start it by running `arduino-cli daemon`") } @@ -56,8 +59,9 @@ func main() { dataDir = filepath.ToSlash(dataDir) defer os.RemoveAll(dataDir) - // Create an instance of the gRPC client. + // Create an instance of the gRPC clients. client := rpc.NewArduinoCoreClient(conn) + settingsClient := settings.NewSettingsClient(conn) // Now we can call various methods of the API... @@ -128,6 +132,17 @@ func main() { // log.Println("calling Upload(arduino:samd:mkr1000, /dev/ttyACM0, VERBOSE, hello.ino)") // callUpload(client, instance) + // Debug a sketch on a board + // Uncomment if you do have an actual board connected via debug port, + // or a board connected to a debugger. + // debugClient := dbg.NewDebugClient(conn) + // debugStreamingClient, err := debugClient.Debug(context.Background()) + // if err != nil { + // log.Fatalf("debug steraming open error: %s\n", err) + // } + // log.Println("calling Debug(arduino:samd:mkr1000, hello.ino)") + // callDebugger(debugStreamingClient, instance) + // List all boards log.Println("calling BoardListAll(mkr)") callListAll(client, instance) @@ -440,7 +455,7 @@ func callBoardAttach(client rpc.ArduinoCoreClient, instance *rpc.Instance) { &rpc.BoardAttachReq{ Instance: instance, BoardUri: "/dev/ttyACM0", - SketchPath: filepath.Join(currDir, "hello.ino"), + SketchPath: filepath.Join(currDir, "hello"), }) if err != nil { @@ -475,7 +490,7 @@ func callCompile(client rpc.ArduinoCoreClient, instance *rpc.Instance) { &rpc.CompileReq{ Instance: instance, Fqbn: "arduino:samd:mkr1000", - SketchPath: filepath.Join(currDir, "hello.ino"), + SketchPath: filepath.Join(currDir, "hello"), Verbose: true, }) @@ -514,7 +529,7 @@ func callUpload(client rpc.ArduinoCoreClient, instance *rpc.Instance) { &rpc.UploadReq{ Instance: instance, Fqbn: "arduino:samd:mkr1000", - SketchPath: filepath.Join(currDir, "hello.ino"), + SketchPath: filepath.Join(currDir, "hello"), Port: "/dev/ttyACM0", Verbose: true, }) @@ -802,3 +817,64 @@ func callLibUninstall(client rpc.ArduinoCoreClient, instance *rpc.Instance) { } } } + +func callDebugger(debugStreamingOpenClient dbg.Debug_DebugClient, instance *rpc.Instance) { + currDir, _ := os.Getwd() + log.Printf("Send debug request") + err := debugStreamingOpenClient.Send(&dbg.DebugReq{ + DebugReq: &dbg.DebugConfigReq{ + Instance: &dbg.Instance{Id: instance.GetId()}, + Fqbn: "arduino:samd:mkr1000", + SketchPath: filepath.Join(currDir, "hello"), + Port: "none", + }}) + if err != nil { + log.Fatalf("Send error: %s\n", err) + } + // Loop and consume the server stream until all the operations are done. + waitForPrompt(debugStreamingOpenClient, "(gdb)") + // Wait for gdb to init and show the prompt + log.Printf("Send 'info registers' rcommand") + err = debugStreamingOpenClient.Send(&dbg.DebugReq{Data: []byte("info registers\n")}) + if err != nil { + log.Fatalf("Send error: %s\n", err) + } + + // Loop and consume the server stream until all the operations are done. + waitForPrompt(debugStreamingOpenClient, "(gdb)") + + // Send quit command to gdb + log.Printf("Send 'quit' command") + err = debugStreamingOpenClient.Send(&dbg.DebugReq{Data: []byte("quit\n")}) + if err != nil { + log.Fatalf("Send error: %s\n", err) + } + + // Close connection with the debug server + log.Printf("Close session") + err = debugStreamingOpenClient.CloseSend() + if err != nil { + log.Fatalf("Send error: %s\n", err) + } +} + +func waitForPrompt(debugStreamingOpenClient dbg.Debug_DebugClient, prompt string) { + var buffer bytes.Buffer + for { + compResp, err := debugStreamingOpenClient.Recv() + + // There was an error. + if err != nil { + log.Fatalf("debug error: %s\n", err) + } + + // Consume output and search for the gdb prompt to exit the loop + if resp := compResp.GetData(); resp != nil { + fmt.Printf("%s", resp) + buffer.Write(resp) + if strings.Contains(buffer.String(), prompt) { + break + } + } + } +} diff --git a/commands/daemon/daemon.go b/commands/daemon/daemon.go index 38e195a3495..579e4abd0f2 100644 --- a/commands/daemon/daemon.go +++ b/commands/daemon/daemon.go @@ -19,9 +19,9 @@ package daemon import ( "context" - "io" "net/http" + "github.com/arduino/arduino-cli/arduino/utils" "github.com/arduino/arduino-cli/commands" "github.com/arduino/arduino-cli/commands/board" "github.com/arduino/arduino-cli/commands/compile" @@ -125,9 +125,9 @@ func (s *ArduinoCoreServerImpl) Version(ctx context.Context, req *rpc.VersionReq func (s *ArduinoCoreServerImpl) Compile(req *rpc.CompileReq, stream rpc.ArduinoCore_CompileServer) error { resp, err := compile.Compile( stream.Context(), req, - feedStream(func(data []byte) { stream.Send(&rpc.CompileResp{OutStream: data}) }), - feedStream(func(data []byte) { stream.Send(&rpc.CompileResp{ErrStream: data}) }), - false) // set debug to false + utils.FeedStreamTo(func(data []byte) { stream.Send(&rpc.CompileResp{OutStream: data}) }), + utils.FeedStreamTo(func(data []byte) { stream.Send(&rpc.CompileResp{ErrStream: data}) }), + false) // Set debug to false if err != nil { return err } @@ -213,8 +213,8 @@ func (s *ArduinoCoreServerImpl) PlatformList(ctx context.Context, req *rpc.Platf func (s *ArduinoCoreServerImpl) Upload(req *rpc.UploadReq, stream rpc.ArduinoCore_UploadServer) error { resp, err := upload.Upload( stream.Context(), req, - feedStream(func(data []byte) { stream.Send(&rpc.UploadResp{OutStream: data}) }), - feedStream(func(data []byte) { stream.Send(&rpc.UploadResp{ErrStream: data}) }), + utils.FeedStreamTo(func(data []byte) { stream.Send(&rpc.UploadResp{OutStream: data}) }), + utils.FeedStreamTo(func(data []byte) { stream.Send(&rpc.UploadResp{ErrStream: data}) }), ) if err != nil { return err @@ -222,21 +222,6 @@ func (s *ArduinoCoreServerImpl) Upload(req *rpc.UploadReq, stream rpc.ArduinoCor return stream.Send(resp) } -func feedStream(streamer func(data []byte)) io.Writer { - r, w := io.Pipe() - go func() { - data := make([]byte, 1024) - for { - if n, err := r.Read(data); err == nil { - streamer(data[:n]) - } else { - return - } - } - }() - return w -} - // LibraryDownload FIXMEDOC func (s *ArduinoCoreServerImpl) LibraryDownload(req *rpc.LibraryDownloadReq, stream rpc.ArduinoCore_LibraryDownloadServer) error { resp, err := lib.LibraryDownload( diff --git a/commands/daemon/debug.go b/commands/daemon/debug.go new file mode 100644 index 00000000000..a373f8c1c82 --- /dev/null +++ b/commands/daemon/debug.go @@ -0,0 +1,58 @@ +// 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 license@arduino.cc. + +package daemon + +import ( + "github.com/arduino/arduino-cli/arduino/utils" + cmd "github.com/arduino/arduino-cli/commands/debug" + dbg "github.com/arduino/arduino-cli/rpc/debug" + "github.com/pkg/errors" +) + +// DebugService implements the `Debug` service +type DebugService struct{} + +// Debug returns a stream response that can be used to fetch data from the +// target. The first message passed through the `Debug` request must +// contain DebugReq configuration params, not data. +func (s *DebugService) Debug(stream dbg.Debug_DebugServer) error { + + // Grab the first message + msg, err := stream.Recv() + if err != nil { + return err + } + + // Ensure it's a config message and not data + req := msg.GetDebugReq() + if req == nil { + return errors.Errorf("First message must contain debug request, not data") + } + + // Launch debug recipe attaching stdin and out to grpc streaming + resp, err := cmd.Debug(stream.Context(), req, + utils.ConsumeStreamFrom(func() ([]byte, error) { + command, err := stream.Recv() + return command.GetData(), err + }), + utils.FeedStreamTo(func(data []byte) { + stream.Send(&dbg.DebugResp{Data: data}) + })) + if err != nil { + return (err) + } + return stream.Send(resp) +} diff --git a/commands/debug/debug.go b/commands/debug/debug.go new file mode 100644 index 00000000000..f329f3b911f --- /dev/null +++ b/commands/debug/debug.go @@ -0,0 +1,221 @@ +// 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 license@arduino.cc. + +package debug + +import ( + "context" + "fmt" + "github.com/pkg/errors" + "io" + "os" + "path/filepath" + "strings" + "time" + + "github.com/arduino/arduino-cli/arduino/cores" + "github.com/arduino/arduino-cli/arduino/cores/packagemanager" + "github.com/arduino/arduino-cli/arduino/sketches" + "github.com/arduino/arduino-cli/commands" + "github.com/arduino/arduino-cli/executils" + dbg "github.com/arduino/arduino-cli/rpc/debug" + "github.com/arduino/go-paths-helper" + "github.com/arduino/go-properties-orderedmap" + "github.com/sirupsen/logrus" +) + +// Debug command launches a debug tool for a sketch. +// It also implements streams routing: +// gRPC In -> tool stdIn +// grpc Out <- tool stdOut +// grpc Out <- tool stdErr +// It also implements tool process lifecycle management +func Debug(ctx context.Context, req *dbg.DebugConfigReq, inStream io.Reader, out io.Writer) (*dbg.DebugResp, error) { + + // Get tool commandLine from core recipe + pm := commands.GetPackageManager(req.GetInstance().GetId()) + commandLine, err := getCommandLine(req, pm) + if err != nil { + return nil, errors.Wrap(err, "Cannot get command line for tool") + } + + // Run Tool + cmd, err := executils.Command(commandLine) + if err != nil { + return nil, errors.Wrap(err, "Cannot execute debug tool") + } + + // Get stdIn pipe from tool + in, err := cmd.StdinPipe() + if err != nil { + return &dbg.DebugResp{Error: err.Error()}, nil + } + defer in.Close() + + // Merge tool StdOut and StdErr to stream them in the io.Writer passed stream + cmd.Stdout = out + cmd.Stderr = out + + // Start the debug command + if err := cmd.Start(); err != nil { + return &dbg.DebugResp{Error: err.Error()}, nil + } + + go func() { + // Copy data from passed inStream into command stdIn + io.Copy(in, inStream) + // In any case, try process termination after a second to avoid leaving + // zombie process. + time.Sleep(time.Second) + cmd.Process.Kill() + }() + + // Wait for process to finish + if err := cmd.Wait(); err != nil { + return &dbg.DebugResp{Error: err.Error()}, nil + } + return &dbg.DebugResp{}, nil +} + +// getCommandLine compose a debug command represented by a core recipe +func getCommandLine(req *dbg.DebugConfigReq, pm *packagemanager.PackageManager) ([]string, error) { + // TODO: make a generic function to extract sketch from request + // and remove duplication in commands/compile.go + if req.GetSketchPath() == "" { + return nil, fmt.Errorf("missing sketchPath") + } + sketchPath := paths.New(req.GetSketchPath()) + sketch, err := sketches.NewSketchFromPath(sketchPath) + if err != nil { + return nil, errors.Wrap(err, "opening sketch") + } + + // FIXME: make a specification on how a port is specified via command line + port := req.GetPort() + if port == "" { + return nil, fmt.Errorf("no debug port provided") + } + + fqbnIn := req.GetFqbn() + if fqbnIn == "" && sketch != nil && sketch.Metadata != nil { + fqbnIn = sketch.Metadata.CPU.Fqbn + } + if fqbnIn == "" { + return nil, fmt.Errorf("no Fully Qualified Board Name provided") + } + fqbn, err := cores.ParseFQBN(fqbnIn) + if err != nil { + return nil, errors.Wrap(err, "error parsing FQBN") + } + + // Find target board and board properties + _, _, board, boardProperties, _, err := pm.ResolveFQBN(fqbn) + if err != nil { + return nil, errors.Wrap(err, "error resolving FQBN") + } + + // Load programmer tool + toolName, have := boardProperties.GetOk("debug.tool") + if !have || toolName == "" { + return nil, fmt.Errorf("cannot get programmer tool: undefined 'debug.tool' property") + } + + var referencedPlatformRelease *cores.PlatformRelease + if split := strings.Split(toolName, ":"); len(split) > 2 { + return nil, fmt.Errorf("invalid 'debug.tool' property: %s", toolName) + } else if len(split) == 2 { + referencedPackageName := split[0] + toolName = split[1] + architecture := board.PlatformRelease.Platform.Architecture + + if referencedPackage := pm.Packages[referencedPackageName]; referencedPackage == nil { + return nil, fmt.Errorf("required platform %s:%s not installed", referencedPackageName, architecture) + } else if referencedPlatform := referencedPackage.Platforms[architecture]; referencedPlatform == nil { + return nil, fmt.Errorf("required platform %s:%s not installed", referencedPackageName, architecture) + } else { + referencedPlatformRelease = pm.GetInstalledPlatformRelease(referencedPlatform) + } + } + + // Build configuration for debug + toolProperties := properties.NewMap() + if referencedPlatformRelease != nil { + toolProperties.Merge(referencedPlatformRelease.Properties) + } + toolProperties.Merge(board.PlatformRelease.Properties) + toolProperties.Merge(board.PlatformRelease.RuntimeProperties()) + toolProperties.Merge(boardProperties) + + requestedToolProperties := toolProperties.SubTree("tools." + toolName) + toolProperties.Merge(requestedToolProperties) + if requiredTools, err := pm.FindToolsRequiredForBoard(board); err == nil { + for _, requiredTool := range requiredTools { + logrus.WithField("tool", requiredTool).Info("Tool required for debug") + toolProperties.Merge(requiredTool.RuntimeProperties()) + } + } + + // Set path to compiled binary + // Make the filename without the FQBN configs part + fqbn.Configs = properties.NewMap() + fqbnSuffix := strings.Replace(fqbn.String(), ":", ".", -1) + + var importPath *paths.Path + var importFile string + if req.GetImportFile() == "" { + importPath = sketch.FullPath + importFile = sketch.Name + "." + fqbnSuffix + } else { + importPath = paths.New(req.GetImportFile()).Parent() + importFile = paths.New(req.GetImportFile()).Base() + } + + outputTmpFile, ok := toolProperties.GetOk("recipe.output.tmp_file") + outputTmpFile = toolProperties.ExpandPropsInString(outputTmpFile) + if !ok { + return nil, fmt.Errorf("property 'recipe.output.tmp_file' not defined") + } + ext := filepath.Ext(outputTmpFile) + if strings.HasSuffix(importFile, ext) { + importFile = importFile[:len(importFile)-len(ext)] + } + + toolProperties.SetPath("build.path", importPath) + toolProperties.Set("build.project_name", importFile) + uploadFile := importPath.Join(importFile + ext) + if _, err := uploadFile.Stat(); err != nil { + if os.IsNotExist(err) { + return nil, fmt.Errorf("compiled sketch %s not found", uploadFile.String()) + } + return nil, errors.Wrap(err, "cannot open sketch") + } + + // Set debug port property + toolProperties.Set("debug.port", port) + if strings.HasPrefix(port, "/dev/") { + toolProperties.Set("debug.port.file", port[5:]) + } else { + toolProperties.Set("debug.port.file", port) + } + + // Build recipe for tool + recipe := toolProperties.Get("debug.pattern") + cmdLine := toolProperties.ExpandPropsInString(recipe) + cmdArgs, err := properties.SplitQuotedString(cmdLine, `"'`, false) + if err != nil { + return nil, fmt.Errorf("invalid recipe '%s': %s", recipe, err) + } + return cmdArgs, nil +} diff --git a/commands/debug/debug_test.go b/commands/debug/debug_test.go new file mode 100644 index 00000000000..73d0a1f4c43 --- /dev/null +++ b/commands/debug/debug_test.go @@ -0,0 +1,87 @@ +// 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 license@arduino.cc. +package debug + +import ( + "fmt" + "path/filepath" + "runtime" + "strings" + "testing" + + "github.com/arduino/arduino-cli/arduino/cores/packagemanager" + dbg "github.com/arduino/arduino-cli/rpc/debug" + "github.com/arduino/go-paths-helper" + "github.com/stretchr/testify/assert" +) + +var customHardware = paths.New("testdata", "custom_hardware") +var dataDir = paths.New("testdata", "data_dir", "packages") +var sketch = "hello" +var sketchPath = paths.New("testdata", sketch) + +func TestGetCommandLine(t *testing.T) { + pm := packagemanager.NewPackageManager(nil, nil, nil, nil) + pm.LoadHardwareFromDirectory(customHardware) + pm.LoadHardwareFromDirectory(dataDir) + + // Windows tools have .exe extension + var toolExtension = "" + if runtime.GOOS == "windows" { + toolExtension = ".exe" + } + + // Arduino Zero has an integrated debugger port, anc it could be debugged directly using USB + req := &dbg.DebugConfigReq{ + Instance: &dbg.Instance{Id: 1}, + Fqbn: "arduino-test:samd:arduino_zero_edbg", + SketchPath: sketchPath.String(), + Port: "none", + } + + goldCommand := fmt.Sprintf("%s/arduino-test/tools/arm-none-eabi-gcc/7-2017q4/bin//arm-none-eabi-gdb%s", dataDir, toolExtension) + + " -ex target extended-remote |" + + fmt.Sprintf(" %s/arduino-test/tools/openocd/0.10.0-arduino7/bin/openocd%s", dataDir, toolExtension) + + fmt.Sprintf(" -s \"%s/arduino-test/tools/openocd/0.10.0-arduino7/share/openocd/scripts/\"", dataDir) + + fmt.Sprintf(" --file \"%s/arduino-test/samd/variants/arduino_zero/openocd_scripts/arduino_zero.cfg\"", customHardware) + + fmt.Sprintf(" -c \"gdb_port pipe\" -c \"telnet_port 0\" -c init -c halt %s/hello.arduino-test.samd.arduino_zero_edbg.elf", sketchPath) + + command, err := getCommandLine(req, pm) + assert.Nil(t, err) + commandToTest := strings.Join(command[:], " ") + assert.Equal(t, filepath.FromSlash(goldCommand), filepath.FromSlash(commandToTest)) + + // Other samd boards such as mkr1000 can be debugged using an external tool such as Atmel ICE connected to + // the board debug port + req2 := &dbg.DebugConfigReq{ + Instance: &dbg.Instance{Id: 1}, + Fqbn: "arduino-test:samd:mkr1000", + SketchPath: sketchPath.String(), + Port: "none", + } + + goldCommand2 := fmt.Sprintf("%s/arduino-test/tools/arm-none-eabi-gcc/7-2017q4/bin//arm-none-eabi-gdb%s", dataDir, toolExtension) + + " -ex target extended-remote |" + + fmt.Sprintf(" %s/arduino-test/tools/openocd/0.10.0-arduino7/bin/openocd%s", dataDir, toolExtension) + + fmt.Sprintf(" -s \"%s/arduino-test/tools/openocd/0.10.0-arduino7/share/openocd/scripts/\"", dataDir) + + fmt.Sprintf(" --file \"%s/arduino-test/samd/variants/mkr1000/openocd_scripts/arduino_zero.cfg\"", customHardware) + + fmt.Sprintf(" -c \"gdb_port pipe\" -c \"telnet_port 0\" -c init -c halt %s/hello.arduino-test.samd.mkr1000.elf", sketchPath) + + command2, err := getCommandLine(req2, pm) + assert.Nil(t, err) + commandToTest2 := strings.Join(command2[:], " ") + assert.Equal(t, filepath.FromSlash(goldCommand2), filepath.FromSlash(commandToTest2)) + +} diff --git a/commands/debug/testdata/custom_hardware/arduino-test/samd/boards.txt b/commands/debug/testdata/custom_hardware/arduino-test/samd/boards.txt new file mode 100644 index 00000000000..ce473db2ef9 --- /dev/null +++ b/commands/debug/testdata/custom_hardware/arduino-test/samd/boards.txt @@ -0,0 +1,114 @@ +# Copyright (c) 2014-2017 Arduino LLC. All right reserved. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +# Arduino Zero (Prorgamming Port) +# --------------------------------------- +arduino_zero_edbg.name=Arduino Zero (Programming Port) +arduino_zero_edbg.vid.0=0x03eb +arduino_zero_edbg.pid.0=0x2157 + +arduino_zero_edbg.debug.tool=gdb +arduino_zero_edbg.upload.tool=openocd +arduino_zero_edbg.upload.protocol=sam-ba +arduino_zero_edbg.upload.maximum_size=262144 +arduino_zero_edbg.upload.use_1200bps_touch=false +arduino_zero_edbg.upload.wait_for_upload_port=false +arduino_zero_edbg.upload.native_usb=false +arduino_zero_edbg.build.mcu=cortex-m0plus +arduino_zero_edbg.build.f_cpu=48000000L +arduino_zero_edbg.build.usb_product="Arduino Zero" +arduino_zero_edbg.build.usb_manufacturer="Arduino LLC" +arduino_zero_edbg.build.board=SAMD_ZERO +arduino_zero_edbg.build.core=arduino +arduino_zero_edbg.build.extra_flags=-D__SAMD21G18A__ {build.usb_flags} +arduino_zero_edbg.build.ldscript=linker_scripts/gcc/flash_with_bootloader.ld +arduino_zero_edbg.build.openocdscript=openocd_scripts/arduino_zero.cfg +arduino_zero_edbg.build.variant=arduino_zero +arduino_zero_edbg.build.variant_system_lib= +arduino_zero_edbg.build.vid=0x2341 +arduino_zero_edbg.build.pid=0x804d +arduino_zero_edbg.bootloader.tool=openocd +arduino_zero_edbg.bootloader.file=zero/samd21_sam_ba.bin + +# Arduino MKR1000 +# ----------------------- +mkr1000.name=Arduino MKR1000 +mkr1000.vid.0=0x2341 +mkr1000.pid.0=0x804e +mkr1000.vid.1=0x2341 +mkr1000.pid.1=0x004e +mkr1000.vid.2=0x2341 +mkr1000.pid.2=0x824e +mkr1000.vid.3=0x2341 +mkr1000.pid.3=0x024e + +mkr1000.debug.tool=gdb +mkr1000.upload.tool=bossac +mkr1000.upload.protocol=sam-ba +mkr1000.upload.maximum_size=262144 +mkr1000.upload.use_1200bps_touch=true +mkr1000.upload.wait_for_upload_port=true +mkr1000.upload.native_usb=true +mkr1000.build.mcu=cortex-m0plus +mkr1000.build.f_cpu=48000000L +mkr1000.build.usb_product="Arduino MKR1000" +mkr1000.build.usb_manufacturer="Arduino LLC" +mkr1000.build.board=SAMD_MKR1000 +mkr1000.build.core=arduino +mkr1000.build.extra_flags=-DUSE_ARDUINO_MKR_PIN_LAYOUT -D__SAMD21G18A__ {build.usb_flags} +mkr1000.build.ldscript=linker_scripts/gcc/flash_with_bootloader.ld +mkr1000.build.openocdscript=openocd_scripts/arduino_zero.cfg +mkr1000.build.variant=mkr1000 +mkr1000.build.vid=0x2341 +mkr1000.build.pid=0x804e +mkr1000.bootloader.tool=openocd +mkr1000.bootloader.file=mkr1000/samd21_sam_ba_arduino_mkr1000.bin + +# Arduino Tian (with) Bootloader +# ------------------------------ +tian.name=Arduino Tian +tian.upload.via_ssh=true +tian.vid.0=0x10C4 +tian.pid.0=0xEA70 +tian.descriptor.0=Enhanced Com Port + +tian.upload.tool=avrdude +#tian.upload.protocol=stk500v2 +tian.upload.protocol=wiring +tian.upload.maximum_size=262144 +tian.upload.use_1200bps_touch=true +tian.upload.wait_for_upload_port=true +tian.upload.native_usb=true +tian.upload.speed=57600 +tian.build.mcu=cortex-m0plus +tian.build.f_cpu=48000000L +tian.build.usb_product="Arduino Tian" +tian.build.board=SAMD_TIAN +tian.build.core=arduino +tian.build.extra_flags=-D__SAMD21G18A__ -mthumb {build.usb_flags} +tian.build.ldscript=linker_scripts/gcc/flash_with_bootloader.ld +tian.build.openocdscript=openocd_scripts/arduino_zero.cfg +tian.build.variant=arduino_mzero +tian.build.variant_system_lib= +tian.build.vid=0x2a03 +tian.build.pid=0x8052 +tian.build.preferred_out_format=hex +tian.bootloader.size=0x4000 +tian.build.emu.mcu=atmega2560 +tian.bootloader.tool=openocd-withbootsize +tian.bootloader.low_fuses=0xff +tian.bootloader.file=sofia/Sofia_Tian_151118.hex +tian.drivers=SiliconLabs-CP2105/Silicon Labs VCP Driver.pkg diff --git a/commands/debug/testdata/custom_hardware/arduino-test/samd/platform.txt b/commands/debug/testdata/custom_hardware/arduino-test/samd/platform.txt new file mode 100644 index 00000000000..ded30da7c9e --- /dev/null +++ b/commands/debug/testdata/custom_hardware/arduino-test/samd/platform.txt @@ -0,0 +1,231 @@ +# Copyright (c) 2014-2015 Arduino LLC. All right reserved. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +# Arduino SAMD Core and platform. +# +# For more info: +# https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5---3rd-party-Hardware-specification + +name=Arduino SAMD (32-bits ARM Cortex-M0+) Boards +version=1.8.5 + +# Compile variables +# ----------------- + +compiler.warning_flags=-w +compiler.warning_flags.none=-w +compiler.warning_flags.default= +compiler.warning_flags.more=-Wall -Wno-expansion-to-defined +compiler.warning_flags.all=-Wall -Wextra -Wno-expansion-to-defined + +compiler.path={runtime.tools.arm-none-eabi-gcc-7-2017q4.path}/bin/ +compiler.c.cmd=arm-none-eabi-gcc +compiler.c.flags=-mcpu={build.mcu} -mthumb -c -g -Os {compiler.warning_flags} -std=gnu11 -ffunction-sections -fdata-sections -nostdlib --param max-inline-insns-single=500 -MMD +compiler.c.elf.cmd=arm-none-eabi-g++ +compiler.c.elf.flags=-Os -Wl,--gc-sections -save-temps +compiler.S.cmd=arm-none-eabi-gcc +compiler.S.flags=-c -g -x assembler-with-cpp -MMD +compiler.cpp.cmd=arm-none-eabi-g++ +compiler.cpp.flags=-mcpu={build.mcu} -mthumb -c -g -Os {compiler.warning_flags} -std=gnu++11 -ffunction-sections -fdata-sections -fno-threadsafe-statics -nostdlib --param max-inline-insns-single=500 -fno-rtti -fno-exceptions -MMD +compiler.ar.cmd=arm-none-eabi-ar +compiler.ar.flags=rcs +compiler.objcopy.cmd=arm-none-eabi-objcopy +compiler.objcopy.eep.flags=-O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0 +compiler.elf2hex.bin.flags=-O binary +compiler.elf2hex.hex.flags=-O ihex -R .eeprom +compiler.elf2hex.cmd=arm-none-eabi-objcopy +compiler.ldflags=-mcpu={build.mcu} -mthumb -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align +compiler.size.cmd=arm-none-eabi-size +compiler.define=-DARDUINO= +compiler.readelf.cmd=arm-none-eabi-readelf + +# this can be overriden in boards.txt +build.extra_flags= + +# These can be overridden in platform.local.txt +compiler.c.extra_flags= +compiler.c.elf.extra_flags= +#compiler.c.elf.extra_flags=-v +compiler.cpp.extra_flags= +compiler.S.extra_flags= +compiler.ar.extra_flags= +compiler.elf2hex.extra_flags= + +compiler.arm.cmsis.c.flags="-I{runtime.tools.CMSIS-4.5.0.path}/CMSIS/Include/" "-I{runtime.tools.CMSIS-Atmel-1.2.0.path}/CMSIS/Device/ATMEL/" +compiler.arm.cmsis.ldflags="-L{runtime.tools.CMSIS-4.5.0.path}/CMSIS/Lib/GCC/" -larm_cortexM0l_math + +compiler.libraries.ldflags= + +# USB Flags +# --------- +build.usb_flags=-DUSB_VID={build.vid} -DUSB_PID={build.pid} -DUSBCON '-DUSB_MANUFACTURER={build.usb_manufacturer}' '-DUSB_PRODUCT={build.usb_product}' + +# Default usb manufacturer will be replaced at compile time using +# numeric vendor ID if available or by board's specific value. +build.usb_manufacturer="Unknown" + +# Compile patterns +# ---------------- + +## Compile c files +recipe.c.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.c.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.c.extra_flags} {build.extra_flags} {compiler.arm.cmsis.c.flags} {includes} "{source_file}" -o "{object_file}" + +## Compile c++ files +recipe.cpp.o.pattern="{compiler.path}{compiler.cpp.cmd}" {compiler.cpp.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.cpp.extra_flags} {build.extra_flags} {compiler.arm.cmsis.c.flags} {includes} "{source_file}" -o "{object_file}" + +## Compile S files +recipe.S.o.pattern="{compiler.path}{compiler.S.cmd}" {compiler.S.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.S.extra_flags} {build.extra_flags} {compiler.arm.cmsis.c.flags} {includes} "{source_file}" -o "{object_file}" + +## Create archives +# archive_file_path is needed for backwards compatibility with IDE 1.6.5 or older, IDE 1.6.6 or newer overrides this value +archive_file_path={build.path}/{archive_file} +recipe.ar.pattern="{compiler.path}{compiler.ar.cmd}" {compiler.ar.flags} {compiler.ar.extra_flags} "{archive_file_path}" "{object_file}" + +## Combine gc-sections, archives, and objects +recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" "-L{build.path}" {compiler.c.elf.flags} {compiler.c.elf.extra_flags} "-T{build.variant.path}/{build.ldscript}" "-Wl,-Map,{build.path}/{build.project_name}.map" --specs=nano.specs --specs=nosys.specs {compiler.ldflags} -o "{build.path}/{build.project_name}.elf" {object_files} {compiler.libraries.ldflags} -Wl,--start-group {compiler.arm.cmsis.ldflags} -lm "{build.path}/{archive_file}" -Wl,--end-group + +## Create output (bin file) +recipe.objcopy.bin.pattern="{compiler.path}{compiler.elf2hex.cmd}" {compiler.elf2hex.bin.flags} {compiler.elf2hex.extra_flags} "{build.path}/{build.project_name}.elf" "{build.path}/{build.project_name}.bin" + +## Create output (hex file) +recipe.objcopy.hex.pattern="{compiler.path}{compiler.elf2hex.cmd}" {compiler.elf2hex.hex.flags} {compiler.elf2hex.extra_flags} "{build.path}/{build.project_name}.elf" "{build.path}/{build.project_name}.hex" + +build.preferred_out_format=bin + +## Save hex +recipe.output.tmp_file={build.project_name}.{build.preferred_out_format} +recipe.output.save_file={build.project_name}.{build.variant}.{build.preferred_out_format} + +## Compute size +recipe.size.pattern="{compiler.path}{compiler.size.cmd}" -A "{build.path}/{build.project_name}.elf" +recipe.size.regex=\.text\s+([0-9]+).* + +# Upload/Debug tools +# ------------------ + +# +# AVRDUDE +# +tools.avrdude.path={runtime.tools.avrdude.path} +tools.avrdude.cmd={path}/bin/avrdude +tools.avrdude.config.path={path}/etc/avrdude.conf + +tools.avrdude.upload.params.verbose=-v -v +tools.avrdude.upload.params.quiet=-q -q +tools.avrdude.upload.params.noverify=-V +tools.avrdude.upload.pattern="{cmd}" "-C{config.path}" {upload.verbose} -p{build.emu.mcu} -c{upload.protocol} -P{serial.port} -b{upload.speed} "-Uflash:w:{build.path}/{build.project_name}.hex:i" + +tools.avrdude_remote.upload.pattern="openocd --version 2>&1 | grep 2016 && if opkg update; then opkg upgrade openocd; exit 1; else echo 'Please connect your board to the Internet in order to upgrade tools' >&2; exit 1; fi || /usr/bin/run-avrdude /tmp/sketch.hex" + +tools.avrdude.network_cmd={runtime.tools.arduinoOTA.path}/bin/arduinoOTA +tools.avrdude.upload.network_pattern="{network_cmd}" -address {serial.port} -port 65280 -username arduino -password "{network.password}" -sketch "{build.path}/{build.project_name}.bin" -upload /sketch -b + +# +# BOSSA +# +tools.bossac.path={runtime.tools.bossac-1.7.0-arduino3.path} +tools.bossac.cmd=bossac +tools.bossac.cmd.windows=bossac.exe + +tools.bossac.upload.params.verbose=-i -d +tools.bossac.upload.params.quiet= +tools.bossac.upload.pattern="{path}/{cmd}" {upload.verbose} --port={serial.port.file} -U {upload.native_usb} -i -e -w -v "{build.path}/{build.project_name}.bin" -R + +tools.bossac_remote.upload.pattern=/usr/bin/run-bossac {upload.verbose} --port=ttyATH0 -U {upload.native_usb} -e -w -v /tmp/sketch.bin -R + +tools.bossac.network_cmd={runtime.tools.arduinoOTA.path}/bin/arduinoOTA +tools.bossac.upload.network_pattern="{network_cmd}" -address {serial.port} -port 65280 -username arduino -password "{network.password}" -sketch "{build.path}/{build.project_name}.bin" -upload /sketch -b + +# +# BOSSA (ignore binary size) +# +tools.bossacI.path={runtime.tools.bossac-1.7.0-arduino3.path} +tools.bossacI.cmd=bossac +tools.bossacI.cmd.windows=bossac.exe + +tools.bossacI.upload.params.verbose=-i -d +tools.bossacI.upload.params.quiet= +tools.bossacI.upload.pattern="{path}/{cmd}" {upload.verbose} --port={serial.port.file} -I -U {upload.native_usb} -i -e -w "{build.path}/{build.project_name}.bin" -R + +tools.bossacI_remote.upload.pattern=/usr/bin/run-bossac {upload.verbose} --port=ttyATH0 -U {upload.native_usb} -e -w -v /tmp/sketch.bin -R + +tools.bossacI.network_cmd={runtime.tools.arduinoOTA.path}/bin/arduinoOTA +tools.bossacI.upload.network_pattern="{network_cmd}" -address {serial.port} -port 65280 -username arduino -password "{network.password}" -sketch "{build.path}/{build.project_name}.bin" -upload /sketch -b + + +# +# OpenOCD sketch upload +# + +tools.openocd.path={runtime.tools.openocd.path} +tools.openocd.cmd=bin/openocd +tools.openocd.cmd.windows=bin/openocd.exe + +tools.openocd.upload.params.verbose=-d2 +tools.openocd.upload.params.quiet=-d0 +tools.openocd.upload.pattern="{path}/{cmd}" {upload.verbose} -s "{path}/share/openocd/scripts/" -f "{runtime.platform.path}/variants/{build.variant}/{build.openocdscript}" -c "telnet_port disabled; program {{build.path}/{build.project_name}.bin} verify reset 0x2000; shutdown" + +tools.openocd.network_cmd={runtime.tools.arduinoOTA.path}/bin/arduinoOTA +tools.openocd.upload.network_pattern={network_cmd} -address {serial.port} -port 65280 -username arduino -password "{network.password}" -sketch "{build.path}/{build.project_name}.bin" -upload /sketch -b + +# Program flashes the binary at 0x0000, so use the linker script without_bootloader +tools.openocd.program.params.verbose=-d2 +tools.openocd.program.params.quiet=-d0 +tools.openocd.program.pattern="{path}/{cmd}" {program.verbose} -s "{path}/share/openocd/scripts/" -f "{runtime.platform.path}/variants/{build.variant}/{build.openocdscript}" -c "telnet_port disabled; program {{build.path}/{build.project_name}.elf} verify reset; shutdown" + +tools.openocd.erase.params.verbose=-d3 +tools.openocd.erase.params.quiet=-d0 +tools.openocd.erase.pattern= + +tools.openocd.bootloader.params.verbose=-d2 +tools.openocd.bootloader.params.quiet=-d0 +tools.openocd.bootloader.pattern="{path}/{cmd}" {bootloader.verbose} -s "{path}/share/openocd/scripts/" -f "{runtime.platform.path}/variants/{build.variant}/{build.openocdscript}" -c "telnet_port disabled; init; halt; at91samd bootloader 0; program {{runtime.platform.path}/bootloaders/{bootloader.file}} verify reset; shutdown" + +# +# OpenOCD sketch upload - version with configurable bootloader size +# FIXME: this programmer is a workaround for default options being overwritten by uploadUsingPreferences +# + +tools.openocd-withbootsize.path={runtime.tools.openocd-0.10.0-arduino7.path} +tools.openocd-withbootsize.cmd=bin/openocd +tools.openocd-withbootsize.cmd.windows=bin/openocd.exe + +tools.openocd-withbootsize.upload.params.verbose=-d2 +tools.openocd-withbootsize.upload.params.quiet=-d0 +tools.openocd-withbootsize.upload.pattern="{path}/{cmd}" {upload.verbose} -s "{path}/share/openocd/scripts/" -f "{runtime.platform.path}/variants/{build.variant}/{build.openocdscript}" -c "telnet_port disabled; program {{build.path}/{build.project_name}.bin} verify reset {bootloader.size}; shutdown" + +# Program flashes the binary at 0x0000, so use the linker script without_bootloader +tools.openocd-withbootsize.program.params.verbose=-d2 +tools.openocd-withbootsize.program.params.quiet=-d0 +tools.openocd-withbootsize.program.pattern="{path}/{cmd}" {program.verbose} -s "{path}/share/openocd/scripts/" -f "{runtime.platform.path}/variants/{build.variant}/{build.openocdscript}" -c "telnet_port disabled; program {{build.path}/{build.project_name}.elf} verify reset; shutdown" + +tools.openocd-withbootsize.erase.params.verbose=-d3 +tools.openocd-withbootsize.erase.params.quiet=-d0 +tools.openocd-withbootsize.erase.pattern= + +tools.openocd-withbootsize.bootloader.params.verbose=-d2 +tools.openocd-withbootsize.bootloader.params.quiet=-d0 +tools.openocd-withbootsize.bootloader.pattern="{path}/{cmd}" {bootloader.verbose} -s "{path}/share/openocd/scripts/" -f "{runtime.platform.path}/variants/{build.variant}/{build.openocdscript}" -c "telnet_port disabled; init; halt; at91samd bootloader 0; program {{runtime.platform.path}/bootloaders/{bootloader.file}} verify reset; shutdown" + +# +# GDB (Debugger) +# + +tools.gdb.path={runtime.tools.arm-none-eabi-gcc-7-2017q4.path}/bin/ +tools.gdb.cmd=arm-none-eabi-gdb +tools.gdb.cmd.windows=arm-none-eabi-gdb.exe + +tools.gdb.debug.pattern="{path}/{cmd}" -ex 'target extended-remote | {tools.openocd.path}/{tools.openocd.cmd} -s "{tools.openocd.path}/share/openocd/scripts/" --file "{runtime.platform.path}/variants/{build.variant}/{build.openocdscript}" -c "gdb_port pipe" -c "telnet_port 0" -c init -c halt' {build.path}/{build.project_name}.elf \ No newline at end of file diff --git a/commands/debug/testdata/data_dir/packages/arduino-test/tools/arm-none-eabi-gcc/7-2017q4/bin/arm-none-eabi-gdb b/commands/debug/testdata/data_dir/packages/arduino-test/tools/arm-none-eabi-gcc/7-2017q4/bin/arm-none-eabi-gdb new file mode 100644 index 00000000000..e69de29bb2d diff --git a/commands/debug/testdata/data_dir/packages/arduino-test/tools/openocd/0.10.0-arduino7/bin/openocd b/commands/debug/testdata/data_dir/packages/arduino-test/tools/openocd/0.10.0-arduino7/bin/openocd new file mode 100644 index 00000000000..e69de29bb2d diff --git a/commands/debug/testdata/hello/hello.arduino-test.samd.arduino_zero_edbg.bin b/commands/debug/testdata/hello/hello.arduino-test.samd.arduino_zero_edbg.bin new file mode 100644 index 00000000000..e69de29bb2d diff --git a/commands/debug/testdata/hello/hello.arduino-test.samd.mkr1000.bin b/commands/debug/testdata/hello/hello.arduino-test.samd.mkr1000.bin new file mode 100644 index 00000000000..e69de29bb2d diff --git a/go.sum b/go.sum index db46a426af6..a07a80b85a8 100644 --- a/go.sum +++ b/go.sum @@ -184,6 +184,7 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3 golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384 h1:TFlARGu6Czu1z7q93HTxcP1P+/ZFC/IKythI5RzrnRg= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135 h1:5Beo0mZN8dRzgrMMkDp0jc8YXQKx9DiJ2k1dkvGsn5A= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= diff --git a/rpc/commands/commands.pb.go b/rpc/commands/commands.pb.go index 780bbed2f1e..59fe7937ed8 100644 --- a/rpc/commands/commands.pb.go +++ b/rpc/commands/commands.pb.go @@ -8,8 +8,6 @@ import ( fmt "fmt" proto "github.com/golang/protobuf/proto" grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" math "math" ) @@ -599,11 +597,11 @@ var fileDescriptor_3690061a1131852d = []byte{ // Reference imports to suppress errors if they are not otherwise used. var _ context.Context -var _ grpc.ClientConnInterface +var _ grpc.ClientConn // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion6 +const _ = grpc.SupportPackageIsVersion4 // ArduinoCoreClient is the client API for ArduinoCore service. // @@ -643,10 +641,10 @@ type ArduinoCoreClient interface { } type arduinoCoreClient struct { - cc grpc.ClientConnInterface + cc *grpc.ClientConn } -func NewArduinoCoreClient(cc grpc.ClientConnInterface) ArduinoCoreClient { +func NewArduinoCoreClient(cc *grpc.ClientConn) ArduinoCoreClient { return &arduinoCoreClient{cc} } @@ -1232,86 +1230,6 @@ type ArduinoCoreServer interface { LibraryList(context.Context, *LibraryListReq) (*LibraryListResp, error) } -// UnimplementedArduinoCoreServer can be embedded to have forward compatible implementations. -type UnimplementedArduinoCoreServer struct { -} - -func (*UnimplementedArduinoCoreServer) Init(req *InitReq, srv ArduinoCore_InitServer) error { - return status.Errorf(codes.Unimplemented, "method Init not implemented") -} -func (*UnimplementedArduinoCoreServer) Destroy(ctx context.Context, req *DestroyReq) (*DestroyResp, error) { - return nil, status.Errorf(codes.Unimplemented, "method Destroy not implemented") -} -func (*UnimplementedArduinoCoreServer) Rescan(ctx context.Context, req *RescanReq) (*RescanResp, error) { - return nil, status.Errorf(codes.Unimplemented, "method Rescan not implemented") -} -func (*UnimplementedArduinoCoreServer) UpdateIndex(req *UpdateIndexReq, srv ArduinoCore_UpdateIndexServer) error { - return status.Errorf(codes.Unimplemented, "method UpdateIndex not implemented") -} -func (*UnimplementedArduinoCoreServer) UpdateLibrariesIndex(req *UpdateLibrariesIndexReq, srv ArduinoCore_UpdateLibrariesIndexServer) error { - return status.Errorf(codes.Unimplemented, "method UpdateLibrariesIndex not implemented") -} -func (*UnimplementedArduinoCoreServer) Version(ctx context.Context, req *VersionReq) (*VersionResp, error) { - return nil, status.Errorf(codes.Unimplemented, "method Version not implemented") -} -func (*UnimplementedArduinoCoreServer) BoardDetails(ctx context.Context, req *BoardDetailsReq) (*BoardDetailsResp, error) { - return nil, status.Errorf(codes.Unimplemented, "method BoardDetails not implemented") -} -func (*UnimplementedArduinoCoreServer) BoardAttach(req *BoardAttachReq, srv ArduinoCore_BoardAttachServer) error { - return status.Errorf(codes.Unimplemented, "method BoardAttach not implemented") -} -func (*UnimplementedArduinoCoreServer) BoardList(ctx context.Context, req *BoardListReq) (*BoardListResp, error) { - return nil, status.Errorf(codes.Unimplemented, "method BoardList not implemented") -} -func (*UnimplementedArduinoCoreServer) BoardListAll(ctx context.Context, req *BoardListAllReq) (*BoardListAllResp, error) { - return nil, status.Errorf(codes.Unimplemented, "method BoardListAll not implemented") -} -func (*UnimplementedArduinoCoreServer) Compile(req *CompileReq, srv ArduinoCore_CompileServer) error { - return status.Errorf(codes.Unimplemented, "method Compile not implemented") -} -func (*UnimplementedArduinoCoreServer) PlatformInstall(req *PlatformInstallReq, srv ArduinoCore_PlatformInstallServer) error { - return status.Errorf(codes.Unimplemented, "method PlatformInstall not implemented") -} -func (*UnimplementedArduinoCoreServer) PlatformDownload(req *PlatformDownloadReq, srv ArduinoCore_PlatformDownloadServer) error { - return status.Errorf(codes.Unimplemented, "method PlatformDownload not implemented") -} -func (*UnimplementedArduinoCoreServer) PlatformUninstall(req *PlatformUninstallReq, srv ArduinoCore_PlatformUninstallServer) error { - return status.Errorf(codes.Unimplemented, "method PlatformUninstall not implemented") -} -func (*UnimplementedArduinoCoreServer) PlatformUpgrade(req *PlatformUpgradeReq, srv ArduinoCore_PlatformUpgradeServer) error { - return status.Errorf(codes.Unimplemented, "method PlatformUpgrade not implemented") -} -func (*UnimplementedArduinoCoreServer) Upload(req *UploadReq, srv ArduinoCore_UploadServer) error { - return status.Errorf(codes.Unimplemented, "method Upload not implemented") -} -func (*UnimplementedArduinoCoreServer) PlatformSearch(ctx context.Context, req *PlatformSearchReq) (*PlatformSearchResp, error) { - return nil, status.Errorf(codes.Unimplemented, "method PlatformSearch not implemented") -} -func (*UnimplementedArduinoCoreServer) PlatformList(ctx context.Context, req *PlatformListReq) (*PlatformListResp, error) { - return nil, status.Errorf(codes.Unimplemented, "method PlatformList not implemented") -} -func (*UnimplementedArduinoCoreServer) LibraryDownload(req *LibraryDownloadReq, srv ArduinoCore_LibraryDownloadServer) error { - return status.Errorf(codes.Unimplemented, "method LibraryDownload not implemented") -} -func (*UnimplementedArduinoCoreServer) LibraryInstall(req *LibraryInstallReq, srv ArduinoCore_LibraryInstallServer) error { - return status.Errorf(codes.Unimplemented, "method LibraryInstall not implemented") -} -func (*UnimplementedArduinoCoreServer) LibraryUninstall(req *LibraryUninstallReq, srv ArduinoCore_LibraryUninstallServer) error { - return status.Errorf(codes.Unimplemented, "method LibraryUninstall not implemented") -} -func (*UnimplementedArduinoCoreServer) LibraryUpgradeAll(req *LibraryUpgradeAllReq, srv ArduinoCore_LibraryUpgradeAllServer) error { - return status.Errorf(codes.Unimplemented, "method LibraryUpgradeAll not implemented") -} -func (*UnimplementedArduinoCoreServer) LibraryResolveDependencies(ctx context.Context, req *LibraryResolveDependenciesReq) (*LibraryResolveDependenciesResp, error) { - return nil, status.Errorf(codes.Unimplemented, "method LibraryResolveDependencies not implemented") -} -func (*UnimplementedArduinoCoreServer) LibrarySearch(ctx context.Context, req *LibrarySearchReq) (*LibrarySearchResp, error) { - return nil, status.Errorf(codes.Unimplemented, "method LibrarySearch not implemented") -} -func (*UnimplementedArduinoCoreServer) LibraryList(ctx context.Context, req *LibraryListReq) (*LibraryListResp, error) { - return nil, status.Errorf(codes.Unimplemented, "method LibraryList not implemented") -} - func RegisterArduinoCoreServer(s *grpc.Server, srv ArduinoCoreServer) { s.RegisterService(&_ArduinoCore_serviceDesc, srv) } diff --git a/rpc/debug/debug.pb.go b/rpc/debug/debug.pb.go new file mode 100644 index 00000000000..fad8b92d951 --- /dev/null +++ b/rpc/debug/debug.pb.go @@ -0,0 +1,385 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: debug/debug.proto + +package debug + +import ( + context "context" + fmt "fmt" + proto "github.com/golang/protobuf/proto" + grpc "google.golang.org/grpc" + math "math" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package + +// The top-level message sent by the client for the `Debug` method. +// Multiple `DebugReq` messages can be sent but the first message +// must contain a `DebugReq` message to initialize the debug session. +// All subsequent messages must contain bytes to be sent to the debug session +// and must not contain a `DebugReq` message. +type DebugReq struct { + // Provides information to the debug that specifies which is the target. + // The first `StreamingOpenReq` message must contain a `DebugReq` + // message. + DebugReq *DebugConfigReq `protobuf:"bytes,1,opt,name=debugReq,proto3" json:"debugReq,omitempty"` + // The data to be sent to the target being monitored. + Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DebugReq) Reset() { *m = DebugReq{} } +func (m *DebugReq) String() string { return proto.CompactTextString(m) } +func (*DebugReq) ProtoMessage() {} +func (*DebugReq) Descriptor() ([]byte, []int) { + return fileDescriptor_5ae24eab94cb53d5, []int{0} +} + +func (m *DebugReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DebugReq.Unmarshal(m, b) +} +func (m *DebugReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DebugReq.Marshal(b, m, deterministic) +} +func (m *DebugReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_DebugReq.Merge(m, src) +} +func (m *DebugReq) XXX_Size() int { + return xxx_messageInfo_DebugReq.Size(m) +} +func (m *DebugReq) XXX_DiscardUnknown() { + xxx_messageInfo_DebugReq.DiscardUnknown(m) +} + +var xxx_messageInfo_DebugReq proto.InternalMessageInfo + +func (m *DebugReq) GetDebugReq() *DebugConfigReq { + if m != nil { + return m.DebugReq + } + return nil +} + +func (m *DebugReq) GetData() []byte { + if m != nil { + return m.Data + } + return nil +} + +type DebugConfigReq struct { + Instance *Instance `protobuf:"bytes,1,opt,name=instance,proto3" json:"instance,omitempty"` + Fqbn string `protobuf:"bytes,2,opt,name=fqbn,proto3" json:"fqbn,omitempty"` + SketchPath string `protobuf:"bytes,3,opt,name=sketch_path,json=sketchPath,proto3" json:"sketch_path,omitempty"` + Port string `protobuf:"bytes,4,opt,name=port,proto3" json:"port,omitempty"` + Verbose bool `protobuf:"varint,5,opt,name=verbose,proto3" json:"verbose,omitempty"` + ImportFile string `protobuf:"bytes,7,opt,name=import_file,json=importFile,proto3" json:"import_file,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DebugConfigReq) Reset() { *m = DebugConfigReq{} } +func (m *DebugConfigReq) String() string { return proto.CompactTextString(m) } +func (*DebugConfigReq) ProtoMessage() {} +func (*DebugConfigReq) Descriptor() ([]byte, []int) { + return fileDescriptor_5ae24eab94cb53d5, []int{1} +} + +func (m *DebugConfigReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DebugConfigReq.Unmarshal(m, b) +} +func (m *DebugConfigReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DebugConfigReq.Marshal(b, m, deterministic) +} +func (m *DebugConfigReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_DebugConfigReq.Merge(m, src) +} +func (m *DebugConfigReq) XXX_Size() int { + return xxx_messageInfo_DebugConfigReq.Size(m) +} +func (m *DebugConfigReq) XXX_DiscardUnknown() { + xxx_messageInfo_DebugConfigReq.DiscardUnknown(m) +} + +var xxx_messageInfo_DebugConfigReq proto.InternalMessageInfo + +func (m *DebugConfigReq) GetInstance() *Instance { + if m != nil { + return m.Instance + } + return nil +} + +func (m *DebugConfigReq) GetFqbn() string { + if m != nil { + return m.Fqbn + } + return "" +} + +func (m *DebugConfigReq) GetSketchPath() string { + if m != nil { + return m.SketchPath + } + return "" +} + +func (m *DebugConfigReq) GetPort() string { + if m != nil { + return m.Port + } + return "" +} + +func (m *DebugConfigReq) GetVerbose() bool { + if m != nil { + return m.Verbose + } + return false +} + +func (m *DebugConfigReq) GetImportFile() string { + if m != nil { + return m.ImportFile + } + return "" +} + +// +type DebugResp struct { + Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` + Error string `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DebugResp) Reset() { *m = DebugResp{} } +func (m *DebugResp) String() string { return proto.CompactTextString(m) } +func (*DebugResp) ProtoMessage() {} +func (*DebugResp) Descriptor() ([]byte, []int) { + return fileDescriptor_5ae24eab94cb53d5, []int{2} +} + +func (m *DebugResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DebugResp.Unmarshal(m, b) +} +func (m *DebugResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DebugResp.Marshal(b, m, deterministic) +} +func (m *DebugResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_DebugResp.Merge(m, src) +} +func (m *DebugResp) XXX_Size() int { + return xxx_messageInfo_DebugResp.Size(m) +} +func (m *DebugResp) XXX_DiscardUnknown() { + xxx_messageInfo_DebugResp.DiscardUnknown(m) +} + +var xxx_messageInfo_DebugResp proto.InternalMessageInfo + +func (m *DebugResp) GetData() []byte { + if m != nil { + return m.Data + } + return nil +} + +func (m *DebugResp) GetError() string { + if m != nil { + return m.Error + } + return "" +} + +// duplicate from commands/common.proto +// as module imports seems not to work +type Instance struct { + Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Instance) Reset() { *m = Instance{} } +func (m *Instance) String() string { return proto.CompactTextString(m) } +func (*Instance) ProtoMessage() {} +func (*Instance) Descriptor() ([]byte, []int) { + return fileDescriptor_5ae24eab94cb53d5, []int{3} +} + +func (m *Instance) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Instance.Unmarshal(m, b) +} +func (m *Instance) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Instance.Marshal(b, m, deterministic) +} +func (m *Instance) XXX_Merge(src proto.Message) { + xxx_messageInfo_Instance.Merge(m, src) +} +func (m *Instance) XXX_Size() int { + return xxx_messageInfo_Instance.Size(m) +} +func (m *Instance) XXX_DiscardUnknown() { + xxx_messageInfo_Instance.DiscardUnknown(m) +} + +var xxx_messageInfo_Instance proto.InternalMessageInfo + +func (m *Instance) GetId() int32 { + if m != nil { + return m.Id + } + return 0 +} + +func init() { + proto.RegisterType((*DebugReq)(nil), "cc.arduino.cli.debug.DebugReq") + proto.RegisterType((*DebugConfigReq)(nil), "cc.arduino.cli.debug.DebugConfigReq") + proto.RegisterType((*DebugResp)(nil), "cc.arduino.cli.debug.DebugResp") + proto.RegisterType((*Instance)(nil), "cc.arduino.cli.debug.Instance") +} + +func init() { proto.RegisterFile("debug/debug.proto", fileDescriptor_5ae24eab94cb53d5) } + +var fileDescriptor_5ae24eab94cb53d5 = []byte{ + // 332 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x52, 0x41, 0x4b, 0xf3, 0x40, + 0x10, 0xfd, 0xb6, 0x5f, 0x63, 0xd3, 0xa9, 0x14, 0x5c, 0x7a, 0x58, 0x7a, 0x68, 0x4b, 0xf0, 0x10, + 0x04, 0xb7, 0x52, 0xf1, 0xe2, 0x49, 0x54, 0x04, 0x2f, 0x22, 0x7b, 0x11, 0xbc, 0xd4, 0x64, 0xb3, + 0x6d, 0x16, 0xd3, 0x6c, 0xba, 0xd9, 0xfa, 0x3b, 0xfd, 0x49, 0xb2, 0x9b, 0x4d, 0x45, 0x28, 0xbd, + 0x24, 0x6f, 0x66, 0xde, 0x9b, 0xb7, 0x33, 0x0c, 0x9c, 0x65, 0x22, 0xdd, 0xad, 0xe7, 0xee, 0x4b, + 0x2b, 0xad, 0x8c, 0xc2, 0x23, 0xce, 0x69, 0xa2, 0xb3, 0x9d, 0x2c, 0x15, 0xe5, 0x85, 0xa4, 0xae, + 0x16, 0x7d, 0x40, 0xf8, 0x68, 0x01, 0x13, 0x5b, 0x7c, 0x07, 0x61, 0xe6, 0x31, 0x41, 0x33, 0x14, + 0x0f, 0x16, 0xe7, 0xf4, 0x90, 0x88, 0x3a, 0xc5, 0x83, 0x2a, 0x57, 0xd2, 0x72, 0xd9, 0x5e, 0x85, + 0x31, 0x74, 0xb3, 0xc4, 0x24, 0xa4, 0x33, 0x43, 0xf1, 0x29, 0x73, 0x38, 0xfa, 0x46, 0x30, 0xfc, + 0x2b, 0xc0, 0xb7, 0x10, 0xca, 0xb2, 0x36, 0x49, 0xc9, 0x85, 0x37, 0x9a, 0x1c, 0x36, 0x7a, 0xf6, + 0x2c, 0xb6, 0xe7, 0x5b, 0x8b, 0xd5, 0x36, 0x2d, 0x9d, 0x45, 0x9f, 0x39, 0x8c, 0xa7, 0x30, 0xa8, + 0x3f, 0x85, 0xe1, 0xf9, 0xb2, 0x4a, 0x4c, 0x4e, 0xfe, 0xbb, 0x12, 0x34, 0xa9, 0xd7, 0xc4, 0xe4, + 0x56, 0x54, 0x29, 0x6d, 0x48, 0xb7, 0x11, 0x59, 0x8c, 0x09, 0xf4, 0xbe, 0x84, 0x4e, 0x55, 0x2d, + 0x48, 0x30, 0x43, 0x71, 0xc8, 0xda, 0xd0, 0xb6, 0x93, 0x1b, 0xcb, 0x59, 0xae, 0x64, 0x21, 0x48, + 0xaf, 0x69, 0xd7, 0xa4, 0x9e, 0x64, 0x21, 0xa2, 0x1b, 0xe8, 0xfb, 0xa5, 0xd5, 0xd5, 0x7e, 0x66, + 0xf4, 0x3b, 0x33, 0x1e, 0x41, 0x20, 0xb4, 0x56, 0xda, 0xbf, 0xb2, 0x09, 0xa2, 0x31, 0x84, 0xed, + 0x40, 0x78, 0x08, 0x1d, 0x99, 0x39, 0x4d, 0xc0, 0x3a, 0x32, 0x5b, 0xbc, 0x41, 0xe0, 0x5a, 0xe2, + 0x97, 0x16, 0x4c, 0x8e, 0xec, 0x9e, 0x89, 0xed, 0x78, 0x7a, 0xb4, 0x5e, 0x57, 0xd1, 0xbf, 0x18, + 0x5d, 0xa1, 0xfb, 0x8b, 0xf7, 0x78, 0x2d, 0x4d, 0xbe, 0x4b, 0x29, 0x57, 0x9b, 0xb9, 0xe7, 0xb7, + 0xff, 0x4b, 0x5e, 0xc8, 0xb9, 0xae, 0x78, 0x73, 0x28, 0xe9, 0x89, 0xbb, 0x94, 0xeb, 0x9f, 0x00, + 0x00, 0x00, 0xff, 0xff, 0xfc, 0x58, 0x74, 0x88, 0x3e, 0x02, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// DebugClient is the client API for Debug service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type DebugClient interface { + Debug(ctx context.Context, opts ...grpc.CallOption) (Debug_DebugClient, error) +} + +type debugClient struct { + cc *grpc.ClientConn +} + +func NewDebugClient(cc *grpc.ClientConn) DebugClient { + return &debugClient{cc} +} + +func (c *debugClient) Debug(ctx context.Context, opts ...grpc.CallOption) (Debug_DebugClient, error) { + stream, err := c.cc.NewStream(ctx, &_Debug_serviceDesc.Streams[0], "/cc.arduino.cli.debug.Debug/Debug", opts...) + if err != nil { + return nil, err + } + x := &debugDebugClient{stream} + return x, nil +} + +type Debug_DebugClient interface { + Send(*DebugReq) error + Recv() (*DebugResp, error) + grpc.ClientStream +} + +type debugDebugClient struct { + grpc.ClientStream +} + +func (x *debugDebugClient) Send(m *DebugReq) error { + return x.ClientStream.SendMsg(m) +} + +func (x *debugDebugClient) Recv() (*DebugResp, error) { + m := new(DebugResp) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +// DebugServer is the server API for Debug service. +type DebugServer interface { + Debug(Debug_DebugServer) error +} + +func RegisterDebugServer(s *grpc.Server, srv DebugServer) { + s.RegisterService(&_Debug_serviceDesc, srv) +} + +func _Debug_Debug_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(DebugServer).Debug(&debugDebugServer{stream}) +} + +type Debug_DebugServer interface { + Send(*DebugResp) error + Recv() (*DebugReq, error) + grpc.ServerStream +} + +type debugDebugServer struct { + grpc.ServerStream +} + +func (x *debugDebugServer) Send(m *DebugResp) error { + return x.ServerStream.SendMsg(m) +} + +func (x *debugDebugServer) Recv() (*DebugReq, error) { + m := new(DebugReq) + if err := x.ServerStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +var _Debug_serviceDesc = grpc.ServiceDesc{ + ServiceName: "cc.arduino.cli.debug.Debug", + HandlerType: (*DebugServer)(nil), + Methods: []grpc.MethodDesc{}, + Streams: []grpc.StreamDesc{ + { + StreamName: "Debug", + Handler: _Debug_Debug_Handler, + ServerStreams: true, + ClientStreams: true, + }, + }, + Metadata: "debug/debug.proto", +} diff --git a/rpc/debug/debug.proto b/rpc/debug/debug.proto new file mode 100644 index 00000000000..7a8b7bb2eec --- /dev/null +++ b/rpc/debug/debug.proto @@ -0,0 +1,62 @@ +// 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 license@arduino.cc. + +syntax = "proto3"; + +package cc.arduino.cli.debug; + +option go_package = "github.com/arduino/arduino-cli/rpc/debug"; + + +// Service that abstract a debug Session usage +service Debug { + rpc Debug(stream DebugReq) returns (stream DebugResp) { } +} + +// The top-level message sent by the client for the `Debug` method. +// Multiple `DebugReq` messages can be sent but the first message +// must contain a `DebugReq` message to initialize the debug session. +// All subsequent messages must contain bytes to be sent to the debug session +// and must not contain a `DebugReq` message. +message DebugReq { + // Content must be either a debug session config or data to be sent. + + // Provides information to the debug that specifies which is the target. + // The first `StreamingOpenReq` message must contain a `DebugReq` + // message. + DebugConfigReq debugReq = 1; + + // The data to be sent to the target being monitored. + bytes data = 2; +} + +message DebugConfigReq { + Instance instance = 1; + string fqbn = 2; + string sketch_path = 3; + string port = 4; + bool verbose = 5; + string import_file = 7; +} + + +// +message DebugResp { + bytes data = 1; + string error = 2; +} + +// TODO remove this in next proto refactoring because is a duplicate from commands/common.proto +message Instance { int32 id = 1; } diff --git a/rpc/monitor/monitor.pb.go b/rpc/monitor/monitor.pb.go index 1a06ba48521..78238c1565a 100644 --- a/rpc/monitor/monitor.pb.go +++ b/rpc/monitor/monitor.pb.go @@ -9,8 +9,6 @@ import ( proto "github.com/golang/protobuf/proto" _struct "github.com/golang/protobuf/ptypes/struct" grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" math "math" ) @@ -268,11 +266,11 @@ var fileDescriptor_94d5950496a7550d = []byte{ // Reference imports to suppress errors if they are not otherwise used. var _ context.Context -var _ grpc.ClientConnInterface +var _ grpc.ClientConn // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion6 +const _ = grpc.SupportPackageIsVersion4 // MonitorClient is the client API for Monitor service. // @@ -282,10 +280,10 @@ type MonitorClient interface { } type monitorClient struct { - cc grpc.ClientConnInterface + cc *grpc.ClientConn } -func NewMonitorClient(cc grpc.ClientConnInterface) MonitorClient { +func NewMonitorClient(cc *grpc.ClientConn) MonitorClient { return &monitorClient{cc} } @@ -325,14 +323,6 @@ type MonitorServer interface { StreamingOpen(Monitor_StreamingOpenServer) error } -// UnimplementedMonitorServer can be embedded to have forward compatible implementations. -type UnimplementedMonitorServer struct { -} - -func (*UnimplementedMonitorServer) StreamingOpen(srv Monitor_StreamingOpenServer) error { - return status.Errorf(codes.Unimplemented, "method StreamingOpen not implemented") -} - func RegisterMonitorServer(s *grpc.Server, srv MonitorServer) { s.RegisterService(&_Monitor_serviceDesc, srv) } diff --git a/rpc/settings/settings.pb.go b/rpc/settings/settings.pb.go index 0537c7d9e3a..1bbc54f255d 100644 --- a/rpc/settings/settings.pb.go +++ b/rpc/settings/settings.pb.go @@ -8,8 +8,6 @@ import ( fmt "fmt" proto "github.com/golang/protobuf/proto" grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" math "math" ) @@ -277,11 +275,11 @@ var fileDescriptor_a4bfd59e429426d0 = []byte{ // Reference imports to suppress errors if they are not otherwise used. var _ context.Context -var _ grpc.ClientConnInterface +var _ grpc.ClientConn // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion6 +const _ = grpc.SupportPackageIsVersion4 // SettingsClient is the client API for Settings service. // @@ -294,10 +292,10 @@ type SettingsClient interface { } type settingsClient struct { - cc grpc.ClientConnInterface + cc *grpc.ClientConn } -func NewSettingsClient(cc grpc.ClientConnInterface) SettingsClient { +func NewSettingsClient(cc *grpc.ClientConn) SettingsClient { return &settingsClient{cc} } @@ -345,23 +343,6 @@ type SettingsServer interface { SetValue(context.Context, *Value) (*SetValueResponse, error) } -// UnimplementedSettingsServer can be embedded to have forward compatible implementations. -type UnimplementedSettingsServer struct { -} - -func (*UnimplementedSettingsServer) GetAll(ctx context.Context, req *GetAllRequest) (*RawData, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetAll not implemented") -} -func (*UnimplementedSettingsServer) Merge(ctx context.Context, req *RawData) (*MergeResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method Merge not implemented") -} -func (*UnimplementedSettingsServer) GetValue(ctx context.Context, req *GetValueRequest) (*Value, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetValue not implemented") -} -func (*UnimplementedSettingsServer) SetValue(ctx context.Context, req *Value) (*SetValueResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method SetValue not implemented") -} - func RegisterSettingsServer(s *grpc.Server, srv SettingsServer) { s.RegisterService(&_Settings_serviceDesc, srv) }