fix serial
This commit is contained in:
165
internal/util/serial/serial_linux.go
Normal file
165
internal/util/serial/serial_linux.go
Normal file
@ -0,0 +1,165 @@
|
||||
//go:build linux
|
||||
// +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()
|
||||
}
|
Reference in New Issue
Block a user