Jean-Paul Calderone <exar...@divmod.com> wrote: > 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:
Thank you for that! See below for the complete prog with your suggested modifications. That seems to solve the problem - I can see the writer pausing and unpausing at the serial port rate. write 16446 write 6430 pause producing resume producing write 65536 write 56724 pause producing resume producing write 65536 write 65536 pause producing It has exposed a problem with the sender not throttling properly now, but I guess that is progress! Thanks for your help Here is the complete program FYI with your suggested mods. #!/usr/bin/python """Transfer data between a serial port and one (or more) TCP connections. options: -h, --help: this help -p, --port=PORT: port, a number, default = 0 or a device name -b, --baud=BAUD: baudrate, default 115200 -t, --tcp=PORT: TCP port number, default 1234 -l, --log: log data streams to 'snifter-0', 'snifter-1' -L, --log_name=NAME: log data streams to '<NAME>-0', '<NAME>-1' """ import sys import getopt from twisted.internet import reactor, protocol, serialport from zope.interface import implements from twisted.internet import protocol, interfaces # FIXME set serial buffer size? SEND_LIMIT 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) self.serial.registerProducer(self, True) self.paused = False self.log = None if log_name is not None: self.log = file('%s-0' % log_name, 'w') def add_tcp(self, tcp_port): """Add a TCPPort to those receiving serial data.""" if self.paused: tcp_port.transport.pauseProducing() self.tcp_ports.append(tcp_port) def del_tcp(self, tcp_port): """Remove a TCPPort from the those receiving serial data.""" self.tcp_ports.remove(tcp_port) def write(self, data): """Write data to the serial port.""" self.serial.write(data) if self.log: self.log.write(data) def pauseProducing(self): """Pause producing event""" print "pause producing" self.paused = True for port in self.tcp_ports: port.transport.pauseProducing() def resumeProducing(self): """Resume producing event""" print "resume producing" self.paused = False for port in self.tcp_ports: port.transport.resumeProducing() def stopProducing(self): """Stop producing event""" print "stop producing" def dataReceived(self, data): """Pass any received data to the list of TCPPorts.""" for tcp_port in self.tcp_ports: tcp_port.write(data) class TCPPort(protocol.Protocol): """Create a TCP server connection and pass data from it to the serial port.""" def __init__(self, serial, log_name, index): """Add this TCPPort to the SerialPort.""" self.serial = serial self.serial.add_tcp(self) self.log = None if log_name is not None: self.log = file('%s-%d' % (log_name, index+1), 'w') def __del__(self): """Remove this TCPPort from the SerialPort.""" self.serial.del_tcp(self) def dataReceived(self, data): """Pass received data to the SerialPort.""" print "write", len(data) self.serial.write(data) def write(self, data): """Write data to the TCP port.""" self.transport.write(data) if self.log is not None: self.log.write(data) class TCPPortFactory(protocol.ServerFactory): """Factory to create TCPPort protocol instances, an instanced SerialPort must be passed in.""" def __init__(self, serial, log_name=None): self.serial = serial self.log_name = log_name self.index = 0 def buildProtocol(self, addr): """Build a TCPPort, passing in the instanced SerialPort.""" p = TCPPort(self.serial, self.log_name, self.index) self.index += 1 p.factory = self return p def usage(text=None): print >>sys.stderr, """Syntax: %s [options]\n%s""" % (sys.argv[0], >>__doc__) if text: print >>sys.stderr, text def main(): """Parse the command line and run the UI""" try: opts, args = getopt.getopt(sys.argv[1:], "hp:b:t:lL:", ["help", "port=", "baud=", "tcp=", "log", "log_name="]) except getopt.GetoptError, e: usage(e) sys.exit(2) tty_port = 0 baudrate = 9600 tcp_port = 1234 log_name = None for o, a in opts: if o in ("-h", "--help"): usage() sys.exit() elif o in ("-p", "--port"): try: tty_port = int(a) except ValueError: tty_port = a elif o in ("-b", "--baud"): try: baudrate = int(a) except ValueError: usage("Bad baud rate %r" % a) elif o in ("-t", "--tcp"): try: tcp_port = int(a) except ValueError: usage("Bad TCP port %r" % a) elif o in ("-l", "--log"): log_name = 'snifter' elif o in ("-L", "--log_name"): log_name = a serial_port = SerialPort(reactor, tty_port, baudrate, log_name) tcp_port_factory = TCPPortFactory(serial_port, log_name) reactor.listenTCP(tcp_port, tcp_port_factory) reactor.run() if __name__ == "__main__": main() -- Nick Craig-Wood <n...@craig-wood.com> -- http://www.craig-wood.com/nick -- http://mail.python.org/mailman/listinfo/python-list