Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 0d8ce36

Browse files
cmaglieper1234
andauthored
Pluggable discovery: board identification can now identify also custom board options (#1674)
* Added test for os-specific config options * Build board config options structures only once and cache them * Board's build options properties are now calculated only once and cached * Added tests for config options ordering It required insertion of test data with the properties.Set method to preserve ordering. * Renamed some variables to improve code readability * Added board config identification subroutines * Added board config detection in 'commands.identify' function * Updated docs * Apply suggestions from code review Co-authored-by: per1234 <accounts@perglass.com> * Fixed comment Co-authored-by: per1234 <accounts@perglass.com>
1 parent 6f14510 commit 0d8ce36

File tree

6 files changed

+565
-279
lines changed

6 files changed

+565
-279
lines changed

‎arduino/cores/board.go‎

Lines changed: 88 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ type Board struct {
2727
BoardID string
2828
Properties *properties.Map `json:"-"`
2929
PlatformRelease *PlatformRelease `json:"-"`
30+
configOptions *properties.Map
31+
configOptionValues map[string]*properties.Map
32+
configOptionProperties map[string]*properties.Map
33+
defaultConfig *properties.Map
3034
identificationProperties []*properties.Map
3135
}
3236

@@ -64,66 +68,74 @@ func (b *Board) String() string {
6468
return b.FQBN()
6569
}
6670

71+
func (b *Board) buildConfigOptionsStructures() {
72+
if b.configOptions != nil {
73+
return
74+
}
75+
76+
b.configOptions = properties.NewMap()
77+
allConfigs := b.Properties.SubTree("menu")
78+
for _, option := range allConfigs.FirstLevelKeys() {
79+
b.configOptions.Set(option, b.PlatformRelease.Menus.Get(option))
80+
}
81+
82+
b.configOptionValues = map[string]*properties.Map{}
83+
b.configOptionProperties = map[string]*properties.Map{}
84+
b.defaultConfig = properties.NewMap()
85+
for option, optionProps := range allConfigs.FirstLevelOf() {
86+
b.configOptionValues[option] = properties.NewMap()
87+
values := optionProps.FirstLevelKeys()
88+
b.defaultConfig.Set(option, values[0])
89+
for _, value := range values {
90+
if label, ok := optionProps.GetOk(value); ok {
91+
b.configOptionValues[option].Set(value, label)
92+
b.configOptionProperties[option+"="+value] = optionProps.SubTree(value)
93+
}
94+
}
95+
}
96+
}
97+
6798
// GetConfigOptions returns an OrderedMap of configuration options for this board.
6899
// The returned map will have key and value as option id and option name, respectively.
69100
func (b *Board) GetConfigOptions() *properties.Map {
70-
res := properties.NewMap()
71-
menu := b.Properties.SubTree("menu")
72-
for _, option := range menu.FirstLevelKeys() {
73-
res.Set(option, b.PlatformRelease.Menus.Get(option))
74-
}
75-
return res
101+
b.buildConfigOptionsStructures()
102+
return b.configOptions
76103
}
77104

78105
// GetConfigOptionValues returns an OrderedMap of possible values for a specific configuratio options
79106
// for this board. The returned map will have key and value as option value and option value name,
80107
// respectively.
81108
func (b *Board) GetConfigOptionValues(option string) *properties.Map {
82-
res := properties.NewMap()
83-
menu := b.Properties.SubTree("menu").SubTree(option)
84-
for _, value := range menu.FirstLevelKeys() {
85-
if label, ok := menu.GetOk(value); ok {
86-
res.Set(value, label)
87-
}
88-
}
89-
return res
109+
b.buildConfigOptionsStructures()
110+
return b.configOptionValues[option]
90111
}
91112

92113
// GetBuildProperties returns the build properties and the build
93114
// platform for the Board with the configuration passed as parameter.
94115
func (b *Board) GetBuildProperties(userConfigs *properties.Map) (*properties.Map, error) {
95-
// Clone user configs because they are destroyed during iteration
96-
userConfigs = userConfigs.Clone()
116+
b.buildConfigOptionsStructures()
117+
118+
// Override default configs with user configs
119+
config := b.defaultConfig.Clone()
120+
config.Merge(userConfigs)
97121

98122
// Start with board's base properties
99123
buildProperties := b.Properties.Clone()
100124

101125
// Add all sub-configurations one by one (a config is: option=value)
102-
menu := b.Properties.SubTree("menu")
103-
for _, option := range menu.FirstLevelKeys() {
104-
optionMenu := menu.SubTree(option)
105-
userValue, haveUserValue := userConfigs.GetOk(option)
106-
if haveUserValue {
107-
userConfigs.Remove(option)
108-
if !optionMenu.ContainsKey(userValue) {
109-
return nil, fmt.Errorf(tr("invalid value '%[1]s' for option '%[2]s'"), userValue, option)
110-
}
111-
} else {
112-
// apply default
113-
userValue = optionMenu.FirstLevelKeys()[0]
114-
}
115-
116-
optionsConf := optionMenu.SubTree(userValue)
117-
buildProperties.Merge(optionsConf)
118-
}
119-
120126
// Check for residual invalid options...
121-
if invalidKeys := userConfigs.Keys(); len(invalidKeys) > 0 {
122-
invalidOption := invalidKeys[0]
123-
if invalidOption == "" {
127+
for option, value := range config.AsMap() {
128+
if option == "" {
124129
return nil, fmt.Errorf(tr("invalid empty option found"))
125130
}
126-
return nil, fmt.Errorf(tr("invalid option '%s'"), invalidOption)
131+
if _, ok := b.configOptions.GetOk(option); !ok {
132+
return nil, fmt.Errorf(tr("invalid option '%s'"), option)
133+
}
134+
optionsConf, ok := b.configOptionProperties[option+"="+value]
135+
if !ok {
136+
return nil, fmt.Errorf(tr("invalid value '%[1]s' for option '%[2]s'"), value, option)
137+
}
138+
buildProperties.Merge(optionsConf)
127139
}
128140

129141
return buildProperties, nil
@@ -153,7 +165,7 @@ func (b *Board) GetIdentificationProperties() []*properties.Map {
153165
}
154166

155167
// IsBoardMatchingIDProperties returns true if the board match the given
156-
// identification properties
168+
// upload port identification properties
157169
func (b *Board) IsBoardMatchingIDProperties(query *properties.Map) bool {
158170
// check checks if the given set of properties p match the "query"
159171
check := func(p *properties.Map) bool {
@@ -179,3 +191,40 @@ func (b *Board) IsBoardMatchingIDProperties(query *properties.Map) bool {
179191
func GetMonitorSettings(protocol string, boardProperties *properties.Map) *properties.Map {
180192
return boardProperties.SubTree("monitor_port." + protocol)
181193
}
194+
195+
// IdentifyBoardConfiguration returns the configuration of the board that can be
196+
// deduced from the given upload port identification properties
197+
func (b *Board) IdentifyBoardConfiguration(query *properties.Map) *properties.Map {
198+
// check checks if the given set of properties p match the "query"
199+
check := func(p *properties.Map) bool {
200+
for k, v := range p.AsMap() {
201+
if !strings.EqualFold(query.Get(k), v) {
202+
return false
203+
}
204+
}
205+
return true
206+
}
207+
checkAll := func(allP []*properties.Map) bool {
208+
for _, p := range allP {
209+
if check(p) {
210+
return true
211+
}
212+
}
213+
return false
214+
}
215+
216+
res := properties.NewMap()
217+
for _, option := range b.GetConfigOptions().Keys() {
218+
values := b.GetConfigOptionValues(option).Keys()
219+
220+
for _, value := range values {
221+
config := option + "=" + value
222+
configProps := b.configOptionProperties[config]
223+
224+
if checkAll(configProps.ExtractSubIndexSets("upload_port")) {
225+
res.Set(option, value)
226+
}
227+
}
228+
}
229+
return res
230+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /