Mercurial > ~darius > hgwebdir.cgi > ZigBee
comparison zb.py @ 11:75f785a09e2e
Add license.
Split test stuff into a separate file.
Fix some bugs..
- Default frame ID to 1 so we get status replies by default.
- Correct address generation routine for TX packets.
Add doc strings and epydoc variable comments.
author | darius@Inchoate |
---|---|
date | Tue, 13 Jan 2009 12:14:13 +1030 |
parents | 4c91fdfc862e |
children | 729f2393f296 |
comparison
equal
deleted
inserted
replaced
10:4c91fdfc862e | 11:75f785a09e2e |
---|---|
1 import serial, inspect, time | 1 # |
2 # Code to talk to MaxStream ZigBee modules in API (no escaped | |
3 # characters) | |
4 # | |
5 # Copyright (c) 2009 | |
6 # Daniel O'Connor <darius@dons.net.au>. All rights reserved. | |
7 # | |
8 # Redistribution and use in source and binary forms, with or without | |
9 # modification, are permitted provided that the following conditions | |
10 # are met: | |
11 # 1. Redistributions of source code must retain the above copyright | |
12 # notice, this list of conditions and the following disclaimer. | |
13 # 2. Redistributions in binary form must reproduce the above copyright | |
14 # notice, this list of conditions and the following disclaimer in the | |
15 # documentation and/or other materials provided with the distribution. | |
16 # | |
17 # THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |
18 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
19 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
20 # ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE | |
21 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
22 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
23 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
24 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
25 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
26 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
27 # SUCH DAMAGE. | |
28 # | |
29 """MaxStream ZigBee module API interface | |
30 | |
31 This code expects the module to be in API mode 1 (no escape | |
32 characters), ie you have done something like.. | |
33 +++ | |
34 ATAP=1 | |
35 ATWR | |
36 ATCN | |
37 | |
38 See here for details | |
39 http://www.digi.com/products/wireless/point-multipoint/xbee-series1-moduledocs.jsp | |
40 """ | |
41 | |
42 import inspect | |
2 | 43 |
3 def easyord(i): | 44 def easyord(i): |
45 """Helper function to return the ordinal of a string, or just the | |
46 passed in value""" | |
4 if (type(i) != type(str())): | 47 if (type(i) != type(str())): |
5 return i | 48 return i |
6 else: | 49 else: |
7 return ord(i) | 50 return ord(i) |
8 | 51 |
9 class PktBase(object): | 52 class PktBase(object): |
53 """Base class for all packet types""" | |
10 PKT_MAXLEN = 2 ** 16 | 54 PKT_MAXLEN = 2 ** 16 |
55 PKT_TYPE = None | |
11 | 56 |
12 def __init__(self): | 57 def __init__(self): |
13 print "Constructing " + self.__class__.__name__ | 58 #print "Constructing " + self.__class__.__name__ |
14 | 59 pass |
60 | |
15 def Encapsulate(self): | 61 def Encapsulate(self): |
62 """Encapsulate the packet""" | |
16 return Packets.Encapsulate([self.PKT_TYPE] + self.data) | 63 return Packets.Encapsulate([self.PKT_TYPE] + self.data) |
64 | |
65 def Pack(self): | |
66 """Return string version of encapsulated packet""" | |
67 return reduce(lambda x, y: str(x) + str(y), self.Encapsulate()) | |
17 | 68 |
18 def resize(self, dlen): | 69 def resize(self, dlen): |
19 """Ensure the data list can hold at least len elements (0 fill)""" | 70 """Ensure the data list can hold at least len elements (0 fill)""" |
20 if (len(self._data) < dlen): | 71 if (len(self._data) < dlen): |
21 self._data = (self._data + [0] * dlen)[0:dlen] | 72 self._data = (self._data + [0] * dlen)[0:dlen] |
22 | 73 |
74 @staticmethod | |
23 def _checklist(list, min = 0, max = 255, maxlen = None): | 75 def _checklist(list, min = 0, max = 255, maxlen = None): |
24 if (maxlen != None and len(list) > maxlen): | 76 if (maxlen != None and len(list) > maxlen): |
25 raise ValueError("must have %d elements" % (maxlen)) | 77 raise ValueError("must have %d elements" % (maxlen)) |
26 | 78 |
27 for i in xrange(len(list)): | 79 for i in xrange(len(list)): |
28 if (easyord(list[i]) < min or easyord(list[i]) > max): | 80 if (easyord(list[i]) < min or easyord(list[i]) > max): |
29 raise ValueError("element %d (= %d) out of range must be between %d and %d inclusive" % | 81 raise ValueError("element %d (= %d) out of range must be between %d and %d inclusive" % |
30 (i, ord(list[i]), min, max)) | 82 (i, ord(list[i]), min, max)) |
31 _checklist = staticmethod(_checklist) | |
32 | 83 |
33 class TXPkts(PktBase): | 84 class TXPkts(PktBase): |
34 """Base class for all packets that go to the module""" | 85 """Base class for all packets that go to the module""" |
35 | 86 |
87 def __init__(self): | |
88 # Frame ID of 0 will prevent TX status pakets being sent | |
89 self._frameid = 1 | |
90 | |
36 def setframeid(self, value): | 91 def setframeid(self, value): |
37 if (value < 0 or value > 255): | 92 if (value < 0 or value > 255): |
38 raise ValueError("FrameID must be 0-255") | 93 raise ValueError("FrameID must be 0-255") |
39 self._frameid = value | 94 self._frameid = value |
40 frameid = property(lambda s: s._frameid, setframeid) | 95 frameid = property(lambda s: s._frameid, setframeid) |
41 | 96 |
42 | |
43 class AT_Cmd(TXPkts): | 97 class AT_Cmd(TXPkts): |
98 """AT command packet""" | |
99 | |
44 PKT_TYPE = 0x08 | 100 PKT_TYPE = 0x08 |
45 PKT_DESC = "AT Command" | 101 PKT_DESC = "AT Command" |
46 | 102 |
47 def __init__(self, cmd = None, cmdarg = None): | 103 def __init__(self, cmd = None, cmdarg = None): |
104 self.frameid = 1 # XXX: why do I need to dupe this? | |
105 self.cmdarg = [] | |
106 | |
48 super(AT_Cmd, self).__init__() | 107 super(AT_Cmd, self).__init__() |
49 if (cmd != None): | 108 if (cmd != None): |
50 self.cmd = cmd | 109 self.cmd = cmd |
51 if (cmdarg != None): | 110 if (cmdarg != None): |
52 self.cmdarg = cmdarg | 111 self.cmdarg = cmdarg |
53 | |
54 self.frameid = 0 | |
55 self.cmdarg = [] | |
56 | 112 |
57 def setcmd(self, value): | 113 def setcmd(self, value): |
58 if (len(value) != 2): | 114 if (len(value) != 2): |
59 raise ValueError("must have 2 elements") | 115 raise ValueError("must have 2 elements") |
60 self._checklist(value, ord('0'), ord('z')) | 116 self._checklist(value, ord('0'), ord('z')) |
69 def getdata(self): | 125 def getdata(self): |
70 return([self.frameid] + map(ord, self.cmd) + map(easyord, self.cmdarg)) | 126 return([self.frameid] + map(ord, self.cmd) + map(easyord, self.cmdarg)) |
71 data = property(getdata) | 127 data = property(getdata) |
72 | 128 |
73 class AT_Cmd_Queue(AT_Cmd): | 129 class AT_Cmd_Queue(AT_Cmd): |
130 """Queued AT command packet""" | |
131 | |
74 PKT_TYPE = 0x09 | 132 PKT_TYPE = 0x09 |
75 PKT_DESC = "AT Command (queued)" | 133 PKT_DESC = "AT Command (queued)" |
76 | 134 |
77 class AT_Response(PktBase): | 135 class AT_Response(PktBase): |
136 """Response from an AT command packet""" | |
137 | |
78 PKT_TYPE = 0x88 | 138 PKT_TYPE = 0x88 |
79 PKT_DESC = "AT Command response" | 139 PKT_DESC = "AT Command response" |
80 frameid = property(lambda s: s._data[0], None) | 140 frameid = property(lambda s: s._data[0], None) |
81 cmd = property(lambda s: chr(s._data[1]) + chr(s._data[2]), None) | 141 cmd = property(lambda s: chr(s._data[1]) + chr(s._data[2]), None) |
82 statusOK = property(lambda s: s._data[3] == 0, None) | 142 statusOK = property(lambda s: s._data[3] == 0, None) |
83 payload = property(lambda s: s._data[4:], None) | 143 payload = property(lambda s: s._data[4:], None) |
84 | 144 |
145 def __init__(self, data = []): | |
146 super(AT_Response, self).__init__() | |
147 self._data = data | |
148 | |
85 class Modem_Status(PktBase): | 149 class Modem_Status(PktBase): |
86 PKT_TYPE = 0x8a | 150 PKT_TYPE = 0x8a |
87 PKT_DESC = "Modem Status" | 151 PKT_DESC = "Modem Status" |
88 | 152 |
89 class RX_16_Bit(PktBase): | 153 class RX_16_Bit(PktBase): |
154 """RX packet from a remote module (16 bit)""" | |
90 PKT_TYPE = 0x81 | 155 PKT_TYPE = 0x81 |
91 PKT_DESC = "RX Packet: 16 bit address" | 156 PKT_DESC = "RX Packet: 16 bit address" |
92 ADDR_SIZE = 2 | 157 ADDR_SIZE = 2 |
158 ADRBCASTMSK = 0x01 | |
159 PANBCASTMSK = 0x02 | |
93 | 160 |
94 def __init__(self, data = []): | 161 def __init__(self, data = []): |
95 super(RX_16_Bit, self).__init__() | 162 super(RX_16_Bit, self).__init__() |
96 self._data = data | 163 self._data = data |
97 | 164 |
98 def __str__(self): | 165 def __str__(self): |
99 return "0x%0*x (%ddBm) -> %s" % (self.ADDR_SIZE * 2, self.sender, | 166 return "RX_%d_Bit 0x%0*x (%ddBm) -> %s" % (self.ADDR_SIZE * 8, self.ADDR_SIZE * 2, |
100 self.rssi, str(self.payload)) | 167 self.sender, self.rssi, self.payloadstr) |
101 | |
102 def getsender(self): | 168 def getsender(self): |
103 value = 0 | 169 value = 0 |
170 # Done this way so we can reuse the code for the 64 bit version | |
104 for i, j in zip(reversed(range(self.ADDR_SIZE)), range(0, self.ADDR_SIZE * 8, 8)): | 171 for i, j in zip(reversed(range(self.ADDR_SIZE)), range(0, self.ADDR_SIZE * 8, 8)): |
105 value |= self._data[i] << j | 172 value |= self._data[i] << j |
106 return value | 173 return value |
174 #: Source module address | |
107 sender = property(getsender, None) | 175 sender = property(getsender, None) |
108 | 176 |
177 def isAdrBcast(self): | |
178 """Is this an address broadcast packet?""" | |
179 return self.flags & self.ADRBCASTMSK | |
180 | |
181 def isPanBcast(self): | |
182 """Is this an PAN broadcast packet?""" | |
183 return self.flags & self.PANBCASTMSK | |
184 | |
185 #: RX signal strength (dBm) | |
109 rssi = property(lambda s: -1 * s._data[s.ADDR_SIZE], None) | 186 rssi = property(lambda s: -1 * s._data[s.ADDR_SIZE], None) |
110 | 187 |
188 #: Return flag byte | |
111 flags = property(lambda s: s._data[s.ADDR_SIZE + 1], None) | 189 flags = property(lambda s: s._data[s.ADDR_SIZE + 1], None) |
112 | 190 |
191 #: Payload (list of ords) | |
113 payload = property(lambda s: s._data[s.ADDR_SIZE + 2:], None) | 192 payload = property(lambda s: s._data[s.ADDR_SIZE + 2:], None) |
114 | 193 |
194 #: String version of payload | |
195 def payloadstr(self): | |
196 return reduce(lambda a, b: a + chr(b), self.payload, "") | |
197 payloadstr = property(payloadstr, None) | |
198 | |
199 | |
115 class RX_64_Bit(RX_16_Bit): | 200 class RX_64_Bit(RX_16_Bit): |
116 PKT_TYPE = 0x80 | 201 PKT_TYPE = 0x80 |
117 PKT_DESC = "RX Packet: 64 bit address" | 202 PKT_DESC = "RX Packet: 64 bit address" |
118 ADDR_SIZE = 8 | 203 ADDR_SIZE = 8 |
119 | 204 |
120 class RXIO_16_Bit(RX_16_Bit): | 205 class RXIO_16_Bit(RX_16_Bit): |
206 """RX I/O packet from remote module (16 bit). | |
207 | |
208 This is sent when a remote module is configured to send data based on its IO or DAC pins | |
209 """ | |
121 PKT_TYPE = 0x83 | 210 PKT_TYPE = 0x83 |
122 PKT_DESC = "RXIO Packet: 16 bit address" | 211 PKT_DESC = "RXIO Packet: 16 bit address" |
123 | 212 |
124 nsamples = property(lambda s: s._data[s.ADDR_SIZE + 2]) | 213 nsamples = property(lambda s: s._data[s.ADDR_SIZE + 2]) |
125 | 214 |
149 PKT_TYPE = 0x82 | 238 PKT_TYPE = 0x82 |
150 PKT_DESC = "RXIO Packet: 64 bit address" | 239 PKT_DESC = "RXIO Packet: 64 bit address" |
151 ADDR_SIZE = 8 | 240 ADDR_SIZE = 8 |
152 | 241 |
153 class TX_16_Bit(TXPkts): | 242 class TX_16_Bit(TXPkts): |
243 """Transmit to a 16 bit destination""" | |
154 PKT_TYPE = 0x01 | 244 PKT_TYPE = 0x01 |
155 PKT_DESC = "TX Packet: 16 bit address" | 245 PKT_DESC = "TX Packet: 16 bit address" |
156 ADDR_SIZE = 2 | 246 ADDR_SIZE = 2 |
247 #: Flag to disable ACK | |
157 FLG_DISABLE_ACK = 0x01 | 248 FLG_DISABLE_ACK = 0x01 |
249 #: Send to broadcast PAN ID | |
158 FLG_BCAST_PANID = 0x04 | 250 FLG_BCAST_PANID = 0x04 |
251 #: Maximum size payload we can send | |
159 PKT_MAX_PAYLOAD = 100 | 252 PKT_MAX_PAYLOAD = 100 |
160 | 253 |
161 def __init__(self, *args): | 254 def __init__(self, *args): |
162 if (len(args) == 1): | 255 """Takes 0 to 2 arguments. First is the recipient, the second is the payload (string)""" |
256 self._flags = 0 | |
257 self.payload = [] | |
258 | |
259 if len(args) == 0: | |
260 pass | |
261 if len(args) == 1: | |
163 super(TX_16_Bit, self).__init__() | 262 super(TX_16_Bit, self).__init__() |
164 self.recipient = args[0] | 263 self.recipient = args[0] |
165 elif (len(args) == 2): | 264 elif len(args) == 2: |
166 super(TX_16_Bit, self).__init__([]) | 265 super(TX_16_Bit, self).__init__() |
167 self.recipient = args[0] | 266 self.recipient = args[0] |
168 self.payload = args[1] | 267 self.payload = args[1] |
169 else: | 268 else: |
170 raise TypeError("__init__ takes 1 list of ordinals or 2 strings") | 269 raise TypeError("incorrect number of arguments"); |
171 | 270 |
172 self.frameid = 0 | 271 def __str__(self): |
173 self.flags = 0 | 272 return "TX_%d_Bit 0x%0*x <- %s" % (self.ADDR_SIZE * 8, self.ADDR_SIZE * 2, self.recipient, |
174 self.payload = [] | 273 self.payload) |
175 | 274 |
176 def setrecipient(self, value): | 275 def setrecipient(self, value): |
177 if (value < 0 or value > 2 ** (self.ADDR_SIZE * 8)): | 276 if (value < 0 or value > 2 ** (self.ADDR_SIZE * 8)): |
178 raise ValueError("value out of range must be between 0 and %d" % (2 ** self.ADDR_SIZE)) | 277 raise ValueError("value out of range must be between 0 and %d" % (2 ** self.ADDR_SIZE)) |
179 | 278 |
180 self._recipient = value | 279 self._recipient = value |
280 | |
281 """Destination address of the packet""" | |
181 recipient = property(lambda s: s._recipient, setrecipient) | 282 recipient = property(lambda s: s._recipient, setrecipient) |
182 | 283 |
183 def setflags(self, value): | 284 def setflags(self, value): |
184 if (value < 0 or value > 255): | 285 if (value < 0 or value > 255): |
185 raise ValueError("Value must be between 0 and 255 inclusive") | 286 raise ValueError("Value must be between 0 and 255 inclusive") |
190 def setpayload(self, value): | 291 def setpayload(self, value): |
191 self._checklist(value, maxlen = self.PKT_MAX_PAYLOAD) | 292 self._checklist(value, maxlen = self.PKT_MAX_PAYLOAD) |
192 self._payload = value | 293 self._payload = value |
193 payload = property(lambda s: s._payload, setpayload) | 294 payload = property(lambda s: s._payload, setpayload) |
194 | 295 |
296 def payloadstr(self): | |
297 return reduce(lambda a, b: a + chr(b), self.payload, "") | |
298 payloadstr = property(payloadstr, None) | |
299 | |
195 def getdata(self): | 300 def getdata(self): |
196 data = [self.frameid] | 301 data = [self.frameid] |
197 for i, j in zip(reversed(range(self.ADDR_SIZE)), range(0, self.ADDR_SIZE * 8, 8)): | 302 for i, j in zip(reversed(range(self.ADDR_SIZE)), reversed(range(0, self.ADDR_SIZE * 8, 8))): |
198 data.append((self.recipient & (0xff << j)) >> j) | 303 data.append((self.recipient & (0xff << j)) >> j) |
199 data.append(self.flags) | 304 data.append(self.flags) |
200 data.extend(map(easyord, self.payload)) | 305 data.extend(map(easyord, self.payload)) |
201 return(data) | 306 return(data) |
202 data = property(getdata) | 307 data = property(getdata) |
211 PKT_DESC = "TX Status" | 316 PKT_DESC = "TX Status" |
212 statusTxt = ['OK', 'No Ack', 'CCA failure', 'Purged'] | 317 statusTxt = ['OK', 'No Ack', 'CCA failure', 'Purged'] |
213 frameid = property(lambda s: s._data[0], None) | 318 frameid = property(lambda s: s._data[0], None) |
214 status = property(lambda s: s._data[1], None) | 319 status = property(lambda s: s._data[1], None) |
215 statusMsg = property(lambda s: s.statusTxt[s._data[1]], None) | 320 statusMsg = property(lambda s: s.statusTxt[s._data[1]], None) |
216 | 321 |
322 def __init__(self, data = []): | |
323 super(TX_Status, self).__init__() | |
324 self._data = data | |
325 | |
217 class Packets(object): | 326 class Packets(object): |
327 """Packet parsing class (misnamed)""" | |
218 PKT_CLASSES = None | 328 PKT_CLASSES = None |
219 | 329 |
330 @classmethod | |
220 def Build(self, data): | 331 def Build(self, data): |
332 """Build a packet from data""" | |
221 if (self.PKT_CLASSES == None): | 333 if (self.PKT_CLASSES == None): |
222 m = inspect.getmodule(self) | 334 m = inspect.getmodule(self) |
223 # Generate list of objects from their names | 335 # Generate list of objects from their names |
224 mobjs = map(lambda n: m.__dict__[n], m.__dict__) | 336 mobjs = map(lambda n: m.__dict__[n], m.__dict__) |
225 # Find all the classes | 337 # Find all the classes |
228 pktclasses = filter(lambda s: issubclass(s, m.PktBase) and s != m.PktBase, pktclasses) | 340 pktclasses = filter(lambda s: issubclass(s, m.PktBase) and s != m.PktBase, pktclasses) |
229 self.PKT_CLASSES = pktclasses | 341 self.PKT_CLASSES = pktclasses |
230 | 342 |
231 for p in self.PKT_CLASSES: | 343 for p in self.PKT_CLASSES: |
232 if (p.PKT_TYPE == data[0]): | 344 if (p.PKT_TYPE == data[0]): |
345 #print "Matched " + str(p.PKT_TYPE) | |
233 return(p(data[1:])) | 346 return(p(data[1:])) |
234 | 347 |
235 raise ValueError("Unknown packet type 0x%02x" % (data[0])) | 348 raise ValueError("Unknown packet type 0x%02x" % (data[0])) |
236 Build = classmethod(Build) | 349 |
237 | 350 @staticmethod |
238 def Encapsulate(data): | 351 def Encapsulate(data): |
352 """Encapsulate a packet so it can be sent to the module. Calculates checksum etc..""" | |
239 pktsum = reduce(lambda x, y: x + y, data) & 0xff | 353 pktsum = reduce(lambda x, y: x + y, data) & 0xff |
240 pkt = [0x7e] + [len(data) >> 8] + [len(data) & 0xff] + data + [0xff - pktsum] | 354 pkt = [0x7e] + [len(data) >> 8] + [len(data) & 0xff] + data + [0xff - pktsum] |
241 return(map(chr, pkt)) | 355 return(map(chr, pkt)) |
242 | 356 |
243 Encapsulate = staticmethod(Encapsulate) | |
244 | |
245 def __init__(self, s = None): | 357 def __init__(self, s = None): |
246 print str(inspect.getmodule(self)) | 358 """Init class, if s is passed in it is used for reading & writing data""" |
359 #print str(inspect.getmodule(self)) | |
247 self.buffer = [] | 360 self.buffer = [] |
248 self.state = 'init' | 361 self.state = 'init' |
249 self.packets = [] | 362 self.packets = [] |
250 | 363 |
251 self.bufmsb = 0 | 364 self.bufmsb = 0 |
254 self.fr_err = 0 # Framing error | 367 self.fr_err = 0 # Framing error |
255 self.ck_err = 0 # Checksum error | 368 self.ck_err = 0 # Checksum error |
256 self.rx_cnt = 0 # Packet count | 369 self.rx_cnt = 0 # Packet count |
257 | 370 |
258 self.pktq = [] | 371 self.pktq = [] |
259 self.s = s | 372 self.s = s # Output handle for convenience methods |
260 | 373 |
261 def writedata(self, data): | 374 def writedata(self, data): |
375 """Convenience method to write data""" | |
262 self.s.write("".join(map(str, data))) | 376 self.s.write("".join(map(str, data))) |
263 | 377 |
264 def getdata(self): | 378 def getdata(self): |
379 """Read data until nothing is available (assumes non-blocking) and process it""" | |
265 l = [] | 380 l = [] |
266 while (1): | 381 while 1: |
267 a = self.s.read() | 382 a = self.s.read() |
268 if (a == ''): | 383 if a == '': |
269 break | 384 break |
270 l.append(ord(a)) | 385 l.append(ord(a)) |
271 | 386 |
272 return self.process(l) | 387 return self.process(l) |
273 | 388 |
389 def processstr(self, data): | |
390 """Process a string of data""" | |
391 return self.process(map(ord, data)) | |
392 | |
274 def process(self, data): | 393 def process(self, data): |
394 """Process (ordinal) data through the state machine. | |
395 | |
396 Returns the number of packets in the queue when finished. Updates | |
397 various internal counters too. | |
398 """ | |
275 pktcount = 0 | 399 pktcount = 0 |
276 for d in data: | 400 for d in data: |
277 if (self.state == 'init'): | 401 if (self.state == 'init'): |
278 if (d != 0x7e): | 402 if (d != 0x7e): |
279 print "Framing error, got 0x%02x, expected 0x7e" % (d) | 403 print "Framing error, got 0x%02x, expected 0x7e" % d |
280 self.fr_err += 1 | 404 self.fr_err += 1 |
281 continue | 405 continue |
282 | 406 |
283 self.state = 'sizemsb' | 407 self.state = 'sizemsb' |
284 elif (self.state == 'sizemsb'): | 408 elif (self.state == 'sizemsb'): |
300 self.buffer = [] | 424 self.buffer = [] |
301 self.ck_err += 1 | 425 self.ck_err += 1 |
302 print "Checksum error, got 0x%02x, expected 0x%02x" % \ | 426 print "Checksum error, got 0x%02x, expected 0x%02x" % \ |
303 (rxcksum, 0xff - pktsum) | 427 (rxcksum, 0xff - pktsum) |
304 else: | 428 else: |
305 print "Got a packet - " + str(self.buffer) | 429 #print "Got a packet - " + str(self.buffer) |
306 p = Packets.Build(self.buffer) | 430 p = Packets.Build(self.buffer) |
307 self.pktq.append(p) | 431 self.pktq.append(p) |
308 self.buffer = [] | 432 self.buffer = [] |
309 pktcount += 1 | 433 pktcount += 1 |
310 self.rx_cnt += 1 | 434 self.rx_cnt += 1 |
312 print "Invalid state %s! Resetting" % (self.state) | 436 print "Invalid state %s! Resetting" % (self.state) |
313 self.state = 'init' | 437 self.state = 'init' |
314 | 438 |
315 return pktcount | 439 return pktcount |
316 | 440 |
317 def polldev(): | |
318 while (1): | |
319 foo = up.getdata() | |
320 for p in up.pktq: | |
321 print p | |
322 | |
323 if (foo == 0): | |
324 time.sleep(0.1) | |
325 | |
326 #for c in dir(): | |
327 # if (issubclass(c, PktBase)): | |
328 # print .. | |
329 | |
330 try: | |
331 s = serial.Serial(port='/dev/cuaU0', baudrate=9600, bytesize=8, parity='N', \ | |
332 stopbits=1, rtscts=0) | |
333 # Non-blocking | |
334 s.timeout = 0 | |
335 #s.write('+++') | |
336 #s.readline(eol='\r') | |
337 except serial.serialutil.SerialException, e: | |
338 print "Can't open serial port - " + str(e) | |
339 s = None | |
340 | |
341 # 0x0001 (-36dBm) -> 1 samples, mask 0x000f, DIO - 0x00f | |
342 goodtest = [126, 0, 10, 131, 0, 1, 36, 0, 1, 0, 15, 0, 15, 56] | |
343 | |
344 # Checksum error | |
345 badtest = [126, 0, 10, 131, 0, 1, 36, 0, 1, 0, 15, 0, 14, 56] | |
346 | |
347 #0x0005 (-36dBm) -> 1 samples, mask 0x020e, DIO - 0x00e, ADC0 - 0x3ff | |
348 adctest = [126, 0, 12, 131, 0, 5, 36, 0, 1, 2, 14, 0, 14, 3, 255, 50] | |
349 | |
350 # Exception | |
351 badpkttypetest = [126, 0, 3, 10, 86, 76, 83] | |
352 | |
353 # Frame ID = 0, Cmd = 'VL', Status = OK, Value = 'VL Result' | |
354 atreply = [126, 0, 14, 136, 0, 86, 76, 0, 86, 76, 32, 82, 101, 115, 117, 108, 116, 148] | |
355 | |
356 up = Packets(s) | |
357 up.process(goodtest) | |
358 up.process(badtest) | |
359 up.process(adctest) | |
360 print up.pktq.pop(0) | |
361 print up.pktq.pop(0) | |
362 |