@@ -21,6 +21,7 @@ import (
2121 "sync"
2222 "time"
2323
24+ "github.com/arduino/arduino-cli/cli/globals"
2425 "github.com/arduino/arduino-cli/executils"
2526 "github.com/arduino/go-properties-orderedmap"
2627 "github.com/pkg/errors"
@@ -30,7 +31,6 @@ import (
3031// with the boards.
3132type PluggableDiscovery struct {
3233 id string
33- args []string
3434 process * executils.Process
3535 outgoingCommandsPipe io.Writer
3636 incomingMessagesChan <- chan * discoveryMessage
@@ -45,20 +45,21 @@ type PluggableDiscovery struct {
4545}
4646
4747type discoveryMessage struct {
48- EventType string `json:"eventType"`
49- Message string `json:"message"`
50- Ports []* Port `json:"ports"`
51- Port * Port `json:"port"`
48+ EventType string `json:"eventType"`
49+ Message string `json:"message"`
50+ Error bool `json:"error"`
51+ ProtocolVersion int `json:"protocolVersion"` // Used in HELLO command
52+ Ports []* Port `json:"ports"` // Used in LIST command
53+ Port * Port `json:"port"` // Used in add and remove events
5254}
5355
5456// Port containts metadata about a port to connect to a board.
5557type Port struct {
56- Address string `json:"address"`
57- AddressLabel string `json:"label"`
58- Protocol string `json:"protocol"`
59- ProtocolLabel string `json:"protocolLabel"`
60- Properties * properties.Map `json:"prefs"`
61- IdentificationProperties * properties.Map `json:"identificationPrefs"`
58+ Address string `json:"address"`
59+ AddressLabel string `json:"label"`
60+ Protocol string `json:"protocol"`
61+ ProtocolLabel string `json:"protocolLabel"`
62+ Properties * properties.Map `json:"properties"`
6263}
6364
6465func (p * Port ) String () string {
@@ -121,20 +122,20 @@ func (disc *PluggableDiscovery) jsonDecodeLoop(in io.Reader, outChan chan<- *dis
121122 disc .statusMutex .Unlock ()
122123 close (outChan )
123124 }
125+
124126 for {
125127 var msg discoveryMessage
126128 if err := decoder .Decode (& msg ); err != nil {
127129 closeAndReportError (err )
128130 return
129131 }
130-
131132 if msg .EventType == "add" {
132133 if msg .Port == nil {
133134 closeAndReportError (errors .New ("invalid 'add' message: missing port" ))
134135 return
135136 }
136137 disc .statusMutex .Lock ()
137- disc .cachedPorts [msg .Port .Address ] = msg .Port
138+ disc .cachedPorts [msg .Port .Address + "|" + msg . Port . Protocol ] = msg .Port
138139 if disc .eventChan != nil {
139140 disc .eventChan <- & Event {"add" , msg .Port }
140141 }
@@ -145,7 +146,7 @@ func (disc *PluggableDiscovery) jsonDecodeLoop(in io.Reader, outChan chan<- *dis
145146 return
146147 }
147148 disc .statusMutex .Lock ()
148- delete (disc .cachedPorts , msg .Port .Address )
149+ delete (disc .cachedPorts , msg .Port .Address + "|" + msg . Port . Protocol )
149150 if disc .eventChan != nil {
150151 disc .eventChan <- & Event {"remove" , msg .Port }
151152 }
@@ -187,13 +188,35 @@ func (disc *PluggableDiscovery) waitMessage(timeout time.Duration) (*discoveryMe
187188}
188189
189190func (disc * PluggableDiscovery ) sendCommand (command string ) error {
190- if n , err := disc .outgoingCommandsPipe .Write ([]byte (command )); err != nil {
191+ data := []byte (command )
192+ for {
193+ n , err := disc .outgoingCommandsPipe .Write (data )
194+ if err != nil {
195+ return err
196+ }
197+ if n == len (data ) {
198+ return nil
199+ }
200+ data = data [n :]
201+ }
202+ }
203+
204+ // Hello sends the HELLO command to the discovery to agree on the pluggable discovery protocol. This
205+ // must be the first command to run in the communication with the discovery.
206+ func (disc * PluggableDiscovery ) Hello () error {
207+ if err := disc .sendCommand ("HELLO 1 \" arduino-cli " + globals .VersionInfo .VersionString + "\" \n " ); err != nil {
191208 return err
192- } else if n < len (command ) {
193- return disc .sendCommand (command [n :])
194- } else {
195- return nil
196209 }
210+ if msg , err := disc .waitMessage (time .Second * 10 ); err != nil {
211+ return err
212+ } else if msg .EventType != "hello" {
213+ return errors .Errorf ("communication out of sync, expected 'hello', received '%s'" , msg .EventType )
214+ } else if msg .Message != "OK" || msg .Error {
215+ return errors .Errorf ("command failed: %s" , msg .Message )
216+ } else if msg .ProtocolVersion > 1 {
217+ return errors .Errorf ("protocol version not supported: requested 1, got %d" , msg .ProtocolVersion )
218+ }
219+ return nil
197220}
198221
199222// Start initializes and start the discovery internal subroutines. This command must be
@@ -206,7 +229,7 @@ func (disc *PluggableDiscovery) Start() error {
206229 return err
207230 } else if msg .EventType != "start" {
208231 return errors .Errorf ("communication out of sync, expected 'start', received '%s'" , msg .EventType )
209- } else if msg .Message != "OK" {
232+ } else if msg .Message != "OK" || msg . Error {
210233 return errors .Errorf ("command failed: %s" , msg .Message )
211234 }
212235 return nil
@@ -223,7 +246,7 @@ func (disc *PluggableDiscovery) Stop() error {
223246 return err
224247 } else if msg .EventType != "stop" {
225248 return errors .Errorf ("communication out of sync, expected 'stop', received '%s'" , msg .EventType )
226- } else if msg .Message != "OK" {
249+ } else if msg .Message != "OK" || msg . Error {
227250 return errors .Errorf ("command failed: %s" , msg .Message )
228251 }
229252 return nil
@@ -238,7 +261,7 @@ func (disc *PluggableDiscovery) Quit() error {
238261 return err
239262 } else if msg .EventType != "quit" {
240263 return errors .Errorf ("communication out of sync, expected 'quit', received '%s'" , msg .EventType )
241- } else if msg .Message != "OK" {
264+ } else if msg .Message != "OK" || msg . Error {
242265 return errors .Errorf ("command failed: %s" , msg .Message )
243266 }
244267 return nil
@@ -254,6 +277,8 @@ func (disc *PluggableDiscovery) List() ([]*Port, error) {
254277 return nil , err
255278 } else if msg .EventType != "list" {
256279 return nil , errors .Errorf ("communication out of sync, expected 'list', received '%s'" , msg .EventType )
280+ } else if msg .Error {
281+ return nil , errors .Errorf ("command failed: %s" , msg .Message )
257282 } else {
258283 return msg .Ports , nil
259284 }
@@ -285,7 +310,13 @@ func (disc *PluggableDiscovery) StartSync() error {
285310 return err
286311 }
287312
288- // START_SYNC does not give any response
313+ if msg , err := disc .waitMessage (time .Second * 10 ); err != nil {
314+ return err
315+ } else if msg .EventType != "start_sync" {
316+ return errors .Errorf ("communication out of sync, expected 'start_sync', received '%s'" , msg .EventType )
317+ } else if msg .Message != "OK" || msg .Error {
318+ return errors .Errorf ("command failed: %s" , msg .Message )
319+ }
289320
290321 disc .eventsMode = true
291322 disc .cachedPorts = map [string ]* Port {}
0 commit comments