@@ -15,6 +15,7 @@ import (
1515 "github.com/arduino/arduino-cli/pkg/fqbn"
1616 rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
1717 "github.com/sirupsen/logrus"
18+ "go.bug.st/f"
1819
1920 "github.com/bcmi-labs/orchestrator/pkg/board/remote"
2021 "github.com/bcmi-labs/orchestrator/pkg/board/remote/adb"
@@ -42,6 +43,26 @@ const (
4243 SerialPath = "/sys/devices/soc0/serial_number"
4344)
4445
46+ func identifyUnoQ (p * rpc.DetectedPort ) {
47+ const UnoQVID = "0x2341"
48+ const UnoQPID = "0x0078"
49+ const UnoQBoardID = "unoq"
50+
51+ // If the board has been already identified as Uno Q, just return true
52+ for _ , b := range p .GetMatchingBoards () {
53+ if b .GetFqbn () == ArduinoUnoQ {
54+ return
55+ }
56+ }
57+
58+ // Otherwise check the VID/PID or board ID
59+ props := p .GetPort ().GetProperties ()
60+ isUnoQ := props ["board" ] == UnoQBoardID || (props ["vid" ] == UnoQVID && props ["pid" ] == UnoQPID )
61+ if isUnoQ {
62+ p .MatchingBoards = append (p .MatchingBoards , & rpc.BoardListItem {Name : "Arduino UNO Q" , Fqbn : ArduinoUnoQ })
63+ }
64+ }
65+
4566// Cache the initialized Arduino CLI service, so it don't need to be re-initialized
4667// TODO: provide a way to get the board information by event instead of polling.
4768var arduinoCLIServer rpc.ArduinoCoreServiceServer
@@ -96,80 +117,95 @@ func FromFQBN(ctx context.Context, fqbn string) ([]Board, error) {
96117 arduinoCLIInstance = inst
97118 }
98119
99- list , err := arduinoCLIServer . BoardList ( ctx , & rpc.BoardListRequest {
120+ listReq := & rpc.BoardListRequest {
100121 Instance : arduinoCLIInstance ,
101- Timeout : 2000 , // 2 seconds
102- Fqbn : fqbn ,
103- } )
122+ Timeout : 100 , // 100 ms
123+ }
124+ list , err := arduinoCLIServer . BoardList ( ctx , listReq )
104125 if err != nil {
105126 return nil , fmt .Errorf ("failed to get info for FQBN %s: %w" , fqbn , err )
106127 }
107128
108- if ports := list .GetPorts (); len (ports ) != 0 {
109- var boards []Board
110- for _ , port := range ports {
111- if port .GetPort () == nil {
112- continue
113- }
129+ ports := list .GetPorts ()
130+ for _ , p := range ports {
131+ identifyUnoQ (p )
132+ }
114133
115- var boardName string
116- if len (port .GetMatchingBoards ()) > 0 {
117- boardName = port .GetMatchingBoards ()[0 ].GetName ()
118- }
134+ portMatchFqbn := func (p * rpc.DetectedPort ) bool {
135+ return slices .ContainsFunc (
136+ p .GetMatchingBoards (),
137+ func (b * rpc.BoardListItem ) bool {
138+ return b .GetFqbn () == fqbn
139+ },
140+ )
141+ }
142+ ports = f .Filter (ports , portMatchFqbn )
119143
120- switch port . GetPort (). GetProtocol () {
121- case SerialProtocol :
122- serial := strings . ToLower ( port . GetPort (). GetHardwareId ()) // in windows this is uppercase.
144+ if len ( ports ) == 0 {
145+ return nil , fmt . Errorf ( "no hardware ID found for FQBN %s" , fqbn )
146+ }
123147
124- // TODO: we should store the board custom name in the product id so we can get it from the discovery service.
125- var customName string
126- if conn , err := adb .FromSerial (serial , "" ); err == nil {
127- if name , err := GetCustomName (ctx , conn ); err == nil {
128- customName = name
129- }
130- }
148+ var boards []Board
149+ for _ , port := range ports {
150+ if port .GetPort () == nil {
151+ continue
152+ }
131153
132- boards = append (boards , Board {
133- Protocol : SerialProtocol ,
134- Serial : serial ,
135- BoardName : boardName ,
136- CustomName : customName ,
137- })
138- case NetworkProtocol :
139- var customName string
140- if name , ok := port .GetPort ().GetProperties ()["hostname" ]; ok {
141- // take the part before the first dot as custom name
142- idx := strings .Index (name , "." )
143- if idx == - 1 {
144- idx = len (name )
145- }
146- customName = name [:idx ]
147- }
154+ var boardName string
155+ if len (port .GetMatchingBoards ()) > 0 {
156+ boardName = port .GetMatchingBoards ()[0 ].GetName ()
157+ }
158+
159+ switch port .GetPort ().GetProtocol () {
160+ case SerialProtocol :
161+ serial := strings .ToLower (port .GetPort ().GetHardwareId ()) // in windows this is uppercase.
148162
149- boards = append (boards , Board {
150- Protocol : NetworkProtocol ,
151- Address : port .GetPort ().GetAddress (),
152- BoardName : boardName ,
153- CustomName : customName ,
154- })
155- default :
156- slog .Warn ("unknown protocol" , "protocol" , port .GetPort ().GetProtocol ())
163+ // TODO: we should store the board custom name in the product id so we can get it from the discovery service.
164+ var customName string
165+ if conn , err := adb .FromSerial (serial , "" ); err == nil {
166+ if name , err := GetCustomName (ctx , conn ); err == nil {
167+ customName = name
168+ }
157169 }
158- }
159170
160- // Sort serial first
161- slices .SortFunc (boards , func (a , b Board ) int {
162- if a .Protocol == "serial" {
163- return - 1
164- } else {
165- return 1
171+ boards = append (boards , Board {
172+ Protocol : SerialProtocol ,
173+ Serial : serial ,
174+ BoardName : boardName ,
175+ CustomName : customName ,
176+ })
177+ case NetworkProtocol :
178+ var customName string
179+ if name , ok := port .GetPort ().GetProperties ()["hostname" ]; ok {
180+ // take the part before the first dot as custom name
181+ idx := strings .Index (name , "." )
182+ if idx == - 1 {
183+ idx = len (name )
184+ }
185+ customName = name [:idx ]
166186 }
167- })
168187
169- return boards , nil
188+ boards = append (boards , Board {
189+ Protocol : NetworkProtocol ,
190+ Address : port .GetPort ().GetAddress (),
191+ BoardName : boardName ,
192+ CustomName : customName ,
193+ })
194+ default :
195+ slog .Warn ("unknown protocol" , "protocol" , port .GetPort ().GetProtocol ())
196+ }
170197 }
171198
172- return nil , fmt .Errorf ("no hardware ID found for FQBN %s" , fqbn )
199+ // Sort serial first
200+ slices .SortFunc (boards , func (a , b Board ) int {
201+ if a .Protocol == "serial" {
202+ return - 1
203+ } else {
204+ return 1
205+ }
206+ })
207+
208+ return boards , nil
173209}
174210
175211func (b * Board ) GetConnection (optPassword ... string ) (remote.RemoteConn , error ) {
0 commit comments