From deb5733c32fd815da615e514180fc6db172a5cf2 Mon Sep 17 00:00:00 2001 From: Cormac Cannon Date: Mon, 14 Dec 2015 16:06:09 +0000 Subject: [PATCH 1/2] Added GetPortsList method to all implementations, shamelessly lifted from the gobug.st/serial package and subject to the conditions of its license (which has been reproduced in source as per terms of said license) Updated serial_posix to support full list of termios baud rates (as per existing serial_linux implementation). Moved posixTimeoutValues method from top level serial.go to new serial_x.go source file, as only required for linux and posix implementations. --- serial.go | 22 --------- serial_linux.go | 5 +- serial_posix.go | 104 +++++++++++++++++++++++++++++++++-------- serial_windows.go | 105 ++++++++++++++++++++++++++++++++++++++++- serial_x.go | 116 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 307 insertions(+), 45 deletions(-) create mode 100644 serial_x.go diff --git a/serial.go b/serial.go index 4717738..7d5172a 100644 --- a/serial.go +++ b/serial.go @@ -95,28 +95,6 @@ func OpenPort(c *Config) (*Port, error) { return openPort(c.Name, c.Baud, c.ReadTimeout) } -// Converts the timeout values for Linux / POSIX systems -func posixTimeoutValues(readTimeout time.Duration) (vmin uint8, vtime uint8) { - const MAXUINT8 = 1<<8 - 1 // 255 - // set blocking / non-blocking read - var minBytesToRead uint8 = 1 - var readTimeoutInDeci int64 - if readTimeout > 0 { - // EOF on zero read - minBytesToRead = 0 - // convert timeout to deciseconds as expected by VTIME - readTimeoutInDeci = (readTimeout.Nanoseconds() / 1e6 / 100) - // capping the timeout - if readTimeoutInDeci < 1 { - // min possible timeout 1 Deciseconds (0.1s) - readTimeoutInDeci = 1 - } else if readTimeoutInDeci > MAXUINT8 { - // max possible timeout is 255 deciseconds (25.5s) - readTimeoutInDeci = MAXUINT8 - } - } - return minBytesToRead, uint8(readTimeoutInDeci) -} // func SendBreak() diff --git a/serial_linux.go b/serial_linux.go index 9f0f884..1939db9 100644 --- a/serial_linux.go +++ b/serial_linux.go @@ -6,7 +6,10 @@ import ( "os" "syscall" "time" - "unsafe" + "strings" + "unsafe" + log "github.com/Sirupsen/logrus" + "fmt" ) func openPort(name string, baud int, readTimeout time.Duration) (p *Port, err error) { diff --git a/serial_posix.go b/serial_posix.go index 95a592b..ce67431 100644 --- a/serial_posix.go +++ b/serial_posix.go @@ -14,7 +14,6 @@ import ( "os" "syscall" "time" - //"unsafe" ) func openPort(name string, baud int, readTimeout time.Duration) (p *Port, err error) { @@ -35,27 +34,92 @@ func openPort(name string, baud int, readTimeout time.Duration) (p *Port, err er f.Close() return nil, err } - var speed C.speed_t - switch baud { - case 115200: - speed = C.B115200 - case 57600: - speed = C.B57600 - case 38400: - speed = C.B38400 - case 19200: - speed = C.B19200 - case 9600: - speed = C.B9600 - case 4800: - speed = C.B4800 - case 2400: - speed = C.B2400 - default: - f.Close() - return nil, fmt.Errorf("Unknown baud rate %v", baud) + + var bauds = map[int]C.speed_t{ + 50: C.B50, + 75: C.B75, + 110: C.B110, + 134: C.B134, + 150: C.B150, + 200: C.B200, + 300: C.B300, + 600: C.B600, + 1200: C.B1200, + 1800: C.B1800, + 2400: C.B2400, + 4800: C.B4800, + 9600: C.B9600, + 19200: C.B19200, + 38400: C.B38400, + 57600: C.B57600, + 115200: C.B115200, + 230400: C.B230400, + 460800: C.B460800, + 500000: C.B500000, + 576000: C.B576000, + 921600: C.B921600, + 1000000: C.B1000000, + 1152000: C.B1152000, + 1500000: C.B1500000, + 2000000: C.B2000000, + 2500000: C.B2500000, + 3000000: C.B3000000, + 3500000: C.B3500000, + 4000000: C.B4000000, } + // var speed C.speed_t + + + // switch baud { + // case 230400: + // speed = C.B230400 + // case 115200: + // speed = C.B115200 + // case 57600: + // speed = C.B57600 + // case 38400: + // speed = C.B38400 + // case 19200: + // speed = C.B19200 + // case 9600: + // speed = C.B9600 + // case 4800: + // speed = C.B4800 + // case 2400: + // speed = C.B2400 + // case 1800: + // speed = C.B1800 + // case 1200: + // speed = C.B1200 + // case 600: + // speed = C.B600 + // case 300: + // speed = C.B300 + // case 200: + // speed = C.B200 + // case 150: + // speed = C.B150 + // case 134: + // speed = C.B134 + // case 110: + // speed = C.B110 + // case 75: + // speed = C.B75 + // case 50: + // speed = C.B50 + // default: + // f.Close() + // return nil, fmt.Errorf("Unknown baud rate %v", baud) + // } + + speed := bauds[baud] + + if speed == 0 { + f.Close() + return nil, fmt.Errorf("Unknown baud rate %v", baud) + } + _, err = C.cfsetispeed(&st, speed) if err != nil { f.Close() diff --git a/serial_windows.go b/serial_windows.go index c158dfa..d57643b 100644 --- a/serial_windows.go +++ b/serial_windows.go @@ -3,6 +3,7 @@ package serial import ( + "errors" "fmt" "os" "sync" @@ -130,7 +131,83 @@ func (p *Port) Read(buf []byte) (int, error) { // Discards data written to the port but not transmitted, // or data received but not read func (p *Port) Flush() error { - return purgeComm(p.fd) + err := purgeComm(p.fd) + clearCommError(p.fd) + return err +} + +/* +This function was taken with minor modifications from the go.bug.st/serial package (https://github.com/bugst/go-serial), and is subject to the conditions of its license (reproduced below): + +Copyright (c) 2014, Cristian Maglie. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*/ +func GetPortsList() ([]string, error) { + subKey, err := syscall.UTF16PtrFromString("HARDWARE\\DEVICEMAP\\SERIALCOMM\\") + if err != nil { + return nil, errors.New("Error enumerating ports") + } + + var h syscall.Handle + if syscall.RegOpenKeyEx(syscall.HKEY_LOCAL_MACHINE, subKey, 0, syscall.KEY_READ, &h) != nil { + return nil, errors.New("Error enumerating ports") + } + defer syscall.RegCloseKey(h) + + var valuesCount uint32 + if syscall.RegQueryInfoKey(h, nil, nil, nil, nil, nil, nil, &valuesCount, nil, nil, nil, nil) != nil { + return nil, errors.New("Error enumerating ports") + } + + list := make([]string, valuesCount) + for i := range list { + var data [1024]uint16 + dataSize := uint32(len(data)) + var name [1024]uint16 + nameSize := uint32(len(name)) + if RegEnumValue(h, uint32(i), &name[0], &nameSize, nil, nil, &data[0], &dataSize) != nil { + return nil, errors.New("Error enumerating ports") + } + list[i] = syscall.UTF16ToString(data[:]) + } + return list, nil +} + +func RegEnumValue(key syscall.Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, class *uint16, value *uint16, valueLen *uint32) (regerrno error) { + r0, _, _ := syscall.Syscall9(nRegEnumValueW, 8, uintptr(key), uintptr(index), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameLen)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(class)), uintptr(unsafe.Pointer(value)), uintptr(unsafe.Pointer(valueLen)), 0) + if r0 != 0 { + return syscall.Errno(r0) + } + return nil } var ( @@ -142,7 +219,9 @@ var ( nCreateEvent, nResetEvent, nPurgeComm, - nFlushFileBuffers uintptr + nFlushFileBuffers, + nClearCommError, + nRegEnumValueW uintptr ) func init() { @@ -151,6 +230,11 @@ func init() { panic("LoadLibrary " + err.Error()) } defer syscall.FreeLibrary(k32) + api32, err := syscall.LoadLibrary("advapi32.dll") + if err != nil { + panic("LoadLibrary " + err.Error()) + } + defer syscall.FreeLibrary(api32) nSetCommState = getProcAddr(k32, "SetCommState") nSetCommTimeouts = getProcAddr(k32, "SetCommTimeouts") @@ -161,6 +245,12 @@ func init() { nResetEvent = getProcAddr(k32, "ResetEvent") nPurgeComm = getProcAddr(k32, "PurgeComm") nFlushFileBuffers = getProcAddr(k32, "FlushFileBuffers") + nClearCommError = getProcAddr(k32, "ClearCommError") + nRegEnumValueW = getProcAddr(api32, "RegEnumValueW") +} + +func clearCommError(h syscall.Handle) error { + return processSyscall(nClearCommError, 1, uintptr(h), 0, 0) } func getProcAddr(lib syscall.Handle, name string) uintptr { @@ -171,6 +261,14 @@ func getProcAddr(lib syscall.Handle, name string) uintptr { return addr } +func processSyscall(systemMethod, nargs, a1, a2, a3 uintptr) error { + result, _, err := syscall.Syscall(systemMethod, nargs, a1, a2, a3) + if result == 0 { + return err + } + return nil +} + func setCommState(h syscall.Handle, baud int) error { var params structDCB params.DCBlength = uint32(unsafe.Sizeof(params)) @@ -178,6 +276,9 @@ func setCommState(h syscall.Handle, baud int) error { params.flags[0] = 0x01 // fBinary params.flags[0] |= 0x10 // Assert DSR + //ADDITION: To help with this problem: http://zachsaw.blogspot.ie/2010/07/net-serialport-woes.html + params.flags[1] &= ^byte(0x40) + params.BaudRate = uint32(baud) params.ByteSize = 8 diff --git a/serial_x.go b/serial_x.go new file mode 100644 index 0000000..96f09e3 --- /dev/null +++ b/serial_x.go @@ -0,0 +1,116 @@ +// +build !windows + +package serial + +import ( + "time" + "io/ioutil" + "regexp" + "strings" +) + +const ( + devFolder = "/dev" + regexFilter = `^(cu|tty)\.?.*` +) + +/* +This function was taken with minor modifications from the go.bug.st/serial package (https://github.com/bugst/go-serial), and is subject to the conditions of its license (reproduced below): + +Copyright (c) 2014, Cristian Maglie. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*/ +func GetPortsList() ([]string, error) { + files, err := ioutil.ReadDir(devFolder) + if err != nil { + return nil, err + } + + ports := make([]string, 0, len(files)) + for _, f := range files { + // Skip folders + if f.IsDir() { + continue + } + + // Keep only devices with the correct name + match, err := regexp.MatchString(regexFilter, f.Name()) + if err != nil { + return nil, err + } + if !match { + continue + } + + portName := devFolder + "/" + f.Name() + + // Check if serial port is real or is a placeholder serial port "ttySxx" + if strings.HasPrefix(f.Name(), "ttyS") { + port, err := openPort(portName, 9600, 100) + if err != nil { + continue + } else { + port.Close() + } + } + + // Save serial port in the resulting list + ports = append(ports, portName) + } + + return ports, nil +} + + +// Converts the timeout values for Linux / POSIX systems +// Moved to this new source module from serial.go +func posixTimeoutValues(readTimeout time.Duration) (vmin uint8, vtime uint8) { + const MAXUINT8 = 1<<8 - 1 // 255 + // set blocking / non-blocking read + var minBytesToRead uint8 = 1 + var readTimeoutInDeci int64 + if readTimeout > 0 { + // EOF on zero read + minBytesToRead = 0 + // convert timeout to deciseconds as expected by VTIME + readTimeoutInDeci = (readTimeout.Nanoseconds() / 1e6 / 100) + // capping the timeout + if readTimeoutInDeci < 1 { + // min possible timeout 1 Deciseconds (0.1s) + readTimeoutInDeci = 1 + } else if readTimeoutInDeci > MAXUINT8 { + // max possible timeout is 255 deciseconds (25.5s) + readTimeoutInDeci = MAXUINT8 + } + } + return minBytesToRead, uint8(readTimeoutInDeci) +} From fad2c08732aa56a6a32d074aa3b9a5753d63ec11 Mon Sep 17 00:00:00 2001 From: Cormac Cannon Date: Thu, 17 Dec 2015 14:31:33 +0000 Subject: [PATCH 2/2] Changes as per PR feedback, namely: Added ListPorts method in serial.go that delegates to platform implementation called listPorts. Associated godoc explicitly states that posix implementation is just a convenient heuristic. Renamed platform-specific implementations in serial_posix.go and serial_windows.go from GetPortsList to listPorts for consistency. Reverted baud-rate additions in serial_posix.go. May be included a future PR. Corrected erroneous exporting of function in serial_windows.go Tidied up posix implementation of listPorts. Externalised portname filter definition to posix_.go --- serial_x.go => posix_all.go | 83 ++++++++++++++-------------- posix_darwin.go | 15 ++++++ posix_linux.go | 15 ++++++ posix_other.go | 10 ++++ serial.go | 10 +++- serial_linux.go | 5 +- serial_posix.go | 104 +++++++----------------------------- serial_windows.go | 6 +-- 8 files changed, 115 insertions(+), 133 deletions(-) rename serial_x.go => posix_all.go (79%) create mode 100644 posix_darwin.go create mode 100644 posix_linux.go create mode 100644 posix_other.go diff --git a/serial_x.go b/posix_all.go similarity index 79% rename from serial_x.go rename to posix_all.go index 96f09e3..b72d66e 100644 --- a/serial_x.go +++ b/posix_all.go @@ -3,17 +3,41 @@ package serial import ( - "time" "io/ioutil" "regexp" "strings" + "time" ) const ( devFolder = "/dev" - regexFilter = `^(cu|tty)\.?.*` ) + +// Converts the timeout values for Linux / POSIX systems +// Moved to this new source module from serial.go +func posixTimeoutValues(readTimeout time.Duration) (vmin uint8, vtime uint8) { + const MAXUINT8 = 1<<8 - 1 // 255 + // set blocking / non-blocking read + var minBytesToRead uint8 = 1 + var readTimeoutInDeci int64 + if readTimeout > 0 { + // EOF on zero read + minBytesToRead = 0 + // convert timeout to deciseconds as expected by VTIME + readTimeoutInDeci = (readTimeout.Nanoseconds() / 1e6 / 100) + // capping the timeout + if readTimeoutInDeci < 1 { + // min possible timeout 1 Deciseconds (0.1s) + readTimeoutInDeci = 1 + } else if readTimeoutInDeci > MAXUINT8 { + // max possible timeout is 255 deciseconds (25.5s) + readTimeoutInDeci = MAXUINT8 + } + } + return minBytesToRead, uint8(readTimeoutInDeci) +} + /* This function was taken with minor modifications from the go.bug.st/serial package (https://github.com/bugst/go-serial), and is subject to the conditions of its license (reproduced below): @@ -49,7 +73,7 @@ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -func GetPortsList() ([]string, error) { +func listPorts() ([]string, error) { files, err := ioutil.ReadDir(devFolder) if err != nil { return nil, err @@ -62,55 +86,34 @@ func GetPortsList() ([]string, error) { continue } - // Keep only devices with the correct name - match, err := regexp.MatchString(regexFilter, f.Name()) + // Keep only devices with name matching the port name filter defined for this platform + // (discarding placeholder entries for non-existent onboard COM ports) + match, err := regexp.MatchString(portNameFilter, f.Name()) if err != nil { return nil, err } - if !match { + if !match || isALegacyPlaceholder(f.Name()) { continue } - portName := devFolder + "/" + f.Name() - - // Check if serial port is real or is a placeholder serial port "ttySxx" - if strings.HasPrefix(f.Name(), "ttyS") { - port, err := openPort(portName, 9600, 100) - if err != nil { - continue - } else { - port.Close() - } - } - // Save serial port in the resulting list - ports = append(ports, portName) + ports = append(ports, devFolder + "/" + f.Name()) } return ports, nil } - -// Converts the timeout values for Linux / POSIX systems -// Moved to this new source module from serial.go -func posixTimeoutValues(readTimeout time.Duration) (vmin uint8, vtime uint8) { - const MAXUINT8 = 1<<8 - 1 // 255 - // set blocking / non-blocking read - var minBytesToRead uint8 = 1 - var readTimeoutInDeci int64 - if readTimeout > 0 { - // EOF on zero read - minBytesToRead = 0 - // convert timeout to deciseconds as expected by VTIME - readTimeoutInDeci = (readTimeout.Nanoseconds() / 1e6 / 100) - // capping the timeout - if readTimeoutInDeci < 1 { - // min possible timeout 1 Deciseconds (0.1s) - readTimeoutInDeci = 1 - } else if readTimeoutInDeci > MAXUINT8 { - // max possible timeout is 255 deciseconds (25.5s) - readTimeoutInDeci = MAXUINT8 +// Checks whether port entry is just a placeholder -- e.g. reserved for a legacy ISA COM +// port that doesn't exist +func isALegacyPlaceholder(portName string) (bool){ + const legacyComPortPrefix = "ttyS" + if strings.HasPrefix(portName, legacyComPortPrefix) { + port, err := openPort(devFolder + "/" + portName, 9600, 100) + if err != nil { + return true; + } else { + port.Close() } } - return minBytesToRead, uint8(readTimeoutInDeci) + return false; } diff --git a/posix_darwin.go b/posix_darwin.go new file mode 100644 index 0000000..ab292d4 --- /dev/null +++ b/posix_darwin.go @@ -0,0 +1,15 @@ +//+build darwin + +package serial + +// +// Apparently OSX creates a CU (Call-Up) and a tty device entry for +// each attached serial device, prefixing them with 'cu.' and 'tty.' +// respectively +// Should maybe restrict filter to cu devices? +// (see http://pbxbook.com/other/mac-tty.html) +// Although linux has dispensed with / deprecated this distinction: +// http://tldp.org/HOWTO/Modem-HOWTO-9.html#ss9.8 +const ( + portNameFilter = `^(cu|tty)\..*` +) diff --git a/posix_linux.go b/posix_linux.go new file mode 100644 index 0000000..23b2190 --- /dev/null +++ b/posix_linux.go @@ -0,0 +1,15 @@ +//+build linux + +package serial + +/* +This heuristic regex filter should catch most serial devices under linux. +The prefixes represent devices of the following types +ttyS: onboard uarts +ttyUSB: USB<->uart bridges +ttyACM: Abstract Control Model devices (e.g. modems -- see https://www.rfc1149.net/blog/2013/03/05/what-is-the-difference-between-devttyusbx-and-devttyacmx/) +ttyAMA: Don't know what AMA stands for, but seems to be used for Raspberry PI onboard ports at least +*/ +const ( + portNameFilter = `^(ttyS|ttyUSB|ttyACM|ttyAMA)\d+` +) diff --git a/posix_other.go b/posix_other.go new file mode 100644 index 0000000..d16b9eb --- /dev/null +++ b/posix_other.go @@ -0,0 +1,10 @@ +// +build !linux,!darwin + +package serial + +/* +This is a catchall for posix platforms other than linux and OS X +*/ +const ( + portNameFilter = `^tty.*` +) diff --git a/serial.go b/serial.go index 7d5172a..c5bfcb0 100644 --- a/serial.go +++ b/serial.go @@ -90,11 +90,19 @@ type Config struct { // CRLFTranslate bool } -// OpenPort opens a serial port with the specified configuration func OpenPort(c *Config) (*Port, error) { return openPort(c.Name, c.Baud, c.ReadTimeout) } +// ListPorts returns a list of serial ports identified on the system. +// The windows implementation queries the registry and should be accurate. +// The implementation for posix platforms just uses an heuristic approach, applying a regex +// filter to the contents of /dev. Sensible defaults for linux and OS X have been defined in +// 'posix_linux.go' and 'posix_darwin.go', respectively. On any other posix platform, +// all devices matching the overly-inclusive pattern '^tty.*' will be returned. +func ListPorts() ([]string, error) { + return listPorts() +} // func SendBreak() diff --git a/serial_linux.go b/serial_linux.go index 1939db9..9f0f884 100644 --- a/serial_linux.go +++ b/serial_linux.go @@ -6,10 +6,7 @@ import ( "os" "syscall" "time" - "strings" - "unsafe" - log "github.com/Sirupsen/logrus" - "fmt" + "unsafe" ) func openPort(name string, baud int, readTimeout time.Duration) (p *Port, err error) { diff --git a/serial_posix.go b/serial_posix.go index ce67431..6339f98 100644 --- a/serial_posix.go +++ b/serial_posix.go @@ -34,92 +34,26 @@ func openPort(name string, baud int, readTimeout time.Duration) (p *Port, err er f.Close() return nil, err } - - var bauds = map[int]C.speed_t{ - 50: C.B50, - 75: C.B75, - 110: C.B110, - 134: C.B134, - 150: C.B150, - 200: C.B200, - 300: C.B300, - 600: C.B600, - 1200: C.B1200, - 1800: C.B1800, - 2400: C.B2400, - 4800: C.B4800, - 9600: C.B9600, - 19200: C.B19200, - 38400: C.B38400, - 57600: C.B57600, - 115200: C.B115200, - 230400: C.B230400, - 460800: C.B460800, - 500000: C.B500000, - 576000: C.B576000, - 921600: C.B921600, - 1000000: C.B1000000, - 1152000: C.B1152000, - 1500000: C.B1500000, - 2000000: C.B2000000, - 2500000: C.B2500000, - 3000000: C.B3000000, - 3500000: C.B3500000, - 4000000: C.B4000000, + var speed C.speed_t + switch baud { + case 115200: + speed = C.B115200 + case 57600: + speed = C.B57600 + case 38400: + speed = C.B38400 + case 19200: + speed = C.B19200 + case 9600: + speed = C.B9600 + case 4800: + speed = C.B4800 + case 2400: + speed = C.B2400 + default: + f.Close() + return nil, fmt.Errorf("Unknown baud rate %v", baud) } - - // var speed C.speed_t - - - // switch baud { - // case 230400: - // speed = C.B230400 - // case 115200: - // speed = C.B115200 - // case 57600: - // speed = C.B57600 - // case 38400: - // speed = C.B38400 - // case 19200: - // speed = C.B19200 - // case 9600: - // speed = C.B9600 - // case 4800: - // speed = C.B4800 - // case 2400: - // speed = C.B2400 - // case 1800: - // speed = C.B1800 - // case 1200: - // speed = C.B1200 - // case 600: - // speed = C.B600 - // case 300: - // speed = C.B300 - // case 200: - // speed = C.B200 - // case 150: - // speed = C.B150 - // case 134: - // speed = C.B134 - // case 110: - // speed = C.B110 - // case 75: - // speed = C.B75 - // case 50: - // speed = C.B50 - // default: - // f.Close() - // return nil, fmt.Errorf("Unknown baud rate %v", baud) - // } - - speed := bauds[baud] - - if speed == 0 { - f.Close() - return nil, fmt.Errorf("Unknown baud rate %v", baud) - } - _, err = C.cfsetispeed(&st, speed) if err != nil { f.Close() diff --git a/serial_windows.go b/serial_windows.go index d57643b..cbede0f 100644 --- a/serial_windows.go +++ b/serial_windows.go @@ -171,7 +171,7 @@ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -func GetPortsList() ([]string, error) { +func listPorts() ([]string, error) { subKey, err := syscall.UTF16PtrFromString("HARDWARE\\DEVICEMAP\\SERIALCOMM\\") if err != nil { return nil, errors.New("Error enumerating ports") @@ -194,7 +194,7 @@ func GetPortsList() ([]string, error) { dataSize := uint32(len(data)) var name [1024]uint16 nameSize := uint32(len(name)) - if RegEnumValue(h, uint32(i), &name[0], &nameSize, nil, nil, &data[0], &dataSize) != nil { + if regEnumValue(h, uint32(i), &name[0], &nameSize, nil, nil, &data[0], &dataSize) != nil { return nil, errors.New("Error enumerating ports") } list[i] = syscall.UTF16ToString(data[:]) @@ -202,7 +202,7 @@ func GetPortsList() ([]string, error) { return list, nil } -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) { r0, _, _ := syscall.Syscall9(nRegEnumValueW, 8, uintptr(key), uintptr(index), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameLen)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(class)), uintptr(unsafe.Pointer(value)), uintptr(unsafe.Pointer(valueLen)), 0) if r0 != 0 { return syscall.Errno(r0)