Share

Python Serial Port Extension

Tracker: Bugs

5 High baudrates not supported on Mac OS X - ID: 2562610
Last Update: Comment added ( cliechti )

Mac OS X TERMIOS API only supports baudrates up to 230400 bps.

Higher baudrates are not supported, and any attempt to use them ends up
with an exception.

On Tiger (10.4.x) and above, it is nevertheless possible to use higher
baudrates, using an IOKit-specific ioctl call.

I have not written a patch yet, but here is a code sample I use to
circumvent the current pyserial limitation on Mac OS X. It should be rather
trivial to adapt it to the actual pyserial mainstream code.

serialclass = serial.Serial
if sys.platform.lower() in ('darwin'):
version = os.uname()[2].split('.')
# Tiger or above can support arbitrary serial speeds
if int(version[0]) >= 8:
# first step: remove all speeds not supported with TERMIOS
# so that pyserial never attempts to use them directly
for b in serial.baudrate_constants.keys():
if b > 230400:
del serial.baudrate_constants[b]
# second step: override the default _reconfigurePort
function
class DarwinSerial(serial.Serial):
def _reconfigurePort(port):
try:
serial.Serial._reconfigurePort(port)
except AttributeError:
# third step: use IOKit-specific call to set
up
# high speeds
import array, fcntl
buf = array.array('i', [int(port._baudrate)])
IOSSIOSPEED = 0x80045402 #_IOW('T', 2,
speed_t)
fcntl.ioctl(port.fd, IOSSIOSPEED, buf, 1)
serialclass = DarwinSerial
if os.path.exists(device):
if stat.S_ISSOCK(os.stat(device)[0]):
from neo.serialext import SerialExtender
serialclass = SerialExtender.serialsocketclass()
port = serialclass(port=device,
baudrate=self.DEFAULT_BAUDRATE,
timeout=0)


Emmanuel Blot ( eblot ) - 2009-02-04 00:24

5

Closed

Accepted

Chris Liechti

None

None

Public


Comments ( 8 )

Date: 2009-07-24 15:55
Sender: cliechtiProject Admin

you could check for the set_special_baudrate function with hasattr()

thanks for your feedback, closing the bug


Date: 2009-07-24 12:56
Sender: eblot

Ok, great, it works with [242], up to 3Mbps on my machine - thanks a lot.

I've added the following piece of code to enable or not the Darwin hack,
depending on the actual pyserial version number. Please, let me know if
there is a better way:
{{{
serialclass = serial.Serial
# hack for Mac OS X hosts: the underlying termios system library
# cannot cope with baudrates > 230kbps with pyserial << 9.7
if sys.platform.lower() in ('darwin'):
if 'version' not in serial.__dict__ or \
serial.version[0] < 9 or serial.version[1] < 7:
from neo.serialext import SerialExtender
serialclass = SerialExtender.darwinserialclass()
}}}



Date: 2009-07-23 23:54
Sender: cliechtiProject Admin

thanks for the feedback. i've updated the posix backend so that is uses a
platform specific way to set non standard baud rates. if you have time,
could you test SVN HEAD?


Date: 2009-07-22 18:20
Sender: eblot

Sorry, I meant:

I've set up a clean Python installation (2.6.2), to be sure that no
previously *installed* modules get in the way.
I may have *forgot* something obvious, but I see no improvement:


Date: 2009-07-22 18:19
Sender: eblot

> the SVN HEAD already contains code to support non standard baudrate on
> POSIX systems. did you test if that works for you too?

I've set up a clean Python installation (2.6.2), to be sure that no
previously modules get in the way.
I may have forget something obvious, but I see no improvement:

# try speed 460800
Traceback (most recent call last):
File "host/bin/neoflasher.py", line 1822, in <module>
loader = NeoFlasher(loadopts)
File "host/bin/neoflasher.py", line 302, in __init__
self._baudrates = self._detect_baudrates(self._port)
File "host/bin/neoflasher.py", line 1615, in _detect_baudrates
port.setBaudrate(speed)
File
"/Users/eblot/Sources/Svn/sourceforge.net/pyserial/trunk/pyserial/serial/serialutil.py",
line 231, in setBaudrate
if self._isOpen: self._reconfigurePort()
File
"/Users/eblot/Sources/Svn/sourceforge.net/pyserial/trunk/pyserial/serial/serialposix.py",
line 308, in _reconfigurePort
termios.tcsetattr(self.fd, TERMIOS.TCSANOW, [iflag, oflag, cflag,
lflag, ispeed, ospeed, cc])
termios.error: (22, 'Invalid argument')

Speeds > 230400 still get rejected.

BTW, you setup.py file is erroneous: it contains an extra ')' character at
the very bottom line, which make the setuptools parser to fail.



Date: 2009-07-21 23:43
Sender: cliechtiProject Admin

the SVN HEAD already contains code to support non standard baudrate on
POSIX systems. did you test if that works for you too?


Date: 2009-05-09 21:21
Sender: nobody

This is actually a broader issue than just support of high baud rates under
Darwin:

1) There's some non-POSIX, Linux-specific code in serialposix.py.

2) Serial.open() silently fails when _reconfigurePort throws an exception.

3) This pertains to all non-standard baud rates, not just high-speed ones.

4) Darwin has its own way of handling non-POSIX baud rates.

Details follow:

1a) The baudrate_constants defined in serialposix.py are not POSIX -- they
are Linux-specific. As a result, when using a "supported" baud rate that
is not supported by termios, the following fails on Darwin (and other
BSDs):

Traceback (most recent call last):
File "./serialtest.py", line 71, in <module>
port.setBaudrate(500000)
File
"/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/serial/serialutil.py",
line 231, in setBaudrate
if self._isOpen: self._reconfigurePort()
File
"/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/serial/serialposix.py",
line 298, in _reconfigurePort
termios.tcsetattr(self.fd, TERMIOS.TCSANOW, [iflag, oflag, cflag,
lflag, ispeed, ospeed, cc])
termios.error: (22, 'Invalid argument')

Emmanuel Blot's code works around this by deleting all high-speed entries
from baudrate_constants. However, this isn't strictly correct, as _none_
of the values in baudrate_constants work outside of Linux. The only reason
the lower constants don't cause a problem is that the lower baud rates are
defined by termio (e.g., "termios.B38400"), in which case
baudrate_constants doesn't get used.

In short, any use of these baudrate_constants is Linux-specific.


1b) TIOCGSERIAL and TIOCSSERIAL are also Linux-specific and not POSIX.
(Also, there's some indication that ASYNC_SPD_CUST is deprecated in Linux.)
Therefore, picking a non-POSIX baud rate that's not in the list of
"supported" constants causes the following failure:

Traceback (most recent call last):
File "./serialtest.py", line 71, in <module>
port.setBaudrate(400000)
File
"/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/serial/serialutil.py",
line 231, in setBaudrate
if self._isOpen: self._reconfigurePort()
File
"/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/serial/serialposix.py",
line 306, in _reconfigurePort
FCNTL.ioctl(self.fd, TERMIOS.TIOCGSERIAL, buf)
AttributeError: 'module' object has no attribute 'TIOCGSERIAL'

Emmanuel Blot's code works around this by catching the AttributeError
exception raised when the TIOCGSERIAL ioctl is attempted (since termios
doesn't define TIOCGSERIAL under Darwin). Fortunately, since setting the
baud rate is the last thing _reconfigurePort does, the workaround can rely
on _reconfigurePort for everything except the custom baud rate.

Again, this method of supporting non-POSIX baud rates is Linux-specific.


2) When using a baud rate not supported by the OS, creating a new Serial()
object silently fails, because open() doesn't raise an exception when
_reconfigurePort fails. Instead, you get the following error as soon as
you try to use the port:

Traceback (most recent call last):
File "./serialtest.py", line 72, in <module>
port.write("\r")
File
"/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/serial/serialposix.py",
line 361, in write
if self.fd is None: raise portNotOpenError
serial.serialutil.SerialException: Port not open


3) As mentioned above, this isn't just high-speed baud rates. Any
non-standard baud rate causes failures:

Traceback (most recent call last):
File "./serialtest.py", line 71, in <module>
port.setBaudrate(128)
File
"/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/serial/serialutil.py",
line 231, in setBaudrate
if self._isOpen: self._reconfigurePort()
File
"/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/serial/serialposix.py",
line 306, in _reconfigurePort
FCNTL.ioctl(self.fd, TERMIOS.TIOCGSERIAL, buf)
AttributeError: 'module' object has no attribute 'TIOCGSERIAL'


4) As Emmanuel Blot pointed out, Darwin (8 and higher) can handle custom,
non-POSIX baud rates via its own special ioctl.

import array
buf = array.array('I', [int(self._baudrate)])
IOSSIOSPEED = 0x80045402 # _IOW('T', 2, speed_t)
fcntl.ioctl(port.fd, IOSSIOSPEED, buf, 1)

I don't know how other BSDs handle non-POSIX baud rates.



Date: 2009-02-04 00:26
Sender: eblot

File Added: hsserial.py


Attached File ( 1 )

Filename Description Download
hsserial.py High speed workaround on Mac OS X Download

Changes ( 15 )

Field Old Value Date By
close_date - 2009-07-24 15:55 cliechti
allow_comments 1 2009-07-24 15:55 cliechti
resolution_id None 2009-07-24 15:55 cliechti
status_id Open 2009-07-24 15:55 cliechti
status_id Pending 2009-07-24 12:56 eblot
close_date 2009-07-23 23:54 2009-07-24 12:56 eblot
status_id Open 2009-07-23 23:54 cliechti
close_date - 2009-07-23 23:54 cliechti
status_id Pending 2009-07-22 18:19 eblot
close_date 2009-07-21 23:43 2009-07-22 18:19 eblot
close_date - 2009-07-21 23:43 cliechti
assigned_to nobody 2009-07-21 23:43 cliechti
status_id Open 2009-07-21 23:43 cliechti
File Added 311924: hsserial.py 2009-02-04 00:26 eblot
summary High baudrates no supported on Mac OS X 2009-02-04 00:25 eblot