Skip to content

Commit 7b44597

Browse files
cmaglied-a-v
authored andcommitted
Add monitor --describe command (arduino#1493)
* Resolve monitors from platform.txt * Implementation of monitor --describe command * fix i18n
1 parent 6ce6a16 commit 7b44597

File tree

10 files changed

+409
-50
lines changed

10 files changed

+409
-50
lines changed

Diff for: arduino/cores/cores.go

+1
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ type PlatformRelease struct {
6262
IsIDEBundled bool `json:"-"`
6363
IsTrusted bool `json:"-"`
6464
PluggableDiscoveryAware bool `json:"-"` // true if the Platform supports pluggable discovery (no compatibility layer required)
65+
Monitors map[string]*MonitorDependency
6566
}
6667

6768
// BoardManifest contains information about a board. These metadata are usually

Diff for: arduino/cores/packagemanager/loader.go

+14
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,7 @@ func (pm *PackageManager) loadPlatformRelease(platform *cores.PlatformRelease, p
326326
} else {
327327
platform.Properties.Set("pluggable_discovery.required.0", "builtin:serial-discovery")
328328
platform.Properties.Set("pluggable_discovery.required.1", "builtin:mdns-discovery")
329+
platform.Properties.Set("pluggable_monitor.required.serial", "builtin:serial-monitor")
329330
}
330331

331332
if platform.Platform.Name == "" {
@@ -359,6 +360,19 @@ func (pm *PackageManager) loadPlatformRelease(platform *cores.PlatformRelease, p
359360
if !platform.PluggableDiscoveryAware {
360361
convertLegacyPlatformToPluggableDiscovery(platform)
361362
}
363+
364+
// Build pluggable monitor references
365+
platform.Monitors = map[string]*cores.MonitorDependency{}
366+
for protocol, ref := range platform.Properties.SubTree("pluggable_monitor.required").AsMap() {
367+
split := strings.Split(ref, ":")
368+
if len(split) != 2 {
369+
return fmt.Errorf(tr("invalid pluggable monitor reference: %s"), ref)
370+
}
371+
platform.Monitors[protocol] = &cores.MonitorDependency{
372+
Packager: split[0],
373+
Name: split[1],
374+
}
375+
}
362376
return nil
363377
}
364378

Diff for: cli/cli.go

+2
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import (
3535
"github.com/arduino/arduino-cli/cli/generatedocs"
3636
"github.com/arduino/arduino-cli/cli/globals"
3737
"github.com/arduino/arduino-cli/cli/lib"
38+
"github.com/arduino/arduino-cli/cli/monitor"
3839
"github.com/arduino/arduino-cli/cli/outdated"
3940
"github.com/arduino/arduino-cli/cli/output"
4041
"github.com/arduino/arduino-cli/cli/sketch"
@@ -93,6 +94,7 @@ func createCliCommandTree(cmd *cobra.Command) {
9394
cmd.AddCommand(daemon.NewCommand())
9495
cmd.AddCommand(generatedocs.NewCommand())
9596
cmd.AddCommand(lib.NewCommand())
97+
cmd.AddCommand(monitor.NewCommand())
9698
cmd.AddCommand(outdated.NewCommand())
9799
cmd.AddCommand(sketch.NewCommand())
98100
cmd.AddCommand(update.NewCommand())

Diff for: cli/monitor/monitor.go

+105
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
// This file is part of arduino-cli.
2+
//
3+
// Copyright 2020 ARDUINO SA (http://www.arduino.cc/)
4+
//
5+
// This software is released under the GNU General Public License version 3,
6+
// which covers the main part of arduino-cli.
7+
// The terms of this license can be found at:
8+
// https://www.gnu.org/licenses/gpl-3.0.en.html
9+
//
10+
// You can be released from the requirements of the above licenses by purchasing
11+
// a commercial license. Buying such a license is mandatory if you want to
12+
// modify or otherwise use the software for commercial activities involving the
13+
// Arduino software without disclosing the source code of your own applications.
14+
// To purchase a commercial license, send an email to [email protected].
15+
16+
package monitor
17+
18+
import (
19+
"context"
20+
"os"
21+
"sort"
22+
"strings"
23+
24+
"github.com/arduino/arduino-cli/cli/arguments"
25+
"github.com/arduino/arduino-cli/cli/errorcodes"
26+
"github.com/arduino/arduino-cli/cli/feedback"
27+
"github.com/arduino/arduino-cli/cli/instance"
28+
"github.com/arduino/arduino-cli/commands/monitor"
29+
"github.com/arduino/arduino-cli/i18n"
30+
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
31+
"github.com/arduino/arduino-cli/table"
32+
"github.com/fatih/color"
33+
"github.com/spf13/cobra"
34+
)
35+
36+
var tr = i18n.Tr
37+
38+
var portArgs arguments.Port
39+
var describe bool
40+
41+
// NewCommand created a new `monitor` command
42+
func NewCommand() *cobra.Command {
43+
cmd := &cobra.Command{
44+
Use: "monitor",
45+
Short: tr("Open a communication port with a board."),
46+
Long: tr("Open a communication port with a board."),
47+
Example: "" +
48+
" " + os.Args[0] + " monitor -p /dev/ttyACM0\n" +
49+
" " + os.Args[0] + " monitor -p /dev/ttyACM0 --describe",
50+
Run: runMonitorCmd,
51+
}
52+
portArgs.AddToCommand(cmd)
53+
cmd.Flags().BoolVar(&describe, "describe", false, tr("Show all the settings of the communication port."))
54+
cmd.MarkFlagRequired("port")
55+
return cmd
56+
}
57+
58+
func runMonitorCmd(cmd *cobra.Command, args []string) {
59+
instance := instance.CreateAndInit()
60+
61+
port, err := portArgs.GetPort(instance, nil)
62+
if err != nil {
63+
feedback.Error(err)
64+
os.Exit(errorcodes.ErrGeneric)
65+
}
66+
67+
if describe {
68+
res, err := monitor.EnumerateMonitorPortSettings(context.Background(), &rpc.EnumerateMonitorPortSettingsRequest{
69+
Instance: instance,
70+
Port: port.ToRPC(),
71+
Fqbn: "",
72+
})
73+
if err != nil {
74+
feedback.Error(tr("Error getting port settings details: %s"), err)
75+
os.Exit(errorcodes.ErrGeneric)
76+
}
77+
feedback.PrintResult(&detailsResult{Settings: res.Settings})
78+
return
79+
}
80+
81+
feedback.Error("Monitor functionality not yet implemented")
82+
os.Exit(errorcodes.ErrGeneric)
83+
}
84+
85+
type detailsResult struct {
86+
Settings []*rpc.MonitorPortSettingDescriptor `json:"settings"`
87+
}
88+
89+
func (r *detailsResult) Data() interface{} {
90+
return r
91+
}
92+
93+
func (r *detailsResult) String() string {
94+
t := table.New()
95+
green := color.New(color.FgGreen)
96+
t.SetHeader(tr("ID"), tr("Setting"), tr("Default"), tr("Values"))
97+
sort.Slice(r.Settings, func(i, j int) bool {
98+
return r.Settings[i].Label < r.Settings[j].Label
99+
})
100+
for _, setting := range r.Settings {
101+
values := strings.Join(setting.EnumValues, ", ")
102+
t.AddRow(setting.SettingId, setting.Label, table.NewCell(setting.Value, green), values)
103+
}
104+
return t.Render()
105+
}

Diff for: commands/daemon/daemon.go

+4-2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"github.com/arduino/arduino-cli/commands/compile"
2727
"github.com/arduino/arduino-cli/commands/core"
2828
"github.com/arduino/arduino-cli/commands/lib"
29+
"github.com/arduino/arduino-cli/commands/monitor"
2930
"github.com/arduino/arduino-cli/commands/sketch"
3031
"github.com/arduino/arduino-cli/commands/upload"
3132
"github.com/arduino/arduino-cli/i18n"
@@ -467,8 +468,9 @@ func (s *ArduinoCoreServerImpl) GitLibraryInstall(req *rpc.GitLibraryInstallRequ
467468
}
468469

469470
// EnumerateMonitorPortSettings FIXMEDOC
470-
func (s *ArduinoCoreServerImpl) EnumerateMonitorPortSettings(context.Context, *rpc.EnumerateMonitorPortSettingsRequest) (*rpc.EnumerateMonitorPortSettingsResponse, error) {
471-
return nil, status.New(codes.Unimplemented, "Not implemented").Err()
471+
func (s *ArduinoCoreServerImpl) EnumerateMonitorPortSettings(ctx context.Context, req *rpc.EnumerateMonitorPortSettingsRequest) (*rpc.EnumerateMonitorPortSettingsResponse, error) {
472+
resp, err := monitor.EnumerateMonitorPortSettings(ctx, req)
473+
return resp, convertErrorToRPCStatus(err)
472474
}
473475

474476
// Monitor FIXMEDOC

Diff for: commands/errors.go

+63
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,32 @@ func (e *MissingPortProtocolError) ToRPCStatus() *status.Status {
162162
return status.New(codes.InvalidArgument, e.Error())
163163
}
164164

165+
// MissingPortError is returned when the port is mandatory and not specified
166+
type MissingPortError struct{}
167+
168+
func (e *MissingPortError) Error() string {
169+
return tr("Missing port")
170+
}
171+
172+
// ToRPCStatus converts the error into a *status.Status
173+
func (e *MissingPortError) ToRPCStatus() *status.Status {
174+
return status.New(codes.InvalidArgument, e.Error())
175+
}
176+
177+
// NoMonitorAvailableForProtocolError is returned when a monitor for the specified port protocol is not available
178+
type NoMonitorAvailableForProtocolError struct {
179+
Protocol string
180+
}
181+
182+
func (e *NoMonitorAvailableForProtocolError) Error() string {
183+
return tr("No monitor available for the port protocol %s", e.Protocol)
184+
}
185+
186+
// ToRPCStatus converts the error into a *status.Status
187+
func (e *NoMonitorAvailableForProtocolError) ToRPCStatus() *status.Status {
188+
return status.New(codes.InvalidArgument, e.Error())
189+
}
190+
165191
// MissingProgrammerError is returned when the programmer is mandatory and not specified
166192
type MissingProgrammerError struct{}
167193

@@ -208,6 +234,25 @@ func (e *ProgrammerNotFoundError) ToRPCStatus() *status.Status {
208234
return status.New(codes.NotFound, e.Error())
209235
}
210236

237+
// MonitorNotFoundError is returned when the pluggable monitor is not found
238+
type MonitorNotFoundError struct {
239+
Monitor string
240+
Cause error
241+
}
242+
243+
func (e *MonitorNotFoundError) Error() string {
244+
return composeErrorMsg(tr("Monitor '%s' not found", e.Monitor), e.Cause)
245+
}
246+
247+
func (e *MonitorNotFoundError) Unwrap() error {
248+
return e.Cause
249+
}
250+
251+
// ToRPCStatus converts the error into a *status.Status
252+
func (e *MonitorNotFoundError) ToRPCStatus() *status.Status {
253+
return status.New(codes.NotFound, e.Error())
254+
}
255+
211256
// InvalidPlatformPropertyError is returned when a property in the platform is not valid
212257
type InvalidPlatformPropertyError struct {
213258
Property string
@@ -454,6 +499,24 @@ func (e *FailedDebugError) ToRPCStatus() *status.Status {
454499
return status.New(codes.Internal, e.Error())
455500
}
456501

502+
// FailedMonitorError is returned when opening the monitor port of a board fails
503+
type FailedMonitorError struct {
504+
Cause error
505+
}
506+
507+
func (e *FailedMonitorError) Error() string {
508+
return composeErrorMsg(tr("Port monitor error"), e.Cause)
509+
}
510+
511+
func (e *FailedMonitorError) Unwrap() error {
512+
return e.Cause
513+
}
514+
515+
// ToRPCStatus converts the error into a *status.Status
516+
func (e *FailedMonitorError) ToRPCStatus() *status.Status {
517+
return status.New(codes.Internal, e.Error())
518+
}
519+
457520
// CompileFailedError is returned when the compile fails
458521
type CompileFailedError struct {
459522
Message string

Diff for: commands/monitor/monitor.go

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// This file is part of arduino-cli.
2+
//
3+
// Copyright 2020 ARDUINO SA (http://www.arduino.cc/)
4+
//
5+
// This software is released under the GNU General Public License version 3,
6+
// which covers the main part of arduino-cli.
7+
// The terms of this license can be found at:
8+
// https://www.gnu.org/licenses/gpl-3.0.en.html
9+
//
10+
// You can be released from the requirements of the above licenses by purchasing
11+
// a commercial license. Buying such a license is mandatory if you want to
12+
// modify or otherwise use the software for commercial activities involving the
13+
// Arduino software without disclosing the source code of your own applications.
14+
// To purchase a commercial license, send an email to [email protected].
15+
16+
package monitor
17+
18+
import (
19+
"github.com/arduino/arduino-cli/arduino/cores"
20+
"github.com/arduino/arduino-cli/arduino/cores/packagemanager"
21+
"github.com/arduino/arduino-cli/commands"
22+
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
23+
)
24+
25+
func findMonitorForProtocolAndBoard(pm *packagemanager.PackageManager, port *rpc.Port, fqbn string) (*cores.MonitorDependency, error) {
26+
if port == nil {
27+
return nil, &commands.MissingPortError{}
28+
}
29+
protocol := port.GetProtocol()
30+
if protocol == "" {
31+
return nil, &commands.MissingPortProtocolError{}
32+
}
33+
34+
// If a board is specified search the monitor in the board package first
35+
if fqbn != "" {
36+
fqbn, err := cores.ParseFQBN(fqbn)
37+
if err != nil {
38+
return nil, &commands.InvalidFQBNError{Cause: err}
39+
}
40+
41+
_, boardPlatform, _, _, _, err := pm.ResolveFQBN(fqbn)
42+
if err != nil {
43+
return nil, &commands.UnknownFQBNError{Cause: err}
44+
}
45+
if mon, ok := boardPlatform.Monitors[protocol]; ok {
46+
return mon, nil
47+
}
48+
}
49+
50+
// Otherwise look in all package for a suitable monitor
51+
for _, platformRel := range pm.InstalledPlatformReleases() {
52+
if mon, ok := platformRel.Monitors[protocol]; ok {
53+
return mon, nil
54+
}
55+
}
56+
return nil, &commands.NoMonitorAvailableForProtocolError{Protocol: protocol}
57+
}

Diff for: commands/monitor/settings.go

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// This file is part of arduino-cli.
2+
//
3+
// Copyright 2020 ARDUINO SA (http://www.arduino.cc/)
4+
//
5+
// This software is released under the GNU General Public License version 3,
6+
// which covers the main part of arduino-cli.
7+
// The terms of this license can be found at:
8+
// https://www.gnu.org/licenses/gpl-3.0.en.html
9+
//
10+
// You can be released from the requirements of the above licenses by purchasing
11+
// a commercial license. Buying such a license is mandatory if you want to
12+
// modify or otherwise use the software for commercial activities involving the
13+
// Arduino software without disclosing the source code of your own applications.
14+
// To purchase a commercial license, send an email to [email protected].
15+
16+
package monitor
17+
18+
import (
19+
"context"
20+
21+
pluggableMonitor "github.com/arduino/arduino-cli/arduino/monitor"
22+
"github.com/arduino/arduino-cli/commands"
23+
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
24+
)
25+
26+
// EnumerateMonitorPortSettings returns a description of the configuration settings of a monitor port
27+
func EnumerateMonitorPortSettings(ctx context.Context, req *rpc.EnumerateMonitorPortSettingsRequest) (*rpc.EnumerateMonitorPortSettingsResponse, error) {
28+
pm := commands.GetPackageManager(req.GetInstance().GetId())
29+
if pm == nil {
30+
return nil, &commands.InvalidInstanceError{}
31+
}
32+
33+
monitorRef, err := findMonitorForProtocolAndBoard(pm, req.GetPort(), req.GetFqbn())
34+
if err != nil {
35+
return nil, err
36+
}
37+
38+
tool := pm.FindMonitorDependency(monitorRef)
39+
if tool == nil {
40+
return nil, &commands.MonitorNotFoundError{Monitor: monitorRef.String()}
41+
}
42+
43+
m := pluggableMonitor.New(monitorRef.Name, tool.InstallDir.Join(monitorRef.Name).String())
44+
45+
if err := m.Run(); err != nil {
46+
return nil, &commands.FailedMonitorError{Cause: err}
47+
}
48+
defer m.Quit()
49+
50+
desc, err := m.Describe()
51+
if err != nil {
52+
return nil, &commands.FailedMonitorError{Cause: err}
53+
}
54+
return &rpc.EnumerateMonitorPortSettingsResponse{Settings: convert(desc)}, nil
55+
}
56+
57+
func convert(desc *pluggableMonitor.PortDescriptor) []*rpc.MonitorPortSettingDescriptor {
58+
res := []*rpc.MonitorPortSettingDescriptor{}
59+
for settingID, descriptor := range desc.ConfigurationParameters {
60+
res = append(res, &rpc.MonitorPortSettingDescriptor{
61+
SettingId: settingID,
62+
Label: descriptor.Label,
63+
Type: descriptor.Type,
64+
EnumValues: descriptor.Values,
65+
Value: descriptor.Selected,
66+
})
67+
}
68+
return res
69+
}

0 commit comments

Comments
 (0)