// +build linux package serial import ( "fmt" "os" "time" "unsafe" "golang.org/x/sys/unix" ) func openPort(name string, baud int, databits byte, parity Parity, stopbits StopBits, readTimeout time.Duration) (p *Port, err error) { var bauds = map[int]uint32{ 50: unix.B50, 75: unix.B75, 110: unix.B110, 134: unix.B134, 150: unix.B150, 200: unix.B200, 300: unix.B300, 600: unix.B600, 1200: unix.B1200, 1800: unix.B1800, 2400: unix.B2400, 4800: unix.B4800, 9600: unix.B9600, 19200: unix.B19200, 38400: unix.B38400, 57600: unix.B57600, 115200: unix.B115200, 230400: unix.B230400, 460800: unix.B460800, 500000: unix.B500000, 576000: unix.B576000, 921600: unix.B921600, 1000000: unix.B1000000, 1152000: unix.B1152000, 1500000: unix.B1500000, 2000000: unix.B2000000, 2500000: unix.B2500000, 3000000: unix.B3000000, 3500000: unix.B3500000, 4000000: unix.B4000000, } rate, ok := bauds[baud] if !ok { return nil, fmt.Errorf("Unrecognized baud rate") } f, err := os.OpenFile(name, unix.O_RDWR|unix.O_NOCTTY|unix.O_NONBLOCK, 0666) if err != nil { return nil, err } defer func() { if err != nil && f != nil { f.Close() } }() // Base settings cflagToUse := unix.CREAD | unix.CLOCAL | rate switch databits { case 5: cflagToUse |= unix.CS5 case 6: cflagToUse |= unix.CS6 case 7: cflagToUse |= unix.CS7 case 8: cflagToUse |= unix.CS8 default: return nil, ErrBadSize } // Stop bits settings switch stopbits { case Stop1: // default is 1 stop bit case Stop2: cflagToUse |= unix.CSTOPB default: // Don't know how to set 1.5 return nil, ErrBadStopBits } // Parity settings switch parity { case ParityNone: // default is no parity case ParityOdd: cflagToUse |= unix.PARENB cflagToUse |= unix.PARODD case ParityEven: cflagToUse |= unix.PARENB default: return nil, ErrBadParity } fd := f.Fd() vmin, vtime := posixTimeoutValues(readTimeout) t := unix.Termios{ Iflag: unix.IGNPAR, Cflag: cflagToUse, Ispeed: rate, Ospeed: rate, } t.Cc[unix.VMIN] = vmin t.Cc[unix.VTIME] = vtime if _, _, errno := unix.Syscall6( unix.SYS_IOCTL, uintptr(fd), uintptr(unix.TCSETS), uintptr(unsafe.Pointer(&t)), 0, 0, 0, ); errno != 0 { return nil, errno } if err = unix.SetNonblock(int(fd), false); err != nil { return } return &Port{f: f}, nil } type Port struct { // We intentionly do not use an "embedded" struct so that we // don't export File f *os.File } func (p *Port) Read(b []byte) (n int, err error) { return p.f.Read(b) } func (p *Port) Write(b []byte) (n int, err error) { return p.f.Write(b) } // Discards data written to the port but not transmitted, // or data received but not read func (p *Port) Flush() error { const TCFLSH = 0x540B _, _, errno := unix.Syscall( unix.SYS_IOCTL, uintptr(p.f.Fd()), uintptr(TCFLSH), uintptr(unix.TCIOFLUSH), ) if errno == 0 { return nil } return errno } func (p *Port) Close() (err error) { return p.f.Close() }