package userial import ( "math" "os" "time" "golang.org/x/sys/unix" ) type Port struct{ f *os.File } // OpenPort opens a named serial device and return a Port data type and error func (spops *Serial) OpenPort(path string) (*Port, error) { f, err := os.OpenFile(path, 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() } }() fg := uint32(spops.baud) | uint32(spops.data) | uint32(spops.stop) | spops.cbit switch spops.prty { case 1: fg |= unix.PARENB case 2: fg |= unix.PARENB fg |= unix.PARODD } t := unix.Termios{ Cflag: fg, Iflag: spops.ibit, Ispeed: uint32(spops.baud), Ospeed: uint32(spops.baud), } t.Cc[unix.VMIN], t.Cc[unix.VTIME] = timeout(spops.tout) if err := unix.IoctlSetTermios( int(f.Fd()), unix.TCSETS, &t); err != nil { return nil, err } if err := unix.SetNonblock(int(f.Fd()), false); err != nil { return nil, err } return &Port{f: f}, err } // Read implement read() method for serial port func (p *Port) Read(b []byte) (int, error) { return p.f.Read(b) } // Write implement write() method for serial port func (p *Port) Write(b []byte) (int, error) { return p.f.Write(b) } // Close implement close() method for serial port func (p *Port) Close() error { return p.f.Close() } // Flush implement flush() method for serial port // flushes both data received but not read, and data written but not transmitted func (p *Port) Flush() error { return unix.IoctlSetInt(int(p.f.Fd()), unix.TCFLSH, unix.TCIOFLUSH) } // Flush implement flush() method for serial port // flushes data received but not read func (p *Port) FlushRead() error { return unix.IoctlSetInt(int(p.f.Fd()), unix.TCFLSH, unix.TCIFLUSH) } // Flush implement flush() method for serial port // flushes data written but not transmitted func (p *Port) FlushWrite() error { return unix.IoctlSetInt(int(p.f.Fd()), unix.TCFLSH, unix.TCOFLUSH) } // SendBreak Sends Break Signal func (p *Port) SendBreak(d time.Duration) error { return unix.IoctlSetInt(int(p.f.Fd()), unix.TCSBRKP, int(d)) } // Available returns how many bytes are unused in the buffer func (p *Port) Available() (int, error) { return unix.IoctlGetInt(int(p.f.Fd()), unix.TIOCINQ) } // Buffered returns the number of bytes that have been written into the current buffer func (p *Port) Buffered() (int, error) { return unix.IoctlGetInt(int(p.f.Fd()), unix.TIOCOUTQ) } // Expose serial fd to use in some special cases, ioctl etc... func (p *Port) File() *os.File { return p.f } func timeout(d time.Duration) (byte, byte) { if d > 0x0 { t := math.Min(math.Max(float64(d.Nanoseconds()/1e6/100), 0x01), 0xff) return 0x0, byte(t) } return 0x1, 0x0 }