aboutsummaryrefslogblamecommitdiff
path: root/ports.go
blob: e5241d17c4a7544e06fe40a147c5275bbd8c7bc6 (plain) (tree)


































































                                                                                       
                                                                                



                                                                           











                                                                          














                                                                                      


                                                              






                                                                                     
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
}

Snix LLC Git Repository Holder Copyright(C) 2022 All Rights Reserved Email To Snix.IR