Merge pull request #145 from cmaglie/send_break

Added support for sending break (unix + windows)
This commit is contained in:
Cristian Maglie
2023-01-02 13:07:23 +01:00
committed by GitHub
11 changed files with 108 additions and 77 deletions

2
go.mod
View File

@@ -5,7 +5,7 @@ go 1.17
require ( require (
github.com/creack/goselect v0.1.2 github.com/creack/goselect v0.1.2
github.com/stretchr/testify v1.7.0 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 ( require (

2
go.sum
View File

@@ -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= 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 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-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 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 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= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=

View File

@@ -48,6 +48,9 @@ type Port interface {
// Close the serial port // Close the serial port
Close() error 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. // NoTimeout should be used as a parameter to SetReadTimeout to disable timeout.

View File

@@ -14,6 +14,8 @@ const regexFilter = "^(cu|tty)\\..*"
const ioctlTcgetattr = unix.TIOCGETA const ioctlTcgetattr = unix.TIOCGETA
const ioctlTcsetattr = unix.TIOCSETA const ioctlTcsetattr = unix.TIOCSETA
const ioctlTcflsh = unix.TIOCFLUSH const ioctlTcflsh = unix.TIOCFLUSH
const ioctlTioccbrk = unix.TIOCCBRK
const ioctlTiocsbrk = unix.TIOCSBRK
func setTermSettingsBaudrate(speed int, settings *unix.Termios) (error, bool) { func setTermSettingsBaudrate(speed int, settings *unix.Termios) (error, bool) {
baudrate, ok := baudrateMap[speed] baudrate, ok := baudrateMap[speed]

View File

@@ -56,6 +56,8 @@ const tcCRTSCTS uint32 = tcCCTS_OFLOW
const ioctlTcgetattr = unix.TIOCGETA const ioctlTcgetattr = unix.TIOCGETA
const ioctlTcsetattr = unix.TIOCSETA const ioctlTcsetattr = unix.TIOCSETA
const ioctlTcflsh = unix.TIOCFLUSH const ioctlTcflsh = unix.TIOCFLUSH
const ioctlTioccbrk = unix.TIOCCBRK
const ioctlTiocsbrk = unix.TIOCSBRK
func toTermiosSpeedType(speed uint32) uint32 { func toTermiosSpeedType(speed uint32) uint32 {
return speed return speed

View File

@@ -63,6 +63,8 @@ const tcCRTSCTS uint32 = unix.CRTSCTS
const ioctlTcgetattr = unix.TCGETS const ioctlTcgetattr = unix.TCGETS
const ioctlTcsetattr = unix.TCSETS const ioctlTcsetattr = unix.TCSETS
const ioctlTcflsh = unix.TCFLSH const ioctlTcflsh = unix.TCFLSH
const ioctlTioccbrk = unix.TIOCCBRK
const ioctlTiocsbrk = unix.TIOCSBRK
func toTermiosSpeedType(speed uint32) uint32 { func toTermiosSpeedType(speed uint32) uint32 {
return speed return speed

View File

@@ -56,6 +56,8 @@ const tcCRTSCTS uint32 = tcCCTS_OFLOW
const ioctlTcgetattr = unix.TIOCGETA const ioctlTcgetattr = unix.TIOCGETA
const ioctlTcsetattr = unix.TIOCSETA const ioctlTcsetattr = unix.TIOCSETA
const ioctlTcflsh = unix.TIOCFLUSH const ioctlTcflsh = unix.TIOCFLUSH
const ioctlTioccbrk = unix.TIOCCBRK
const ioctlTiocsbrk = unix.TIOCSBRK
func toTermiosSpeedType(speed uint32) int32 { func toTermiosSpeedType(speed uint32) int32 {
return int32(speed) return int32(speed)

View File

@@ -4,6 +4,7 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// //
//go:build linux || darwin || freebsd || openbsd
// +build linux darwin freebsd openbsd // +build linux darwin freebsd openbsd
package serial package serial
@@ -117,6 +118,20 @@ func (port *unixPort) Write(p []byte) (n int, err error) {
return 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 { func (port *unixPort) SetMode(mode *Mode) error {
settings, err := port.getTermSettings() settings, err := port.getTermSettings()
if err != nil { if err != nil {

View File

@@ -381,6 +381,20 @@ func (port *windowsPort) SetReadTimeout(timeout time.Duration) error {
return nil 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) { func createOverlappedEvent() (*syscall.Overlapped, error) {
h, err := createEvent(nil, true, false, nil) h, err := createEvent(nil, true, false, nil)
return &syscall.Overlapped{HEvent: h}, err return &syscall.Overlapped{HEvent: h}, err

View File

@@ -25,3 +25,7 @@ package serial
//sys getOverlappedResult(handle syscall.Handle, overlapEvent *syscall.Overlapped, n *uint32, wait bool) (err error) = GetOverlappedResult //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 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

View File

@@ -19,6 +19,7 @@ const (
var ( var (
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING) errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
errERROR_EINVAL error = syscall.EINVAL
) )
// errnoErr returns common boxed Errno values, to prevent // errnoErr returns common boxed Errno values, to prevent
@@ -26,7 +27,7 @@ var (
func errnoErr(e syscall.Errno) error { func errnoErr(e syscall.Errno) error {
switch e { switch e {
case 0: case 0:
return nil return errERROR_EINVAL
case errnoERROR_IO_PENDING: case errnoERROR_IO_PENDING:
return errERROR_IO_PENDING return errERROR_IO_PENDING
} }
@@ -41,15 +42,17 @@ var (
modkernel32 = windows.NewLazySystemDLL("kernel32.dll") modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
procRegEnumValueW = modadvapi32.NewProc("RegEnumValueW") procRegEnumValueW = modadvapi32.NewProc("RegEnumValueW")
procGetCommState = modkernel32.NewProc("GetCommState") procClearCommBreak = modkernel32.NewProc("ClearCommBreak")
procSetCommState = modkernel32.NewProc("SetCommState") procCreateEventW = modkernel32.NewProc("CreateEventW")
procSetCommTimeouts = modkernel32.NewProc("SetCommTimeouts")
procEscapeCommFunction = modkernel32.NewProc("EscapeCommFunction") procEscapeCommFunction = modkernel32.NewProc("EscapeCommFunction")
procGetCommModemStatus = modkernel32.NewProc("GetCommModemStatus") procGetCommModemStatus = modkernel32.NewProc("GetCommModemStatus")
procCreateEventW = modkernel32.NewProc("CreateEventW") procGetCommState = modkernel32.NewProc("GetCommState")
procResetEvent = modkernel32.NewProc("ResetEvent")
procGetOverlappedResult = modkernel32.NewProc("GetOverlappedResult") procGetOverlappedResult = modkernel32.NewProc("GetOverlappedResult")
procPurgeComm = modkernel32.NewProc("PurgeComm") 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) { 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 return
} }
func getCommState(handle syscall.Handle, dcb *dcb) (err error) { func clearCommBreak(handle syscall.Handle) (err error) {
r1, _, e1 := syscall.Syscall(procGetCommState.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(dcb)), 0) r1, _, e1 := syscall.Syscall(procClearCommBreak.Addr(), 1, uintptr(handle), 0, 0)
if r1 == 0 { if r1 == 0 {
if e1 != 0 { err = errnoErr(e1)
err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
} }
return return
} }
func setCommState(handle syscall.Handle, dcb *dcb) (err error) { func createEvent(eventAttributes *uint32, manualReset bool, initialState bool, name *uint16) (handle syscall.Handle, err error) {
r1, _, e1 := syscall.Syscall(procSetCommState.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(dcb)), 0) var _p0 uint32
if r1 == 0 { if manualReset {
if e1 != 0 { _p0 = 1
err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
} }
return var _p1 uint32
} if initialState {
_p1 = 1
func setCommTimeouts(handle syscall.Handle, timeouts *commTimeouts) (err error) { }
r1, _, e1 := syscall.Syscall(procSetCommTimeouts.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(timeouts)), 0) r0, _, e1 := syscall.Syscall6(procCreateEventW.Addr(), 4, uintptr(unsafe.Pointer(eventAttributes)), uintptr(_p0), uintptr(_p1), uintptr(unsafe.Pointer(name)), 0, 0)
if r1 == 0 { handle = syscall.Handle(r0)
if e1 != 0 { if handle == 0 {
err = errnoErr(e1) err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
} }
return return
} }
@@ -108,39 +100,10 @@ func getCommModemStatus(handle syscall.Handle, bits *uint32) (res bool) {
return return
} }
func createEvent(eventAttributes *uint32, manualReset bool, initialState bool, name *uint16) (handle syscall.Handle, err error) { func getCommState(handle syscall.Handle, dcb *dcb) (err error) {
var _p0 uint32 r1, _, e1 := syscall.Syscall(procGetCommState.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(dcb)), 0)
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)
if r1 == 0 { if r1 == 0 {
if e1 != 0 { err = errnoErr(e1)
err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
} }
return return
} }
@@ -149,16 +112,10 @@ func getOverlappedResult(handle syscall.Handle, overlapEvent *syscall.Overlapped
var _p0 uint32 var _p0 uint32
if wait { if wait {
_p0 = 1 _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) 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 r1 == 0 {
if e1 != 0 { err = errnoErr(e1)
err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
} }
return return
} }
@@ -166,11 +123,39 @@ func getOverlappedResult(handle syscall.Handle, overlapEvent *syscall.Overlapped
func purgeComm(handle syscall.Handle, flags uint32) (err error) { func purgeComm(handle syscall.Handle, flags uint32) (err error) {
r1, _, e1 := syscall.Syscall(procPurgeComm.Addr(), 2, uintptr(handle), uintptr(flags), 0) r1, _, e1 := syscall.Syscall(procPurgeComm.Addr(), 2, uintptr(handle), uintptr(flags), 0)
if r1 == 0 { if r1 == 0 {
if e1 != 0 { err = errnoErr(e1)
err = errnoErr(e1) }
} else { return
err = syscall.EINVAL }
}
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 return
} }