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 all 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
43 changes: 43 additions & 0 deletions arduino/cores/board.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,3 +139,46 @@ 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 checks if the given set of properties p match the "query"
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
}

// First check the identification properties with sub index "upload_port.N.xxx"
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 > 1 {
// Always check sub-id 0 and 1 (https://github.com/arduino/arduino-cli/issues/456)
break
}
}

// if there are no subindexed then check the whole "upload_port.xxx"
if !haveIndexedProperties {
return check(portIDPropsSet)
}
silvanocerza marked this conversation as resolved.
Show resolved Hide resolved

return false
}
150 changes: 150 additions & 0 deletions arduino/cores/board_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -339,3 +339,153 @@ func TestBoardOptions(t *testing.T) {
// require.NoError(t, err, "marshaling result")
// fmt.Print(string(data))
}

func TestBoardMatching(t *testing.T) {
brd01 := &Board{
Properties: properties.NewFromHashmap(map[string]string{
"upload_port.pid": "0x0010",
"upload_port.vid": "0x2341",
}),
}
require.True(t, brd01.IsBoardMatchingIDProperties(properties.NewFromHashmap(map[string]string{
"pid": "0x0010",
"vid": "0x2341",
})))
require.False(t, brd01.IsBoardMatchingIDProperties(properties.NewFromHashmap(map[string]string{
"pid": "xxx",
"vid": "0x2341",
})))
require.False(t, brd01.IsBoardMatchingIDProperties(properties.NewFromHashmap(map[string]string{
"pid": "0x0010",
})))
// Extra port properties are OK
require.True(t, brd01.IsBoardMatchingIDProperties(properties.NewFromHashmap(map[string]string{
"pid": "0x0010",
"vid": "0x2341",
"serial": "942947289347893247",
})))

// Indexed identifications
brd02 := &Board{
Properties: properties.NewFromHashmap(map[string]string{
"upload_port.0.pid": "0x0010",
"upload_port.0.vid": "0x2341",
"upload_port.1.pid": "0x0042",
"upload_port.1.vid": "0x2341",
"upload_port.2.pid": "0x0010",
"upload_port.2.vid": "0x2A03",
"upload_port.3.pid": "0x0042",
"upload_port.3.vid": "0x2A03",
"upload_port.4.pid": "0x0210",
"upload_port.4.vid": "0x2341",
"upload_port.5.pid": "0x0242",
"upload_port.5.vid": "0x2341",
}),
}
require.True(t, brd02.IsBoardMatchingIDProperties(properties.NewFromHashmap(map[string]string{
"pid": "0x0242",
"vid": "0x2341",
})))
require.True(t, brd02.IsBoardMatchingIDProperties(properties.NewFromHashmap(map[string]string{
"pid": "0x0242",
"vid": "0x2341",
"serial": "897439287289347",
})))

// Indexed starting from 1
brd03 := &Board{
Properties: properties.NewFromHashmap(map[string]string{
"upload_port.1.pid": "0x0042",
"upload_port.1.vid": "0x2341",
"upload_port.2.pid": "0x0010",
"upload_port.2.vid": "0x2A03",
"upload_port.3.pid": "0x0042",
"upload_port.3.vid": "0x2A03",
"upload_port.4.pid": "0x0210",
"upload_port.4.vid": "0x2341",
"upload_port.5.pid": "0x0242",
"upload_port.5.vid": "0x2341",
}),
}
require.True(t, brd03.IsBoardMatchingIDProperties(properties.NewFromHashmap(map[string]string{
"pid": "0x0242",
"vid": "0x2341",
})))
require.True(t, brd03.IsBoardMatchingIDProperties(properties.NewFromHashmap(map[string]string{
"pid": "0x0242",
"vid": "0x2341",
"serial": "897439287289347",
})))

// Mixed indentificiations (not-permitted)
brd04 := &Board{
Properties: properties.NewFromHashmap(map[string]string{
"upload_port.pid": "0x2222",
"upload_port.vid": "0x3333",
"upload_port.0.pid": "0x0010",
"upload_port.0.vid": "0x2341",
"upload_port.1.pid": "0x0042",
"upload_port.1.vid": "0x2341",
"upload_port.2.pid": "0x0010",
"upload_port.2.vid": "0x2A03",
"upload_port.3.pid": "0x0042",
"upload_port.3.vid": "0x2A03",
}),
}
require.True(t, brd04.IsBoardMatchingIDProperties(properties.NewFromHashmap(map[string]string{
"pid": "0x0042",
"vid": "0x2341",
})))
require.True(t, brd04.IsBoardMatchingIDProperties(properties.NewFromHashmap(map[string]string{
"pid": "0x0042",
"vid": "0x2341",
"serial": "897439287289347",
})))
require.False(t, brd04.IsBoardMatchingIDProperties(properties.NewFromHashmap(map[string]string{
"pid": "0x2222",
"vid": "0x3333",
})))
require.False(t, brd04.IsBoardMatchingIDProperties(properties.NewFromHashmap(map[string]string{
"pid": "0x2222",
"vid": "0x3333",
"serial": "897439287289347",
})))

// Mixed protocols
brd05 := &Board{
Properties: properties.NewFromHashmap(map[string]string{
"upload_port.0.pid": "0x0010",
"upload_port.0.vid": "0x2341",
"upload_port.1.pears": "2",
"upload_port.1.apples": "3",
"upload_port.1.lemons": "X",
"upload_port.2.pears": "100",
"upload_port.3.mac": "0x0010",
"upload_port.3.vid": "0x2341",
}),
}
require.True(t, brd05.IsBoardMatchingIDProperties(properties.NewFromHashmap(map[string]string{
"pid": "0x0010",
"vid": "0x2341",
})))
require.True(t, brd05.IsBoardMatchingIDProperties(properties.NewFromHashmap(map[string]string{
"pears": "2",
"apples": "3",
"lemons": "X",
})))
require.True(t, brd05.IsBoardMatchingIDProperties(properties.NewFromHashmap(map[string]string{
"pears": "100",
})))
require.True(t, brd05.IsBoardMatchingIDProperties(properties.NewFromHashmap(map[string]string{
"mac": "0x0010",
"vid": "0x2341",
})))
require.False(t, brd05.IsBoardMatchingIDProperties(properties.NewFromHashmap(map[string]string{
"pears": "2",
})))
require.True(t, brd05.IsBoardMatchingIDProperties(properties.NewFromHashmap(map[string]string{
"pears": "100",
"apples": "300",
"lemons": "XXX",
})))
}
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
Loading