diff --git a/go.mod b/go.mod index 80dddac..c3abe90 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.17 require ( github.com/creack/goselect v0.1.2 github.com/stretchr/testify v1.7.0 - golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf + golang.org/x/sys v0.0.0-20220829200755-d48e67d00261 ) require ( diff --git a/go.sum b/go.sum index 2abf8f5..dac8e08 100644 --- a/go.sum +++ b/go.sum @@ -9,6 +9,8 @@ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5Cc github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf h1:2ucpDCmfkl8Bd/FsLtiD653Wf96cW37s+iGx93zsu4k= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220829200755-d48e67d00261 h1:v6hYoSR9T5oet+pMXwUWkbiVqx/63mlHjefrHmxwfeY= +golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= diff --git a/serial.go b/serial.go index e072d42..2bb7f3e 100644 --- a/serial.go +++ b/serial.go @@ -48,6 +48,9 @@ type Port interface { // Close the serial port Close() error + + // Break sends a break for a determined time + Break(time.Duration) error } // NoTimeout should be used as a parameter to SetReadTimeout to disable timeout. diff --git a/serial_darwin.go b/serial_darwin.go index f30dc8d..6c448a7 100644 --- a/serial_darwin.go +++ b/serial_darwin.go @@ -14,6 +14,8 @@ const regexFilter = "^(cu|tty)\\..*" const ioctlTcgetattr = unix.TIOCGETA const ioctlTcsetattr = unix.TIOCSETA const ioctlTcflsh = unix.TIOCFLUSH +const ioctlTioccbrk = unix.TIOCCBRK +const ioctlTiocsbrk = unix.TIOCSBRK func setTermSettingsBaudrate(speed int, settings *unix.Termios) (error, bool) { baudrate, ok := baudrateMap[speed] diff --git a/serial_freebsd.go b/serial_freebsd.go index ca1ef76..1ccaf33 100644 --- a/serial_freebsd.go +++ b/serial_freebsd.go @@ -56,6 +56,8 @@ const tcCRTSCTS uint32 = tcCCTS_OFLOW const ioctlTcgetattr = unix.TIOCGETA const ioctlTcsetattr = unix.TIOCSETA const ioctlTcflsh = unix.TIOCFLUSH +const ioctlTioccbrk = unix.TIOCCBRK +const ioctlTiocsbrk = unix.TIOCSBRK func toTermiosSpeedType(speed uint32) uint32 { return speed diff --git a/serial_linux.go b/serial_linux.go index 1d6edb3..116474d 100644 --- a/serial_linux.go +++ b/serial_linux.go @@ -63,6 +63,8 @@ const tcCRTSCTS uint32 = unix.CRTSCTS const ioctlTcgetattr = unix.TCGETS const ioctlTcsetattr = unix.TCSETS const ioctlTcflsh = unix.TCFLSH +const ioctlTioccbrk = unix.TIOCCBRK +const ioctlTiocsbrk = unix.TIOCSBRK func toTermiosSpeedType(speed uint32) uint32 { return speed diff --git a/serial_openbsd.go b/serial_openbsd.go index e9d71a4..bf38bba 100644 --- a/serial_openbsd.go +++ b/serial_openbsd.go @@ -56,6 +56,8 @@ const tcCRTSCTS uint32 = tcCCTS_OFLOW const ioctlTcgetattr = unix.TIOCGETA const ioctlTcsetattr = unix.TIOCSETA const ioctlTcflsh = unix.TIOCFLUSH +const ioctlTioccbrk = unix.TIOCCBRK +const ioctlTiocsbrk = unix.TIOCSBRK func toTermiosSpeedType(speed uint32) int32 { return int32(speed) diff --git a/serial_unix.go b/serial_unix.go index e171001..0e83018 100644 --- a/serial_unix.go +++ b/serial_unix.go @@ -4,6 +4,7 @@ // license that can be found in the LICENSE file. // +//go:build linux || darwin || freebsd || openbsd // +build linux darwin freebsd openbsd package serial @@ -117,6 +118,20 @@ func (port *unixPort) Write(p []byte) (n int, err error) { return } +func (port *unixPort) Break(t time.Duration) error { + if err := unix.IoctlSetInt(port.handle, ioctlTiocsbrk, 0); err != nil { + return err + } + + time.Sleep(t) + + if err := unix.IoctlSetInt(port.handle, ioctlTioccbrk, 0); err != nil { + return err + } + + return nil +} + func (port *unixPort) SetMode(mode *Mode) error { settings, err := port.getTermSettings() if err != nil { diff --git a/serial_windows.go b/serial_windows.go index 1a3db7a..e393d4e 100644 --- a/serial_windows.go +++ b/serial_windows.go @@ -381,6 +381,20 @@ func (port *windowsPort) SetReadTimeout(timeout time.Duration) error { return nil } +func (port *windowsPort) Break(d time.Duration) error { + if err := setCommBreak(port.handle); err != nil { + return &PortError{causedBy: err} + } + + time.Sleep(d) + + if err := clearCommBreak(port.handle); err != nil { + return &PortError{causedBy: err} + } + + return nil +} + func createOverlappedEvent() (*syscall.Overlapped, error) { h, err := createEvent(nil, true, false, nil) return &syscall.Overlapped{HEvent: h}, err diff --git a/syscall_windows.go b/syscall_windows.go index baa4deb..3b86776 100644 --- a/syscall_windows.go +++ b/syscall_windows.go @@ -25,3 +25,7 @@ package serial //sys getOverlappedResult(handle syscall.Handle, overlapEvent *syscall.Overlapped, n *uint32, wait bool) (err error) = GetOverlappedResult //sys purgeComm(handle syscall.Handle, flags uint32) (err error) = PurgeComm + +//sys setCommBreak(handle syscall.Handle) (err error) = SetCommBreak + +//sys clearCommBreak(handle syscall.Handle) (err error) = ClearCommBreak diff --git a/zsyscall_windows.go b/zsyscall_windows.go index 9c42379..a2411a6 100644 --- a/zsyscall_windows.go +++ b/zsyscall_windows.go @@ -19,6 +19,7 @@ const ( var ( errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING) + errERROR_EINVAL error = syscall.EINVAL ) // errnoErr returns common boxed Errno values, to prevent @@ -26,7 +27,7 @@ var ( func errnoErr(e syscall.Errno) error { switch e { case 0: - return nil + return errERROR_EINVAL case errnoERROR_IO_PENDING: return errERROR_IO_PENDING } @@ -41,15 +42,17 @@ var ( modkernel32 = windows.NewLazySystemDLL("kernel32.dll") procRegEnumValueW = modadvapi32.NewProc("RegEnumValueW") - procGetCommState = modkernel32.NewProc("GetCommState") - procSetCommState = modkernel32.NewProc("SetCommState") - procSetCommTimeouts = modkernel32.NewProc("SetCommTimeouts") + procClearCommBreak = modkernel32.NewProc("ClearCommBreak") + procCreateEventW = modkernel32.NewProc("CreateEventW") procEscapeCommFunction = modkernel32.NewProc("EscapeCommFunction") procGetCommModemStatus = modkernel32.NewProc("GetCommModemStatus") - procCreateEventW = modkernel32.NewProc("CreateEventW") - procResetEvent = modkernel32.NewProc("ResetEvent") + procGetCommState = modkernel32.NewProc("GetCommState") procGetOverlappedResult = modkernel32.NewProc("GetOverlappedResult") procPurgeComm = modkernel32.NewProc("PurgeComm") + procResetEvent = modkernel32.NewProc("ResetEvent") + procSetCommBreak = modkernel32.NewProc("SetCommBreak") + procSetCommState = modkernel32.NewProc("SetCommState") + procSetCommTimeouts = modkernel32.NewProc("SetCommTimeouts") ) func regEnumValue(key syscall.Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, class *uint16, value *uint16, valueLen *uint32) (regerrno error) { @@ -60,38 +63,27 @@ func regEnumValue(key syscall.Handle, index uint32, name *uint16, nameLen *uint3 return } -func getCommState(handle syscall.Handle, dcb *dcb) (err error) { - r1, _, e1 := syscall.Syscall(procGetCommState.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(dcb)), 0) +func clearCommBreak(handle syscall.Handle) (err error) { + r1, _, e1 := syscall.Syscall(procClearCommBreak.Addr(), 1, uintptr(handle), 0, 0) if r1 == 0 { - if e1 != 0 { - err = errnoErr(e1) - } else { - err = syscall.EINVAL - } + err = errnoErr(e1) } return } -func setCommState(handle syscall.Handle, dcb *dcb) (err error) { - r1, _, e1 := syscall.Syscall(procSetCommState.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(dcb)), 0) - if r1 == 0 { - if e1 != 0 { - err = errnoErr(e1) - } else { - err = syscall.EINVAL - } +func createEvent(eventAttributes *uint32, manualReset bool, initialState bool, name *uint16) (handle syscall.Handle, err error) { + var _p0 uint32 + if manualReset { + _p0 = 1 } - return -} - -func setCommTimeouts(handle syscall.Handle, timeouts *commTimeouts) (err error) { - r1, _, e1 := syscall.Syscall(procSetCommTimeouts.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(timeouts)), 0) - if r1 == 0 { - if e1 != 0 { - err = errnoErr(e1) - } else { - err = syscall.EINVAL - } + var _p1 uint32 + if initialState { + _p1 = 1 + } + r0, _, e1 := syscall.Syscall6(procCreateEventW.Addr(), 4, uintptr(unsafe.Pointer(eventAttributes)), uintptr(_p0), uintptr(_p1), uintptr(unsafe.Pointer(name)), 0, 0) + handle = syscall.Handle(r0) + if handle == 0 { + err = errnoErr(e1) } return } @@ -108,39 +100,10 @@ func getCommModemStatus(handle syscall.Handle, bits *uint32) (res bool) { return } -func createEvent(eventAttributes *uint32, manualReset bool, initialState bool, name *uint16) (handle syscall.Handle, err error) { - var _p0 uint32 - if manualReset { - _p0 = 1 - } else { - _p0 = 0 - } - var _p1 uint32 - if initialState { - _p1 = 1 - } else { - _p1 = 0 - } - r0, _, e1 := syscall.Syscall6(procCreateEventW.Addr(), 4, uintptr(unsafe.Pointer(eventAttributes)), uintptr(_p0), uintptr(_p1), uintptr(unsafe.Pointer(name)), 0, 0) - handle = syscall.Handle(r0) - if handle == 0 { - if e1 != 0 { - err = errnoErr(e1) - } else { - err = syscall.EINVAL - } - } - return -} - -func resetEvent(handle syscall.Handle) (err error) { - r1, _, e1 := syscall.Syscall(procResetEvent.Addr(), 1, uintptr(handle), 0, 0) +func getCommState(handle syscall.Handle, dcb *dcb) (err error) { + r1, _, e1 := syscall.Syscall(procGetCommState.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(dcb)), 0) if r1 == 0 { - if e1 != 0 { - err = errnoErr(e1) - } else { - err = syscall.EINVAL - } + err = errnoErr(e1) } return } @@ -149,16 +112,10 @@ func getOverlappedResult(handle syscall.Handle, overlapEvent *syscall.Overlapped var _p0 uint32 if wait { _p0 = 1 - } else { - _p0 = 0 } r1, _, e1 := syscall.Syscall6(procGetOverlappedResult.Addr(), 4, uintptr(handle), uintptr(unsafe.Pointer(overlapEvent)), uintptr(unsafe.Pointer(n)), uintptr(_p0), 0, 0) if r1 == 0 { - if e1 != 0 { - err = errnoErr(e1) - } else { - err = syscall.EINVAL - } + err = errnoErr(e1) } return } @@ -166,11 +123,39 @@ func getOverlappedResult(handle syscall.Handle, overlapEvent *syscall.Overlapped func purgeComm(handle syscall.Handle, flags uint32) (err error) { r1, _, e1 := syscall.Syscall(procPurgeComm.Addr(), 2, uintptr(handle), uintptr(flags), 0) if r1 == 0 { - if e1 != 0 { - err = errnoErr(e1) - } else { - err = syscall.EINVAL - } + err = errnoErr(e1) + } + return +} + +func resetEvent(handle syscall.Handle) (err error) { + r1, _, e1 := syscall.Syscall(procResetEvent.Addr(), 1, uintptr(handle), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func setCommBreak(handle syscall.Handle) (err error) { + r1, _, e1 := syscall.Syscall(procSetCommBreak.Addr(), 1, uintptr(handle), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func setCommState(handle syscall.Handle, dcb *dcb) (err error) { + r1, _, e1 := syscall.Syscall(procSetCommState.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(dcb)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func setCommTimeouts(handle syscall.Handle, timeouts *commTimeouts) (err error) { + r1, _, e1 := syscall.Syscall(procSetCommTimeouts.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(timeouts)), 0) + if r1 == 0 { + err = errnoErr(e1) } return }