Skip to content

Commit a7d97e7

Browse files
committed
Implemented serial-discovery
1 parent 62c3b75 commit a7d97e7

File tree

8 files changed

+1176
-62
lines changed

8 files changed

+1176
-62
lines changed

.licensed.yml

+1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ allowed:
5555
# The following are based on: https://www.gnu.org/licenses/license-list.html#GPLCompatibleLicenses
5656
- gpl-1.0-or-later
5757
- gpl-1.0+ # Deprecated ID for `gpl-1.0-or-later`
58+
- gpl-2.0
5859
- gpl-2.0-or-later
5960
- gpl-2.0+ # Deprecated ID for `gpl-2.0-or-later`
6061
- gpl-3.0-only

.licenses/arduino-create-agent/go/github.com/arduino/go-properties-orderedmap.dep.yml

+350
Large diffs are not rendered by default.

.licenses/arduino-create-agent/go/github.com/arduino/pluggable-discovery-protocol-handler/v2.dep.yml

+709
Large diffs are not rendered by default.

go.mod

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ require (
77
github.com/ProtonMail/go-crypto v1.1.0-alpha.0
88
github.com/arduino/go-paths-helper v1.12.0
99
github.com/arduino/go-serial-utils v0.1.2
10+
github.com/arduino/pluggable-discovery-protocol-handler/v2 v2.2.0
1011
github.com/blang/semver v3.5.1+incompatible
1112
github.com/codeclysm/extract/v3 v3.1.1
1213
github.com/gin-contrib/cors v1.5.0
@@ -28,6 +29,7 @@ require (
2829

2930
require (
3031
github.com/AnatolyRugalev/goregen v0.1.0 // indirect
32+
github.com/arduino/go-properties-orderedmap v1.8.0 // indirect
3133
github.com/bytedance/sonic v1.10.1 // indirect
3234
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
3335
github.com/chenzhuoyu/iasm v0.9.0 // indirect

go.sum

+5
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,15 @@ github.com/AnatolyRugalev/goregen v0.1.0 h1:xrdXkLaskMnbxW0x4FWNj2yoednv0X2bcTBW
44
github.com/AnatolyRugalev/goregen v0.1.0/go.mod h1:sVlY1tjcirqLBRZnCcIq1+7/Lwmqz5g7IK8AStjOVzI=
55
github.com/ProtonMail/go-crypto v1.1.0-alpha.0 h1:nHGfwXmFvJrSR9xu8qL7BkO4DqTHXE9N5vPhgY2I+j0=
66
github.com/ProtonMail/go-crypto v1.1.0-alpha.0/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
7+
github.com/arduino/go-paths-helper v1.0.1/go.mod h1:HpxtKph+g238EJHq4geEPv9p+gl3v5YYu35Yb+w31Ck=
78
github.com/arduino/go-paths-helper v1.12.0 h1:xizOQtI9iHdl19qXd1EmWg5i9W//2bOCOYwlNv8F61E=
89
github.com/arduino/go-paths-helper v1.12.0/go.mod h1:jcpW4wr0u69GlXhTYydsdsqAjLaYK5n7oWHfKqOG6LM=
10+
github.com/arduino/go-properties-orderedmap v1.8.0 h1:wEfa6hHdpezrVOh787OmClsf/Kd8qB+zE3P2Xbrn0CQ=
11+
github.com/arduino/go-properties-orderedmap v1.8.0/go.mod h1:DKjD2VXY/NZmlingh4lSFMEYCVubfeArCsGPGDwb2yk=
912
github.com/arduino/go-serial-utils v0.1.2 h1:MRFwME4w/uaVkJ1R+wzz4KSbI9cF9IDVrYorazvjpTk=
1013
github.com/arduino/go-serial-utils v0.1.2/go.mod h1:kzIsNPgz8DFAd1sAFKve4ubxrdGcwQ4XzvRLlztsgnE=
14+
github.com/arduino/pluggable-discovery-protocol-handler/v2 v2.2.0 h1:v7og6LpskewFabmaShKVzWXl5MXbmsxaRP3yo4dJta8=
15+
github.com/arduino/pluggable-discovery-protocol-handler/v2 v2.2.0/go.mod h1:1dgblsmK2iBx3L5iNTyRIokeaxbTLUrYiUbHBK6yC3Y=
1116
github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=
1217
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
1318
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=

main.go

+2-10
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ import (
4040
"github.com/arduino/arduino-create-agent/systray"
4141
"github.com/arduino/arduino-create-agent/tools"
4242
"github.com/arduino/arduino-create-agent/updater"
43-
"github.com/arduino/arduino-create-agent/upload"
4443
v2 "github.com/arduino/arduino-create-agent/v2"
4544
paths "github.com/arduino/go-paths-helper"
4645
cors "github.com/gin-contrib/cors"
@@ -345,22 +344,15 @@ func loop() {
345344
}
346345
}
347346

347+
// launch the discoveries for the running system
348+
go serialPorts.Run()
348349
// launch the hub routine which is the singleton for the websocket server
349350
go h.run()
350351
// launch our serial port routine
351352
go sh.run()
352353
// launch our dummy data routine
353354
//go d.run()
354355

355-
go func() {
356-
for {
357-
if !upload.Busy {
358-
serialPorts.Update()
359-
}
360-
time.Sleep(2 * time.Second)
361-
}
362-
}()
363-
364356
r := gin.New()
365357

366358
socketHandler := wsHandler().ServeHTTP

serial.go

+107-48
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,14 @@ package main
1919

2020
import (
2121
"encoding/json"
22+
"slices"
2223
"strconv"
2324
"strings"
2425
"sync"
26+
"time"
2527

28+
discovery "github.com/arduino/pluggable-discovery-protocol-handler/v2"
2629
"github.com/sirupsen/logrus"
27-
"go.bug.st/serial/enumerator"
2830
)
2931

3032
type writeRequest struct {
@@ -51,9 +53,8 @@ type serialhub struct {
5153

5254
// SerialPortList is the serial port list
5355
type SerialPortList struct {
54-
Ports []SpPortItem
55-
portsLock sync.Mutex
56-
enumerationLock sync.Mutex
56+
Ports []*SpPortItem
57+
portsLock sync.Mutex
5758
}
5859

5960
// SpPortItem is the serial port item
@@ -146,60 +147,118 @@ func (sp *SerialPortList) List() {
146147
}
147148
}
148149

149-
func (sp *SerialPortList) Update() {
150-
if !sp.enumerationLock.TryLock() {
151-
// already enumerating...
152-
return
150+
// Run is the main loop for port discovery and management
151+
func (sp *SerialPortList) Run() {
152+
for retries := 0; retries < 10; retries++ {
153+
sp.runSerialDiscovery()
154+
155+
logrus.Errorf("Serial discovery stopped working, restarting it in 10 seconds...")
156+
time.Sleep(10 * time.Second)
153157
}
154-
defer sp.enumerationLock.Unlock()
158+
logrus.Errorf("Failed restarting serial discovery. Giving up...")
159+
}
155160

156-
livePorts, _ := enumerator.GetDetailedPortsList()
157-
// TODO: report error?
161+
func (sp *SerialPortList) runSerialDiscovery() {
162+
// First ensure that all the discoveries are available
163+
if err := Tools.Download("builtin", "serial-discovery", "latest", "keep"); err != nil {
164+
logrus.Errorf("Error downloading serial-discovery: %s", err)
165+
panic(err)
166+
}
167+
sd, err := Tools.GetLocation("serial-discovery")
168+
if err != nil {
169+
logrus.Errorf("Error downloading serial-discovery: %s", err)
170+
panic(err)
171+
}
172+
d := discovery.NewClient("serial", sd+"/serial-discovery")
173+
dLogger := logrus.WithField("discovery", "serial")
174+
if *verbose {
175+
d.SetLogger(dLogger)
176+
}
177+
d.SetUserAgent("arduino-create-agent/" + version)
178+
if err := d.Run(); err != nil {
179+
logrus.Errorf("Error running serial-discovery: %s", err)
180+
panic(err)
181+
}
182+
defer d.Quit()
158183

159-
var ports []SpPortItem
160-
for _, livePort := range livePorts {
161-
if !livePort.IsUSB {
162-
continue
163-
}
164-
vid, pid := "0x"+livePort.VID, "0x"+livePort.PID
165-
if vid == "0x0000" || pid == "0x0000" {
166-
continue
167-
}
168-
if portsFilter != nil && !portsFilter.MatchString(livePort.Name) {
169-
logrus.Debugf("ignoring port not matching filter. port: %v\n", livePort)
170-
continue
171-
}
184+
events, err := d.StartSync(10)
185+
if err != nil {
186+
logrus.Errorf("Error downloading serial-discovery: %s", err)
187+
panic(err)
188+
}
172189

173-
port := SpPortItem{
174-
Name: livePort.Name,
175-
SerialNumber: livePort.SerialNumber,
176-
VendorID: vid,
177-
ProductID: pid,
178-
Ver: version,
179-
IsOpen: false,
180-
IsPrimary: false,
181-
Baud: 0,
182-
BufferAlgorithm: "",
190+
logrus.Infof("Serial discovery started, watching for events")
191+
for ev := range events {
192+
logrus.WithField("event", ev).Debugf("Serial discovery event")
193+
switch ev.Type {
194+
case "add":
195+
sp.add(ev.Port)
196+
case "remove":
197+
sp.remove(ev.Port)
183198
}
199+
}
184200

185-
// we have a full clean list of ports now. iterate thru them
186-
// to append the open/close state, baud rates, etc to make
187-
// a super clean nice list to send back to browser
201+
sp.reset()
202+
logrus.Errorf("Serial discovery stopped.")
203+
}
188204

189-
// figure out if port is open
190-
if myport, isFound := sh.FindPortByName(port.Name); isFound {
191-
// and update data with the open port parameters
192-
port.IsOpen = true
193-
port.Baud = myport.portConf.Baud
194-
port.BufferAlgorithm = myport.BufferType
195-
}
205+
func (sp *SerialPortList) reset() {
206+
sp.portsLock.Lock()
207+
defer sp.portsLock.Unlock()
208+
sp.Ports = []*SpPortItem{}
209+
}
210+
211+
func (sp *SerialPortList) add(addedPort *discovery.Port) {
212+
if addedPort.Protocol != "serial" {
213+
return
214+
}
215+
props := addedPort.Properties
216+
if !props.ContainsKey("vid") {
217+
return
218+
}
219+
vid, pid := props.Get("vid"), props.Get("pid")
220+
if vid == "0x0000" || pid == "0x0000" {
221+
return
222+
}
223+
if portsFilter != nil && !portsFilter.MatchString(addedPort.Address) {
224+
logrus.Debugf("ignoring port not matching filter. port: %v\n", addedPort.Address)
225+
return
226+
}
196227

197-
ports = append(ports, port)
228+
sp.portsLock.Lock()
229+
defer sp.portsLock.Unlock()
230+
231+
// If the port is already in the list, just update the metadata...
232+
for _, oldPort := range sp.Ports {
233+
if oldPort.Name == addedPort.Address {
234+
oldPort.SerialNumber = props.Get("serialNumber")
235+
oldPort.VendorID = vid
236+
oldPort.ProductID = pid
237+
return
238+
}
198239
}
240+
// ...otherwise, add it to the list
241+
sp.Ports = append(sp.Ports, &SpPortItem{
242+
Name: addedPort.Address,
243+
SerialNumber: props.Get("serialNumber"),
244+
VendorID: vid,
245+
ProductID: pid,
246+
Ver: version,
247+
IsOpen: false,
248+
IsPrimary: false,
249+
Baud: 0,
250+
BufferAlgorithm: "",
251+
})
252+
}
253+
254+
func (sp *SerialPortList) remove(removedPort *discovery.Port) {
255+
sp.portsLock.Lock()
256+
defer sp.portsLock.Unlock()
199257

200-
serialPorts.portsLock.Lock()
201-
serialPorts.Ports = ports
202-
serialPorts.portsLock.Unlock()
258+
// Remove the port from the list
259+
sp.Ports = slices.DeleteFunc(sp.Ports, func(oldPort *SpPortItem) bool {
260+
return oldPort.Name == removedPort.Address
261+
})
203262
}
204263

205264
func spErr(err string) {

serialport.go

-4
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,6 @@ func (p *serport) writerNoBuf() {
232232
log.Println(msgstr)
233233
h.broadcastSys <- []byte(msgstr)
234234
p.portIo.Close()
235-
serialPorts.Update()
236235
serialPorts.List()
237236
}
238237

@@ -327,7 +326,6 @@ func spHandlerOpen(portname string, baud int, buftype string) {
327326
sh.register <- p
328327
defer func() { sh.unregister <- p }()
329328

330-
serialPorts.Update()
331329
serialPorts.List()
332330

333331
// this is internally buffered thread to not send to serial port if blocked
@@ -339,7 +337,6 @@ func spHandlerOpen(portname string, baud int, buftype string) {
339337

340338
p.reader(buftype)
341339

342-
serialPorts.Update()
343340
serialPorts.List()
344341
}
345342

@@ -352,6 +349,5 @@ func spHandlerClose(p *serport) {
352349
func spCloseReal(p *serport) {
353350
p.bufferwatcher.Close()
354351
p.portIo.Close()
355-
serialPorts.Update()
356352
serialPorts.List()
357353
}

0 commit comments

Comments
 (0)