From 433065e7a8984c09c082c997be950d67a9f9aa93 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 9 May 2022 20:25:01 +0000 Subject: userial snix repository --- example/main.go | 51 +++++++++++++++++++++++++++++++ go.mod | 5 ++++ go.sum | 2 ++ header.go | 71 +++++++++++++++++++++++++++++++++++++++++++ ports.go | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ serial.go | 66 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 288 insertions(+) create mode 100644 example/main.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 header.go create mode 100644 ports.go create mode 100644 serial.go diff --git a/example/main.go b/example/main.go new file mode 100644 index 0000000..76b8079 --- /dev/null +++ b/example/main.go @@ -0,0 +1,51 @@ +package main + +import ( + "io" + "log" + "os" + + "snix.ir/userial" +) + +// we need something to read, so we gonna mess with terminal.. +const cisco_router_cmd = ` +enable +show ip int br + +conf t + +int gig0/0 +ip addr 192.168.122.200 255.255.255.0 +no shut + +do show ip int br + +` + +func main() { + + // default conf + p, err := serial.NewSerial().OpenPort("/dev/ttyACM0") + + // serial port with custom config + // + // p_dev := "/dev/ttyACM0" + // s := serial.NewSerial().SetBuadRate(serial.B0019200) + // p, err = s.SetParity(serial.ParityEvn).OpenPort(p_dev) + + if err != nil { + log.Fatal(err) + } + + defer p.Close() + + if _, err := p.Write([]byte(cisco_router_cmd)); err != nil { + panic(err) + } + + if _, err := io.Copy(os.Stdout, p); err != nil { + panic(err) + } + +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..2259256 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module snix.ir/userial + +go 1.18 + +require golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..67ddd69 --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 h1:nonptSpoQ4vQjyraW20DXPAglgQfVnM9ZC6MmNLMR60= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/header.go b/header.go new file mode 100644 index 0000000..9af74ac --- /dev/null +++ b/header.go @@ -0,0 +1,71 @@ +package userial + +import ( + "golang.org/x/sys/unix" +) + +type ( + baudrates rune + paritybit byte + databitcs byte + stopbitcs byte + hwcontrol byte +) + +const ( + Hardware hwcontrol = iota + Softeare + None +) + +const ( + B0000050 baudrates = 0x01 + iota + B0000075 + B0000110 + B0000134 + B0000150 + B0000200 + B0000300 + B0000600 + B0001200 + B0001800 + B0002400 + B0004800 + B0009600 + B0019200 + B0038400 + + B0057600 baudrates = 0xFF2 + iota + B0115200 + B0230400 + B0460800 + B0500000 + B0576000 + B0921600 + B1000000 + B1152000 + B1500000 + B2000000 + B2500000 + B3000000 + B3500000 + B4000000 +) + +const ( + ParityNon paritybit = iota + ParityEvn + ParityOdd +) + +const ( + StopBitA stopbitcs = 0x00 // stop bit 1 + StopBitB stopbitcs = unix.CSTOPB // stop bit 2 +) + +const ( + CS5 databitcs = unix.CS5 // databit 5 + CS6 databitcs = unix.CS6 // databit 6 + CS7 databitcs = unix.CS7 // databit 7 + CS8 databitcs = unix.CS8 // databit 8 (default) +) diff --git a/ports.go b/ports.go new file mode 100644 index 0000000..2742e60 --- /dev/null +++ b/ports.go @@ -0,0 +1,93 @@ +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 +func (p *Port) Flush() error { + return unix.IoctlSetInt(int(p.f.Fd()), unix.TCFLSH, unix.TCIOFLUSH) +} + +// 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) +} + +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 +} diff --git a/serial.go b/serial.go new file mode 100644 index 0000000..e3cd3cb --- /dev/null +++ b/serial.go @@ -0,0 +1,66 @@ +package userial + +import ( + "time" + + "golang.org/x/sys/unix" +) + +type Serial struct { + baud baudrates + data databitcs + prty paritybit + stop stopbitcs + cbit uint32 + ibit uint32 + tout time.Duration +} + +// NewSerial return a Serial data type with default settings +func NewSerial() *Serial { + return &Serial{ + baud: B0009600, data: CS8, prty: ParityNon, stop: StopBitA, + cbit: unix.CREAD | unix.CLOCAL, ibit: unix.IGNPAR, + } +} + +func (p *Serial) GetBuadRate() baudrates { return p.baud } +func (p *Serial) GetDataBit() databitcs { return p.data } +func (p *Serial) GetParity() paritybit { return p.prty } +func (p *Serial) GetStopBit() stopbitcs { return p.stop } +func (p *Serial) GetTimeout() time.Duration { return p.tout } + +func (p *Serial) SetBuadRate(v baudrates) *Serial { p.baud = v; return p } +func (p *Serial) SetDataBit(v databitcs) *Serial { p.data = v; return p } +func (p *Serial) SetParity(v paritybit) *Serial { p.prty = v; return p } +func (p *Serial) SetStopBit(v stopbitcs) *Serial { p.stop = v; return p } +func (p *Serial) SetTimeout(d time.Duration) *Serial { p.tout = d; return p } + +func (p *Serial) SetFlowControl(val hwcontrol) *Serial { + switch val { + case Hardware: + p.ibit &^= unix.IXON | unix.IXOFF | unix.IXANY + p.cbit |= unix.CRTSCTS + case Softeare: + p.ibit |= unix.IXON | unix.IXOFF | unix.IXANY + p.cbit &^= unix.CRTSCTS + case None: + p.ibit &^= unix.IXON | unix.IXOFF | unix.IXANY + p.cbit &^= unix.CRTSCTS + } + return p +} + +func (p *Serial) GetFlowControl() hwcontrol { + + if p.cbit&unix.CRTSCTS == unix.CRTSCTS { + return Hardware + } + + if p.ibit&(unix.IXON|unix.IXOFF| + unix.IXANY) == (unix.IXON | unix.IXOFF | unix.IXANY) { + return Softeare + } + + return None +} -- cgit v1.2.3