From 869acb1c2d5585bc57e598c3e6392a3f5dad6c15 Mon Sep 17 00:00:00 2001 From: Wilhelm Wijkander Date: Tue, 3 Jan 2023 21:07:19 +0100 Subject: [PATCH] Add break support by JulianJacobi from https://github.com/tarm/serial/pull/110 --- serial.go | 4 ---- serial_linux.go | 21 +++++++++++++++++++++ serial_posix.go | 12 ++++++++++++ serial_windows.go | 29 +++++++++++++++++++++++++++++ 4 files changed, 62 insertions(+), 4 deletions(-) diff --git a/serial.go b/serial.go index f61ea28..85326bc 100644 --- a/serial.go +++ b/serial.go @@ -161,7 +161,3 @@ func posixTimeoutValues(readTimeout time.Duration) (vmin uint8, vtime uint8) { } return minBytesToRead, uint8(readTimeoutInDeci) } - -// func SendBreak() - -// func RegisterBreakHandler(func()) diff --git a/serial_linux.go b/serial_linux.go index 65420f3..ceefcd6 100644 --- a/serial_linux.go +++ b/serial_linux.go @@ -159,6 +159,27 @@ func (p *Port) Flush() error { return errno } +// SendBreak sends a break (bus low value) for a given duration. +// In POSIX and linux implementations there are two cases for the duration value: +// +// if duration is zero there a break with at least 0.25 seconds +// but not more than 0.5 seconds will be send. If duration is not zero, +// than it's implementaion specific, which unit is used for duration. +// For more information tae a look at tcsendbreak(3) and ioctl_tty(2) +func (p *Port) SendBreak(d time.Duration) error { + _, _, errno := unix.Syscall( + unix.SYS_IOCTL, + uintptr(p.f.Fd()), + uintptr(unix.TCSBRK), + uintptr(d.Milliseconds()), + ) + + if errno == 0 { + return nil + } + return errno +} + func (p *Port) Close() (err error) { return p.f.Close() } diff --git a/serial_posix.go b/serial_posix.go index d733f0f..0b95159 100644 --- a/serial_posix.go +++ b/serial_posix.go @@ -192,6 +192,18 @@ func (p *Port) Flush() error { return err } +// SendBreak sends a break (bus low value) for a given duration. +// In POSIX and linux implementations there are two cases for the duration value: +// +// if duration is zero there a break with at least 0.25 seconds +// but not more than 0.5 seconds will be send. If duration is not zero, +// than it's implementaion specific, which unit is used for duration. +// For more information tae a look at tcsendbreak(3) and ioctl_tty(2) +func (p *Port) SendBreak(d time.Duration) error { + _, err := C.tcsendbreak(C.int(p.f.Fd()), C.int(d.Milliseconds())) + return err +} + func (p *Port) Close() (err error) { return p.f.Close() } diff --git a/serial_windows.go b/serial_windows.go index 2a9c004..ece531b 100644 --- a/serial_windows.go +++ b/serial_windows.go @@ -133,6 +133,18 @@ func (p *Port) Flush() error { return purgeComm(p.fd) } +// SendBreak sends a break (bus low value) for a given duration. +// In POSIX and linux implementations the default behavior on zero duration +// is to send at least 0.25 seconds and not more than 0.5 seconds. +// To be compatible to linux and unix behavior we use 0.25 seconds +// as duration if a duration of zero is given. +func (p *Port) SendBreak(d time.Duration) error { + if d.Milliseconds() == 0 { + d = 250 * time.Millisecond + } + return sendCommBread(p.fd, d) +} + var ( nSetCommState, nSetCommTimeouts, @@ -142,6 +154,8 @@ var ( nCreateEvent, nResetEvent, nPurgeComm, + nSetCommBreak, + nClearCommBreak, nFlushFileBuffers uintptr ) @@ -160,6 +174,8 @@ func init() { nCreateEvent = getProcAddr(k32, "CreateEventW") nResetEvent = getProcAddr(k32, "ResetEvent") nPurgeComm = getProcAddr(k32, "PurgeComm") + nSetCommBreak = getProcAddr(k32, "SetCommBreak") + nClearCommBreak = getProcAddr(k32, "ClearCommBreak") nFlushFileBuffers = getProcAddr(k32, "FlushFileBuffers") } @@ -303,6 +319,19 @@ func purgeComm(h syscall.Handle) error { return nil } +func sendCommBreak(h syscall.Hande, d time.duration) error { + r, _, err := syscall.Syscall(nSetCommBreak, 1, uintptr(h), 0, 0) + if r == 0 { + return err + } + time.Sleep(d) + r, _, err = syscall.Syscall(nClearCommBreak, 1, uintptr(h), 0, 0) + if r == 0 { + return err + } + return nil +} + func newOverlapped() (*syscall.Overlapped, error) { var overlapped syscall.Overlapped r, _, err := syscall.Syscall6(nCreateEvent, 4, 0, 1, 0, 0, 0, 0)