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