On Mon, 23 Mar 2009 05:30:04 -0500, Nick Craig-Wood <n...@craig-wood.com> wrote:
Jean-Paul Calderone <exar...@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
--
http://mail.python.org/mailman/listinfo/python-list

Reply via email to