aboutsummaryrefslogtreecommitdiff
path: root/ports.go
blob: e5241d17c4a7544e06fe40a147c5275bbd8c7bc6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
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