diff --git a/arduino/cores/board.go b/arduino/cores/board.go index 3195fb8f14f..c5cd73daafd 100644 --- a/arduino/cores/board.go +++ b/arduino/cores/board.go @@ -27,6 +27,10 @@ type Board struct { BoardID string Properties *properties.Map `json:"-"` PlatformRelease *PlatformRelease `json:"-"` + configOptions *properties.Map + configOptionValues map[string]*properties.Map + configOptionProperties map[string]*properties.Map + defaultConfig *properties.Map identificationProperties []*properties.Map } @@ -64,66 +68,74 @@ func (b *Board) String() string { return b.FQBN() } +func (b *Board) buildConfigOptionsStructures() { + if b.configOptions != nil { + return + } + + b.configOptions = properties.NewMap() + allConfigs := b.Properties.SubTree("menu") + for _, option := range allConfigs.FirstLevelKeys() { + b.configOptions.Set(option, b.PlatformRelease.Menus.Get(option)) + } + + b.configOptionValues = map[string]*properties.Map{} + b.configOptionProperties = map[string]*properties.Map{} + b.defaultConfig = properties.NewMap() + for option, optionProps := range allConfigs.FirstLevelOf() { + b.configOptionValues[option] = properties.NewMap() + values := optionProps.FirstLevelKeys() + b.defaultConfig.Set(option, values[0]) + for _, value := range values { + if label, ok := optionProps.GetOk(value); ok { + b.configOptionValues[option].Set(value, label) + b.configOptionProperties[option+"="+value] = optionProps.SubTree(value) + } + } + } +} + // GetConfigOptions returns an OrderedMap of configuration options for this board. // The returned map will have key and value as option id and option name, respectively. func (b *Board) GetConfigOptions() *properties.Map { - res := properties.NewMap() - menu := b.Properties.SubTree("menu") - for _, option := range menu.FirstLevelKeys() { - res.Set(option, b.PlatformRelease.Menus.Get(option)) - } - return res + b.buildConfigOptionsStructures() + return b.configOptions } // GetConfigOptionValues returns an OrderedMap of possible values for a specific configuratio options // for this board. The returned map will have key and value as option value and option value name, // respectively. func (b *Board) GetConfigOptionValues(option string) *properties.Map { - res := properties.NewMap() - menu := b.Properties.SubTree("menu").SubTree(option) - for _, value := range menu.FirstLevelKeys() { - if label, ok := menu.GetOk(value); ok { - res.Set(value, label) - } - } - return res + b.buildConfigOptionsStructures() + return b.configOptionValues[option] } // GetBuildProperties returns the build properties and the build // platform for the Board with the configuration passed as parameter. func (b *Board) GetBuildProperties(userConfigs *properties.Map) (*properties.Map, error) { - // Clone user configs because they are destroyed during iteration - userConfigs = userConfigs.Clone() + b.buildConfigOptionsStructures() + + // Override default configs with user configs + config := b.defaultConfig.Clone() + config.Merge(userConfigs) // Start with board's base properties buildProperties := b.Properties.Clone() // Add all sub-configurations one by one (a config is: option=value) - menu := b.Properties.SubTree("menu") - for _, option := range menu.FirstLevelKeys() { - optionMenu := menu.SubTree(option) - userValue, haveUserValue := userConfigs.GetOk(option) - if haveUserValue { - userConfigs.Remove(option) - if !optionMenu.ContainsKey(userValue) { - return nil, fmt.Errorf(tr("invalid value '%[1]s' for option '%[2]s'"), userValue, option) - } - } else { - // apply default - userValue = optionMenu.FirstLevelKeys()[0] - } - - optionsConf := optionMenu.SubTree(userValue) - buildProperties.Merge(optionsConf) - } - // Check for residual invalid options... - if invalidKeys := userConfigs.Keys(); len(invalidKeys) > 0 { - invalidOption := invalidKeys[0] - if invalidOption == "" { + for option, value := range config.AsMap() { + if option == "" { return nil, fmt.Errorf(tr("invalid empty option found")) } - return nil, fmt.Errorf(tr("invalid option '%s'"), invalidOption) + if _, ok := b.configOptions.GetOk(option); !ok { + return nil, fmt.Errorf(tr("invalid option '%s'"), option) + } + optionsConf, ok := b.configOptionProperties[option+"="+value] + if !ok { + return nil, fmt.Errorf(tr("invalid value '%[1]s' for option '%[2]s'"), value, option) + } + buildProperties.Merge(optionsConf) } return buildProperties, nil @@ -153,7 +165,7 @@ func (b *Board) GetIdentificationProperties() []*properties.Map { } // IsBoardMatchingIDProperties returns true if the board match the given -// identification properties +// upload port identification properties func (b *Board) IsBoardMatchingIDProperties(query *properties.Map) bool { // check checks if the given set of properties p match the "query" check := func(p *properties.Map) bool { @@ -179,3 +191,40 @@ func (b *Board) IsBoardMatchingIDProperties(query *properties.Map) bool { func GetMonitorSettings(protocol string, boardProperties *properties.Map) *properties.Map { return boardProperties.SubTree("monitor_port." + protocol) } + +// IdentifyBoardConfiguration returns the configuration of the board that can be +// deduced from the given upload port identification properties +func (b *Board) IdentifyBoardConfiguration(query *properties.Map) *properties.Map { + // check checks if the given set of properties p match the "query" + check := func(p *properties.Map) bool { + for k, v := range p.AsMap() { + if !strings.EqualFold(query.Get(k), v) { + return false + } + } + return true + } + checkAll := func(allP []*properties.Map) bool { + for _, p := range allP { + if check(p) { + return true + } + } + return false + } + + res := properties.NewMap() + for _, option := range b.GetConfigOptions().Keys() { + values := b.GetConfigOptionValues(option).Keys() + + for _, value := range values { + config := option + "=" + value + configProps := b.configOptionProperties[config] + + if checkAll(configProps.ExtractSubIndexSets("upload_port")) { + res.Set(option, value) + } + } + } + return res +} diff --git a/arduino/cores/board_test.go b/arduino/cores/board_test.go index 3eeb35d16a2..a0665e26c5f 100644 --- a/arduino/cores/board_test.go +++ b/arduino/cores/board_test.go @@ -22,36 +22,40 @@ import ( "github.com/stretchr/testify/require" ) +var boardUnoProperties = properties.NewMap() + +func init() { + boardUnoProperties.Set("name", "Arduino/Genuino Uno") + boardUnoProperties.Set("vid.0", "0x2341") + boardUnoProperties.Set("pid.0", "0x0043") + boardUnoProperties.Set("vid.1", "0x2341") + boardUnoProperties.Set("pid.1", "0x0001") + boardUnoProperties.Set("vid.2", "0x2A03") + boardUnoProperties.Set("pid.2", "0x0043") + boardUnoProperties.Set("vid.3", "0x2341") + boardUnoProperties.Set("pid.3", "0x0243") + boardUnoProperties.Set("upload.tool", "avrdude") + boardUnoProperties.Set("upload.protocol", "arduino") + boardUnoProperties.Set("upload.maximum_size", "32256") + boardUnoProperties.Set("upload.maximum_data_size", "2048") + boardUnoProperties.Set("upload.speed", "115200") + boardUnoProperties.Set("bootloader.tool", "avrdude") + boardUnoProperties.Set("bootloader.low_fuses", "0xFF") + boardUnoProperties.Set("bootloader.high_fuses", "0xDE") + boardUnoProperties.Set("bootloader.extended_fuses", "0xFD") + boardUnoProperties.Set("bootloader.unlock_bits", "0x3F") + boardUnoProperties.Set("bootloader.lock_bits", "0x0F") + boardUnoProperties.Set("bootloader.file", "optiboot/optiboot_atmega328.hex") + boardUnoProperties.Set("build.mcu", "atmega328p") + boardUnoProperties.Set("build.f_cpu", "16000000L") + boardUnoProperties.Set("build.board", "AVR_UNO") + boardUnoProperties.Set("build.core", "arduino") + boardUnoProperties.Set("build.variant", "standard") +} + var boardUno = &Board{ - BoardID: "uno", - Properties: properties.NewFromHashmap(map[string]string{ - "name": "Arduino/Genuino Uno", - "vid.0": "0x2341", - "pid.0": "0x0043", - "vid.1": "0x2341", - "pid.1": "0x0001", - "vid.2": "0x2A03", - "pid.2": "0x0043", - "vid.3": "0x2341", - "pid.3": "0x0243", - "upload.tool": "avrdude", - "upload.protocol": "arduino", - "upload.maximum_size": "32256", - "upload.maximum_data_size": "2048", - "upload.speed": "115200", - "bootloader.tool": "avrdude", - "bootloader.low_fuses": "0xFF", - "bootloader.high_fuses": "0xDE", - "bootloader.extended_fuses": "0xFD", - "bootloader.unlock_bits": "0x3F", - "bootloader.lock_bits": "0x0F", - "bootloader.file": "optiboot/optiboot_atmega328.hex", - "build.mcu": "atmega328p", - "build.f_cpu": "16000000L", - "build.board": "AVR_UNO", - "build.core": "arduino", - "build.variant": "standard", - }), + BoardID: "uno", + Properties: boardUnoProperties, PlatformRelease: &PlatformRelease{ Platform: &Platform{ Architecture: "avr", @@ -59,54 +63,60 @@ var boardUno = &Board{ Name: "arduino", }, }, + Menus: properties.NewMap(), }, } +var boardMegaProperties = properties.NewMap() + +func init() { + boardMegaProperties.Set("name", "Arduino/Genuino Mega or Mega 2560") + boardMegaProperties.Set("vid.0", "0x2341") + boardMegaProperties.Set("pid.0", "0x0010") + boardMegaProperties.Set("vid.1", "0x2341") + boardMegaProperties.Set("pid.1", "0x0042") + boardMegaProperties.Set("vid.2", "0x2A03") + boardMegaProperties.Set("pid.2", "0x0010") + boardMegaProperties.Set("vid.3", "0x2A03") + boardMegaProperties.Set("pid.3", "0x0042") + boardMegaProperties.Set("vid.4", "0x2341") + boardMegaProperties.Set("pid.4", "0x0210") + boardMegaProperties.Set("vid.5", "0x2341") + boardMegaProperties.Set("pid.5", "0x0242") + boardMegaProperties.Set("upload.tool", "avrdude") + boardMegaProperties.Set("upload.maximum_data_size", "8192") + boardMegaProperties.Set("bootloader.tool", "avrdude") + boardMegaProperties.Set("bootloader.low_fuses", "0xFF") + boardMegaProperties.Set("bootloader.unlock_bits", "0x3F") + boardMegaProperties.Set("bootloader.lock_bits", "0x0F") + boardMegaProperties.Set("build.f_cpu", "16000000L") + boardMegaProperties.Set("build.core", "arduino") + boardMegaProperties.Set("build.variant", "mega") + boardMegaProperties.Set("build.board", "AVR_MEGA2560") + boardMegaProperties.Set("menu.cpu.atmega2560", "ATmega2560 (Mega 2560)") + boardMegaProperties.Set("menu.cpu.atmega2560.upload.protocol", "wiring") + boardMegaProperties.Set("menu.cpu.atmega2560.upload.maximum_size", "253952") + boardMegaProperties.Set("menu.cpu.atmega2560.upload.speed", "115200") + boardMegaProperties.Set("menu.cpu.atmega2560.bootloader.high_fuses", "0xD8") + boardMegaProperties.Set("menu.cpu.atmega2560.bootloader.extended_fuses", "0xFD") + boardMegaProperties.Set("menu.cpu.atmega2560.bootloader.file", "stk500v2/stk500boot_v2_mega2560.hex") + boardMegaProperties.Set("menu.cpu.atmega2560.build.mcu", "atmega2560") + boardMegaProperties.Set("menu.cpu.atmega2560.build.board", "AVR_MEGA2560") + boardMegaProperties.Set("menu.cpu.atmega1280", "ATmega1280") + boardMegaProperties.Set("menu.cpu.atmega1280.upload.protocol", "arduino") + boardMegaProperties.Set("menu.cpu.atmega1280.upload.maximum_size", "126976") + boardMegaProperties.Set("menu.cpu.atmega1280.upload.speed", "57600") + boardMegaProperties.Set("menu.cpu.atmega1280.bootloader.high_fuses", "0xDA") + boardMegaProperties.Set("menu.cpu.atmega1280.bootloader.extended_fuses", "0xF5") + boardMegaProperties.Set("menu.cpu.atmega1280.bootloader.file", "atmega/ATmegaBOOT_168_atmega1280.hex") + boardMegaProperties.Set("menu.cpu.atmega1280.build.mcu", "atmega1280") + boardMegaProperties.Set("menu.cpu.atmega1280.build.board", "AVR_MEGA") +} + var boardMega = &Board{ - BoardID: "mega", - Properties: properties.NewFromHashmap(map[string]string{ - "name": "Arduino/Genuino Mega or Mega 2560", - "vid.0": "0x2341", - "pid.0": "0x0010", - "vid.1": "0x2341", - "pid.1": "0x0042", - "vid.2": "0x2A03", - "pid.2": "0x0010", - "vid.3": "0x2A03", - "pid.3": "0x0042", - "vid.4": "0x2341", - "pid.4": "0x0210", - "vid.5": "0x2341", - "pid.5": "0x0242", - "upload.tool": "avrdude", - "upload.maximum_data_size": "8192", - "bootloader.tool": "avrdude", - "bootloader.low_fuses": "0xFF", - "bootloader.unlock_bits": "0x3F", - "bootloader.lock_bits": "0x0F", - "build.f_cpu": "16000000L", - "build.core": "arduino", - "build.variant": "mega", - "build.board": "AVR_MEGA2560", - "menu.cpu.atmega2560": "ATmega2560 (Mega 2560)", - "menu.cpu.atmega2560.upload.protocol": "wiring", - "menu.cpu.atmega2560.upload.maximum_size": "253952", - "menu.cpu.atmega2560.upload.speed": "115200", - "menu.cpu.atmega2560.bootloader.high_fuses": "0xD8", - "menu.cpu.atmega2560.bootloader.extended_fuses": "0xFD", - "menu.cpu.atmega2560.bootloader.file": "stk500v2/stk500boot_v2_mega2560.hex", - "menu.cpu.atmega2560.build.mcu": "atmega2560", - "menu.cpu.atmega2560.build.board": "AVR_MEGA2560", - "menu.cpu.atmega1280": "ATmega1280", - "menu.cpu.atmega1280.upload.protocol": "arduino", - "menu.cpu.atmega1280.upload.maximum_size": "126976", - "menu.cpu.atmega1280.upload.speed": "57600", - "menu.cpu.atmega1280.bootloader.high_fuses": "0xDA", - "menu.cpu.atmega1280.bootloader.extended_fuses": "0xF5", - "menu.cpu.atmega1280.bootloader.file": "atmega/ATmegaBOOT_168_atmega1280.hex", - "menu.cpu.atmega1280.build.mcu": "atmega1280", - "menu.cpu.atmega1280.build.board": "AVR_MEGA", - }), + BoardID: "mega", + Properties: boardMegaProperties, + PlatformRelease: &PlatformRelease{ Platform: &Platform{ Architecture: "avr", @@ -114,39 +124,47 @@ var boardMega = &Board{ Name: "arduino", }, }, + Menus: properties.NewFromHashmap(map[string]string{ + "cpu": "Processor", + }), }, } +var boardWatterottTiny841Properties = properties.NewMap() + +func init() { + boardWatterottTiny841Properties.Set("name", "ATtiny841 (8 MHz)") + boardWatterottTiny841Properties.Set("menu.core.arduino", "Standard Arduino") + boardWatterottTiny841Properties.Set("menu.core.arduino.build.core", "arduino:arduino") + boardWatterottTiny841Properties.Set("menu.core.arduino.build.variant", "tiny14") + boardWatterottTiny841Properties.Set("menu.core.spencekonde", "ATtiny841 (by Spence Konde)") + boardWatterottTiny841Properties.Set("menu.core.spencekonde.build.core", "tiny841") + boardWatterottTiny841Properties.Set("menu.core.spencekonde.build.variant", "tiny14") + boardWatterottTiny841Properties.Set("menu.info.info", "Press Reset, when Uploading is shown.") + boardWatterottTiny841Properties.Set("vid.0", "0x16D0") + boardWatterottTiny841Properties.Set("pid.0", "0x0753") + boardWatterottTiny841Properties.Set("bootloader.tool", "avrdude") + boardWatterottTiny841Properties.Set("bootloader.low_fuses", "0xE2") + boardWatterottTiny841Properties.Set("bootloader.high_fuses", "0xDD") + boardWatterottTiny841Properties.Set("bootloader.extended_fuses", "0xFE") + boardWatterottTiny841Properties.Set("bootloader.unlock_bits", "0xFF") + boardWatterottTiny841Properties.Set("bootloader.lock_bits", "0xFF") + boardWatterottTiny841Properties.Set("bootloader.file", "micronucleus-t841.hex") + boardWatterottTiny841Properties.Set("upload.tool", "micronucleus") + boardWatterottTiny841Properties.Set("upload.protocol", "usb") + boardWatterottTiny841Properties.Set("upload.wait_for_upload_port", "false") + boardWatterottTiny841Properties.Set("upload.use_1200bps_touch", "false") + boardWatterottTiny841Properties.Set("upload.disable_flushing", "false") + boardWatterottTiny841Properties.Set("upload.maximum_size", "6500") + boardWatterottTiny841Properties.Set("build.mcu", "attiny841") + boardWatterottTiny841Properties.Set("build.f_cpu", "8000000L") + boardWatterottTiny841Properties.Set("build.board", "AVR_ATTINY841") + +} + var boardWatterottTiny841 = &Board{ - BoardID: "attiny841", - Properties: properties.NewFromHashmap(map[string]string{ - "name": "ATtiny841 (8 MHz)", - "menu.core.arduino": "Standard Arduino", - "menu.core.arduino.build.core": "arduino:arduino", - "menu.core.arduino.build.variant": "tiny14", - "menu.core.spencekonde": "ATtiny841 (by Spence Konde)", - "menu.core.spencekonde.build.core": "tiny841", - "menu.core.spencekonde.build.variant": "tiny14", - "menu.info.info": "Press Reset, when Uploading is shown.", - "vid.0": "0x16D0", - "pid.0": "0x0753", - "bootloader.tool": "avrdude", - "bootloader.low_fuses": "0xE2", - "bootloader.high_fuses": "0xDD", - "bootloader.extended_fuses": "0xFE", - "bootloader.unlock_bits": "0xFF", - "bootloader.lock_bits": "0xFF", - "bootloader.file": "micronucleus-t841.hex", - "upload.tool": "micronucleus", - "upload.protocol": "usb", - "upload.wait_for_upload_port": "false", - "upload.use_1200bps_touch": "false", - "upload.disable_flushing": "false", - "upload.maximum_size": "6500", - "build.mcu": "attiny841", - "build.f_cpu": "8000000L", - "build.board": "AVR_ATTINY841", - }), + BoardID: "attiny841", + Properties: boardWatterottTiny841Properties, PlatformRelease: &PlatformRelease{ Platform: &Platform{ Architecture: "avr", @@ -154,6 +172,10 @@ var boardWatterottTiny841 = &Board{ Name: "watterott", }, }, + Menus: properties.NewFromHashmap(map[string]string{ + "core": "Core", + "info": "Info", + }), }, } @@ -186,111 +208,114 @@ func TestBoard(t *testing.T) { } func TestBoardOptions(t *testing.T) { - expConf2560 := properties.NewFromHashmap(map[string]string{ - "bootloader.extended_fuses": "0xFD", - "bootloader.file": "stk500v2/stk500boot_v2_mega2560.hex", - "bootloader.high_fuses": "0xD8", - "bootloader.lock_bits": "0x0F", - "bootloader.low_fuses": "0xFF", - "bootloader.tool": "avrdude", - "bootloader.unlock_bits": "0x3F", - "build.board": "AVR_MEGA2560", - "build.core": "arduino", - "build.f_cpu": "16000000L", - "build.mcu": "atmega2560", - "build.variant": "mega", - "menu.cpu.atmega1280": "ATmega1280", - "menu.cpu.atmega1280.bootloader.extended_fuses": "0xF5", - "menu.cpu.atmega1280.bootloader.file": "atmega/ATmegaBOOT_168_atmega1280.hex", - "menu.cpu.atmega1280.bootloader.high_fuses": "0xDA", - "menu.cpu.atmega1280.build.board": "AVR_MEGA", - "menu.cpu.atmega1280.build.mcu": "atmega1280", - "menu.cpu.atmega1280.upload.maximum_size": "126976", - "menu.cpu.atmega1280.upload.protocol": "arduino", - "menu.cpu.atmega1280.upload.speed": "57600", - "menu.cpu.atmega2560": "ATmega2560 (Mega 2560)", - "menu.cpu.atmega2560.bootloader.extended_fuses": "0xFD", - "menu.cpu.atmega2560.bootloader.file": "stk500v2/stk500boot_v2_mega2560.hex", - "menu.cpu.atmega2560.bootloader.high_fuses": "0xD8", - "menu.cpu.atmega2560.build.board": "AVR_MEGA2560", - "menu.cpu.atmega2560.build.mcu": "atmega2560", - "menu.cpu.atmega2560.upload.maximum_size": "253952", - "menu.cpu.atmega2560.upload.protocol": "wiring", - "menu.cpu.atmega2560.upload.speed": "115200", - "name": "Arduino/Genuino Mega or Mega 2560", - "pid.0": "0x0010", - "pid.1": "0x0042", - "pid.2": "0x0010", - "pid.3": "0x0042", - "pid.4": "0x0210", - "pid.5": "0x0242", - "upload.maximum_data_size": "8192", - "upload.maximum_size": "253952", - "upload.protocol": "wiring", - "upload.speed": "115200", - "upload.tool": "avrdude", - "vid.0": "0x2341", - "vid.1": "0x2341", - "vid.2": "0x2A03", - "vid.3": "0x2A03", - "vid.4": "0x2341", - "vid.5": "0x2341", - }) + expConf2560 := properties.NewMap() + expConf2560.Set("bootloader.extended_fuses", "0xFD") + expConf2560.Set("bootloader.file", "stk500v2/stk500boot_v2_mega2560.hex") + expConf2560.Set("bootloader.high_fuses", "0xD8") + expConf2560.Set("bootloader.lock_bits", "0x0F") + expConf2560.Set("bootloader.low_fuses", "0xFF") + expConf2560.Set("bootloader.tool", "avrdude") + expConf2560.Set("bootloader.unlock_bits", "0x3F") + expConf2560.Set("build.board", "AVR_MEGA2560") + expConf2560.Set("build.core", "arduino") + expConf2560.Set("build.f_cpu", "16000000L") + expConf2560.Set("build.mcu", "atmega2560") + expConf2560.Set("build.variant", "mega") + expConf2560.Set("menu.cpu.atmega1280", "ATmega1280") + expConf2560.Set("menu.cpu.atmega1280.bootloader.extended_fuses", "0xF5") + expConf2560.Set("menu.cpu.atmega1280.bootloader.file", "atmega/ATmegaBOOT_168_atmega1280.hex") + expConf2560.Set("menu.cpu.atmega1280.bootloader.high_fuses", "0xDA") + expConf2560.Set("menu.cpu.atmega1280.build.board", "AVR_MEGA") + expConf2560.Set("menu.cpu.atmega1280.build.mcu", "atmega1280") + expConf2560.Set("menu.cpu.atmega1280.upload.maximum_size", "126976") + expConf2560.Set("menu.cpu.atmega1280.upload.protocol", "arduino") + expConf2560.Set("menu.cpu.atmega1280.upload.speed", "57600") + expConf2560.Set("menu.cpu.atmega2560", "ATmega2560 (Mega 2560)") + expConf2560.Set("menu.cpu.atmega2560.bootloader.extended_fuses", "0xFD") + expConf2560.Set("menu.cpu.atmega2560.bootloader.file", "stk500v2/stk500boot_v2_mega2560.hex") + expConf2560.Set("menu.cpu.atmega2560.bootloader.high_fuses", "0xD8") + expConf2560.Set("menu.cpu.atmega2560.build.board", "AVR_MEGA2560") + expConf2560.Set("menu.cpu.atmega2560.build.mcu", "atmega2560") + expConf2560.Set("menu.cpu.atmega2560.upload.maximum_size", "253952") + expConf2560.Set("menu.cpu.atmega2560.upload.protocol", "wiring") + expConf2560.Set("menu.cpu.atmega2560.upload.speed", "115200") + expConf2560.Set("name", "Arduino/Genuino Mega or Mega 2560") + expConf2560.Set("pid.0", "0x0010") + expConf2560.Set("pid.1", "0x0042") + expConf2560.Set("pid.2", "0x0010") + expConf2560.Set("pid.3", "0x0042") + expConf2560.Set("pid.4", "0x0210") + expConf2560.Set("pid.5", "0x0242") + expConf2560.Set("upload.maximum_data_size", "8192") + expConf2560.Set("upload.maximum_size", "253952") + expConf2560.Set("upload.protocol", "wiring") + expConf2560.Set("upload.speed", "115200") + expConf2560.Set("upload.tool", "avrdude") + expConf2560.Set("vid.0", "0x2341") + expConf2560.Set("vid.1", "0x2341") + expConf2560.Set("vid.2", "0x2A03") + expConf2560.Set("vid.3", "0x2A03") + expConf2560.Set("vid.4", "0x2341") + expConf2560.Set("vid.5", "0x2341") conf2560, err := boardMega.GeneratePropertiesForConfiguration("cpu=atmega2560") require.NoError(t, err, "generating cpu=atmega2560 configuration") require.EqualValues(t, expConf2560.AsMap(), conf2560.AsMap(), "configuration for cpu=atmega2560") - - expConf1280 := properties.NewFromHashmap(map[string]string{ - "bootloader.extended_fuses": "0xF5", - "bootloader.file": "atmega/ATmegaBOOT_168_atmega1280.hex", - "bootloader.high_fuses": "0xDA", - "bootloader.lock_bits": "0x0F", - "bootloader.low_fuses": "0xFF", - "bootloader.tool": "avrdude", - "bootloader.unlock_bits": "0x3F", - "build.board": "AVR_MEGA", - "build.core": "arduino", - "build.f_cpu": "16000000L", - "build.mcu": "atmega1280", - "build.variant": "mega", - "menu.cpu.atmega1280": "ATmega1280", - "menu.cpu.atmega1280.bootloader.extended_fuses": "0xF5", - "menu.cpu.atmega1280.bootloader.file": "atmega/ATmegaBOOT_168_atmega1280.hex", - "menu.cpu.atmega1280.bootloader.high_fuses": "0xDA", - "menu.cpu.atmega1280.build.board": "AVR_MEGA", - "menu.cpu.atmega1280.build.mcu": "atmega1280", - "menu.cpu.atmega1280.upload.maximum_size": "126976", - "menu.cpu.atmega1280.upload.protocol": "arduino", - "menu.cpu.atmega1280.upload.speed": "57600", - "menu.cpu.atmega2560": "ATmega2560 (Mega 2560)", - "menu.cpu.atmega2560.bootloader.extended_fuses": "0xFD", - "menu.cpu.atmega2560.bootloader.file": "stk500v2/stk500boot_v2_mega2560.hex", - "menu.cpu.atmega2560.bootloader.high_fuses": "0xD8", - "menu.cpu.atmega2560.build.board": "AVR_MEGA2560", - "menu.cpu.atmega2560.build.mcu": "atmega2560", - "menu.cpu.atmega2560.upload.maximum_size": "253952", - "menu.cpu.atmega2560.upload.protocol": "wiring", - "menu.cpu.atmega2560.upload.speed": "115200", - "name": "Arduino/Genuino Mega or Mega 2560", - "pid.0": "0x0010", - "pid.1": "0x0042", - "pid.2": "0x0010", - "pid.3": "0x0042", - "pid.4": "0x0210", - "pid.5": "0x0242", - "upload.maximum_data_size": "8192", - "upload.maximum_size": "126976", - "upload.protocol": "arduino", - "upload.speed": "57600", - "upload.tool": "avrdude", - "vid.0": "0x2341", - "vid.1": "0x2341", - "vid.2": "0x2A03", - "vid.3": "0x2A03", - "vid.4": "0x2341", - "vid.5": "0x2341", - }) + require.EqualValues(t, map[string]string{"cpu": "Processor"}, boardMega.GetConfigOptions().AsMap()) + require.EqualValues(t, map[string]string{ + "atmega1280": "ATmega1280", + "atmega2560": "ATmega2560 (Mega 2560)", + }, boardMega.GetConfigOptionValues("cpu").AsMap()) + require.EqualValues(t, map[string]string{"cpu": "atmega2560"}, boardMega.defaultConfig.AsMap()) + expConf1280 := properties.NewMap() + expConf1280.Set("bootloader.extended_fuses", "0xF5") + expConf1280.Set("bootloader.file", "atmega/ATmegaBOOT_168_atmega1280.hex") + expConf1280.Set("bootloader.high_fuses", "0xDA") + expConf1280.Set("bootloader.lock_bits", "0x0F") + expConf1280.Set("bootloader.low_fuses", "0xFF") + expConf1280.Set("bootloader.tool", "avrdude") + expConf1280.Set("bootloader.unlock_bits", "0x3F") + expConf1280.Set("build.board", "AVR_MEGA") + expConf1280.Set("build.core", "arduino") + expConf1280.Set("build.f_cpu", "16000000L") + expConf1280.Set("build.mcu", "atmega1280") + expConf1280.Set("build.variant", "mega") + expConf1280.Set("menu.cpu.atmega1280", "ATmega1280") + expConf1280.Set("menu.cpu.atmega1280.bootloader.extended_fuses", "0xF5") + expConf1280.Set("menu.cpu.atmega1280.bootloader.file", "atmega/ATmegaBOOT_168_atmega1280.hex") + expConf1280.Set("menu.cpu.atmega1280.bootloader.high_fuses", "0xDA") + expConf1280.Set("menu.cpu.atmega1280.build.board", "AVR_MEGA") + expConf1280.Set("menu.cpu.atmega1280.build.mcu", "atmega1280") + expConf1280.Set("menu.cpu.atmega1280.upload.maximum_size", "126976") + expConf1280.Set("menu.cpu.atmega1280.upload.protocol", "arduino") + expConf1280.Set("menu.cpu.atmega1280.upload.speed", "57600") + expConf1280.Set("menu.cpu.atmega2560", "ATmega2560 (Mega 2560)") + expConf1280.Set("menu.cpu.atmega2560.bootloader.extended_fuses", "0xFD") + expConf1280.Set("menu.cpu.atmega2560.bootloader.file", "stk500v2/stk500boot_v2_mega2560.hex") + expConf1280.Set("menu.cpu.atmega2560.bootloader.high_fuses", "0xD8") + expConf1280.Set("menu.cpu.atmega2560.build.board", "AVR_MEGA2560") + expConf1280.Set("menu.cpu.atmega2560.build.mcu", "atmega2560") + expConf1280.Set("menu.cpu.atmega2560.upload.maximum_size", "253952") + expConf1280.Set("menu.cpu.atmega2560.upload.protocol", "wiring") + expConf1280.Set("menu.cpu.atmega2560.upload.speed", "115200") + expConf1280.Set("name", "Arduino/Genuino Mega or Mega 2560") + expConf1280.Set("pid.0", "0x0010") + expConf1280.Set("pid.1", "0x0042") + expConf1280.Set("pid.2", "0x0010") + expConf1280.Set("pid.3", "0x0042") + expConf1280.Set("pid.4", "0x0210") + expConf1280.Set("pid.5", "0x0242") + expConf1280.Set("upload.maximum_data_size", "8192") + expConf1280.Set("upload.maximum_size", "126976") + expConf1280.Set("upload.protocol", "arduino") + expConf1280.Set("upload.speed", "57600") + expConf1280.Set("upload.tool", "avrdude") + expConf1280.Set("vid.0", "0x2341") + expConf1280.Set("vid.1", "0x2341") + expConf1280.Set("vid.2", "0x2A03") + expConf1280.Set("vid.3", "0x2A03") + expConf1280.Set("vid.4", "0x2341") + expConf1280.Set("vid.5", "0x2341") conf1280, err := boardMega.GeneratePropertiesForConfiguration("cpu=atmega1280") require.NoError(t, err, "generating cpu=atmega1280 configuration") require.EqualValues(t, expConf1280.AsMap(), conf1280.AsMap(), "configuration for cpu=atmega1280") @@ -301,36 +326,35 @@ func TestBoardOptions(t *testing.T) { _, err = boardUno.GeneratePropertiesForConfiguration("cpu=atmega1280") require.Error(t, err, "generating cpu=atmega1280 configuration") - expWatterott := properties.NewFromHashmap(map[string]string{ - "bootloader.extended_fuses": "0xFE", - "bootloader.file": "micronucleus-t841.hex", - "bootloader.high_fuses": "0xDD", - "bootloader.lock_bits": "0xFF", - "bootloader.low_fuses": "0xE2", - "bootloader.tool": "avrdude", - "bootloader.unlock_bits": "0xFF", - "build.board": "AVR_ATTINY841", - "build.core": "tiny841", - "build.f_cpu": "8000000L", - "build.mcu": "attiny841", - "build.variant": "tiny14", - "menu.core.arduino": "Standard Arduino", - "menu.core.arduino.build.core": "arduino:arduino", - "menu.core.arduino.build.variant": "tiny14", - "menu.core.spencekonde": "ATtiny841 (by Spence Konde)", - "menu.core.spencekonde.build.core": "tiny841", - "menu.core.spencekonde.build.variant": "tiny14", - "menu.info.info": "Press Reset, when Uploading is shown.", - "name": "ATtiny841 (8 MHz)", - "pid.0": "0x0753", - "upload.disable_flushing": "false", - "upload.maximum_size": "6500", - "upload.protocol": "usb", - "upload.tool": "micronucleus", - "upload.use_1200bps_touch": "false", - "upload.wait_for_upload_port": "false", - "vid.0": "0x16D0", - }) + expWatterott := properties.NewMap() + expWatterott.Set("bootloader.extended_fuses", "0xFE") + expWatterott.Set("bootloader.file", "micronucleus-t841.hex") + expWatterott.Set("bootloader.high_fuses", "0xDD") + expWatterott.Set("bootloader.lock_bits", "0xFF") + expWatterott.Set("bootloader.low_fuses", "0xE2") + expWatterott.Set("bootloader.tool", "avrdude") + expWatterott.Set("bootloader.unlock_bits", "0xFF") + expWatterott.Set("build.board", "AVR_ATTINY841") + expWatterott.Set("build.core", "tiny841") + expWatterott.Set("build.f_cpu", "8000000L") + expWatterott.Set("build.mcu", "attiny841") + expWatterott.Set("build.variant", "tiny14") + expWatterott.Set("menu.core.arduino", "Standard Arduino") + expWatterott.Set("menu.core.arduino.build.core", "arduino:arduino") + expWatterott.Set("menu.core.arduino.build.variant", "tiny14") + expWatterott.Set("menu.core.spencekonde", "ATtiny841 (by Spence Konde)") + expWatterott.Set("menu.core.spencekonde.build.core", "tiny841") + expWatterott.Set("menu.core.spencekonde.build.variant", "tiny14") + expWatterott.Set("menu.info.info", "Press Reset, when Uploading is shown.") + expWatterott.Set("name", "ATtiny841 (8 MHz)") + expWatterott.Set("pid.0", "0x0753") + expWatterott.Set("upload.disable_flushing", "false") + expWatterott.Set("upload.maximum_size", "6500") + expWatterott.Set("upload.protocol", "usb") + expWatterott.Set("upload.tool", "micronucleus") + expWatterott.Set("upload.use_1200bps_touch", "false") + expWatterott.Set("upload.wait_for_upload_port", "false") + expWatterott.Set("vid.0", "0x16D0") confWatterott, err := boardWatterottTiny841.GeneratePropertiesForConfiguration("core=spencekonde,info=info") require.NoError(t, err, "generating core=spencekonde,info=info configuration") require.EqualValues(t, expWatterott.AsMap(), confWatterott.AsMap(), "generating core=spencekonde,info=info configuration") @@ -340,6 +364,47 @@ func TestBoardOptions(t *testing.T) { // fmt.Print(string(data)) } +func TestOSSpecificBoardOptions(t *testing.T) { + boardWihOSSpecificOptionProperties := properties.NewMap() + boardWihOSSpecificOptionProperties.Set("menu.UploadSpeed.115200", "115200") + boardWihOSSpecificOptionProperties.Set("menu.UploadSpeed.115200.upload.speed", "115200") + boardWihOSSpecificOptionProperties.Set("menu.UploadSpeed.9600", "9600") + boardWihOSSpecificOptionProperties.Set("menu.UploadSpeed.9600.upload.speed", "9600") + boardWihOSSpecificOptionProperties.Set("menu.UploadSpeed.57600", "57600") + boardWihOSSpecificOptionProperties.Set("menu.UploadSpeed.57600.upload.speed", "57600") + boardWihOSSpecificOptionProperties.Set("menu.UploadSpeed.230400", "230400") + boardWihOSSpecificOptionProperties.Set("menu.UploadSpeed.230400.macosx", "230400") + boardWihOSSpecificOptionProperties.Set("menu.UploadSpeed.230400.upload.speed", "230400") + boardWihOSSpecificOptionProperties.Set("menu.UploadSpeed.256000.windows", "256000") + boardWihOSSpecificOptionProperties.Set("menu.UploadSpeed.256000.upload.speed", "256000") + boardWihOSSpecificOptionProperties.Set("menu.UploadSpeed.460800", "460800") + boardWihOSSpecificOptionProperties.Set("menu.UploadSpeed.460800.macosx", "460800") + boardWihOSSpecificOptionProperties.Set("menu.UploadSpeed.460800.upload.speed", "460800") + boardWihOSSpecificOptionProperties.Set("menu.UploadSpeed.512000.windows", "512000") + boardWihOSSpecificOptionProperties.Set("menu.UploadSpeed.512000.upload.speed", "512000") + boardWihOSSpecificOptionProperties.Set("menu.UploadSpeed.921600", "921600") + boardWihOSSpecificOptionProperties.Set("menu.UploadSpeed.921600.upload.speed", "921600") + + boardWithOSSpecificOptions := &Board{ + BoardID: "test", + Properties: boardWihOSSpecificOptionProperties, + PlatformRelease: &PlatformRelease{ + Platform: &Platform{ + Architecture: "test", + Package: &Package{ + Name: "test", + }, + }, + Menus: properties.NewFromHashmap(map[string]string{ + "UploadSpeed": "Upload Speed", + }), + }, + } + + _, err := boardWithOSSpecificOptions.GeneratePropertiesForConfiguration("UploadSpeed=256000") + require.Error(t, err) +} + func TestBoardMatching(t *testing.T) { brd01 := &Board{ Properties: properties.NewFromHashmap(map[string]string{ @@ -489,3 +554,81 @@ func TestBoardMatching(t *testing.T) { "lemons": "XXX", }))) } + +func TestBoardConfigMatching(t *testing.T) { + brd01 := &Board{ + Properties: properties.NewFromHashmap(map[string]string{ + "upload_port.pid": "0x0010", + "upload_port.vid": "0x2341", + "menu.cpu.atmega1280": "ATmega1280", + "menu.cpu.atmega1280.upload_port.cpu": "atmega1280", + "menu.cpu.atmega1280.build_cpu": "atmega1280", + "menu.cpu.atmega2560": "ATmega2560", + "menu.cpu.atmega2560.upload_port.cpu": "atmega2560", + "menu.cpu.atmega2560.build_cpu": "atmega2560", + "menu.mem.1k": "1KB", + "menu.mem.1k.upload_port.mem": "1", + "menu.mem.1k.build_mem": "1024", + "menu.mem.2k": "2KB", + "menu.mem.2k.upload_port.1.mem": "2", + "menu.mem.2k.upload_port.2.ab": "ef", + "menu.mem.2k.upload_port.2.cd": "gh", + "menu.mem.2k.build_mem": "2048", + }), + PlatformRelease: &PlatformRelease{ + Platform: &Platform{ + Architecture: "avr", + Package: &Package{ + Name: "arduino", + }, + }, + Menus: properties.NewFromHashmap(map[string]string{ + "cpu": "Processor", + "mem": "Memory", + }), + }, + } + + type m map[string]string + type Test struct { + testName string + identificationProps map[string]string + configOutput map[string]string + } + + tests := []Test{ + {"Simple", + m{"pid": "0x0010", "vid": "0x2341"}, + m{}}, + {"WithConfig1", + m{"pid": "0x0010", "vid": "0x2341", "cpu": "atmega2560"}, + m{"cpu": "atmega2560"}}, + {"WithConfig2", + m{"pid": "0x0010", "vid": "0x2341", "cpu": "atmega1280"}, + m{"cpu": "atmega1280"}}, + {"WithDoubleConfig1", + m{"pid": "0x0010", "vid": "0x2341", "cpu": "atmega1280", "mem": "1"}, + m{"cpu": "atmega1280", "mem": "1k"}}, + {"WithDoubleConfig2", + m{"pid": "0x0010", "vid": "0x2341", "cpu": "atmega1280", "ab": "ef"}, + m{"cpu": "atmega1280"}}, + {"WithDoubleConfig3", + m{"pid": "0x0010", "vid": "0x2341", "cpu": "atmega1280", "ab": "ef", "cd": "gh"}, + m{"cpu": "atmega1280", "mem": "2k"}}, + {"WithIncompleteIdentificationProps", + m{"cpu": "atmega1280"}, + nil}, + } + for _, test := range tests { + t.Run(test.testName, func(t *testing.T) { + identificationProps := properties.NewFromHashmap(test.identificationProps) + if test.configOutput != nil { + require.True(t, brd01.IsBoardMatchingIDProperties(identificationProps)) + config := brd01.IdentifyBoardConfiguration(identificationProps) + require.EqualValues(t, test.configOutput, config.AsMap()) + } else { + require.False(t, brd01.IsBoardMatchingIDProperties(identificationProps)) + } + }) + } +} diff --git a/arduino/cores/packagemanager/identify.go b/arduino/cores/packagemanager/identify.go index b785bf02263..22d8382cd67 100644 --- a/arduino/cores/packagemanager/identify.go +++ b/arduino/cores/packagemanager/identify.go @@ -35,3 +35,12 @@ func (pme *Explorer) IdentifyBoard(idProps *properties.Map) []*cores.Board { return foundBoards } + +// IdentifyBoardConfiguration returns the configuration of the board that can be +// deduced from the given upload port identification properties +func (pm *PackageManager) IdentifyBoardConfiguration(idProps *properties.Map, board *cores.Board) *properties.Map { + if idProps.Size() == 0 { + return properties.NewMap() + } + return board.IdentifyBoardConfiguration(idProps) +} diff --git a/arduino/cores/packagemanager/loader.go b/arduino/cores/packagemanager/loader.go index 298669186fb..462576255ab 100644 --- a/arduino/cores/packagemanager/loader.go +++ b/arduino/cores/packagemanager/loader.go @@ -458,27 +458,27 @@ func (pm *Builder) loadBoards(platform *cores.PlatformRelease) error { } boardsTxtPath := platform.InstallDir.Join("boards.txt") - boardsProperties, err := properties.LoadFromPath(boardsTxtPath) + allBoardsProperties, err := properties.LoadFromPath(boardsTxtPath) if err != nil { return err } boardsLocalTxtPath := platform.InstallDir.Join("boards.local.txt") - if localProperties, err := properties.SafeLoadFromPath(boardsLocalTxtPath); err == nil { - boardsProperties.Merge(localProperties) + if boardsLocalProperties, err := properties.SafeLoadFromPath(boardsLocalTxtPath); err == nil { + allBoardsProperties.Merge(boardsLocalProperties) } else { return err } - platform.Menus = boardsProperties.SubTree("menu") + platform.Menus = allBoardsProperties.SubTree("menu") // Build to boards structure following the boards.txt board ordering - for _, boardID := range boardsProperties.FirstLevelKeys() { + for _, boardID := range allBoardsProperties.FirstLevelKeys() { if boardID == "menu" { // This is not a board id so we remove it to correctly set all other boards properties continue } - boardProperties := boardsProperties.SubTree(boardID) + boardProperties := allBoardsProperties.SubTree(boardID) var board *cores.Board if !platform.PluggableDiscoveryAware { convertVidPidIdentificationPropertiesToPluggableDiscovery(boardProperties) diff --git a/commands/board/list.go b/commands/board/list.go index 1a81a187f85..13f1dbd05ad 100644 --- a/commands/board/list.go +++ b/commands/board/list.go @@ -27,6 +27,7 @@ import ( "time" "github.com/arduino/arduino-cli/arduino" + "github.com/arduino/arduino-cli/arduino/cores" "github.com/arduino/arduino-cli/arduino/cores/packagemanager" "github.com/arduino/arduino-cli/arduino/discovery" "github.com/arduino/arduino-cli/arduino/httpclient" @@ -124,13 +125,19 @@ func identify(pme *packagemanager.Explorer, port *discovery.Port) ([]*rpc.BoardL // first query installed cores through the Package Manager logrus.Debug("Querying installed cores for board identification...") for _, board := range pme.IdentifyBoard(port.Properties) { + fqbn, err := cores.ParseFQBN(board.FQBN()) + if err != nil { + return nil, &arduino.InvalidFQBNError{Cause: err} + } + fqbn.Configs = board.IdentifyBoardConfiguration(port.Properties) + // We need the Platform maintaner for sorting so we set it here platform := &rpc.Platform{ Maintainer: board.PlatformRelease.Platform.Package.Maintainer, } boards = append(boards, &rpc.BoardListItem{ Name: board.Name(), - Fqbn: board.FQBN(), + Fqbn: fqbn.String(), Platform: platform, }) } diff --git a/docs/pluggable-discovery-specification.md b/docs/pluggable-discovery-specification.md index e713cb98cdb..16d196c5bf0 100644 --- a/docs/pluggable-discovery-specification.md +++ b/docs/pluggable-discovery-specification.md @@ -377,3 +377,81 @@ myboard.upload_port.1.apples=40 will match on both `pears=20, apples=30` and `pears=30, apples=40` but not `pears=20, apples=40`, in that sense each "set" of identification properties is independent from each other and cannot be mixed for port matching. + +#### Identification of board options + +[Custom board options](platform-specification.md#custom-board-options) can also be identified. + +Identification property values are associated with a custom board option by the board definition in +[`boards.txt`](platform-specification.md#boardstxt). Two formats are available. + +If only a single set of identification properties are associated with the option: + +``` +BOARD_ID.menu.MENU_ID.OPTION_ID.upload_port.PORT_PROPERTY_KEY=PORT_PROPERTY_VALUE +``` + +If one or more sets of identification properties are associated with the option, an index number is used for each set: + +``` +BOARD_ID.menu.MENU_ID.OPTION_ID.upload_port.SET_INDEX.PORT_PROPERTY_KEY=PORT_PROPERTY_VALUE +``` + +If multiple identification properties are associated within a set, all must match for the option to be identified. + +Let's see an example to clarify it, in the following `boards.txt`: + +``` +myboard.upload_port.pid=0x0010 +myboard.upload_port.vid=0x2341 +myboard.menu.cpu.atmega1280=ATmega1280 +myboard.menu.cpu.atmega1280.upload_port.c=atmega1280 <--- identification property for cpu=atmega1280 +myboard.menu.cpu.atmega1280.build_cpu=atmega1280 +myboard.menu.cpu.atmega2560=ATmega2560 +myboard.menu.cpu.atmega2560.upload_port.c=atmega2560 <--- identification property for cpu=atmega2560 +myboard.menu.cpu.atmega2560.build_cpu=atmega2560 +myboard.menu.mem.1k=1KB +myboard.menu.mem.1k.upload_port.mem=1 <--- identification property for mem=1k +myboard.menu.mem.1k.build_mem=1024 +myboard.menu.mem.2k=2KB +myboard.menu.mem.2k.upload_port.1.mem=2 <------ identification property for mem=2k (case 1) +myboard.menu.mem.2k.upload_port.2.ab=ef <---\ +myboard.menu.mem.2k.upload_port.2.cd=gh <---+-- identification property for mem=2k (case 2) +myboard.menu.mem.2k.build_mem=2048 +``` + +we have a board called `myboard` with two custom menu options `cpu` and `mem`. + +A port with the following identification properties: + +``` +vid=0x0010 +pid=0x2341 +c=atmega2560 +``` + +will be identified as FQBN `mypackage:avr:myboard:cpu=atmega2560` because of the property `c=atmega2560`. + +A port with the following identification properties: + +``` +vid=0x0010 +pid=0x2341 +c=atmega2560 +mem=2 +``` + +will be identified as FQBN `mypackage:avr:myboard:cpu=atmega2560,mem=2k`. + +A port with the following identification properties: + +``` +vid=0x0010 +pid=0x2341 +c=atmega2560 +ab=ef +cd=gh +``` + +will be identified as FQBN `mypackage:avr:myboard:cpu=atmega2560,mem=2k` too (they will match the second identification +properties set for `mem=2k`). pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy