Skip to content

Commit e8938fa

Browse files
committed
update goselect to 0.1.3
1 parent 0996f84 commit e8938fa

File tree

4 files changed

+67
-29
lines changed

4 files changed

+67
-29
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ module go.bug.st/serial
33
go 1.17
44

55
require (
6-
github.com/creack/goselect v0.1.2
6+
github.com/creack/goselect v0.1.3
77
github.com/stretchr/testify v1.8.4
88
golang.org/x/sys v0.19.0
99
)

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
github.com/creack/goselect v0.1.2 h1:2DNy14+JPjRBgPzAd1thbQp4BSIihxcBf0IXhQXDRa0=
2-
github.com/creack/goselect v0.1.2/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY=
1+
github.com/creack/goselect v0.1.3 h1:MaGNMclRo7P2Jl21hBpR1Cn33ITSbKP6E49RtfblLKc=
2+
github.com/creack/goselect v0.1.3/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY=
33
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
44
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
55
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=

serial_unix.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ func nativeOpen(portName string, mode *Mode) (*unixPort, error) {
241241
// Explicitly disable RTS/CTS flow control
242242
setTermSettingsCtsRts(false, settings)
243243

244-
if port.setTermSettings(settings) != nil {
244+
if err = port.setTermSettings(settings); err != nil {
245245
port.Close()
246246
return nil, &PortError{code: InvalidSerialPort, causedBy: fmt.Errorf("error setting term settings: %w", err)}
247247
}

serial_windows.go

Lines changed: 63 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package serial
1919

2020
import (
2121
"errors"
22+
"strings"
2223
"sync"
2324
"syscall"
2425
"time"
@@ -28,8 +29,9 @@ import (
2829
)
2930

3031
type windowsPort struct {
31-
mu sync.Mutex
32-
handle windows.Handle
32+
mu sync.Mutex
33+
handle windows.Handle
34+
hasTimeout bool
3335
}
3436

3537
func nativeGetPortsList() ([]string, error) {
@@ -44,12 +46,22 @@ func nativeGetPortsList() ([]string, error) {
4446
}
4547
defer key.Close()
4648

47-
list, err := key.ReadValueNames(0)
49+
names, err := key.ReadValueNames(0)
4850
if err != nil {
4951
return nil, &PortError{code: ErrorEnumeratingPorts, causedBy: err}
5052
}
5153

52-
return list, nil
54+
var values []string
55+
for _, n := range names {
56+
v, _, err := key.GetStringValue(n)
57+
if err != nil || v == "" {
58+
continue
59+
}
60+
61+
values = append(values, v)
62+
}
63+
64+
return values, nil
5365
}
5466

5567
func (port *windowsPort) Close() error {
@@ -72,26 +84,33 @@ func (port *windowsPort) Read(p []byte) (int, error) {
7284
}
7385
defer windows.CloseHandle(ev.HEvent)
7486

75-
err = windows.ReadFile(port.handle, p, &readed, ev)
76-
if err == windows.ERROR_IO_PENDING {
77-
err = windows.GetOverlappedResult(port.handle, ev, &readed, true)
78-
}
79-
switch err {
80-
case nil:
81-
// operation completed successfully
82-
case windows.ERROR_OPERATION_ABORTED:
83-
// port may have been closed
84-
return int(readed), &PortError{code: PortClosed, causedBy: err}
85-
default:
86-
// error happened
87-
return int(readed), err
88-
}
89-
if readed > 0 {
90-
return int(readed), nil
91-
}
87+
for {
88+
err = windows.ReadFile(port.handle, p, &readed, ev)
89+
if err == windows.ERROR_IO_PENDING {
90+
err = windows.GetOverlappedResult(port.handle, ev, &readed, true)
91+
}
92+
switch err {
93+
case nil:
94+
// operation completed successfully
95+
case windows.ERROR_OPERATION_ABORTED:
96+
// port may have been closed
97+
return int(readed), &PortError{code: PortClosed, causedBy: err}
98+
default:
99+
// error happened
100+
return int(readed), err
101+
}
102+
if readed > 0 {
103+
return int(readed), nil
104+
}
92105

93-
// Timeout
94-
return 0, nil
106+
// Timeout
107+
port.mu.Lock()
108+
hasTimeout := port.hasTimeout
109+
port.mu.Unlock()
110+
if hasTimeout {
111+
return 0, nil
112+
}
113+
}
95114
}
96115

97116
func (port *windowsPort) Write(p []byte) (int, error) {
@@ -275,10 +294,19 @@ func (port *windowsPort) GetModemStatusBits() (*ModemStatusBits, error) {
275294
}
276295

277296
func (port *windowsPort) SetReadTimeout(timeout time.Duration) error {
297+
// This is a brutal hack to make the CH340 chipset work properly.
298+
// Normally this value should be 0xFFFFFFFE but, after a lot of
299+
// tinkering, I discovered that any value with the highest
300+
// bit set will make the CH340 driver behave like the timeout is 0,
301+
// in the best cases leading to a spinning loop...
302+
// (could this be a wrong signed vs unsigned conversion in the driver?)
303+
// https://github.com/arduino/serial-monitor/issues/112
304+
const MaxReadTotalTimeoutConstant = 0x7FFFFFFE
305+
278306
commTimeouts := &windows.CommTimeouts{
279307
ReadIntervalTimeout: 0xFFFFFFFF,
280308
ReadTotalTimeoutMultiplier: 0xFFFFFFFF,
281-
ReadTotalTimeoutConstant: 0xFFFFFFFE,
309+
ReadTotalTimeoutConstant: MaxReadTotalTimeoutConstant,
282310
WriteTotalTimeoutConstant: 0,
283311
WriteTotalTimeoutMultiplier: 0,
284312
}
@@ -287,12 +315,20 @@ func (port *windowsPort) SetReadTimeout(timeout time.Duration) error {
287315
if ms > 0xFFFFFFFE || ms < 0 {
288316
return &PortError{code: InvalidTimeoutValue}
289317
}
318+
319+
if ms > MaxReadTotalTimeoutConstant {
320+
ms = MaxReadTotalTimeoutConstant
321+
}
322+
290323
commTimeouts.ReadTotalTimeoutConstant = uint32(ms)
291324
}
292325

326+
port.mu.Lock()
327+
defer port.mu.Unlock()
293328
if err := windows.SetCommTimeouts(port.handle, commTimeouts); err != nil {
294329
return &PortError{code: InvalidTimeoutValue, causedBy: err}
295330
}
331+
port.hasTimeout = (timeout != NoTimeout)
296332

297333
return nil
298334
}
@@ -317,7 +353,9 @@ func createOverlappedEvent() (*windows.Overlapped, error) {
317353
}
318354

319355
func nativeOpen(portName string, mode *Mode) (*windowsPort, error) {
320-
portName = "\\\\.\\" + portName
356+
if !strings.HasPrefix(portName, `\\.\`) {
357+
portName = `\\.\` + portName
358+
}
321359
path, err := windows.UTF16PtrFromString(portName)
322360
if err != nil {
323361
return nil, err

0 commit comments

Comments
 (0)