package serialport import ( "fmt" "os" "golang.org/x/sys/unix" ) func Open115200(path string) (*os.File, error) { file, err := os.OpenFile(path, os.O_RDWR|unix.O_NOCTTY, 0) if err != nil { return nil, err } termios, err := unix.IoctlGetTermios(int(file.Fd()), unix.TCGETS) if err != nil { file.Close() return nil, err } 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 }