SetReadTimeout: windows implementation

This commit is contained in:
Cristian Maglie
2020-05-11 00:01:36 +01:00
parent 2cb14f049c
commit 23dbc8b9ba

View File

@@ -18,13 +18,15 @@ package serial
*/
import (
"syscall"
"sync"
"syscall"
"time"
)
type windowsPort struct {
mu sync.Mutex
handle syscall.Handle
mu sync.Mutex
handle syscall.Handle
readTimeoutCycles int64
}
func nativeGetPortsList() ([]string, error) {
@@ -80,6 +82,8 @@ func (port *windowsPort) Read(p []byte) (int, error) {
return 0, err
}
defer syscall.CloseHandle(ev.HEvent)
cycles := int64(0)
for {
err := syscall.ReadFile(port.handle, p, &readed, ev)
if err == syscall.ERROR_IO_PENDING {
@@ -103,6 +107,14 @@ func (port *windowsPort) Read(p []byte) (int, error) {
return 0, err
}
if port.readTimeoutCycles != -1 {
cycles++
if cycles == port.readTimeoutCycles {
// Timeout
return 0, nil
}
}
// At the moment it seems that the only reliable way to check if
// a serial port is alive in Windows is to check if the SetCommState
// function fails.
@@ -370,6 +382,31 @@ func (port *windowsPort) GetModemStatusBits() (*ModemStatusBits, error) {
}, nil
}
func (port *windowsPort) SetReadTimeout(timeout time.Duration) error {
var cycles, cycleDuration int64
if timeout == NoTimeout {
cycles = -1
cycleDuration = 1000
} else {
cycles = timeout.Milliseconds()/1000 + 1
cycleDuration = timeout.Milliseconds() / cycles
}
err := setCommTimeouts(port.handle, &commTimeouts{
ReadIntervalTimeout: 0xFFFFFFFF,
ReadTotalTimeoutMultiplier: 0xFFFFFFFF,
ReadTotalTimeoutConstant: uint32(cycleDuration),
WriteTotalTimeoutConstant: 0,
WriteTotalTimeoutMultiplier: 0,
})
if err != nil {
return &PortError{code: InvalidTimeoutValue, causedBy: err}
}
port.readTimeoutCycles = cycles
return nil
}
func createOverlappedEvent() (*syscall.Overlapped, error) {
h, err := createEvent(nil, true, false, nil)
return &syscall.Overlapped{HEvent: h}, err
@@ -435,18 +472,9 @@ func nativeOpen(portName string, mode *Mode) (*windowsPort, error) {
return nil, &PortError{code: InvalidSerialPort}
}
// Set timeouts to 1 second
timeouts := &commTimeouts{
ReadIntervalTimeout: 0xFFFFFFFF,
ReadTotalTimeoutMultiplier: 0xFFFFFFFF,
ReadTotalTimeoutConstant: 1000, // 1 sec
WriteTotalTimeoutConstant: 0,
WriteTotalTimeoutMultiplier: 0,
}
if setCommTimeouts(port.handle, timeouts) != nil {
if port.SetReadTimeout(NoTimeout) != nil {
port.Close()
return nil, &PortError{code: InvalidSerialPort}
}
return port, nil
}