Skip to content

Commit da06bca

Browse files
committed
[draft] added support for Windows hotplugging
1 parent 738bb67 commit da06bca

File tree

5 files changed

+116
-5
lines changed

5 files changed

+116
-5
lines changed

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,7 @@ require (
99

1010
require (
1111
github.com/arduino/go-paths-helper v1.8.0 // indirect
12+
github.com/arduino/go-win32-utils v0.0.0-20230306145551-565922dbd838 // indirect
1213
github.com/pkg/errors v0.9.1 // indirect
14+
golang.org/x/sys v0.6.0 // indirect
1315
)

go.sum

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,10 @@ github.com/arduino/go-paths-helper v1.8.0/go.mod h1:V82BWgAAp4IbmlybxQdk9Bpkz8M4
5151
github.com/arduino/go-properties-orderedmap v1.7.1 h1:HQ9Pn/mk3+XyfrE39EEvaZwJkrvgiVSY5Oq3JSEfOR4=
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=
54+
github.com/arduino/go-win32-utils v0.0.0-20180330194947-ed041402e83b h1:3PjgYG5gVPA7cipp7vIR2lF96KkEJIFBJ+ANnuv6J20=
5455
github.com/arduino/go-win32-utils v0.0.0-20180330194947-ed041402e83b/go.mod h1:iIPnclBMYm1g32Q5kXoqng4jLhMStReIP7ZxaoUC2y8=
56+
github.com/arduino/go-win32-utils v0.0.0-20230306145551-565922dbd838 h1:pxJdhxH4FzhpIhf3sBqyexLkeP+8iHabs3WctX97P9Y=
57+
github.com/arduino/go-win32-utils v0.0.0-20230306145551-565922dbd838/go.mod h1:0jqM7doGEAs6DaJCxxhLBUDS5OawrqF48HqXkcEie/Q=
5558
github.com/arduino/pluggable-discovery-protocol-handler/v2 v2.1.1 h1:MPQZ2YImq5qBiOPwTFGOrl6E99XGSRHc+UzHA6hsjvc=
5659
github.com/arduino/pluggable-discovery-protocol-handler/v2 v2.1.1/go.mod h1:2lA930B1Xu/otYT1kbx3l1n5vFJuuyPNkQaqOoQHmPE=
5760
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
@@ -472,6 +475,8 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc
472475
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
473476
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
474477
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
478+
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
479+
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
475480
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
476481
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
477482
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: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
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 2 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, write to the Free Software
17+
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18+
19+
//go:build !windows
20+
21+
package main
22+
23+
import (
24+
discovery "github.com/arduino/pluggable-discovery-protocol-handler/v2"
25+
)
26+
27+
func (d *DFUDiscovery) sync(eventCB discovery.EventCallback, errorCB discovery.ErrorCallback) error {
28+
return d.libusbSync(eventCB, errorCB)
29+
}

sync_windows.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
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 2 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, write to the Free Software
17+
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18+
19+
package main
20+
21+
import (
22+
"context"
23+
"time"
24+
25+
"github.com/arduino/go-win32-utils/devicenotification"
26+
discovery "github.com/arduino/pluggable-discovery-protocol-handler/v2"
27+
)
28+
29+
func (d *DFUDiscovery) sync(eventCB discovery.EventCallback, errorCB discovery.ErrorCallback) error {
30+
ctx, cancel := context.WithCancel(context.Background())
31+
d.close = cancel
32+
33+
deviceEventChan := make(chan bool, 1)
34+
go func() {
35+
err := devicenotification.Start(ctx, func() {
36+
select {
37+
case deviceEventChan <- true:
38+
default:
39+
}
40+
}, errorCB)
41+
if err != nil {
42+
errorCB(err.Error())
43+
}
44+
}()
45+
46+
go func() {
47+
d.sendUpdates(eventCB, errorCB)
48+
49+
for {
50+
select {
51+
case <-ctx.Done():
52+
return
53+
case <-deviceEventChan:
54+
}
55+
56+
again:
57+
d.sendUpdates(eventCB, errorCB)
58+
59+
// Trigger another update after 500ms because Windows might signal a
60+
// new port much before it becomes actually available.
61+
select {
62+
case <-ctx.Done():
63+
return
64+
case <-deviceEventChan:
65+
goto again
66+
case <-time.After(time.Millisecond * 500):
67+
}
68+
d.sendUpdates(eventCB, errorCB)
69+
}
70+
}()
71+
return nil
72+
}

0 commit comments

Comments
 (0)