From 72e9c64715eb5ed7b2bd0fe4575fb3600d50c818 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Wed, 23 Feb 2022 17:40:00 +0100 Subject: [PATCH 01/10] Added test for os-specific config options --- arduino/cores/board_test.go | 41 +++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/arduino/cores/board_test.go b/arduino/cores/board_test.go index 3eeb35d16a2..1e78f1167fe 100644 --- a/arduino/cores/board_test.go +++ b/arduino/cores/board_test.go @@ -340,6 +340,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{ From c48573a453121dc791b62dceb6e5691e494ff9eb Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Tue, 22 Feb 2022 18:13:34 +0100 Subject: [PATCH 02/10] Build board config options structures only once and cache them --- arduino/cores/board.go | 50 +++++++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/arduino/cores/board.go b/arduino/cores/board.go index 3195fb8f14f..0504e8b0b68 100644 --- a/arduino/cores/board.go +++ b/arduino/cores/board.go @@ -24,10 +24,12 @@ import ( // Board represents a board loaded from an installed platform type Board struct { - BoardID string - Properties *properties.Map `json:"-"` - PlatformRelease *PlatformRelease `json:"-"` - identificationProperties []*properties.Map + BoardID string + Properties *properties.Map `json:"-"` + PlatformRelease *PlatformRelease `json:"-"` + configOptions *properties.Map + configOptionValues map[string]*properties.Map + identificationProperties []*properties.Map } // HasUsbID returns true if the board match the usb vid and pid parameters @@ -64,29 +66,41 @@ 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{} + for configName, options := range allConfigs.FirstLevelOf() { + b.configOptionValues[configName] = properties.NewMap() + for _, value := range options.FirstLevelKeys() { + if label, ok := options.GetOk(value); ok { + b.configOptionValues[configName].Set(value, label) + } + } + } +} + // 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 From db2a3d15bb8945b80c886daa5797b782cc49b680 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Wed, 23 Feb 2022 10:36:17 +0100 Subject: [PATCH 03/10] Board's build options properties are now calculated only once and cached --- arduino/cores/board.go | 68 ++++++++++++++++++------------------- arduino/cores/board_test.go | 8 +++++ 2 files changed, 41 insertions(+), 35 deletions(-) diff --git a/arduino/cores/board.go b/arduino/cores/board.go index 0504e8b0b68..8b3e596ebb2 100644 --- a/arduino/cores/board.go +++ b/arduino/cores/board.go @@ -24,12 +24,14 @@ import ( // Board represents a board loaded from an installed platform type Board struct { - BoardID string - Properties *properties.Map `json:"-"` - PlatformRelease *PlatformRelease `json:"-"` - configOptions *properties.Map - configOptionValues map[string]*properties.Map - identificationProperties []*properties.Map + 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 } // HasUsbID returns true if the board match the usb vid and pid parameters @@ -78,11 +80,16 @@ func (b *Board) buildConfigOptionsStructures() { } b.configOptionValues = map[string]*properties.Map{} - for configName, options := range allConfigs.FirstLevelOf() { - b.configOptionValues[configName] = properties.NewMap() - for _, value := range options.FirstLevelKeys() { - if label, ok := options.GetOk(value); ok { - b.configOptionValues[configName].Set(value, label) + 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) } } } @@ -106,38 +113,29 @@ func (b *Board) GetConfigOptionValues(option string) *properties.Map { // 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 diff --git a/arduino/cores/board_test.go b/arduino/cores/board_test.go index 1e78f1167fe..41f3cf2a970 100644 --- a/arduino/cores/board_test.go +++ b/arduino/cores/board_test.go @@ -59,6 +59,7 @@ var boardUno = &Board{ Name: "arduino", }, }, + Menus: properties.NewMap(), }, } @@ -114,6 +115,9 @@ var boardMega = &Board{ Name: "arduino", }, }, + Menus: properties.NewFromHashmap(map[string]string{ + "cpu": "Processor", + }), }, } @@ -154,6 +158,10 @@ var boardWatterottTiny841 = &Board{ Name: "watterott", }, }, + Menus: properties.NewFromHashmap(map[string]string{ + "core": "Core", + "info": "Info", + }), }, } From c921d0c5defe558f7f439c2ba45266c643221380 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Wed, 23 Feb 2022 17:29:01 +0100 Subject: [PATCH 04/10] Added tests for config options ordering It required insertion of test data with the properties.Set method to preserve ordering. --- arduino/cores/board_test.go | 482 +++++++++++++++++++----------------- 1 file changed, 249 insertions(+), 233 deletions(-) diff --git a/arduino/cores/board_test.go b/arduino/cores/board_test.go index 41f3cf2a970..e42f57125d4 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", @@ -63,51 +67,56 @@ var boardUno = &Board{ }, } +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", @@ -121,36 +130,41 @@ var boardMega = &Board{ }, } +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", @@ -194,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") @@ -309,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") From baecc789347c132a38cd267a79a30bceea7224f0 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Wed, 23 Feb 2022 23:41:27 +0100 Subject: [PATCH 05/10] Renamed some variables to improve code readability --- arduino/cores/packagemanager/loader.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) 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) From 14a424b84d5e769725a43ebdb24d33f212a5b207 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Thu, 24 Feb 2022 00:05:39 +0100 Subject: [PATCH 06/10] Added board config identification subroutines --- arduino/cores/board.go | 39 +++++++++++- arduino/cores/board_test.go | 78 ++++++++++++++++++++++++ arduino/cores/packagemanager/identify.go | 9 +++ 3 files changed, 125 insertions(+), 1 deletion(-) diff --git a/arduino/cores/board.go b/arduino/cores/board.go index 8b3e596ebb2..c5cd73daafd 100644 --- a/arduino/cores/board.go +++ b/arduino/cores/board.go @@ -165,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 { @@ -191,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 e42f57125d4..a0665e26c5f 100644 --- a/arduino/cores/board_test.go +++ b/arduino/cores/board_test.go @@ -554,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..fb7d7d6f1de 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 a set of identification properties for configuration options +// of a board. +func (pm *PackageManager) IdentifyBoardConfiguration(idProps *properties.Map, board *cores.Board) *properties.Map { + if idProps.Size() == 0 { + return properties.NewMap() + } + return board.IdentifyBoardConfiguration(idProps) +} From ccceb6c5ae38ed1585446dbe68425c6509cdcb78 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Thu, 24 Feb 2022 12:22:16 +0100 Subject: [PATCH 07/10] Added board config detection in 'commands.identify' function --- commands/board/list.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) 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, }) } From 1bcdd33255293129cfa80f1b5fb6d016cfdd3c3a Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Fri, 14 Oct 2022 15:07:55 +0200 Subject: [PATCH 08/10] Updated docs --- docs/pluggable-discovery-specification.md | 64 +++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/docs/pluggable-discovery-specification.md b/docs/pluggable-discovery-specification.md index e713cb98cdb..e68a4a421b2 100644 --- a/docs/pluggable-discovery-specification.md +++ b/docs/pluggable-discovery-specification.md @@ -377,3 +377,67 @@ 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 + +The board identification can also identify [custom board options](platform-specification.md#custom-board-options) if the +corresponding `upload_port` properties are defined: + +``` +BOARDNAME.menu.MENUNAME.MENUOPTION.upload_port.IDENTIFIER=Value +BOARDNAME.menu.MENUNAME.MENUOPTION.upload_port.#.IDENTIFIER=Value +``` + +a discovery tools capable of detecting which menu options where used could report properties to match those lines. 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`. The discovery may provide extra +identification properties to determine the custom menu options of the connected board, for example the following +properties: + +``` +vid=0x0010 +pid=0x2341 +c=atmega2560 +``` + +will match the FQBN `mypackage:avr:myboard:cpu=atmega2560` becuase of the property `c=atmega2560`. The identification +properties: + +``` +vid=0x0010 +pid=0x2341 +c=atmega2560 +mem=2 +``` + +will match the FQBN `mypackage:avr:myboard:cpu=atmega2560,mem=2k`. The identification properties: + +``` +vid=0x0010 +pid=0x2341 +c=atmega2560 +ab=ef +cd=gh +``` + +will match the FQBN `mypackage:avr:myboard:cpu=atmega2560,mem=2k` too (they will match the second set for `mem=2k`). From d0ebfd755b645a536c393334ac16c32145e81bb6 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Mon, 17 Oct 2022 11:00:12 +0200 Subject: [PATCH 09/10] Apply suggestions from code review Co-authored-by: per1234 --- docs/pluggable-discovery-specification.md | 40 +++++++++++++++-------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/docs/pluggable-discovery-specification.md b/docs/pluggable-discovery-specification.md index e68a4a421b2..16d196c5bf0 100644 --- a/docs/pluggable-discovery-specification.md +++ b/docs/pluggable-discovery-specification.md @@ -380,16 +380,26 @@ will match on both `pears=20, apples=30` and `pears=30, apples=40` but not `pear #### Identification of board options -The board identification can also identify [custom board options](platform-specification.md#custom-board-options) if the -corresponding `upload_port` properties are defined: +[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: ``` -BOARDNAME.menu.MENUNAME.MENUOPTION.upload_port.IDENTIFIER=Value -BOARDNAME.menu.MENUNAME.MENUOPTION.upload_port.#.IDENTIFIER=Value +BOARD_ID.menu.MENU_ID.OPTION_ID.upload_port.SET_INDEX.PORT_PROPERTY_KEY=PORT_PROPERTY_VALUE ``` -a discovery tools capable of detecting which menu options where used could report properties to match those lines. Let's -see an example to clarify it, in the following `boards.txt`: +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 @@ -410,9 +420,9 @@ myboard.menu.mem.2k.upload_port.2.cd=gh <---+-- identifica myboard.menu.mem.2k.build_mem=2048 ``` -we have a board called `myboard` with two custom menu options `cpu` and `mem`. The discovery may provide extra -identification properties to determine the custom menu options of the connected board, for example the following -properties: +we have a board called `myboard` with two custom menu options `cpu` and `mem`. + +A port with the following identification properties: ``` vid=0x0010 @@ -420,8 +430,9 @@ pid=0x2341 c=atmega2560 ``` -will match the FQBN `mypackage:avr:myboard:cpu=atmega2560` becuase of the property `c=atmega2560`. The identification -properties: +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 @@ -430,7 +441,9 @@ c=atmega2560 mem=2 ``` -will match the FQBN `mypackage:avr:myboard:cpu=atmega2560,mem=2k`. The identification properties: +will be identified as FQBN `mypackage:avr:myboard:cpu=atmega2560,mem=2k`. + +A port with the following identification properties: ``` vid=0x0010 @@ -440,4 +453,5 @@ ab=ef cd=gh ``` -will match the FQBN `mypackage:avr:myboard:cpu=atmega2560,mem=2k` too (they will match the second set for `mem=2k`). +will be identified as FQBN `mypackage:avr:myboard:cpu=atmega2560,mem=2k` too (they will match the second identification +properties set for `mem=2k`). From 024597e331e612748ae2ee39058cece2d04039fd Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Tue, 18 Oct 2022 17:35:36 +0200 Subject: [PATCH 10/10] Fixed comment --- arduino/cores/packagemanager/identify.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arduino/cores/packagemanager/identify.go b/arduino/cores/packagemanager/identify.go index fb7d7d6f1de..22d8382cd67 100644 --- a/arduino/cores/packagemanager/identify.go +++ b/arduino/cores/packagemanager/identify.go @@ -36,8 +36,8 @@ func (pme *Explorer) IdentifyBoard(idProps *properties.Map) []*cores.Board { return foundBoards } -// IdentifyBoardConfiguration returns a set of identification properties for configuration options -// of a board. +// 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()