Skip to content

Commit fc2573a

Browse files
committed
Added support for Windows hotplugging
1 parent 7897dbc commit fc2573a

File tree

5 files changed

+113
-5
lines changed

5 files changed

+113
-5
lines changed

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@ go 1.19
44

55
require (
66
github.com/arduino/go-properties-orderedmap v1.7.1
7+
github.com/arduino/go-win32-utils v1.0.0
78
github.com/arduino/pluggable-discovery-protocol-handler/v2 v2.1.1
89
)
910

1011
require (
1112
github.com/arduino/go-paths-helper v1.8.0 // indirect
1213
github.com/pkg/errors v0.9.1 // indirect
14+
golang.org/x/sys v0.6.0 // indirect
1315
)

go.sum

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ github.com/arduino/go-properties-orderedmap v1.7.1 h1:HQ9Pn/mk3+XyfrE39EEvaZwJkr
5252
github.com/arduino/go-properties-orderedmap v1.7.1/go.mod h1:DKjD2VXY/NZmlingh4lSFMEYCVubfeArCsGPGDwb2yk=
5353
github.com/arduino/go-timeutils v0.0.0-20171220113728-d1dd9e313b1b/go.mod h1:uwGy5PpN4lqW97FiLnbcx+xx8jly5YuPMJWfVwwjJiQ=
5454
github.com/arduino/go-win32-utils v0.0.0-20180330194947-ed041402e83b/go.mod h1:iIPnclBMYm1g32Q5kXoqng4jLhMStReIP7ZxaoUC2y8=
55+
github.com/arduino/go-win32-utils v1.0.0 h1:/cXB86sOJxOsCHP7sQmXGLkdValwJt56mIwOHYxgQjQ=
56+
github.com/arduino/go-win32-utils v1.0.0/go.mod h1:0jqM7doGEAs6DaJCxxhLBUDS5OawrqF48HqXkcEie/Q=
5557
github.com/arduino/pluggable-discovery-protocol-handler/v2 v2.1.1 h1:MPQZ2YImq5qBiOPwTFGOrl6E99XGSRHc+UzHA6hsjvc=
5658
github.com/arduino/pluggable-discovery-protocol-handler/v2 v2.1.1/go.mod h1:2lA930B1Xu/otYT1kbx3l1n5vFJuuyPNkQaqOoQHmPE=
5759
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
@@ -472,6 +474,8 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc
472474
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
473475
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
474476
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
477+
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
478+
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
475479
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
476480
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
477481
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

main.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -74,26 +74,30 @@ func (d *DFUDiscovery) Quit() {
7474

7575
// Stop is the handler for the pluggable-discovery STOP command
7676
func (d *DFUDiscovery) Stop() error {
77-
if d.closeChan != nil {
78-
close(d.closeChan)
79-
d.closeChan = nil
77+
if d.close != nil {
78+
d.close()
79+
d.close = nil
8080
}
8181
C.libusbClose()
8282
return nil
8383
}
8484

8585
// StartSync is the handler for the pluggable-discovery START_SYNC command
8686
func (d *DFUDiscovery) StartSync(eventCB discovery.EventCallback, errorCB discovery.ErrorCallback) error {
87+
d.portsCache = map[string]*discovery.Port{}
8788
if cErr := C.libusbOpen(); cErr != nil {
8889
return fmt.Errorf("can't open libusb: %s", C.GoString(cErr))
8990
}
91+
return d.sync(eventCB, errorCB)
92+
}
93+
94+
func (d *DFUDiscovery) libusbSync(eventCB discovery.EventCallback, errorCB discovery.ErrorCallback) error {
9095
if err := C.libusbHotplugRegisterCallback(); err != nil {
9196
return errors.New(C.GoString(err))
9297
}
9398

9499
closeChan := make(chan struct{})
95100
go func() {
96-
d.portsCache = map[string]*discovery.Port{}
97101
d.sendUpdates(eventCB, errorCB)
98102
for {
99103
if C.libusbHandleEvents() != 0 {
@@ -102,7 +106,6 @@ func (d *DFUDiscovery) StartSync(eventCB discovery.EventCallback, errorCB discov
102106
select {
103107
case <-closeChan:
104108
C.libusbHotplugDeregisterCallback()
105-
d.portsCache = nil
106109
return
107110
default:
108111
}

sync_unix.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// This file is part of dfu-discovery.
2+
//
3+
// Copyright 2023 ARDUINO SA (http://www.arduino.cc/)
4+
//
5+
// This program is free software: you can redistribute it and/or modify
6+
// it under the terms of the GNU General Public License as published by
7+
// the Free Software Foundation, either version 3 of the License, or
8+
// (at your option) any later version.
9+
//
10+
// This program is distributed in the hope that it will be useful,
11+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
// GNU General Public License for more details.
14+
//
15+
// You should have received a copy of the GNU General Public License
16+
// along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
18+
//go:build !windows
19+
20+
package main
21+
22+
import (
23+
discovery "github.com/arduino/pluggable-discovery-protocol-handler/v2"
24+
)
25+
26+
func (d *DFUDiscovery) sync(eventCB discovery.EventCallback, errorCB discovery.ErrorCallback) error {
27+
return d.libusbSync(eventCB, errorCB)
28+
}

sync_windows.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// This file is part of dfu-discovery.
2+
//
3+
// Copyright 2023 ARDUINO SA (http://www.arduino.cc/)
4+
//
5+
// This program is free software: you can redistribute it and/or modify
6+
// it under the terms of the GNU General Public License as published by
7+
// the Free Software Foundation, either version 3 of the License, or
8+
// (at your option) any later version.
9+
//
10+
// This program is distributed in the hope that it will be useful,
11+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
// GNU General Public License for more details.
14+
//
15+
// You should have received a copy of the GNU General Public License
16+
// along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
18+
package main
19+
20+
import (
21+
"context"
22+
"time"
23+
24+
"github.com/arduino/go-win32-utils/devicenotification"
25+
discovery "github.com/arduino/pluggable-discovery-protocol-handler/v2"
26+
)
27+
28+
func (d *DFUDiscovery) sync(eventCB discovery.EventCallback, errorCB discovery.ErrorCallback) error {
29+
ctx, cancel := context.WithCancel(context.Background())
30+
d.close = cancel
31+
32+
deviceEventChan := make(chan bool, 1)
33+
go func() {
34+
err := devicenotification.Start(ctx, func() {
35+
select {
36+
case deviceEventChan <- true:
37+
default:
38+
}
39+
}, errorCB)
40+
if err != nil {
41+
errorCB(err.Error())
42+
}
43+
}()
44+
45+
go func() {
46+
d.sendUpdates(eventCB, errorCB)
47+
48+
for {
49+
select {
50+
case <-ctx.Done():
51+
return
52+
case <-deviceEventChan:
53+
}
54+
55+
again:
56+
d.sendUpdates(eventCB, errorCB)
57+
58+
// Trigger another update after 500ms because Windows might signal a
59+
// new port much before it becomes actually available.
60+
select {
61+
case <-ctx.Done():
62+
return
63+
case <-deviceEventChan:
64+
goto again
65+
case <-time.After(time.Millisecond * 500):
66+
}
67+
d.sendUpdates(eventCB, errorCB)
68+
}
69+
}()
70+
return nil
71+
}

0 commit comments

Comments
 (0)