Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented pluggable discovery board matching #1330

Merged
merged 4 commits into from
Jun 21, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions arduino/cores/board.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,3 +139,43 @@ func (b *Board) GeneratePropertiesForConfiguration(config string) (*properties.M
}
return b.GetBuildProperties(fqbn.Configs)
}

// IsBoardMatchingIDProperties returns true if the board match the given
// identification properties
func (b *Board) IsBoardMatchingIDProperties(query *properties.Map) bool {
cmaglie marked this conversation as resolved.
Show resolved Hide resolved
portIDPropsSet := b.Properties.SubTree("upload_port")
if portIDPropsSet.Size() == 0 {
return false
}

check := func(p *properties.Map) bool {
cmaglie marked this conversation as resolved.
Show resolved Hide resolved
for k, v := range p.AsMap() {
if !strings.EqualFold(query.Get(k), v) {
return false
}
}
return true
}

idx := 0
haveIndexedProperties := false
for {
idProps := portIDPropsSet.SubTree(fmt.Sprintf("%d", idx))
idx++
if idProps.Size() > 0 {
haveIndexedProperties = true
if check(idProps) {
return true
}
} else if idx > 0 {
// Always check sub-id 0 and 1 (https://github.com/arduino/arduino-cli/issues/456)
break
}
}

if !haveIndexedProperties {
return check(portIDPropsSet)
}
silvanocerza marked this conversation as resolved.
Show resolved Hide resolved

return false
}
27 changes: 14 additions & 13 deletions arduino/cores/cores.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,19 +44,20 @@ type PlatformReleaseHelp struct {

// PlatformRelease represents a release of a plaform package.
type PlatformRelease struct {
Resource *resources.DownloadResource
Version *semver.Version
BoardsManifest []*BoardManifest
Dependencies ToolDependencies // The Dependency entries to load tools.
Help PlatformReleaseHelp `json:"-"`
Platform *Platform `json:"-"`
Properties *properties.Map `json:"-"`
Boards map[string]*Board `json:"-"`
Programmers map[string]*Programmer `json:"-"`
Menus *properties.Map `json:"-"`
InstallDir *paths.Path `json:"-"`
IsIDEBundled bool `json:"-"`
IsTrusted bool `json:"-"`
Resource *resources.DownloadResource
Version *semver.Version
BoardsManifest []*BoardManifest
Dependencies ToolDependencies // The Dependency entries to load tools.
Help PlatformReleaseHelp `json:"-"`
Platform *Platform `json:"-"`
Properties *properties.Map `json:"-"`
Boards map[string]*Board `json:"-"`
Programmers map[string]*Programmer `json:"-"`
Menus *properties.Map `json:"-"`
InstallDir *paths.Path `json:"-"`
IsIDEBundled bool `json:"-"`
IsTrusted bool `json:"-"`
PluggableDiscoveryAware bool `json:"-"` // true if the Platform supports pluggable discovery (no compatibility layer required)
}

// BoardManifest contains information about a board. These metadata are usually
Expand Down
34 changes: 3 additions & 31 deletions arduino/cores/packagemanager/identify.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,48 +16,20 @@
package packagemanager

import (
"fmt"
"strings"

"github.com/arduino/arduino-cli/arduino/cores"
properties "github.com/arduino/go-properties-orderedmap"
)

// IdentifyBoard returns a list of boards matching the provided identification properties.
// IdentifyBoard returns a list of boards whose identification properties match the
// provided ones.
func (pm *PackageManager) IdentifyBoard(idProps *properties.Map) []*cores.Board {
if idProps.Size() == 0 {
return []*cores.Board{}
}

checkSuffix := func(props *properties.Map, s string) (present bool, matched bool) {
for k, v1 := range idProps.AsMap() {
v2, ok := props.GetOk(k + s)
if !ok {
return false, false
}
if !strings.EqualFold(v1, v2) {
return true, false
}
}
return false, true
}

foundBoards := []*cores.Board{}
for _, board := range pm.InstalledBoards() {
if _, matched := checkSuffix(board.Properties, ""); matched {
if board.IsBoardMatchingIDProperties(idProps) {
foundBoards = append(foundBoards, board)
continue
}
id := 0
for {
present, matched := checkSuffix(board.Properties, fmt.Sprintf(".%d", id))
if matched {
foundBoards = append(foundBoards, board)
}
if !present && id > 0 { // Always check id 0 and 1 (https://github.com/arduino/arduino-cli/issues/456)
break
}
id++
}
}

Expand Down
51 changes: 51 additions & 0 deletions arduino/cores/packagemanager/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"fmt"
"os"
"path/filepath"
"strconv"
"strings"

"github.com/arduino/arduino-cli/arduino/cores"
Expand Down Expand Up @@ -319,6 +320,10 @@ func (pm *PackageManager) loadPlatformRelease(platform *cores.PlatformRelease, p
return fmt.Errorf("loading %s: %s", platformTxtLocalPath, err)
}

if platform.Properties.SubTree("discovery").Size() > 0 {
platform.PluggableDiscoveryAware = true
}
cmaglie marked this conversation as resolved.
Show resolved Hide resolved

if platform.Platform.Name == "" {
if name, ok := platform.Properties.GetOk("name"); ok {
platform.Platform.Name = name
Expand Down Expand Up @@ -380,6 +385,14 @@ func (pm *PackageManager) loadBoards(platform *cores.PlatformRelease) error {
platform.Menus = properties.NewMap()
}

if !platform.PluggableDiscoveryAware {
for _, boardProperties := range propertiesByBoard {
convertVidPidIdentificationPropertiesToPluggableDiscovery(boardProperties)
}
}

platform.Menus = propertiesByBoard["menu"]

// This is not a board id so we remove it to correctly
// set all other boards properties
delete(propertiesByBoard, "menu")
Expand Down Expand Up @@ -420,6 +433,44 @@ func (pm *PackageManager) loadBoards(platform *cores.PlatformRelease) error {
return nil
}

// Converts the old:
//
// - xxx.vid.N
// - xxx.pid.N
//
// properties into pluggable discovery compatible:
//
// - xxx.upload_port.N.vid
// - xxx.upload_port.N.pid
//
func convertVidPidIdentificationPropertiesToPluggableDiscovery(boardProperties *properties.Map) {
n := 0
outputVidPid := func(vid, pid string) {
boardProperties.Set(fmt.Sprintf("upload_port.%d.vid", n), vid)
boardProperties.Set(fmt.Sprintf("upload_port.%d.pid", n), pid)
n++
}
if boardProperties.ContainsKey("vid") && boardProperties.ContainsKey("pid") {
outputVidPid(boardProperties.Get("vid"), boardProperties.Get("pid"))
}

for _, k := range boardProperties.Keys() {
if strings.HasPrefix(k, "vid.") {
idx, err := strconv.ParseUint(k[4:], 10, 64)
if err != nil {
continue
}
vidKey := fmt.Sprintf("vid.%d", idx)
pidKey := fmt.Sprintf("pid.%d", idx)
vid, vidOk := boardProperties.GetOk(vidKey)
pid, pidOk := boardProperties.GetOk(pidKey)
if vidOk && pidOk {
outputVidPid(vid, pid)
}
}
}
}

func (pm *PackageManager) loadToolsFromPackage(targetPackage *cores.Package, toolsPath *paths.Path) []*status.Status {
pm.Log.Infof("Loading tools from dir: %s", toolsPath)

Expand Down
105 changes: 105 additions & 0 deletions arduino/cores/packagemanager/loader_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// This file is part of arduino-cli.
//
// Copyright 2020 ARDUINO SA (http://www.arduino.cc/)
//
// This software is released under the GNU General Public License version 3,
// which covers the main part of arduino-cli.
// The terms of this license can be found at:
// https://www.gnu.org/licenses/gpl-3.0.en.html
//
// You can be released from the requirements of the above licenses by purchasing
// a commercial license. Buying such a license is mandatory if you want to
// modify or otherwise use the software for commercial activities involving the
// Arduino software without disclosing the source code of your own applications.
// To purchase a commercial license, send an email to [email protected].

package packagemanager

import (
"testing"

"github.com/arduino/go-properties-orderedmap"
"github.com/stretchr/testify/require"
)

func TestVidPidConvertionToPluggableDiscovery(t *testing.T) {
m, err := properties.LoadFromBytes([]byte(`
arduino_zero_edbg.name=Arduino Zero (Programming Port)
arduino_zero_edbg.vid.0=0x03eb
arduino_zero_edbg.pid.0=0x2157
arduino_zero_edbg_2.name=Arduino Zero (Programming Port)
arduino_zero_edbg_2.vid=0x03eb
arduino_zero_edbg_2.pid=0x2157
arduino_zero_edbg_3.name=Arduino Zero (Programming Port)
arduino_zero_edbg_3.vid=0x03eb
arduino_zero_edbg_3.pid=0x2157
arduino_zero_edbg_3.vid.0=0x03ea
arduino_zero_edbg_3.pid.0=0x2157
arduino_zero_native.name=Arduino Zero (Native USB Port)
arduino_zero_native.vid.0=0x2341
arduino_zero_native.pid.0=0x804d
arduino_zero_native.vid.1=0x2341
arduino_zero_native.pid.1=0x004d
arduino_zero_native.vid.2=0x2341
arduino_zero_native.pid.2=0x824d
arduino_zero_native.vid.3=0x2341
arduino_zero_native.pid.3=0x024d
`))
require.NoError(t, err)

zero := m.SubTree("arduino_zero_edbg")
convertVidPidIdentificationPropertiesToPluggableDiscovery(zero)
require.Equal(t, `properties.Map{
"name": "Arduino Zero (Programming Port)",
"vid.0": "0x03eb",
"pid.0": "0x2157",
"upload_port.0.vid": "0x03eb",
"upload_port.0.pid": "0x2157",
}`, zero.Dump())

zero2 := m.SubTree("arduino_zero_edbg_2")
convertVidPidIdentificationPropertiesToPluggableDiscovery(zero2)
require.Equal(t, `properties.Map{
"name": "Arduino Zero (Programming Port)",
"vid": "0x03eb",
"pid": "0x2157",
"upload_port.0.vid": "0x03eb",
"upload_port.0.pid": "0x2157",
}`, zero2.Dump())

zero3 := m.SubTree("arduino_zero_edbg_3")
convertVidPidIdentificationPropertiesToPluggableDiscovery(zero3)
require.Equal(t, `properties.Map{
"name": "Arduino Zero (Programming Port)",
"vid": "0x03eb",
"pid": "0x2157",
"vid.0": "0x03ea",
"pid.0": "0x2157",
"upload_port.0.vid": "0x03eb",
"upload_port.0.pid": "0x2157",
"upload_port.1.vid": "0x03ea",
"upload_port.1.pid": "0x2157",
}`, zero3.Dump())

zero4 := m.SubTree("arduino_zero_native")
convertVidPidIdentificationPropertiesToPluggableDiscovery(zero4)
require.Equal(t, `properties.Map{
"name": "Arduino Zero (Native USB Port)",
"vid.0": "0x2341",
"pid.0": "0x804d",
"vid.1": "0x2341",
"pid.1": "0x004d",
"vid.2": "0x2341",
"pid.2": "0x824d",
"vid.3": "0x2341",
"pid.3": "0x024d",
"upload_port.0.vid": "0x2341",
"upload_port.0.pid": "0x804d",
"upload_port.1.vid": "0x2341",
"upload_port.1.pid": "0x004d",
"upload_port.2.vid": "0x2341",
"upload_port.2.pid": "0x824d",
"upload_port.3.vid": "0x2341",
"upload_port.3.pid": "0x024d",
}`, zero4.Dump())
}
18 changes: 9 additions & 9 deletions commands/board/list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func TestGetByVidPid(t *testing.T) {
require.Equal(t, "0XF069", res[0].Pid)

// wrong vid (too long), wrong pid (not an hex value)
res, err = apiByVidPid("0xfffff", "0xDEFG")
_, err = apiByVidPid("0xfffff", "0xDEFG")
require.NotNil(t, err)
}

Expand Down Expand Up @@ -130,11 +130,11 @@ func TestBoardIdentifySorting(t *testing.T) {
platformRelease := platform.GetOrCreateRelease(semver.MustParse("0.0.0"))
platformRelease.InstallDir = dataDir
board := platformRelease.GetOrCreateBoard("boardA")
board.Properties.Set("vid", "0x0000")
board.Properties.Set("pid", "0x0000")
board.Properties.Set("upload_port.vid", "0x0000")
board.Properties.Set("upload_port.pid", "0x0000")
board = platformRelease.GetOrCreateBoard("boardB")
board.Properties.Set("vid", "0x0000")
board.Properties.Set("pid", "0x0000")
board.Properties.Set("upload_port.vid", "0x0000")
board.Properties.Set("upload_port.pid", "0x0000")

// Create some Arduino boards with same VID:PID combination as boards created previously
pack = pm.Packages.GetOrCreatePackage("arduino")
Expand All @@ -143,11 +143,11 @@ func TestBoardIdentifySorting(t *testing.T) {
platformRelease = platform.GetOrCreateRelease(semver.MustParse("0.0.0"))
platformRelease.InstallDir = dataDir
board = platformRelease.GetOrCreateBoard("nessuno")
board.Properties.Set("vid", "0x0000")
board.Properties.Set("pid", "0x0000")
board.Properties.Set("upload_port.vid", "0x0000")
board.Properties.Set("upload_port.pid", "0x0000")
board = platformRelease.GetOrCreateBoard("assurdo")
board.Properties.Set("vid", "0x0000")
board.Properties.Set("pid", "0x0000")
board.Properties.Set("upload_port.vid", "0x0000")
board.Properties.Set("upload_port.pid", "0x0000")

idPrefs := properties.NewMap()
idPrefs.Set("vid", "0x0000")
Expand Down