changeset 14:ac60a9244bdf

Use proper telnet protocol classes. Means we use raw/character at a time stuff and don't get extra echos. Keeps track of each line to log it to the file as well as printing the last seen line on client connect.
author darius@Inchoate
date Sat, 17 Jan 2009 14:42:51 +1030
parents 729f2393f296
children a472d6eab97e
files zbmux.py
diffstat 1 files changed, 53 insertions(+), 21 deletions(-) [+]
line wrap: on
line diff
--- a/zbmux.py	Sat Jan 17 14:39:50 2009 +1030
+++ b/zbmux.py	Sat Jan 17 14:42:51 2009 +1030
@@ -28,10 +28,12 @@
 
 from twisted.internet.serialport import SerialPort
 from twisted.internet.protocol import Protocol
+from twisted.conch.telnet import TelnetTransport, TelnetBootstrapProtocol
+from twisted.conch.insults import insults
 from twisted.protocols import basic
 from twisted.internet import protocol, reactor
 from twisted.python import log
-import sys, zb, logging, logging.handlers
+import sys, zb, logging, logging.handlers, string
 
 portname = '/dev/cuaU0'
 baudrate = 38400
@@ -39,27 +41,52 @@
 baseport = 1080
 zbids = [1, 2]
 
-class ZBClient(basic.LineReceiver):
+class ZBClient(insults.TerminalProtocol):
     """Client for the TCP connection"""
-
+    #: Time to wait before sending pending data (seconds)
+    QUEUE_TIME = 0.1
+    
     def connectionMade(self):
         log.msg("Got new client")
-        self.factory.clients.append(self)
+        log.msg("Me - %s, terminal - %s" % (str(type(self)), str(type(self.terminal))))
+        self.terminal.eraseDisplay()
+        self.terminal.resetPrivateModes([])
+        
+        # Send the last whole line we've seen out
         if self.factory.lastline != None:
             self.message(self.factory.lastline)
+            
+        self.pending = ""
+        self.pendtimer = None
+        self.factory.clients.append(self)
         
     def connectionLost(self, reason):
         log.msg("Lost a client")
         self.factory.clients.remove(self)
-
-    def lineReceived(self, line):
-        """Got a line - send it to our ZB module"""
-        #log.msg("Got line " + line)
-        self.factory.proto.sendData(self.factory.zbid, line + '\n')
-
+        
+    def keystrokeReceived(self, keyID, modifier):
+        """Got some data, add it to the pending output queue"""
+        if modifier != None:
+            print "Received unhandled modifier: %s" % (str(modifier))
+            return
+        #if keyID not in string.printable:
+        #    print "Received unhandled keyID: %r" % (keyID,)
+        #    return
+        #log.msg("Got key ->%s<-" % (keyID))
+        self.pending = self.pending + keyID
+        if self.pendtimer == None:
+            self.pendtimer = reactor.callLater(self.QUEUE_TIME, self.sendData)
+            
+    def sendData(self):
+        """Send pending data to module"""
+        #log.msg("sending " + self.pending)
+        self.factory.zbproto.sendData(self.factory.zbid, self.pending)
+        self.pending = ""
+        self.pendtimer = None
+        
     def message(self, message):
         """Called to write a mesage to our client"""
-        self.transport.write(message)
+        self.terminal.write(message)
         
 class ZBFactory(protocol.ServerFactory):
     """Factory for a ZB module
@@ -68,9 +95,8 @@
 """
     protocol = ZBClient
     
-    def __init__(self, zbid, proto, lognamebase):
+    def __init__(self, zbid, lognamebase):
         self.zbid = zbid
-        self.proto = proto
         self.clients = []
         self.tmpline = ""
         self.lastline = None
@@ -118,19 +144,21 @@
                     #log.msg("Rx'd from %d => %s" % (a.sender, a.payloadstr))
                     for f in self.factories:
                         f.message(a.sender, a.payloadstr)
-                    
+                if type(a) == type(zb.TX_Status()):
+                    #log.msg("Tx status for frame %d is %s" % (a.frameid, a.statusMsg))
+                    pass
+                
     def sendData(self, zbid, data):
         """Sends a chunk of data to our ZB module"""
         #log.msg("%d <= %s" % (zbid, data))
-
+        
         # Chop up data into pieces the module can handle
-        maxsz = 10
-        #maxsz = zb.TX_16_Bit.PKT_MAX_PAYLOAD
+        maxsz = zb.TX_16_Bit.PKT_MAX_PAYLOAD
         for i, j in zip(range(0, len(data), maxsz), range(maxsz, len(data) + maxsz, maxsz)):
             p = zb.TX_16_Bit(zbid, data[i:j])
             self.transport.write(p.Pack())
             #log.msg("sent " + str(p))
-        
+            
 if __name__ == '__main__':
     logFile = sys.stdout
     log.startLogging(logFile)
@@ -141,8 +169,12 @@
 
     # Per-module TCP listener
     for id in zbids:
-        zbfactory = ZBFactory(id, zbproto, lognamebase)
-        zbproto.factories.append(zbfactory)
-        reactor.listenTCP(baseport + id, zbfactory)
+        f = ZBFactory(id, lognamebase)
+        f.zbproto = zbproto
+        f.protocol = lambda: TelnetTransport(TelnetBootstrapProtocol,
+                                             insults.ServerProtocol,
+                                             ZBClient)
+        zbproto.factories.append(f)
+        reactor.listenTCP(baseport + id, f)
 
     reactor.run()