Skip to content

Commit 25d9100

Browse files
cmaglieper1234
andauthored
Extended Pluggable Monitor specification to allow board-specific settings to be applied (#1855)
* Added methods to obtain specific monitor settings for a board * Updated documentation * Implementaion of board-specific monitor settings * Allow submenu properties to override monitor settings * Apply code review changes to docs * Apply suggestions from code review Co-authored-by: per1234 <[email protected]> Co-authored-by: per1234 <[email protected]>
1 parent ae06539 commit 25d9100

File tree

6 files changed

+184
-17
lines changed

6 files changed

+184
-17
lines changed

Diff for: arduino/cores/board.go

+6
Original file line numberDiff line numberDiff line change
@@ -173,3 +173,9 @@ func (b *Board) IsBoardMatchingIDProperties(query *properties.Map) bool {
173173
}
174174
return false
175175
}
176+
177+
// GetMonitorSettings returns the settings for the pluggable monitor of the given protocol
178+
// and set of board properties.
179+
func GetMonitorSettings(protocol string, boardProperties *properties.Map) *properties.Map {
180+
return boardProperties.SubTree("monitor_port." + protocol)
181+
}

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

+37-1
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,7 @@ func (pm *Builder) loadBoards(platform *cores.PlatformRelease) error {
504504
convertVidPidIdentificationPropertiesToPluggableDiscovery(boardProperties)
505505
convertUploadToolsToPluggableDiscovery(boardProperties)
506506
}
507+
convertLegacySerialPortRTSDTRSettingsToPluggableMonitor(boardProperties)
507508

508509
// The board's ID must be available in a board's properties since it can
509510
// be used in all configuration files for several reasons, like setting compilation
@@ -523,6 +524,42 @@ func (pm *Builder) loadBoards(platform *cores.PlatformRelease) error {
523524
return nil
524525
}
525526

527+
// Converts the old:
528+
//
529+
// - xxx.serial.disableRTS=true
530+
// - xxx.serial.disableDTR=true
531+
//
532+
// properties into pluggable monitor compatible:
533+
//
534+
// - xxx.monitor_port.serial.rts=off
535+
// - xxx.monitor_port.serial.dtr=off
536+
func convertLegacySerialPortRTSDTRSettingsToPluggableMonitor(boardProperties *properties.Map) {
537+
disabledToOnOff := func(k string) string {
538+
if boardProperties.GetBoolean(k) {
539+
return "off" // Disabled
540+
}
541+
return "on" // Not disabled
542+
}
543+
if boardProperties.ContainsKey("serial.disableDTR") {
544+
boardProperties.Set("monitor_port.serial.dtr", disabledToOnOff("serial.disableDTR"))
545+
}
546+
if boardProperties.ContainsKey("serial.disableRTS") {
547+
boardProperties.Set("monitor_port.serial.rts", disabledToOnOff("serial.disableRTS"))
548+
}
549+
for _, k := range boardProperties.Keys() {
550+
if strings.HasSuffix(k, ".serial.disableDTR") {
551+
boardProperties.Set(
552+
strings.TrimSuffix(k, ".serial.disableDTR")+".monitor_port.serial.dtr",
553+
disabledToOnOff(k))
554+
}
555+
if strings.HasSuffix(k, ".serial.disableRTS") {
556+
boardProperties.Set(
557+
strings.TrimSuffix(k, ".serial.disableRTS")+".monitor_port.serial.rts",
558+
disabledToOnOff(k))
559+
}
560+
}
561+
}
562+
526563
// Converts the old:
527564
//
528565
// - xxx.vid.N
@@ -532,7 +569,6 @@ func (pm *Builder) loadBoards(platform *cores.PlatformRelease) error {
532569
//
533570
// - xxx.upload_port.N.vid
534571
// - xxx.upload_port.N.pid
535-
//
536572
func convertVidPidIdentificationPropertiesToPluggableDiscovery(boardProperties *properties.Map) {
537573
n := 0
538574
outputVidPid := func(vid, pid string) {

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

+61
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,67 @@ arduino_zero_native.pid.3=0x024d
106106
}`, zero4.Dump())
107107
}
108108

109+
func TestDisableDTRRTSConversionToPluggableMonitor(t *testing.T) {
110+
m, err := properties.LoadFromBytes([]byte(`
111+
menu.rts=RTS
112+
menu.dtr=DTR
113+
foo.menu.rts.on=On
114+
foo.menu.rts.on.serial.disableRTS=false
115+
foo.menu.rts.off=Off
116+
foo.menu.rts.off.serial.disableRTS=true
117+
foo.menu.dtr.on=On
118+
foo.menu.dtr.on.serial.disableDTR=false
119+
foo.menu.dtr.off=Off
120+
foo.menu.dtr.off.serial.disableDTR=true
121+
122+
arduino_zero.serial.disableDTR=true
123+
arduino_zero.serial.disableRTS=true
124+
125+
arduino_zero_edbg.serial.disableDTR=false
126+
arduino_zero_edbg.serial.disableRTS=true
127+
`))
128+
require.NoError(t, err)
129+
130+
{
131+
zero := m.SubTree("arduino_zero")
132+
convertLegacySerialPortRTSDTRSettingsToPluggableMonitor(zero)
133+
require.Equal(t, `properties.Map{
134+
"serial.disableDTR": "true",
135+
"serial.disableRTS": "true",
136+
"monitor_port.serial.dtr": "off",
137+
"monitor_port.serial.rts": "off",
138+
}`, zero.Dump())
139+
}
140+
{
141+
zeroEdbg := m.SubTree("arduino_zero_edbg")
142+
convertLegacySerialPortRTSDTRSettingsToPluggableMonitor(zeroEdbg)
143+
require.Equal(t, `properties.Map{
144+
"serial.disableDTR": "false",
145+
"serial.disableRTS": "true",
146+
"monitor_port.serial.dtr": "on",
147+
"monitor_port.serial.rts": "off",
148+
}`, zeroEdbg.Dump())
149+
}
150+
{
151+
foo := m.SubTree("foo")
152+
convertLegacySerialPortRTSDTRSettingsToPluggableMonitor(foo)
153+
require.Equal(t, `properties.Map{
154+
"menu.rts.on": "On",
155+
"menu.rts.on.serial.disableRTS": "false",
156+
"menu.rts.off": "Off",
157+
"menu.rts.off.serial.disableRTS": "true",
158+
"menu.dtr.on": "On",
159+
"menu.dtr.on.serial.disableDTR": "false",
160+
"menu.dtr.off": "Off",
161+
"menu.dtr.off.serial.disableDTR": "true",
162+
"menu.rts.on.monitor_port.serial.rts": "on",
163+
"menu.rts.off.monitor_port.serial.rts": "off",
164+
"menu.dtr.on.monitor_port.serial.dtr": "on",
165+
"menu.dtr.off.monitor_port.serial.dtr": "off",
166+
}`, foo.Dump())
167+
}
168+
}
169+
109170
func TestLoadDiscoveries(t *testing.T) {
110171
// Create all the necessary data to load discoveries
111172
fakePath := paths.New("fake-path")

Diff for: commands/monitor/monitor.go

+25-15
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ func Monitor(ctx context.Context, req *rpc.MonitorRequest) (*PortProxy, *pluggab
6767
}
6868
defer release()
6969

70-
m, err := findMonitorForProtocolAndBoard(pme, req.GetPort().GetProtocol(), req.GetFqbn())
70+
m, boardSettings, err := findMonitorAndSettingsForProtocolAndBoard(pme, req.GetPort().GetProtocol(), req.GetFqbn())
7171
if err != nil {
7272
return nil, nil, err
7373
}
@@ -82,18 +82,25 @@ func Monitor(ctx context.Context, req *rpc.MonitorRequest) (*PortProxy, *pluggab
8282
return nil, nil, &arduino.FailedMonitorError{Cause: err}
8383
}
8484

85-
monIO, err := m.Open(req.GetPort().GetAddress(), req.GetPort().GetProtocol())
86-
if err != nil {
87-
m.Quit()
88-
return nil, nil, &arduino.FailedMonitorError{Cause: err}
89-
}
85+
// Apply user-requested settings
9086
if portConfig := req.GetPortConfiguration(); portConfig != nil {
9187
for _, setting := range portConfig.Settings {
88+
boardSettings.Remove(setting.SettingId) // Remove board settings overridden by the user
9289
if err := m.Configure(setting.SettingId, setting.Value); err != nil {
9390
logrus.Errorf("Could not set configuration %s=%s: %s", setting.SettingId, setting.Value, err)
9491
}
9592
}
9693
}
94+
// Apply specific board settings
95+
for setting, value := range boardSettings.AsMap() {
96+
m.Configure(setting, value)
97+
}
98+
99+
monIO, err := m.Open(req.GetPort().GetAddress(), req.GetPort().GetProtocol())
100+
if err != nil {
101+
m.Quit()
102+
return nil, nil, &arduino.FailedMonitorError{Cause: err}
103+
}
97104

98105
logrus.Infof("Port %s successfully opened", req.GetPort().GetAddress())
99106
return &PortProxy{
@@ -106,36 +113,39 @@ func Monitor(ctx context.Context, req *rpc.MonitorRequest) (*PortProxy, *pluggab
106113
}, descriptor, nil
107114
}
108115

109-
func findMonitorForProtocolAndBoard(pme *packagemanager.Explorer, protocol, fqbn string) (*pluggableMonitor.PluggableMonitor, error) {
116+
func findMonitorAndSettingsForProtocolAndBoard(pme *packagemanager.Explorer, protocol, fqbn string) (*pluggableMonitor.PluggableMonitor, *properties.Map, error) {
110117
if protocol == "" {
111-
return nil, &arduino.MissingPortProtocolError{}
118+
return nil, nil, &arduino.MissingPortProtocolError{}
112119
}
113120

114121
var monitorDepOrRecipe *cores.MonitorDependency
122+
boardSettings := properties.NewMap()
115123

116124
// If a board is specified search the monitor in the board package first
117125
if fqbn != "" {
118126
fqbn, err := cores.ParseFQBN(fqbn)
119127
if err != nil {
120-
return nil, &arduino.InvalidFQBNError{Cause: err}
128+
return nil, nil, &arduino.InvalidFQBNError{Cause: err}
121129
}
122130

123131
_, boardPlatform, _, boardProperties, _, err := pme.ResolveFQBN(fqbn)
124132
if err != nil {
125-
return nil, &arduino.UnknownFQBNError{Cause: err}
133+
return nil, nil, &arduino.UnknownFQBNError{Cause: err}
126134
}
127135

136+
boardSettings = cores.GetMonitorSettings(protocol, boardProperties)
137+
128138
if mon, ok := boardPlatform.Monitors[protocol]; ok {
129139
monitorDepOrRecipe = mon
130140
} else if recipe, ok := boardPlatform.MonitorsDevRecipes[protocol]; ok {
131141
// If we have a recipe we must resolve it
132142
cmdLine := boardProperties.ExpandPropsInString(recipe)
133143
cmdArgs, err := properties.SplitQuotedString(cmdLine, `"'`, false)
134144
if err != nil {
135-
return nil, &arduino.InvalidArgumentError{Message: tr("Invalid recipe in platform.txt"), Cause: err}
145+
return nil, nil, &arduino.InvalidArgumentError{Message: tr("Invalid recipe in platform.txt"), Cause: err}
136146
}
137147
id := fmt.Sprintf("%s-%s", boardPlatform, protocol)
138-
return pluggableMonitor.New(id, cmdArgs...), nil
148+
return pluggableMonitor.New(id, cmdArgs...), boardSettings, nil
139149
}
140150
}
141151

@@ -150,17 +160,17 @@ func findMonitorForProtocolAndBoard(pme *packagemanager.Explorer, protocol, fqbn
150160
}
151161

152162
if monitorDepOrRecipe == nil {
153-
return nil, &arduino.NoMonitorAvailableForProtocolError{Protocol: protocol}
163+
return nil, nil, &arduino.NoMonitorAvailableForProtocolError{Protocol: protocol}
154164
}
155165

156166
// If it is a monitor dependency, resolve tool and create a monitor client
157167
tool := pme.FindMonitorDependency(monitorDepOrRecipe)
158168
if tool == nil {
159-
return nil, &arduino.MonitorNotFoundError{Monitor: monitorDepOrRecipe.String()}
169+
return nil, nil, &arduino.MonitorNotFoundError{Monitor: monitorDepOrRecipe.String()}
160170
}
161171

162172
return pluggableMonitor.New(
163173
monitorDepOrRecipe.Name,
164174
tool.InstallDir.Join(monitorDepOrRecipe.Name).String(),
165-
), nil
175+
), boardSettings, nil
166176
}

Diff for: commands/monitor/settings.go

+14-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ func EnumerateMonitorPortSettings(ctx context.Context, req *rpc.EnumerateMonitor
3232
}
3333
defer release()
3434

35-
m, err := findMonitorForProtocolAndBoard(pme, req.GetPortProtocol(), req.GetFqbn())
35+
m, boardSettings, err := findMonitorAndSettingsForProtocolAndBoard(pme, req.GetPortProtocol(), req.GetFqbn())
3636
if err != nil {
3737
return nil, err
3838
}
@@ -46,6 +46,19 @@ func EnumerateMonitorPortSettings(ctx context.Context, req *rpc.EnumerateMonitor
4646
if err != nil {
4747
return nil, &arduino.FailedMonitorError{Cause: err}
4848
}
49+
50+
// Apply default settings for this board and protocol
51+
for setting, value := range boardSettings.AsMap() {
52+
if param, ok := desc.ConfigurationParameters[setting]; ok {
53+
for _, v := range param.Values {
54+
if v == value {
55+
param.Selected = value
56+
break
57+
}
58+
}
59+
}
60+
}
61+
4962
return &rpc.EnumerateMonitorPortSettingsResponse{Settings: convert(desc)}, nil
5063
}
5164

Diff for: docs/platform-specification.md

+41
Original file line numberDiff line numberDiff line change
@@ -903,6 +903,47 @@ will allow all legacy non-pluggable platforms to migrate to pluggable monitor wi
903903

904904
For detailed information, see the [Pluggable Monitor specification](pluggable-monitor-specification.md).
905905

906+
#### Port configuration
907+
908+
Each pluggable monitor has its own default settings that can be overridden using the following board properties:
909+
910+
```
911+
BOARD_ID.monitor_port.PROTOCOL.SETTING_NAME=SETTING_VALUE
912+
```
913+
914+
where:
915+
916+
- `BOARD_ID` is the board identifier
917+
- `PROTOCOL` is the port protocol
918+
- `SETTING_NAME` and `SETTING_VALUE` are the port setting and the desired value
919+
920+
For example, let's suppose that a board needs the `baudrate` setting of the `serial` port to be `9600`, then the
921+
corresponding properties in the `boards.txt` file will be:
922+
923+
```
924+
myboard.monitor_port.serial.baudrate=9600
925+
```
926+
927+
The settings available in a specific pluggable monitor can be
928+
[queried directly from it](pluggable-monitor-specification.md#describe-command).
929+
930+
#### Legacy `serial.disableRTS` and `serial.disableDTR` properties
931+
932+
In the old Arduino IDE (<=1.8.x) we used the properties:
933+
934+
```
935+
BOARD_ID.serial.disableRTS=true
936+
BOARD_ID.serial.disableDTR=true
937+
```
938+
939+
to disable RTS and DTR when opening the serial monitor. To keep backward compatibilty the properties above are
940+
automatically converted to the corresponding pluggable monitor properties:
941+
942+
```
943+
BOARD_ID.monitor_port.serial.rts=off
944+
BOARD_ID.monitor_port.serial.dtr=off
945+
```
946+
906947
### Verbose parameter
907948

908949
It is possible for the user to enable verbosity from the Preferences panel of the IDEs or Arduino CLI's `--verbose`

0 commit comments

Comments
 (0)