1818package board
1919
2020import (
21+ "encoding/json"
22+ "fmt"
23+ "io/ioutil"
24+ "net/http"
25+
26+ "github.com/arduino/arduino-cli/cli/globals"
2127 "github.com/arduino/arduino-cli/commands"
2228 rpc "github.com/arduino/arduino-cli/rpc/commands"
2329 "github.com/pkg/errors"
2430)
2531
32+ var (
33+ // ErrNotFound is returned when the API returns 404
34+ ErrNotFound = errors .New ("board not found" )
35+ )
36+
37+ func apiByVidPid (url string ) ([]* rpc.BoardListItem , error ) {
38+ retVal := []* rpc.BoardListItem {}
39+ req , _ := http .NewRequest ("GET" , url , nil )
40+ req .Header = globals .HTTPClientHeader
41+ req .Header .Set ("Content-Type" , "application/json" )
42+
43+ if res , err := http .DefaultClient .Do (req ); err == nil {
44+ if res .StatusCode >= 400 {
45+ if res .StatusCode == 404 {
46+ return nil , ErrNotFound
47+ }
48+ return nil , errors .Errorf ("the server responded with status %s" , res .Status )
49+ }
50+
51+ body , _ := ioutil .ReadAll (res .Body )
52+ res .Body .Close ()
53+
54+ var dat map [string ]interface {}
55+ err = json .Unmarshal (body , & dat )
56+ if err != nil {
57+ return nil , errors .Wrap (err , "error processing response from server" )
58+ }
59+
60+ name , nameFound := dat ["name" ].(string )
61+ fqbn , fbqnFound := dat ["fqbn" ].(string )
62+
63+ if ! nameFound || ! fbqnFound {
64+ return nil , errors .New ("wrong format in server response" )
65+ }
66+
67+ retVal = append (retVal , & rpc.BoardListItem {
68+ Name : name ,
69+ FQBN : fqbn ,
70+ })
71+ } else {
72+ return nil , errors .Wrap (err , "error querying Arduino Cloud Api" )
73+ }
74+
75+ return retVal , nil
76+ }
77+
2678// List FIXMEDOC
27- func List (instanceID int32 ) (* rpc.BoardListResp , error ) {
79+ func List (instanceID int32 ) ([] * rpc.DetectedPort , error ) {
2880 pm := commands .GetPackageManager (instanceID )
2981 if pm == nil {
3082 return nil , errors .New ("invalid instance" )
@@ -40,29 +92,51 @@ func List(instanceID int32) (*rpc.BoardListResp, error) {
4092 }
4193 defer serialDiscovery .Close ()
4294
43- resp := & rpc.BoardListResp {Ports : []* rpc.DetectedPort {}}
44-
4595 ports , err := serialDiscovery .List ()
4696 if err != nil {
4797 return nil , errors .Wrap (err , "error getting port list from serial-discovery" )
4898 }
4999
100+ retVal := []* rpc.DetectedPort {}
50101 for _ , port := range ports {
51102 b := []* rpc.BoardListItem {}
103+
104+ // first query installed cores through the Package Manager
52105 for _ , board := range pm .IdentifyBoard (port .IdentificationPrefs ) {
53106 b = append (b , & rpc.BoardListItem {
54107 Name : board .Name (),
55108 FQBN : board .FQBN (),
56109 })
57110 }
111+
112+ // if installed cores didn't recognize the board, try querying
113+ // the builder API
114+ if len (b ) == 0 {
115+ url := fmt .Sprintf ("https://builder.arduino.cc/v3/boards/byVidPid/%s/%s" ,
116+ port .IdentificationPrefs .Get ("vid" ),
117+ port .IdentificationPrefs .Get ("pid" ))
118+ items , err := apiByVidPid (url )
119+ if err == ErrNotFound {
120+ // the board couldn't be detected, keep going with the next port
121+ continue
122+ } else if err != nil {
123+ // this is bad, bail out
124+ return nil , errors .Wrap (err , "error getting board info from Arduino Cloud" )
125+ }
126+
127+ b = items
128+ }
129+
130+ // boards slice can be empty at this point if neither the cores nor the
131+ // API managed to recognize the connected board
58132 p := & rpc.DetectedPort {
59133 Address : port .Address ,
60134 Protocol : port .Protocol ,
61135 ProtocolLabel : port .ProtocolLabel ,
62136 Boards : b ,
63137 }
64- resp . Ports = append (resp . Ports , p )
138+ retVal = append (retVal , p )
65139 }
66140
67- return resp , nil
141+ return retVal , nil
68142}
0 commit comments