Skip to content

Commit 00fca38

Browse files
committed
Added first implementation of USB DFU probe
1 parent 48a7bda commit 00fca38

File tree

3 files changed

+95
-3
lines changed

3 files changed

+95
-3
lines changed

go.mod

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ module github.com/arduino/dfu-discovery
22

33
go 1.19
44

5-
require github.com/arduino/pluggable-discovery-protocol-handler/v2 v2.1.1
5+
require (
6+
github.com/arduino/go-properties-orderedmap v1.7.1
7+
github.com/arduino/pluggable-discovery-protocol-handler/v2 v2.1.1
8+
)
69

710
require (
811
github.com/arduino/go-paths-helper v1.8.0 // indirect
9-
github.com/arduino/go-properties-orderedmap v1.7.1 // indirect
1012
github.com/pkg/errors v0.9.1 // indirect
1113
)

main.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,8 @@ const char *libusbOpen() {
3838
void libusbClose() {
3939
libusb_exit(ctx);
4040
ctx = NULL;
41-
}
41+
}
42+
43+
void dfuProbeDevices() {
44+
probe_devices(ctx);
45+
}

main.go

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,16 @@ char *get_path(libusb_device *dev);
1313
// Defined in main.c
1414
const char *libusbOpen();
1515
void libusbClose();
16+
void dfuProbeDevices();
1617
*/
1718
import "C"
1819

1920
import (
2021
"fmt"
2122
"os"
23+
"time"
2224

25+
"github.com/arduino/go-properties-orderedmap"
2326
discovery "github.com/arduino/pluggable-discovery-protocol-handler/v2"
2427
)
2528

@@ -34,6 +37,7 @@ func main() {
3437

3538
// DFUDiscovery is the implementation of the DFU pluggable-discovery
3639
type DFUDiscovery struct {
40+
closeChan chan<- struct{}
3741
}
3842

3943
// Hello is the handler for the pluggable-discovery HELLO command
@@ -43,10 +47,15 @@ func (d *DFUDiscovery) Hello(userAgent string, protocolVersion int) error {
4347

4448
// Quit is the handler for the pluggable-discovery QUIT command
4549
func (d *DFUDiscovery) Quit() {
50+
d.Stop()
4651
}
4752

4853
// Stop is the handler for the pluggable-discovery STOP command
4954
func (d *DFUDiscovery) Stop() error {
55+
if d.closeChan != nil {
56+
close(d.closeChan)
57+
d.closeChan = nil
58+
}
5059
C.libusbClose()
5160
return nil
5261
}
@@ -56,9 +65,86 @@ func (d *DFUDiscovery) StartSync(eventCB discovery.EventCallback, errorCB discov
5665
if cErr := C.libusbOpen(); cErr != nil {
5766
return fmt.Errorf("can't open libusb: %s", C.GoString(cErr))
5867
}
68+
closeChan := make(chan struct{})
69+
go func() {
70+
for {
71+
d.sendUpdates(eventCB, errorCB)
72+
select {
73+
case <-time.After(5 * time.Second):
74+
case <-closeChan:
75+
return
76+
}
77+
}
78+
}()
79+
d.closeChan = closeChan
5980
return nil
6081
}
6182

83+
func (d *DFUDiscovery) sendUpdates(eventCB discovery.EventCallback, errorCB discovery.ErrorCallback) {
84+
C.dfuProbeDevices()
85+
for _, dfuIf := range d.getDFUInterfaces() {
86+
eventCB("add", dfuIf.AsDiscoveryPort())
87+
}
88+
}
89+
6290
func getPath(dev *C.struct_libusb_device) string {
6391
return C.GoString(C.get_path(dev))
6492
}
93+
94+
// DFUInterface represents a DFU Interface
95+
type DFUInterface struct {
96+
Path string
97+
AltName string
98+
VID, PID uint16
99+
SerialNumber string
100+
Flags uint32
101+
}
102+
103+
// AsDiscoveryPort converts this DFUInterface into a discovery.Port
104+
func (i *DFUInterface) AsDiscoveryPort() *discovery.Port {
105+
props := properties.NewMap()
106+
props.Set("vid", fmt.Sprintf("%04X", i.VID))
107+
props.Set("pid", fmt.Sprintf("%04X", i.PID))
108+
if i.SerialNumber != "" {
109+
props.Set("serial", i.SerialNumber)
110+
}
111+
// ProtocolLabel: pdfu.flags & DFU_IFF_DFU ? "DFU" : "Runtime"
112+
return &discovery.Port{
113+
Address: i.Path,
114+
AddressLabel: i.Path,
115+
Protocol: "dfu",
116+
ProtocolLabel: "USB DFU",
117+
Properties: props,
118+
HardwareID: props.Get("serial"),
119+
}
120+
}
121+
122+
func (d *DFUDiscovery) getDFUInterfaces() []*DFUInterface {
123+
res := []*DFUInterface{}
124+
for pdfu := C.dfu_root; pdfu != nil; pdfu = pdfu.next {
125+
fmt.Println(pdfu)
126+
if (pdfu.flags & C.DFU_IFF_DFU) == 0 {
127+
// decide what to do with DFU runtime objects
128+
// for the time being, ignore them
129+
continue
130+
}
131+
ifPath := getPath(pdfu.dev)
132+
// for i := 0; i < index; i++ {
133+
// // allow only one object
134+
// if j["ports"][i]["address"] == ifPath {
135+
// index = i
136+
// break
137+
// }
138+
// }
139+
140+
dfuIf := &DFUInterface{
141+
Path: ifPath,
142+
AltName: C.GoString(pdfu.alt_name),
143+
VID: uint16(pdfu.vendor),
144+
PID: uint16(pdfu.product),
145+
SerialNumber: C.GoString(pdfu.serial_name),
146+
}
147+
res = append(res, dfuIf)
148+
}
149+
return res
150+
}

0 commit comments

Comments
 (0)