test_ieee.py
Go to the documentation of this file.
1 #! /usr/bin/python
2 """
3 test_ieee.py
4 
5 By Paul Malmsten, 2010
6 pmalmsten@gmail.com
7 
8 Tests the XBee (IEEE 802.15.4) implementation class for XBee API compliance
9 """
10 import unittest
11 from xbee.tests.Fake import FakeDevice, FakeReadDevice
12 from xbee.ieee import XBee
13 
14 class InitXBee(unittest.TestCase):
15  """
16  Base initalization class
17  """
18  def setUp(self):
19  """
20  Initialize XBee object
21  """
22  self.xbee = XBee(None)
23 
25  """
26  _build_command should properly build a command packet
27  """
28 
30  """
31  if not enough or incorrect data is provided, an exception should
32  be raised.
33  """
34  try:
35  self.xbee._build_command("at")
36  except KeyError:
37  # Test passes
38  return
39 
40  # No exception? Fail.
41  self.fail(
42  "An exception was not raised with improper data supplied"
43  )
44 
46  """
47  if data of incorrect length is provided, an exception should be
48  raised
49  """
50  try:
51  self.xbee._build_command("at", frame_id="AB", command="MY")
52  except ValueError:
53  # Test passes
54  return
55 
56  # No exception? Fail.
57  self.fail(
58  "An exception was not raised with improper data length"
59  )
60 
61  def test_build_at(self):
62  """
63  _build_command should build a valid at command packet which has
64  no parameter data to be saved
65  """
66 
67  at_command = "MY"
68  frame = chr(43)
69  data = self.xbee._build_command(
70  "at",
71  frame_id=frame,
72  command=at_command
73  )
74 
75  expected_data = '\x08+MY'
76  self.assertEqual(data, expected_data)
77 
79  """
80  _build_command should build a valid at command packet which has
81  no parameter data to be saved and no frame specified (the
82  default value of \x00 should be used)
83  """
84 
85  at_command = "MY"
86  data = self.xbee._build_command("at", command=at_command)
87 
88  expected_data = '\x08\x00MY'
89  self.assertEqual(data, expected_data)
90 
92  """
93  _split_response should properly split a response packet
94  """
95 
97  """
98  if a response begins with an unrecognized id byte,
99  _split_response should raise an exception
100  """
101  data = '\x23\x00\x00\x00'
102 
103  try:
104  self.xbee._split_response(data)
105  except KeyError:
106  # Passes
107  return
108 
109  # Test Fails
110  self.fail()
111 
113  """
114  if a response doesn't match the specification's layout,
115  _split_response should raise an exception
116  """
117  # Over length
118  data = '\x8a\x00\x00\x00'
119  self.assertRaises(ValueError, self.xbee._split_response, data)
120 
122  """
123  if a response doesn't match the specification's layout,
124  _split_response should raise an exception
125  """
126  # Under length
127  data = '\x8a'
128  self.assertRaises(ValueError, self.xbee._split_response, data)
129 
131  """
132  _split_response should properly split a status response packet
133  """
134  data = '\x8a\x01'
135 
136  info = self.xbee._split_response(data)
137  expected_info = {'id':'status',
138  'status':'\x01'}
139 
140  self.assertEqual(info, expected_info)
141 
143  """
144  _split_response should properly split an at_response packet which
145  has no parameter data
146  """
147 
148  data = '\x88DMY\x01'
149  info = self.xbee._split_response(data)
150  expected_info = {'id':'at_response',
151  'frame_id':'D',
152  'command':'MY',
153  'status':'\x01'}
154  self.assertEqual(info, expected_info)
155 
157  """
158  _split_response should properly split an at_response packet which
159  has parameter data
160  """
161 
162  data = '\x88DMY\x01ABCDEF'
163  info = self.xbee._split_response(data)
164  expected_info = {'id':'at_response',
165  'frame_id':'D',
166  'command':'MY',
167  'status':'\x01',
168  'parameter':'ABCDEF'}
169  self.assertEqual(info, expected_info)
170 
171 
173  """
174  XBee class should properly parse IO data received from an XBee
175  device
176  """
177 
179  """
180  _parse_samples should properly parse a packet containing a single
181  sample of only digital io data
182  """
183  # One sample, ADC disabled and DIO8 enabled, DIO 0-7 enabled
184  header = '\x01\x01\xFF'
185 
186  # First 7 bits ignored, DIO8 high, DIO 0-7 high
187  sample = '\x01\xFF'
188  data = header + sample
189 
190  expected_results = [{'dio-0':True,
191  'dio-1':True,
192  'dio-2':True,
193  'dio-3':True,
194  'dio-4':True,
195  'dio-5':True,
196  'dio-6':True,
197  'dio-7':True,
198  'dio-8':True}]
199 
200  results = self.xbee._parse_samples(data)
201 
202  self.assertEqual(results, expected_results)
203 
205  """
206  _parse_samples should properly parse a packet containing a single
207  sample of only digital io data, which alternates between on and
208  off
209  """
210  # One sample, ADC disabled and DIO8 enabled, DIO 0-7 enabled
211  header = '\x01\x01\xFF'
212 
213  # First 7 bits ignored, DIO8 low, DIO 0-7 alternating
214  sample = '\x00\xAA'
215  data = header + sample
216 
217  expected_results = [{'dio-0':False,
218  'dio-1':True,
219  'dio-2':False,
220  'dio-3':True,
221  'dio-4':False,
222  'dio-5':True,
223  'dio-6':False,
224  'dio-7':True,
225  'dio-8':False}]
226 
227  results = self.xbee._parse_samples(data)
228 
229  self.assertEqual(results, expected_results)
230 
232  """
233  _parse_samples should properly parse a packet containing a single
234  sample of only digital io data for only a subset of the
235  available pins
236  """
237  # One sample, ADC disabled
238  # DIO 1,3,5,7 enabled
239  header = '\x01\x00\xAA'
240 
241  # First 7 bits ignored, DIO8 low, DIO 0-7 alternating
242  sample = '\x00\xAA'
243  data = header + sample
244 
245  expected_results = [{'dio-1':True,
246  'dio-3':True,
247  'dio-5':True,
248  'dio-7':True}]
249 
250  results = self.xbee._parse_samples(data)
251 
252  self.assertEqual(results, expected_results)
253 
255  """
256  _parse_samples should properly parse a packet containing a single
257  sample of only digital io data for only a subset of the
258  available pins
259  """
260  # One sample, ADC disabled
261  # DIO 0 enabled
262  header = '\x01\x00\x01'
263 
264  # First 7 bits ignored, DIO8 low, DIO 0-7 alternating
265  sample = '\x00\xAA'
266  data = header + sample
267 
268  expected_results = [{'dio-0':False}]
269 
270  results = self.xbee._parse_samples(data)
271 
272  self.assertEqual(results, expected_results)
273 
275  """
276  _parse_samples should properly parse a packet containing two
277  samples of only digital io data for one dio line
278  """
279  # Two samples, ADC disabled
280  # DIO 0 enabled
281  header = '\x02\x00\x01'
282 
283  # First 7 bits ignored, DIO8 low, DIO 0-7 alternating
284  sample = '\x00\xAA' + '\x00\x01'
285  data = header + sample
286 
287  expected_results = [{'dio-0':False},
288  {'dio-0':True}]
289 
290  results = self.xbee._parse_samples(data)
291 
292  self.assertEqual(results, expected_results)
293 
295  """
296  _parse_samples should properly parse a packet containing three
297  samples of only digital io data
298  """
299  # Three samples, ADC disabled and DIO8 enabled, DIO 0-7 enabled
300  header = '\x03\x01\xFF'
301 
302  # First 7 bits ignored
303  # First sample: all bits on
304  # Second sample: alternating bits on
305  # Third sample: all bits off
306  sample = '\x01\xFF' + '\x00\xAA' + '\x00\x00'
307  data = header + sample
308 
309  expected_results = [{'dio-0':True,
310  'dio-1':True,
311  'dio-2':True,
312  'dio-3':True,
313  'dio-4':True,
314  'dio-5':True,
315  'dio-6':True,
316  'dio-7':True,
317  'dio-8':True},
318  {'dio-0':False,
319  'dio-1':True,
320  'dio-2':False,
321  'dio-3':True,
322  'dio-4':False,
323  'dio-5':True,
324  'dio-6':False,
325  'dio-7':True,
326  'dio-8':False},
327  {'dio-0':False,
328  'dio-1':False,
329  'dio-2':False,
330  'dio-3':False,
331  'dio-4':False,
332  'dio-5':False,
333  'dio-6':False,
334  'dio-7':False,
335  'dio-8':False}]
336 
337  results = self.xbee._parse_samples(data)
338 
339  self.assertEqual(results, expected_results)
340 
342  """
343  _parse_samples should parse a data packet containing multiple
344  samples of adc data from multiple pins in the proper order
345  """
346  # One sample, ADC 0,1 enabled
347  # DIO disabled
348  header = '\x02\x06\x00'
349 
350  # No dio data
351  # ADC0 value of 0
352  # ADC1 value of 255
353  # ADC0 value of 5
354  # ADC1 value of 7
355  sample = '\x00\x00' + '\x00\xFF' + '\x00\x05' + '\x00\x07'
356  data = header + sample
357 
358  expected_results = [{'adc-0':0,
359  'adc-1':255},
360  {'adc-0':5,
361  'adc-1':7}]
362 
363  results = self.xbee._parse_samples(data)
364 
365  self.assertEqual(results, expected_results)
366 
368  """
369  _parse_samples should properly parse a packet containing a single
370  sample of digital and analog io data for only a subset of the
371  available pins
372  """
373  # One sample, ADC 0 enabled
374  # DIO 1,3,5,7 enabled
375  header = '\x01\x02\xAA'
376 
377  # First 7 bits ignored, DIO8 low, DIO 0-7 alternating
378  # ADC0 value of 255
379  sample = '\x00\xAA\x00\xFF'
380  data = header + sample
381 
382  expected_results = [{'dio-1':True,
383  'dio-3':True,
384  'dio-5':True,
385  'dio-7':True,
386  'adc-0':255}]
387 
388  results = self.xbee._parse_samples(data)
389 
390  self.assertEqual(results, expected_results)
391 
392 class TestWriteToDevice(unittest.TestCase):
393  """
394  XBee class should properly write binary data in a valid API
395  frame to a given serial device, including a valid command packet.
396  """
397 
399  """
400  calling send should write a full API frame containing the
401  API AT command packet to the serial device.
402  """
403 
404  serial_port = FakeDevice()
405  xbee = XBee(serial_port)
406 
407  # Send an AT command
408  xbee.send('at', frame_id='A', command='MY')
409 
410  # Expect a full packet to be written to the device
411  expected_data = '\x7E\x00\x04\x08AMY\x10'
412  self.assertEqual(serial_port.data, expected_data)
413 
414 
416  """
417  calling send should write a full API frame containing the
418  API AT command packet to the serial device.
419  """
420 
421  serial_port = FakeDevice()
422  xbee = XBee(serial_port)
423 
424  # Send an AT command
425  xbee.send(
426  'at',
427  frame_id='A',
428  command='MY',
429  parameter='\x00\x00'
430  )
431 
432  # Expect a full packet to be written to the device
433  expected_data = '\x7E\x00\x06\x08AMY\x00\x00\x10'
434  self.assertEqual(serial_port.data, expected_data)
435 
436 class TestSendShorthand(unittest.TestCase):
437  """
438  Tests shorthand for sending commands to an XBee provided by
439  XBee.__getattr__
440  """
441 
442  def setUp(self):
443  """
444  Prepare a fake device to read from
445  """
446  self.ser = FakeDevice()
447  self.xbee = XBee(self.ser)
448 
450  """
451  Send an AT command with a shorthand call
452  """
453  # Send an AT command
454  self.xbee.at(frame_id='A', command='MY')
455 
456  # Expect a full packet to be written to the device
457  expected_data = '\x7E\x00\x04\x08AMY\x10'
458  self.assertEqual(self.ser.data, expected_data)
459 
461  """
462  calling send should write a full API frame containing the
463  API AT command packet to the serial device.
464  """
465 
466  # Send an AT command
467  self.xbee.at(frame_id='A', command='MY', parameter='\x00\x00')
468 
469  # Expect a full packet to be written to the device
470  expected_data = '\x7E\x00\x06\x08AMY\x00\x00\x10'
471  self.assertEqual(self.ser.data, expected_data)
472 
474  """
475  When shorthand is disabled, any attempt at calling a
476  non-existant attribute should raise AttributeError
477  """
478  self.xbee = XBee(self.ser, shorthand=False)
479 
480  try:
481  self.xbee.at
482  except AttributeError:
483  pass
484  else:
485  self.fail("Specified shorthand command should not exist")
486 
487 class TestReadFromDevice(unittest.TestCase):
488  """
489  XBee class should properly read and parse binary data from a serial
490  port device.
491  """
492  def test_read_at(self):
493  """
494  read and parse a parameterless AT command
495  """
496  device = FakeReadDevice('\x7E\x00\x05\x88DMY\x01\x8c')
497  xbee = XBee(device)
498 
499  info = xbee.wait_read_frame()
500  expected_info = {'id':'at_response',
501  'frame_id':'D',
502  'command':'MY',
503  'status':'\x01'}
504  self.assertEqual(info, expected_info)
505 
507  """
508  read and parse an AT command with a parameter
509  """
510  device = FakeReadDevice(
511  '\x7E\x00\x08\x88DMY\x01\x00\x00\x00\x8c'
512  )
513  xbee = XBee(device)
514 
515  info = xbee.wait_read_frame()
516  expected_info = {'id':'at_response',
517  'frame_id':'D',
518  'command':'MY',
519  'status':'\x01',
520  'parameter':'\x00\x00\x00'}
521  self.assertEqual(info, expected_info)
522 
523  def test_read_io_data(self):
524  """
525  XBee class should properly read and parse incoming IO data
526  """
527  ## Build IO data
528  # One sample, ADC 0 enabled
529  # DIO 1,3,5,7 enabled
530  header = '\x01\x02\xAA'
531 
532  # First 7 bits ignored, DIO8 low, DIO 0-7 alternating
533  # ADC0 value of 255
534  sample = '\x00\xAA\x00\xFF'
535  data = header + sample
536 
537  ## Wrap data in frame
538  # RX frame data
539  rx_io_resp = '\x83\x00\x01\x28\x00'
540 
541  device = FakeReadDevice(
542  '\x7E\x00\x0C'+ rx_io_resp + data + '\xfd'
543  )
544  xbee = XBee(device)
545 
546  info = xbee.wait_read_frame()
547  expected_info = {'id':'rx_io_data',
548  'source_addr':'\x00\x01',
549  'rssi':'\x28',
550  'options':'\x00',
551  'samples': [{'dio-1':True,
552  'dio-3':True,
553  'dio-5':True,
554  'dio-7':True,
555  'adc-0':255}]
556  }
557  self.assertEqual(info, expected_info)
558 
559 
560 if __name__ == '__main__':
561  unittest.main()
Definition: ieee.py:1


rosserial_xbee
Author(s): Adam Stambler
autogenerated on Fri Jun 7 2019 22:03:11