fix: 修复串口 read timeout 未生效的问题
Some checks failed
test / native-os-build (macOS-latest) (push) Has been cancelled
test / native-os-build (ubuntu-latest) (push) Has been cancelled
test / native-os-build (windows-latest) (push) Has been cancelled
test / cross-os-build (freebsd amd64) (push) Has been cancelled
test / cross-os-build (linux ppc64le) (push) Has been cancelled
test / cross-os-build (openbsd 386) (push) Has been cancelled
test / cross-os-build (openbsd amd64) (push) Has been cancelled
test / cross-os-build (openbsd arm) (push) Has been cancelled
Some checks failed
test / native-os-build (macOS-latest) (push) Has been cancelled
test / native-os-build (ubuntu-latest) (push) Has been cancelled
test / native-os-build (windows-latest) (push) Has been cancelled
test / cross-os-build (freebsd amd64) (push) Has been cancelled
test / cross-os-build (linux ppc64le) (push) Has been cancelled
test / cross-os-build (openbsd 386) (push) Has been cancelled
test / cross-os-build (openbsd amd64) (push) Has been cancelled
test / cross-os-build (openbsd arm) (push) Has been cancelled
- 将串口文件描述符设置为非阻塞模式,确保 read() 不会阻塞 - 修改 VMIN 从 1 改为 0,让 select() 正确控制读取超时 - 添加 Timeout 错误代码,超时时正确返回错误而不是 (0, nil) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -163,6 +163,8 @@ const (
|
|||||||
ErrorEnumeratingPorts
|
ErrorEnumeratingPorts
|
||||||
// PortClosed the port has been closed while the operation is in progress
|
// PortClosed the port has been closed while the operation is in progress
|
||||||
PortClosed
|
PortClosed
|
||||||
|
// Timeout the read operation timed out
|
||||||
|
Timeout
|
||||||
// FunctionNotImplemented the requested function is not implemented
|
// FunctionNotImplemented the requested function is not implemented
|
||||||
FunctionNotImplemented
|
FunctionNotImplemented
|
||||||
)
|
)
|
||||||
@@ -192,6 +194,8 @@ func (e PortError) EncodedErrorString() string {
|
|||||||
return "Could not enumerate serial ports"
|
return "Could not enumerate serial ports"
|
||||||
case PortClosed:
|
case PortClosed:
|
||||||
return "Port has been closed"
|
return "Port has been closed"
|
||||||
|
case Timeout:
|
||||||
|
return "Read timeout"
|
||||||
case FunctionNotImplemented:
|
case FunctionNotImplemented:
|
||||||
return "Function not implemented"
|
return "Function not implemented"
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -119,7 +119,8 @@ func (port *unixPort) Read(p []byte) (int, error) {
|
|||||||
if port.readTimeout == NoTimeout {
|
if port.readTimeout == NoTimeout {
|
||||||
continue // 无超时设置,继续等待
|
continue // 无超时设置,继续等待
|
||||||
}
|
}
|
||||||
return 0, nil // 返回0字节表示超时
|
// 超时应返回 Timeout 错误,而不是 (0, nil)
|
||||||
|
return 0, &PortError{code: Timeout, causedBy: unix.ETIMEDOUT}
|
||||||
}
|
}
|
||||||
|
|
||||||
n, err := unix.Read(port.handle, p)
|
n, err := unix.Read(port.handle, p)
|
||||||
@@ -352,7 +353,9 @@ func nativeOpen(portName string, mode *Mode) (*unixPort, error) {
|
|||||||
return nil, &PortError{code: InvalidSerialPort, causedBy: fmt.Errorf("error configuring port: %w", err)}
|
return nil, &PortError{code: InvalidSerialPort, causedBy: fmt.Errorf("error configuring port: %w", err)}
|
||||||
}
|
}
|
||||||
|
|
||||||
unix.SetNonblock(h, false)
|
// Set non-blocking mode to ensure read() doesn't block after select() returns
|
||||||
|
// The select() call provides the timeout mechanism, not the read() call
|
||||||
|
unix.SetNonblock(h, true)
|
||||||
|
|
||||||
port.acquireExclusiveAccess()
|
port.acquireExclusiveAccess()
|
||||||
|
|
||||||
@@ -513,7 +516,14 @@ func setRawMode(settings *unix.Termios) {
|
|||||||
settings.Oflag &^= unix.OPOST
|
settings.Oflag &^= unix.OPOST
|
||||||
|
|
||||||
// Block reads until at least one char is available (no timeout)
|
// Block reads until at least one char is available (no timeout)
|
||||||
settings.Cc[unix.VMIN] = 1
|
// VMIN=1: Block until at least 1 byte is available
|
||||||
|
// VTIME=0: No inter-character timeout (not used with VMIN=1)
|
||||||
|
//
|
||||||
|
// NOTE: When readTimeout is set, the select() system call provides the timeout
|
||||||
|
// and VMIN/VTIME settings are not used for timeout purposes.
|
||||||
|
// However, VMIN=1 can cause issues with select() on some platforms/
|
||||||
|
// terminal drivers. Using VMIN=0 allows select() to work reliably.
|
||||||
|
settings.Cc[unix.VMIN] = 0
|
||||||
settings.Cc[unix.VTIME] = 0
|
settings.Cc[unix.VTIME] = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user