comparison zbmux.py @ 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 a3ec3f2988ac
children a472d6eab97e
comparison
equal deleted inserted replaced
13:729f2393f296 14:ac60a9244bdf
26 # SUCH DAMAGE. 26 # SUCH DAMAGE.
27 # 27 #
28 28
29 from twisted.internet.serialport import SerialPort 29 from twisted.internet.serialport import SerialPort
30 from twisted.internet.protocol import Protocol 30 from twisted.internet.protocol import Protocol
31 from twisted.conch.telnet import TelnetTransport, TelnetBootstrapProtocol
32 from twisted.conch.insults import insults
31 from twisted.protocols import basic 33 from twisted.protocols import basic
32 from twisted.internet import protocol, reactor 34 from twisted.internet import protocol, reactor
33 from twisted.python import log 35 from twisted.python import log
34 import sys, zb, logging, logging.handlers 36 import sys, zb, logging, logging.handlers, string
35 37
36 portname = '/dev/cuaU0' 38 portname = '/dev/cuaU0'
37 baudrate = 38400 39 baudrate = 38400
38 lognamebase = '/tmp/zbmux-%d.log' 40 lognamebase = '/tmp/zbmux-%d.log'
39 baseport = 1080 41 baseport = 1080
40 zbids = [1, 2] 42 zbids = [1, 2]
41 43
42 class ZBClient(basic.LineReceiver): 44 class ZBClient(insults.TerminalProtocol):
43 """Client for the TCP connection""" 45 """Client for the TCP connection"""
44 46 #: Time to wait before sending pending data (seconds)
47 QUEUE_TIME = 0.1
48
45 def connectionMade(self): 49 def connectionMade(self):
46 log.msg("Got new client") 50 log.msg("Got new client")
47 self.factory.clients.append(self) 51 log.msg("Me - %s, terminal - %s" % (str(type(self)), str(type(self.terminal))))
52 self.terminal.eraseDisplay()
53 self.terminal.resetPrivateModes([])
54
55 # Send the last whole line we've seen out
48 if self.factory.lastline != None: 56 if self.factory.lastline != None:
49 self.message(self.factory.lastline) 57 self.message(self.factory.lastline)
58
59 self.pending = ""
60 self.pendtimer = None
61 self.factory.clients.append(self)
50 62
51 def connectionLost(self, reason): 63 def connectionLost(self, reason):
52 log.msg("Lost a client") 64 log.msg("Lost a client")
53 self.factory.clients.remove(self) 65 self.factory.clients.remove(self)
54 66
55 def lineReceived(self, line): 67 def keystrokeReceived(self, keyID, modifier):
56 """Got a line - send it to our ZB module""" 68 """Got some data, add it to the pending output queue"""
57 #log.msg("Got line " + line) 69 if modifier != None:
58 self.factory.proto.sendData(self.factory.zbid, line + '\n') 70 print "Received unhandled modifier: %s" % (str(modifier))
59 71 return
72 #if keyID not in string.printable:
73 # print "Received unhandled keyID: %r" % (keyID,)
74 # return
75 #log.msg("Got key ->%s<-" % (keyID))
76 self.pending = self.pending + keyID
77 if self.pendtimer == None:
78 self.pendtimer = reactor.callLater(self.QUEUE_TIME, self.sendData)
79
80 def sendData(self):
81 """Send pending data to module"""
82 #log.msg("sending " + self.pending)
83 self.factory.zbproto.sendData(self.factory.zbid, self.pending)
84 self.pending = ""
85 self.pendtimer = None
86
60 def message(self, message): 87 def message(self, message):
61 """Called to write a mesage to our client""" 88 """Called to write a mesage to our client"""
62 self.transport.write(message) 89 self.terminal.write(message)
63 90
64 class ZBFactory(protocol.ServerFactory): 91 class ZBFactory(protocol.ServerFactory):
65 """Factory for a ZB module 92 """Factory for a ZB module
66 93
67 Represents a remote ZB module and has zero or more clients and a log file. 94 Represents a remote ZB module and has zero or more clients and a log file.
68 """ 95 """
69 protocol = ZBClient 96 protocol = ZBClient
70 97
71 def __init__(self, zbid, proto, lognamebase): 98 def __init__(self, zbid, lognamebase):
72 self.zbid = zbid 99 self.zbid = zbid
73 self.proto = proto
74 self.clients = [] 100 self.clients = []
75 self.tmpline = "" 101 self.tmpline = ""
76 self.lastline = None 102 self.lastline = None
77 103
78 # Open logger 104 # Open logger
116 #log.msg("type is " + str(type(a))) 142 #log.msg("type is " + str(type(a)))
117 if type(a) == type(zb.RX_16_Bit()): 143 if type(a) == type(zb.RX_16_Bit()):
118 #log.msg("Rx'd from %d => %s" % (a.sender, a.payloadstr)) 144 #log.msg("Rx'd from %d => %s" % (a.sender, a.payloadstr))
119 for f in self.factories: 145 for f in self.factories:
120 f.message(a.sender, a.payloadstr) 146 f.message(a.sender, a.payloadstr)
121 147 if type(a) == type(zb.TX_Status()):
148 #log.msg("Tx status for frame %d is %s" % (a.frameid, a.statusMsg))
149 pass
150
122 def sendData(self, zbid, data): 151 def sendData(self, zbid, data):
123 """Sends a chunk of data to our ZB module""" 152 """Sends a chunk of data to our ZB module"""
124 #log.msg("%d <= %s" % (zbid, data)) 153 #log.msg("%d <= %s" % (zbid, data))
125 154
126 # Chop up data into pieces the module can handle 155 # Chop up data into pieces the module can handle
127 maxsz = 10 156 maxsz = zb.TX_16_Bit.PKT_MAX_PAYLOAD
128 #maxsz = zb.TX_16_Bit.PKT_MAX_PAYLOAD
129 for i, j in zip(range(0, len(data), maxsz), range(maxsz, len(data) + maxsz, maxsz)): 157 for i, j in zip(range(0, len(data), maxsz), range(maxsz, len(data) + maxsz, maxsz)):
130 p = zb.TX_16_Bit(zbid, data[i:j]) 158 p = zb.TX_16_Bit(zbid, data[i:j])
131 self.transport.write(p.Pack()) 159 self.transport.write(p.Pack())
132 #log.msg("sent " + str(p)) 160 #log.msg("sent " + str(p))
133 161
134 if __name__ == '__main__': 162 if __name__ == '__main__':
135 logFile = sys.stdout 163 logFile = sys.stdout
136 log.startLogging(logFile) 164 log.startLogging(logFile)
137 165
138 # ZigBee serial protocol handler 166 # ZigBee serial protocol handler
139 zbproto = ZBProto() 167 zbproto = ZBProto()
140 SerialPort(zbproto, portname, reactor, baudrate = 38400) 168 SerialPort(zbproto, portname, reactor, baudrate = 38400)
141 169
142 # Per-module TCP listener 170 # Per-module TCP listener
143 for id in zbids: 171 for id in zbids:
144 zbfactory = ZBFactory(id, zbproto, lognamebase) 172 f = ZBFactory(id, lognamebase)
145 zbproto.factories.append(zbfactory) 173 f.zbproto = zbproto
146 reactor.listenTCP(baseport + id, zbfactory) 174 f.protocol = lambda: TelnetTransport(TelnetBootstrapProtocol,
175 insults.ServerProtocol,
176 ZBClient)
177 zbproto.factories.append(f)
178 reactor.listenTCP(baseport + id, f)
147 179
148 reactor.run() 180 reactor.run()