Mercurial > ~darius > hgwebdir.cgi > ZigBee
view zbmux.tac @ 24:c6ee9eae9e49
Add some tests to zb.py.
author | Daniel O'Connor <darius@dons.net.au> |
---|---|
date | Tue, 16 Apr 2013 08:20:15 +0930 |
parents | 08535b12504f |
children |
line wrap: on
line source
# # Mux the ZB module to TCP ports # # Run me like so... # twistd -l zbmux.log --pidfile=zbmux.pid -y zbmux.tac # # Copyright (c) 2009 # Daniel O'Connor <darius@dons.net.au>. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # from twisted.application import internet, service 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, string portname = '/dev/cuaU0' baudrate = 38400 lognamebase = '/home/darius/projects/ZigBee/zbmux-%d.log' baseport = 1080 zbids = [1, 2, 3] 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.terminal.eraseDisplay() self.terminal.resetPrivateModes([]) # Send the last whole line we've seen out for l in self.factory.lastlines: self.message(l + '\n') 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 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.terminal.write(message) class ZBFactory(protocol.ServerFactory): """Factory for a ZB module Represents a remote ZB module and has zero or more clients and a log file. """ protocol = ZBClient def __init__(self, zbid, lognamebase): self.zbid = zbid self.clients = [] self.tmpline = "" self.lastlines = [] # Open logger self.logger = logging.getLogger('Zigbee-%d' % (zbid)) self.logger.setLevel(logging.DEBUG) # Add the log message handler to the logger handler = logging.handlers.RotatingFileHandler( lognamebase % (zbid), maxBytes = 5 * 1024 * 1024, backupCount = 10) self.logger.addHandler(handler) def message(self, zbid, message): """Called when we get a message, check it's for us - if it is log it and write to our clients""" if zbid != self.zbid: return for c in self.clients: c.message(message) # Logger is line oriented, convert from packet oriented here self.tmpline = self.tmpline + message tmp = self.tmpline.split('\n') for l in tmp[0:-1]: self.lastlines.append(l) self.lastlines = self.lastlines[-5:] self.logger.debug(l.replace('\n', '')) self.tmpline = tmp[-1] class ZBProto(Protocol): """Protocol to handle packets from the ZB module on the serial port""" def __init__(self): self.pkts = zb.Packets() self.factories = [] def dataReceived(self, data): """Parses data from ZB module into packets, calls each factory if a RX packet is received""" #log.msg("Read data " + data) if self.pkts.processstr(data) > 0: while len(self.pkts.pktq) > 0: a = self.pkts.pktq.pop(0) #log.msg("type is " + str(type(a))) if type(a) == type(zb.RX_16_Bit()): #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 = 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)) application = service.Application('zbmux') # ZigBee serial protocol handler zbproto = ZBProto() SerialPort(zbproto, portname, reactor, baudrate = 38400) # Per-module TCP listener for id in zbids: f = ZBFactory(id, lognamebase) f.zbproto = zbproto f.protocol = lambda: TelnetTransport(TelnetBootstrapProtocol, insults.ServerProtocol, ZBClient) zbproto.factories.append(f) internet.TCPServer(baseport + id, f).setServiceParent( service.IServiceCollection(application)) ###################################################################### # # These lines tell Emacs to edit this file in Python mode #;;; Local Variables: *** #;;; mode:python *** #;;; End: ***