Async serial communication/threads sharing data
Jean-Paul Calderone
exarkun at divmod.com
Mon Mar 23 08:16:26 EDT 2009
On Mon, 23 Mar 2009 05:30:04 -0500, Nick Craig-Wood <nick at craig-wood.com> wrote:
>Jean-Paul Calderone <exarkun at divmod.com> wrote:
> [snip]
>>
>> In the case of a TCP to serial forwarder, you don't actually have to
>> implement either a producer or a consumer, since both the TCP connection
>> and the serial connection are already both producers and consumers. All
>> you need to do is hook them up to each other so that when the send buffer
>> of one fills up, the other one gets paused, and when the buffer is empty
>> again, it gets resumed.
>
>I eventually came up with this which seems to work, but I'm not sure
>it is the best way of doing it as it had to mess about with the
>twisted internals to get the number of bytes in the serial port
>output buffer.
This is sort of on the right track. Here's how to do it without
touching implementation details:
>
>class SerialPort(protocol.Protocol):
> """Create a serial port connection and pass data from it to a known list of TCP ports."""
>
> def __init__(self, port, reactor, baudrate, log_name=None):
> self.tcp_ports = []
> self.serial = serialport.SerialPort(self, reactor, port, baudrate, rtscts=0)
Here, register this object to receive buffer full and not-full events from
the serial port:
self.serial.registerProducer(self, True)
And an attribute to keep track of our state:
self.paused = False
> self.log = None
> if log_name is not None:
> self.log = file('%s-0' % log_name, 'w')
>
I'm not exactly sure where `self.tcp_ports´ gets populated, so I'll make a method to do it:
def addPort(self, port):
if self.paused:
port.transport.pauseProducing()
self.tcp_ports.append(port)
Now a method to handle serial port buffer full events:
def pauseProducing(self):
self.paused = True
for port in self.tcp_ports:
port.transport.pauseProducing()
And a method to handle buffer no longer full events:
def resumeProducing(self):
self.paused = False
for port in self.tcp_ports:
port.transport.resumeProducing()
With these, you can get rid of `throttle´ entirely.
> def write(self, data):
> """Write data to the serial port."""
> self.serial.write(data)
> if self.log:
> self.log.write(data)
> self.throttle()
>
> def throttle(self):
> """
> Pause the inputs if there is too much data in the output buffer
> """
> bytes_in_buffer = len(self.serial.dataBuffer) + self.serial._tempDataLen
> too_full = bytes_in_buffer > 1024
> for tcp_port in self.tcp_ports:
> if too_full:
> tcp_port.transport.pauseProducing()
> else:
> tcp_port.transport.resumeProducing()
> if too_full:
> reactor.callLater(0.1, self.throttle)
>
Jean-Paul
More information about the Python-list
mailing list