Fix Linux UART baud selection on cold boot #11
@@ -19,19 +19,45 @@ func Open115200(path string) (*os.File, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
termios.Iflag = 0
|
||||
termios.Oflag = 0
|
||||
termios.Lflag = 0
|
||||
termios.Cflag &^= unix.CSIZE | unix.PARENB | unix.CSTOPB | unix.CRTSCTS
|
||||
termios.Cflag |= unix.CS8 | unix.CREAD | unix.CLOCAL
|
||||
termios.Ispeed = unix.B115200
|
||||
termios.Ospeed = unix.B115200
|
||||
termios.Cc[unix.VMIN] = 1
|
||||
termios.Cc[unix.VTIME] = 0
|
||||
configureRaw115200(termios)
|
||||
|
||||
if err := unix.IoctlSetTermios(int(file.Fd()), unix.TCSETS, termios); err != nil {
|
||||
file.Close()
|
||||
return nil, fmt.Errorf("configure %s: %w", path, err)
|
||||
}
|
||||
|
||||
effective, err := unix.IoctlGetTermios(int(file.Fd()), unix.TCGETS)
|
||||
if err != nil {
|
||||
file.Close()
|
||||
return nil, fmt.Errorf("read back %s: %w", path, err)
|
||||
}
|
||||
if err := verifyBaud(*effective, unix.B115200); err != nil {
|
||||
file.Close()
|
||||
return nil, fmt.Errorf("verify %s: %w", path, err)
|
||||
}
|
||||
return file, nil
|
||||
}
|
||||
|
||||
// configureRaw115200 keeps the raw 115200 8N1 blocking-read configuration.
|
||||
// On Linux TCSETS takes the line speed from the CBAUD bits in Cflag, so
|
||||
// CBAUD must be cleared and B115200 selected there; Ispeed/Ospeed alone
|
||||
// leave an inherited baud (for example 9600 from boot defaults) in effect.
|
||||
func configureRaw115200(termios *unix.Termios) {
|
||||
termios.Iflag = 0
|
||||
termios.Oflag = 0
|
||||
termios.Lflag = 0
|
||||
termios.Cflag &^= unix.CSIZE | unix.PARENB | unix.CSTOPB | unix.CRTSCTS | unix.CBAUD
|
||||
termios.Cflag |= unix.B115200
|
||||
termios.Cflag |= unix.CS8 | unix.CREAD | unix.CLOCAL
|
||||
termios.Ispeed = unix.B115200
|
||||
termios.Ospeed = unix.B115200
|
||||
termios.Cc[unix.VMIN] = 1
|
||||
termios.Cc[unix.VTIME] = 0
|
||||
}
|
||||
|
||||
func verifyBaud(termios unix.Termios, baud uint32) error {
|
||||
if got := termios.Cflag & unix.CBAUD; got != baud {
|
||||
return fmt.Errorf("effective baud bits %#o, want %#o", got, baud)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
package serialport
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func TestConfigureRaw115200OverridesInheritedBaud(t *testing.T) {
|
||||
var termios unix.Termios
|
||||
termios.Iflag = unix.IGNBRK | unix.ICRNL
|
||||
termios.Oflag = unix.OPOST
|
||||
termios.Lflag = unix.ICANON | unix.ECHO
|
||||
termios.Cflag = unix.B9600 | unix.CS8 | unix.CREAD | unix.CLOCAL | unix.HUPCL
|
||||
termios.Ispeed = unix.B9600
|
||||
termios.Ospeed = unix.B9600
|
||||
|
||||
configureRaw115200(&termios)
|
||||
|
||||
if got := termios.Cflag & unix.CBAUD; got != unix.B115200 {
|
||||
t.Fatalf("effective baud bits=%#o want %#o", got, unix.B115200)
|
||||
}
|
||||
if got := termios.Cflag & unix.CSIZE; got != unix.CS8 {
|
||||
t.Fatalf("character size bits=%#o want %#o", got, unix.CS8)
|
||||
}
|
||||
for _, flag := range []uint32{unix.CREAD, unix.CLOCAL} {
|
||||
if termios.Cflag&flag == 0 {
|
||||
t.Fatalf("flag %#o lost", flag)
|
||||
}
|
||||
}
|
||||
for _, flag := range []uint32{unix.PARENB, unix.CSTOPB, unix.CRTSCTS} {
|
||||
if termios.Cflag&flag != 0 {
|
||||
t.Fatalf("flag %#o must be cleared", flag)
|
||||
}
|
||||
}
|
||||
if termios.Iflag != 0 || termios.Oflag != 0 || termios.Lflag != 0 {
|
||||
t.Fatal("raw mode must clear Iflag, Oflag and Lflag")
|
||||
}
|
||||
if termios.Ispeed != unix.B115200 || termios.Ospeed != unix.B115200 {
|
||||
t.Fatalf("speed fields=%d/%d want 115200/115200", termios.Ispeed, termios.Ospeed)
|
||||
}
|
||||
if termios.Cc[unix.VMIN] != 1 || termios.Cc[unix.VTIME] != 0 {
|
||||
t.Fatalf("VMIN=%d VTIME=%d want 1/0", termios.Cc[unix.VMIN], termios.Cc[unix.VTIME])
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerifyBaudAcceptsOnlyConfiguredLineSpeed(t *testing.T) {
|
||||
var inherited unix.Termios
|
||||
inherited.Cflag = unix.B9600 | unix.CS8
|
||||
if err := verifyBaud(inherited, unix.B115200); err == nil {
|
||||
t.Fatal("inherited 9600 line speed must fail verification")
|
||||
}
|
||||
|
||||
var configured unix.Termios
|
||||
configured.Cflag = unix.B115200 | unix.CS8 | unix.CREAD
|
||||
if err := verifyBaud(configured, unix.B115200); err != nil {
|
||||
t.Fatalf("115200 line speed must verify: %v", err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user