From a3909960d32f490b79b8e23631aeb55c4896d483 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Sat, 22 Oct 2016 15:39:46 +0200 Subject: [PATCH 1/4] Removed termiosMask(..) and use the correct bitmask type This requires a bit of copying in darwin 386/amd64 but simplifies the overall design. --- serial_darwin.go | 42 ------------------- serial_darwin_386.go | 42 ++++++++++++++++++- serial_darwin_amd64.go | 40 +++++++++++++++++- serial_freebsd.go | 20 ++++----- serial_linux.go | 14 ++----- serial_unix.go | 92 +++++++++++++++++++++++++++--------------- 6 files changed, 149 insertions(+), 101 deletions(-) diff --git a/serial_darwin.go b/serial_darwin.go index e30c1a4..393236d 100644 --- a/serial_darwin.go +++ b/serial_darwin.go @@ -11,48 +11,6 @@ import "syscall" const devFolder = "/dev" const regexFilter = "^(cu|tty)\\..*" -// termios manipulation functions - -var baudrateMap = map[int]uint{ - 0: syscall.B9600, // Default to 9600 - 50: syscall.B50, - 75: syscall.B75, - 110: syscall.B110, - 134: syscall.B134, - 150: syscall.B150, - 200: syscall.B200, - 300: syscall.B300, - 600: syscall.B600, - 1200: syscall.B1200, - 1800: syscall.B1800, - 2400: syscall.B2400, - 4800: syscall.B4800, - 9600: syscall.B9600, - 19200: syscall.B19200, - 38400: syscall.B38400, - 57600: syscall.B57600, - 115200: syscall.B115200, - 230400: syscall.B230400, -} - -var databitsMap = map[int]uint{ - 0: syscall.CS8, // Default to 8 bits - 5: syscall.CS5, - 6: syscall.CS6, - 7: syscall.CS7, - 8: syscall.CS8, -} - -const tcCMSPAR uint = 0 // may be CMSPAR or PAREXT -const tcIUCLC uint = 0 - -const tcCCTS_OFLOW uint = 0x00010000 -const tcCRTS_IFLOW uint = 0x00020000 - -const tcCRTSCTS uint = (tcCCTS_OFLOW | tcCRTS_IFLOW) - -// syscall wrappers - //sys ioctl(fd int, req uint64, data uintptr) (err error) const ioctlTcgetattr = syscall.TIOCGETA diff --git a/serial_darwin_386.go b/serial_darwin_386.go index 43f0375..a1a6771 100644 --- a/serial_darwin_386.go +++ b/serial_darwin_386.go @@ -6,6 +6,44 @@ package serial // import "go.bug.st/serial.v1" -func termiosMask(data uint) uint32 { - return uint32(data) +import "syscall" + +// termios manipulation functions + +var baudrateMap = map[int]uint32{ + 0: syscall.B9600, // Default to 9600 + 50: syscall.B50, + 75: syscall.B75, + 110: syscall.B110, + 134: syscall.B134, + 150: syscall.B150, + 200: syscall.B200, + 300: syscall.B300, + 600: syscall.B600, + 1200: syscall.B1200, + 1800: syscall.B1800, + 2400: syscall.B2400, + 4800: syscall.B4800, + 9600: syscall.B9600, + 19200: syscall.B19200, + 38400: syscall.B38400, + 57600: syscall.B57600, + 115200: syscall.B115200, + 230400: syscall.B230400, } + +var databitsMap = map[int]uint32{ + 0: syscall.CS8, // Default to 8 bits + 5: syscall.CS5, + 6: syscall.CS6, + 7: syscall.CS7, + 8: syscall.CS8, +} + +const tcCMSPAR uint32 = 0 // may be CMSPAR or PAREXT +const tcIUCLC uint32 = 0 + +const tcCCTS_OFLOW uint32 = 0x00010000 +const tcCRTS_IFLOW uint32 = 0x00020000 + +const tcCRTSCTS uint32 = (tcCCTS_OFLOW | tcCRTS_IFLOW) diff --git a/serial_darwin_amd64.go b/serial_darwin_amd64.go index 0e70ce5..b721d78 100644 --- a/serial_darwin_amd64.go +++ b/serial_darwin_amd64.go @@ -6,8 +6,44 @@ package serial // import "go.bug.st/serial.v1" +import "syscall" + // termios manipulation functions -func termiosMask(data uint) uint64 { - return uint64(data) +var baudrateMap = map[int]uint64{ + 0: syscall.B9600, // Default to 9600 + 50: syscall.B50, + 75: syscall.B75, + 110: syscall.B110, + 134: syscall.B134, + 150: syscall.B150, + 200: syscall.B200, + 300: syscall.B300, + 600: syscall.B600, + 1200: syscall.B1200, + 1800: syscall.B1800, + 2400: syscall.B2400, + 4800: syscall.B4800, + 9600: syscall.B9600, + 19200: syscall.B19200, + 38400: syscall.B38400, + 57600: syscall.B57600, + 115200: syscall.B115200, + 230400: syscall.B230400, } + +var databitsMap = map[int]uint64{ + 0: syscall.CS8, // Default to 8 bits + 5: syscall.CS5, + 6: syscall.CS6, + 7: syscall.CS7, + 8: syscall.CS8, +} + +const tcCMSPAR uint64 = 0 // may be CMSPAR or PAREXT +const tcIUCLC uint64 = 0 + +const tcCCTS_OFLOW uint64 = 0x00010000 +const tcCRTS_IFLOW uint64 = 0x00020000 + +const tcCRTSCTS uint64 = (tcCCTS_OFLOW | tcCRTS_IFLOW) diff --git a/serial_freebsd.go b/serial_freebsd.go index 046c489..1e09349 100644 --- a/serial_freebsd.go +++ b/serial_freebsd.go @@ -13,7 +13,7 @@ const regexFilter = "^(cu|tty)\\..*" // termios manipulation functions -var baudrateMap = map[int]uint{ +var baudrateMap = map[int]uint32{ 0: syscall.B9600, // Default to 9600 50: syscall.B50, 75: syscall.B75, @@ -37,7 +37,7 @@ var baudrateMap = map[int]uint{ 921600: syscall.B921600, } -var databitsMap = map[int]uint{ +var databitsMap = map[int]uint32{ 0: syscall.CS8, // Default to 8 bits 5: syscall.CS5, 6: syscall.CS6, @@ -45,19 +45,13 @@ var databitsMap = map[int]uint{ 8: syscall.CS8, } -const tcCMSPAR uint = 0 // may be CMSPAR or PAREXT -const tcIUCLC uint = 0 +const tcCMSPAR uint32 = 0 // may be CMSPAR or PAREXT +const tcIUCLC uint32 = 0 -const tcCCTS_OFLOW uint = 0x00010000 -const tcCRTS_IFLOW uint = 0x00020000 +const tcCCTS_OFLOW uint32 = 0x00010000 +const tcCRTS_IFLOW uint32 = 0x00020000 -const tcCRTSCTS uint = tcCCTS_OFLOW - -func termiosMask(data uint) uint32 { - return uint32(data) -} - -// syscall wrappers +const tcCRTSCTS uint32 = tcCCTS_OFLOW //sys ioctl(fd int, req uint64, data uintptr) (err error) diff --git a/serial_linux.go b/serial_linux.go index 1490a5e..89f3aed 100644 --- a/serial_linux.go +++ b/serial_linux.go @@ -13,7 +13,7 @@ const regexFilter = "(ttyS|ttyUSB|ttyACM|ttyAMA|rfcomm|ttyO)[0-9]{1,3}" // termios manipulation functions -var baudrateMap = map[int]uint{ +var baudrateMap = map[int]uint32{ 0: syscall.B9600, // Default to 9600 50: syscall.B50, 75: syscall.B75, @@ -47,7 +47,7 @@ var baudrateMap = map[int]uint{ 4000000: syscall.B4000000, } -var databitsMap = map[int]uint{ +var databitsMap = map[int]uint32{ 0: syscall.CS8, // Default to 8 bits 5: syscall.CS5, 6: syscall.CS6, @@ -55,16 +55,10 @@ var databitsMap = map[int]uint{ 8: syscall.CS8, } -const tcCMSPAR uint = 0 // may be CMSPAR or PAREXT +const tcCMSPAR uint32 = 0 // may be CMSPAR or PAREXT const tcIUCLC = syscall.IUCLC -const tcCRTSCTS uint = 0x80000000 - -func termiosMask(data uint) uint32 { - return uint32(data) -} - -// syscall wrappers +const tcCRTSCTS uint32 = 0x80000000 //sys ioctl(fd int, req uint64, data uintptr) (err error) diff --git a/serial_unix.go b/serial_unix.go index c481ffb..b5cf703 100644 --- a/serial_unix.go +++ b/serial_unix.go @@ -148,38 +148,43 @@ func setTermSettingsBaudrate(speed int, settings *syscall.Termios) error { return &PortError{code: InvalidSpeed} } // revert old baudrate - var BAUDMASK uint for _, rate := range baudrateMap { - BAUDMASK |= rate + settings.Cflag &^= rate } - settings.Cflag &= ^termiosMask(BAUDMASK) // set new baudrate - settings.Cflag |= termiosMask(baudrate) - settings.Ispeed = termiosMask(baudrate) - settings.Ospeed = termiosMask(baudrate) + settings.Cflag |= baudrate + settings.Ispeed = baudrate + settings.Ospeed = baudrate return nil } func setTermSettingsParity(parity Parity, settings *syscall.Termios) error { switch parity { case NoParity: - settings.Cflag &= ^termiosMask(syscall.PARENB | syscall.PARODD | tcCMSPAR) - settings.Iflag &= ^termiosMask(syscall.INPCK) + settings.Cflag &^= syscall.PARENB + settings.Cflag &^= syscall.PARODD + settings.Cflag &^= tcCMSPAR + settings.Iflag &^= syscall.INPCK case OddParity: - settings.Cflag |= termiosMask(syscall.PARENB | syscall.PARODD) - settings.Cflag &= ^termiosMask(tcCMSPAR) - settings.Iflag |= termiosMask(syscall.INPCK) + settings.Cflag |= syscall.PARENB + settings.Cflag |= syscall.PARODD + settings.Cflag &^= tcCMSPAR + settings.Iflag |= syscall.INPCK case EvenParity: - settings.Cflag &= ^termiosMask(syscall.PARODD | tcCMSPAR) - settings.Cflag |= termiosMask(syscall.PARENB) - settings.Iflag |= termiosMask(syscall.INPCK) + settings.Cflag |= syscall.PARENB + settings.Cflag &^= syscall.PARODD + settings.Cflag &^= tcCMSPAR + settings.Iflag |= syscall.INPCK case MarkParity: - settings.Cflag |= termiosMask(syscall.PARENB | syscall.PARODD | tcCMSPAR) - settings.Iflag |= termiosMask(syscall.INPCK) + settings.Cflag |= syscall.PARENB + settings.Cflag |= syscall.PARODD + settings.Cflag |= tcCMSPAR + settings.Iflag |= syscall.INPCK case SpaceParity: - settings.Cflag &= ^termiosMask(syscall.PARODD) - settings.Cflag |= termiosMask(syscall.PARENB | tcCMSPAR) - settings.Iflag |= termiosMask(syscall.INPCK) + settings.Cflag |= syscall.PARENB + settings.Cflag &^= syscall.PARODD + settings.Cflag |= tcCMSPAR + settings.Iflag |= syscall.INPCK } return nil } @@ -189,40 +194,63 @@ func setTermSettingsDataBits(bits int, settings *syscall.Termios) error { if !ok { return &PortError{code: InvalidDataBits} } - settings.Cflag &= ^termiosMask(syscall.CSIZE) - settings.Cflag |= termiosMask(databits) + // Remove previous databits setting + settings.Cflag &^= syscall.CSIZE + // Set requested databits + settings.Cflag |= databits return nil } func setTermSettingsStopBits(bits StopBits, settings *syscall.Termios) error { switch bits { case OneStopBit: - settings.Cflag &= ^termiosMask(syscall.CSTOPB) + settings.Cflag &^= syscall.CSTOPB case OnePointFiveStopBits, TwoStopBits: - settings.Cflag |= termiosMask(syscall.CSTOPB) + settings.Cflag |= syscall.CSTOPB } return nil } func setTermSettingsCtsRts(enable bool, settings *syscall.Termios) { if enable { - settings.Cflag |= termiosMask(tcCRTSCTS) + settings.Cflag |= tcCRTSCTS } else { - settings.Cflag &= ^termiosMask(tcCRTSCTS) + settings.Cflag &^= tcCRTSCTS } } func setRawMode(settings *syscall.Termios) { // Set local mode - settings.Cflag |= termiosMask(syscall.CREAD | syscall.CLOCAL) + settings.Cflag |= syscall.CREAD + settings.Cflag |= syscall.CLOCAL // Set raw mode - settings.Lflag &= ^termiosMask(syscall.ICANON | syscall.ECHO | syscall.ECHOE | syscall.ECHOK | - syscall.ECHONL | syscall.ECHOCTL | syscall.ECHOPRT | syscall.ECHOKE | syscall.ISIG | syscall.IEXTEN) - settings.Iflag &= ^termiosMask(syscall.IXON | syscall.IXOFF | syscall.IXANY | syscall.INPCK | - syscall.IGNPAR | syscall.PARMRK | syscall.ISTRIP | syscall.IGNBRK | syscall.BRKINT | syscall.INLCR | - syscall.IGNCR | syscall.ICRNL | tcIUCLC) - settings.Oflag &= ^termiosMask(syscall.OPOST) + settings.Lflag &^= syscall.ICANON + settings.Lflag &^= syscall.ECHO + settings.Lflag &^= syscall.ECHOE + settings.Lflag &^= syscall.ECHOK + settings.Lflag &^= syscall.ECHONL + settings.Lflag &^= syscall.ECHOCTL + settings.Lflag &^= syscall.ECHOPRT + settings.Lflag &^= syscall.ECHOKE + settings.Lflag &^= syscall.ISIG + settings.Lflag &^= syscall.IEXTEN + + settings.Iflag &^= syscall.IXON + settings.Iflag &^= syscall.IXOFF + settings.Iflag &^= syscall.IXANY + settings.Iflag &^= syscall.INPCK + settings.Iflag &^= syscall.IGNPAR + settings.Iflag &^= syscall.PARMRK + settings.Iflag &^= syscall.ISTRIP + settings.Iflag &^= syscall.IGNBRK + settings.Iflag &^= syscall.BRKINT + settings.Iflag &^= syscall.INLCR + settings.Iflag &^= syscall.IGNCR + settings.Iflag &^= syscall.ICRNL + settings.Iflag &^= tcIUCLC + + settings.Oflag &^= syscall.OPOST // Block reads until at least one char is available (no timeout) settings.Cc[syscall.VMIN] = 1 From c534e6fb455042237ad9044cfcd50ce2ac3ea668 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Sat, 22 Oct 2016 15:48:43 +0200 Subject: [PATCH 2/4] Improved error reporting for parity settings --- serial.go | 4 ++++ serial_unix.go | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/serial.go b/serial.go index 6fb2ef2..96a9b09 100644 --- a/serial.go +++ b/serial.go @@ -94,6 +94,8 @@ const ( InvalidSpeed // InvalidDataBits the number of data bits is not valid or not supported InvalidDataBits + // InvalidParity the selected parity is not valid or not supported + InvalidParity // ErrorEnumeratingPorts an error occurred while listing serial port ErrorEnumeratingPorts ) @@ -113,6 +115,8 @@ func (e PortError) EncodedErrorString() string { return "Invalid port speed" case InvalidDataBits: return "Invalid port data bits" + case InvalidParity: + return "Port parity invalid or not supported" case ErrorEnumeratingPorts: return "Could not enumerate serial ports" default: diff --git a/serial_unix.go b/serial_unix.go index b5cf703..5c20b68 100644 --- a/serial_unix.go +++ b/serial_unix.go @@ -176,15 +176,23 @@ func setTermSettingsParity(parity Parity, settings *syscall.Termios) error { settings.Cflag &^= tcCMSPAR settings.Iflag |= syscall.INPCK case MarkParity: + if tcCMSPAR == 0 { + return &PortError{code: InvalidParity} + } settings.Cflag |= syscall.PARENB settings.Cflag |= syscall.PARODD settings.Cflag |= tcCMSPAR settings.Iflag |= syscall.INPCK case SpaceParity: + if tcCMSPAR == 0 { + return &PortError{code: InvalidParity} + } settings.Cflag |= syscall.PARENB settings.Cflag &^= syscall.PARODD settings.Cflag |= tcCMSPAR settings.Iflag |= syscall.INPCK + default: + return &PortError{code: InvalidParity} } return nil } From f78e270591687fd4e536dd1bfae1f00b8b79ae6b Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Sat, 22 Oct 2016 15:50:10 +0200 Subject: [PATCH 3/4] Slightly improved error messages --- serial.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/serial.go b/serial.go index 96a9b09..7b82518 100644 --- a/serial.go +++ b/serial.go @@ -112,9 +112,9 @@ func (e PortError) EncodedErrorString() string { case PermissionDenied: return "Permission denied" case InvalidSpeed: - return "Invalid port speed" + return "Port speed invalid or not supported" case InvalidDataBits: - return "Invalid port data bits" + return "Port data bits invalid or not supported" case InvalidParity: return "Port parity invalid or not supported" case ErrorEnumeratingPorts: From cb166b5b850dee60bc5f9929301cf6e180399868 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Sat, 22 Oct 2016 15:52:27 +0200 Subject: [PATCH 4/4] Improved error reporting on setting stop bits --- serial.go | 4 ++++ serial_unix.go | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/serial.go b/serial.go index 7b82518..6b932d0 100644 --- a/serial.go +++ b/serial.go @@ -96,6 +96,8 @@ const ( InvalidDataBits // InvalidParity the selected parity is not valid or not supported InvalidParity + // InvalidStopBits the selected number of stop bits is not valid or not supported + InvalidStopBits // ErrorEnumeratingPorts an error occurred while listing serial port ErrorEnumeratingPorts ) @@ -117,6 +119,8 @@ func (e PortError) EncodedErrorString() string { return "Port data bits invalid or not supported" case InvalidParity: return "Port parity invalid or not supported" + case InvalidStopBits: + return "Port stop bits invalid or not supported" case ErrorEnumeratingPorts: return "Could not enumerate serial ports" default: diff --git a/serial_unix.go b/serial_unix.go index 5c20b68..2368cdc 100644 --- a/serial_unix.go +++ b/serial_unix.go @@ -213,8 +213,12 @@ func setTermSettingsStopBits(bits StopBits, settings *syscall.Termios) error { switch bits { case OneStopBit: settings.Cflag &^= syscall.CSTOPB - case OnePointFiveStopBits, TwoStopBits: + case OnePointFiveStopBits: + return &PortError{code: InvalidStopBits} + case TwoStopBits: settings.Cflag |= syscall.CSTOPB + default: + return &PortError{code: InvalidStopBits} } return nil }