Mercurial > ~darius > hgwebdir.cgi > ZigBee
comparison zbmux.py @ 12:a3ec3f2988ac
Initial commit of zbmux.
This program demultiplexes packets from remote ZB modules to feed into a log
file. Also allows user(s) to telnet to a port to talk to a particular module.
Needs more work. eg - TCP connections should be in raw mode, not line.
- There is no way to access statistics for each module.
author | darius@Inchoate |
---|---|
date | Tue, 13 Jan 2009 12:17:02 +1030 |
parents | |
children | ac60a9244bdf |
comparison
equal
deleted
inserted
replaced
11:75f785a09e2e | 12:a3ec3f2988ac |
---|---|
1 # | |
2 # Mux the ZB module to TCP ports | |
3 # | |
4 # Copyright (c) 2009 | |
5 # Daniel O'Connor <darius@dons.net.au>. All rights reserved. | |
6 # | |
7 # Redistribution and use in source and binary forms, with or without | |
8 # modification, are permitted provided that the following conditions | |
9 # are met: | |
10 # 1. Redistributions of source code must retain the above copyright | |
11 # notice, this list of conditions and the following disclaimer. | |
12 # 2. Redistributions in binary form must reproduce the above copyright | |
13 # notice, this list of conditions and the following disclaimer in the | |
14 # documentation and/or other materials provided with the distribution. | |
15 # | |
16 # THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |
17 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
18 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
19 # ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE | |
20 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
21 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
22 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
23 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
24 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
25 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
26 # SUCH DAMAGE. | |
27 # | |
28 | |
29 from twisted.internet.serialport import SerialPort | |
30 from twisted.internet.protocol import Protocol | |
31 from twisted.protocols import basic | |
32 from twisted.internet import protocol, reactor | |
33 from twisted.python import log | |
34 import sys, zb, logging, logging.handlers | |
35 | |
36 portname = '/dev/cuaU0' | |
37 baudrate = 38400 | |
38 lognamebase = '/tmp/zbmux-%d.log' | |
39 baseport = 1080 | |
40 zbids = [1, 2] | |
41 | |
42 class ZBClient(basic.LineReceiver): | |
43 """Client for the TCP connection""" | |
44 | |
45 def connectionMade(self): | |
46 log.msg("Got new client") | |
47 self.factory.clients.append(self) | |
48 if self.factory.lastline != None: | |
49 self.message(self.factory.lastline) | |
50 | |
51 def connectionLost(self, reason): | |
52 log.msg("Lost a client") | |
53 self.factory.clients.remove(self) | |
54 | |
55 def lineReceived(self, line): | |
56 """Got a line - send it to our ZB module""" | |
57 #log.msg("Got line " + line) | |
58 self.factory.proto.sendData(self.factory.zbid, line + '\n') | |
59 | |
60 def message(self, message): | |
61 """Called to write a mesage to our client""" | |
62 self.transport.write(message) | |
63 | |
64 class ZBFactory(protocol.ServerFactory): | |
65 """Factory for a ZB module | |
66 | |
67 Represents a remote ZB module and has zero or more clients and a log file. | |
68 """ | |
69 protocol = ZBClient | |
70 | |
71 def __init__(self, zbid, proto, lognamebase): | |
72 self.zbid = zbid | |
73 self.proto = proto | |
74 self.clients = [] | |
75 self.tmpline = "" | |
76 self.lastline = None | |
77 | |
78 # Open logger | |
79 self.logger = logging.getLogger('Zigbee-%d' % (zbid)) | |
80 self.logger.setLevel(logging.DEBUG) | |
81 | |
82 # Add the log message handler to the logger | |
83 handler = logging.handlers.RotatingFileHandler( | |
84 lognamebase % (zbid), maxBytes = 20 * 1024, backupCount = 5) | |
85 | |
86 self.logger.addHandler(handler) | |
87 | |
88 def message(self, zbid, message): | |
89 """Called when we get a message, check it's for us - if it is log it and write to our clients""" | |
90 if zbid != self.zbid: | |
91 return | |
92 | |
93 for c in self.clients: | |
94 c.message(message) | |
95 | |
96 # Logger is line oriented, convert from packet oriented here | |
97 self.tmpline = self.tmpline + message | |
98 tmp = self.tmpline.split('\n') | |
99 for l in tmp[0:-1]: | |
100 self.lastline = l # Stores last seen line for new clients | |
101 self.logger.debug(l.replace('\n', '')) | |
102 self.tmpline = tmp[-1] | |
103 | |
104 class ZBProto(Protocol): | |
105 """Protocol to handle packets from the ZB module on the serial port""" | |
106 def __init__(self): | |
107 self.pkts = zb.Packets() | |
108 self.factories = [] | |
109 | |
110 def dataReceived(self, data): | |
111 """Parses data from ZB module into packets, calls each factory if a RX packet is received""" | |
112 #log.msg("Read data " + data) | |
113 if self.pkts.processstr(data) > 0: | |
114 while len(self.pkts.pktq) > 0: | |
115 a = self.pkts.pktq.pop(0) | |
116 #log.msg("type is " + str(type(a))) | |
117 if type(a) == type(zb.RX_16_Bit()): | |
118 #log.msg("Rx'd from %d => %s" % (a.sender, a.payloadstr)) | |
119 for f in self.factories: | |
120 f.message(a.sender, a.payloadstr) | |
121 | |
122 def sendData(self, zbid, data): | |
123 """Sends a chunk of data to our ZB module""" | |
124 #log.msg("%d <= %s" % (zbid, data)) | |
125 | |
126 # Chop up data into pieces the module can handle | |
127 maxsz = 10 | |
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)): | |
130 p = zb.TX_16_Bit(zbid, data[i:j]) | |
131 self.transport.write(p.Pack()) | |
132 #log.msg("sent " + str(p)) | |
133 | |
134 if __name__ == '__main__': | |
135 logFile = sys.stdout | |
136 log.startLogging(logFile) | |
137 | |
138 # ZigBee serial protocol handler | |
139 zbproto = ZBProto() | |
140 SerialPort(zbproto, portname, reactor, baudrate = 38400) | |
141 | |
142 # Per-module TCP listener | |
143 for id in zbids: | |
144 zbfactory = ZBFactory(id, zbproto, lognamebase) | |
145 zbproto.factories.append(zbfactory) | |
146 reactor.listenTCP(baseport + id, zbfactory) | |
147 | |
148 reactor.run() |