From ff38fe2a780f46777bf5ed91729ec99d01e88918 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Polomsk=C3=BD?= Date: Sat, 9 May 2020 08:34:28 +0200 Subject: [PATCH 1/3] add support for drain Tested on Mac OS, Linux and Windows with UART emulated on USB. I wrote general BSD code, because it should work, but I am not able to test it. On Mac OS I am quite sure that drain behaves as expected because it fixed an issue with buffer overflow (which OS does not report but fails). For Windows it seems that drain is actually part of `Write`, because `Write` was long and `Drain` was fast. But I have not found any mention in Win32 docs about buffering and asynchronous write, so I put there flushing code to be sure, and this code did not break anything. For Linux `Drain` is also taking more time than writing so it looks working too. --- serial.go | 3 +++ serial_bsd.go | 10 ++++++++++ serial_linux.go | 10 ++++++++++ serial_windows.go | 4 ++++ 4 files changed, 27 insertions(+) create mode 100644 serial_bsd.go diff --git a/serial.go b/serial.go index 2bb7f3e..4420100 100644 --- a/serial.go +++ b/serial.go @@ -26,6 +26,9 @@ type Port interface { // Returns the number of bytes written. Write(p []byte) (n int, err error) + // Wait until all data in the buffer are sent + Drain() error + // ResetInputBuffer Purges port read buffer ResetInputBuffer() error diff --git a/serial_bsd.go b/serial_bsd.go new file mode 100644 index 0000000..4db5b3d --- /dev/null +++ b/serial_bsd.go @@ -0,0 +1,10 @@ +//go:build darwin || dragonfly || freebsd || netbsd || openbsd +// +build darwin dragonfly freebsd netbsd openbsd + +package serial + +import "golang.org/x/sys/unix" + +func (port *unixPort) Drain() error { + return unix.IoctlSetInt(port.handle, unix.TIOCDRAIN, 0) +} diff --git a/serial_linux.go b/serial_linux.go index 116474d..0ac0f39 100644 --- a/serial_linux.go +++ b/serial_linux.go @@ -85,3 +85,13 @@ func setTermSettingsBaudrate(speed int, settings *unix.Termios) (error, bool) { settings.Ospeed = toTermiosSpeedType(baudrate) return nil, false } + +func (port *unixPort) Drain() error { + // simulate drain with change settings with TCSETSW + settings, err := port.getTermSettings() + if err != nil { + return err + } + + return unix.IoctlSetTermios(port.handle, unix.TCSETSW, settings) +} diff --git a/serial_windows.go b/serial_windows.go index e393d4e..5c4a576 100644 --- a/serial_windows.go +++ b/serial_windows.go @@ -119,6 +119,10 @@ func (port *windowsPort) Write(p []byte) (int, error) { return int(writed), err } +func (port *windowsPort) Drain() (err error) { + return syscall.FlushFileBuffers(port.handle) +} + const ( purgeRxAbort uint32 = 0x0002 purgeRxClear = 0x0008 From bafe3137499d5f80f2948a7d900378194bf90a2a Mon Sep 17 00:00:00 2001 From: Andre Renaud Date: Fri, 24 Mar 2023 16:09:44 +1300 Subject: [PATCH 2/3] Rework for Linux & BSD differences --- serial_bsd.go | 1 - serial_linux.go | 8 +------- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/serial_bsd.go b/serial_bsd.go index 4db5b3d..4e1f226 100644 --- a/serial_bsd.go +++ b/serial_bsd.go @@ -1,5 +1,4 @@ //go:build darwin || dragonfly || freebsd || netbsd || openbsd -// +build darwin dragonfly freebsd netbsd openbsd package serial diff --git a/serial_linux.go b/serial_linux.go index 0ac0f39..c8a7651 100644 --- a/serial_linux.go +++ b/serial_linux.go @@ -87,11 +87,5 @@ func setTermSettingsBaudrate(speed int, settings *unix.Termios) (error, bool) { } func (port *unixPort) Drain() error { - // simulate drain with change settings with TCSETSW - settings, err := port.getTermSettings() - if err != nil { - return err - } - - return unix.IoctlSetTermios(port.handle, unix.TCSETSW, settings) + return unix.IoctlSetInt(port.handle, unix.TCSBRK, 1) } From cce21700ebb37329e433df2a9c056d0bc512d0af Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Wed, 9 Aug 2023 18:29:02 +0200 Subject: [PATCH 3/3] Added informative comment --- serial_linux.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/serial_linux.go b/serial_linux.go index c8a7651..adc1149 100644 --- a/serial_linux.go +++ b/serial_linux.go @@ -87,5 +87,8 @@ func setTermSettingsBaudrate(speed int, settings *unix.Termios) (error, bool) { } func (port *unixPort) Drain() error { + // It's not super well documented, but this is the same as calling tcdrain: + // - https://git.musl-libc.org/cgit/musl/tree/src/termios/tcdrain.c + // - https://elixir.bootlin.com/linux/v6.2.8/source/drivers/tty/tty_io.c#L2673 return unix.IoctlSetInt(port.handle, unix.TCSBRK, 1) }