diff --git a/serial_darwin.go b/serial_darwin.go index 7bce6c9..8b27a82 100644 --- a/serial_darwin.go +++ b/serial_darwin.go @@ -14,3 +14,18 @@ const regexFilter = "^(cu|tty)\\..*" const ioctlTcgetattr = unix.TIOCGETA const ioctlTcsetattr = unix.TIOCSETA const ioctlTcflsh = unix.TIOCFLUSH + +func setTermSettingsBaudrate(speed int, settings *unix.Termios) (error, bool) { + baudrate, ok := baudrateMap[speed] + if !ok { + return nil, true + } + settings.Ispeed = toTermiosSpeedType(baudrate) + settings.Ospeed = toTermiosSpeedType(baudrate) + return nil, false +} + +func (port *unixPort) setSpecialBaudrate(speed uint32) error { + const kIOSSIOSPEED = 0x80045402 + return unix.IoctlSetPointerInt(port.handle, kIOSSIOSPEED, int(speed)) +} diff --git a/serial_freebsd.go b/serial_freebsd.go index a56a4bf..b648b52 100644 --- a/serial_freebsd.go +++ b/serial_freebsd.go @@ -60,3 +60,26 @@ const ioctlTcflsh = unix.TIOCFLUSH func toTermiosSpeedType(speed uint32) uint32 { return speed } + +func setTermSettingsBaudrate(speed int, settings *unix.Termios) (error, bool) { + baudrate, ok := baudrateMap[speed] + if !ok { + return nil, true + } + // XXX: Is Cflag really needed + // revert old baudrate + for _, rate := range baudrateMap { + settings.Cflag &^= rate + } + // set new baudrate + settings.Cflag |= baudrate + + settings.Ispeed = toTermiosSpeedType(baudrate) + settings.Ospeed = toTermiosSpeedType(baudrate) + return nil, false +} + +func (port *unixPort) setSpecialBaudrate(speed uint32) error { + // TODO: unimplemented + return &PortError{code: InvalidSpeed} +} diff --git a/serial_linux.go b/serial_linux.go index 1c8fd8d..eab3803 100644 --- a/serial_linux.go +++ b/serial_linux.go @@ -67,3 +67,31 @@ const ioctlTcflsh = unix.TCFLSH func toTermiosSpeedType(speed uint32) uint32 { return speed } + +func setTermSettingsBaudrate(speed int, settings *unix.Termios) (error, bool) { + baudrate, ok := baudrateMap[speed] + if !ok { + return nil, true + } + // revert old baudrate + for _, rate := range baudrateMap { + settings.Cflag &^= rate + } + // set new baudrate + settings.Cflag |= baudrate + settings.Ispeed = toTermiosSpeedType(baudrate) + settings.Ospeed = toTermiosSpeedType(baudrate) + return nil, false +} + +func (port *unixPort) setSpecialBaudrate(speed uint32) error { + settings, err := unix.IoctlGetTermios(port.handle, unix.TCGETS2) + if err != nil { + return err + } + settings.Cflag &^= unix.CBAUD + settings.Cflag |= unix.BOTHER + settings.Ispeed = speed + settings.Ospeed = speed + return unix.IoctlSetTermios(port.handle, unix.TCSETS2, settings) +} diff --git a/serial_openbsd.go b/serial_openbsd.go index 5f626f3..ad68957 100644 --- a/serial_openbsd.go +++ b/serial_openbsd.go @@ -60,3 +60,26 @@ const ioctlTcflsh = unix.TIOCFLUSH func toTermiosSpeedType(speed uint32) int32 { return int32(speed) } + +func setTermSettingsBaudrate(speed int, settings *unix.Termios) (error, bool) { + baudrate, ok := baudrateMap[speed] + if !ok { + return nil, true + } + // XXX: Is Cflag really needed + // revert old baudrate + for _, rate := range baudrateMap { + settings.Cflag &^= rate + } + // set new baudrate + settings.Cflag |= baudrate + + settings.Ispeed = toTermiosSpeedType(baudrate) + settings.Ospeed = toTermiosSpeedType(baudrate) + return nil, false +} + +func (port *unixPort) setSpecialBaudrate(speed uint32) error { + // TODO: unimplemented + return &PortError{code: InvalidSpeed} +} diff --git a/serial_unix.go b/serial_unix.go index 0143aa2..143818e 100644 --- a/serial_unix.go +++ b/serial_unix.go @@ -126,9 +126,6 @@ func (port *unixPort) SetMode(mode *Mode) error { if err != nil { return err } - if err := setTermSettingsBaudrate(mode.BaudRate, settings); err != nil { - return err - } if err := setTermSettingsParity(mode.Parity, settings); err != nil { return err } @@ -138,7 +135,23 @@ func (port *unixPort) SetMode(mode *Mode) error { if err := setTermSettingsStopBits(mode.StopBits, settings); err != nil { return err } - return port.setTermSettings(settings) + requireSpecialBaudrate := false + if err, special := setTermSettingsBaudrate(mode.BaudRate, settings); err != nil { + return err + } else if special { + requireSpecialBaudrate = true + } + if err := port.setTermSettings(settings); err != nil { + return err + } + if requireSpecialBaudrate { + // MacOSX require this one to be the last operation otherwise an + // 'Invalid serial port' error is produced. + if err := port.setSpecialBaudrate(uint32(mode.BaudRate)); err != nil { + return err + } + } + return nil } func (port *unixPort) SetDTR(dtr bool) error { @@ -206,11 +219,6 @@ func nativeOpen(portName string, mode *Mode) (*unixPort, error) { } // Setup serial port - if port.SetMode(mode) != nil { - port.Close() - return nil, &PortError{code: InvalidSerialPort} - } - settings, err := port.getTermSettings() if err != nil { port.Close() @@ -228,6 +236,13 @@ func nativeOpen(portName string, mode *Mode) (*unixPort, error) { return nil, &PortError{code: InvalidSerialPort} } + // MacOSX require that this operation is the last one otherwise an + // 'Invalid serial port' error is returned... don't know why... + if port.SetMode(mode) != nil { + port.Close() + return nil, &PortError{code: InvalidSerialPort} + } + unix.SetNonblock(h, false) port.acquireExclusiveAccess() @@ -289,22 +304,6 @@ func nativeGetPortsList() ([]string, error) { // termios manipulation functions -func setTermSettingsBaudrate(speed int, settings *unix.Termios) error { - baudrate, ok := baudrateMap[speed] - if !ok { - return &PortError{code: InvalidSpeed} - } - // revert old baudrate - for _, rate := range baudrateMap { - settings.Cflag &^= rate - } - // set new baudrate - settings.Cflag |= baudrate - settings.Ispeed = toTermiosSpeedType(baudrate) - settings.Ospeed = toTermiosSpeedType(baudrate) - return nil -} - func setTermSettingsParity(parity Parity, settings *unix.Termios) error { switch parity { case NoParity: