Is there a way to connect to an RFC2217 networked serial port with Twisted Python?
Pyserial seems to support it via the serial.serial_for_url("rfc2217://...")
function. And they indicate that twisted uses pyserial for managing serial connections, however twisted.internet.serialport.SerialPort
seems to expect a port name or number which suggests it is just passing this to the serial.Serial
constructor.
I can use socat to create a PTY externally and pass the dev name to twisted which works fine, but I was wondering if I can bypass this step by using the pyserial support directly.
socat PTY,link=/dev/myport TCP:192.168.1.222:9001
Edit: The pyserial faq suggests this modification for instantiating serial objects:
try:
s = serial.serial_for_url(...)
except AttributeError:
s = serial.Serial(...)
Not sure if this helps though...
I have come to the conclusion that using Pyserial's RFC2217 support with Twisted Python is non-trivial. Pyserial's implementation of RFC2217, besides being currently experimental, uses threads to manage the socket connection which they state as being a problem for select based applications:
The current implementation starts a thread that keeps reading from the (internal) socket. The thread is managed automatically by the rfc2217.Serial port object on open()/close(). However it may be a problem for user applications that like to use select instead of threads.
It is fairly straight forward to subclass t.i.serialport.SerialPort and overwrite the _serialFactory method (which creates the pyserial object to be used for accessing the serial port)
class SerialPort(serialport.SerialPort):
def _serialFactory(self, dev, *args, **kwargs):
" pyserial recommends the following for supporting serial urls "
try:
return serial.serial_for_url(dev)
except AttributeError:
return serial.Serial(dev, *args, **kwargs)
However, the resulting object lacks a file descriptor and so the fileno()
method (used internally by t.i._posixserialport
) throws an exception.
--- <exception caught here> ---
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/twisted/internet/base.py", line 1204, in mainLoop
self.doIteration(t)
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/twisted/internet/selectreactor.py", line 105, in doSelect
[], timeout)
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/twisted/internet/_posixserialport.py", line 48, in fileno
return self._serial.fd
exceptions.AttributeError: 'Serial' object has no attribute 'fd'
The current workarounds are to either use socat
as described in the question, or for the network serial server I'm using (Brainboxes ES-842) you can configure it in "Raw TCP" mode instead of "Telnet/RFC2217" mode and just use your existing protocol over a TCP connection (as long as you're not depending on flow control or other serial control lines and can use a predefined fixed baud rate).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With