zigbee.py
Go to the documentation of this file.
00001 """
00002 zigbee.py
00003 
00004 By Greg Rapp, 2010
00005 Inspired by code written by Paul Malmsten, 2010
00006 Inspired by code written by Amit Synderman and Marco Sangalli
00007 gdrapp@gmail.com
00008 
00009 This module implements an XBee ZB (ZigBee) API library.
00010 """
00011 import struct
00012 from xbee.base import XBeeBase
00013 
00014 class ZigBee(XBeeBase):
00015     """
00016     Provides an implementation of the XBee API for XBee ZB (ZigBee) modules
00017     with recent firmware.
00018     
00019     Commands may be sent to a device by instantiating this class with
00020     a serial port object (see PySerial) and then calling the send
00021     method with the proper information specified by the API. Data may
00022     be read from a device synchronously by calling wait_read_frame.
00023     For asynchronous reads, see the defintion of XBeeBase.
00024     """
00025     # Packets which can be sent to an XBee
00026     
00027     # Format: 
00028     #        {name of command:
00029     #           [{name:field name, len:field length, default: default value sent}
00030     #            ...
00031     #            ]
00032     #         ...
00033     #         }
00034     api_commands = {"at":
00035                         [{'name':'id',        'len':1,      'default':'\x08'},
00036                          {'name':'frame_id',  'len':1,      'default':'\x01'},
00037                          {'name':'command',   'len':2,      'default':None},
00038                          {'name':'parameter', 'len':None,   'default':None}],
00039                     "queued_at":
00040                         [{'name':'id',        'len':1,      'default':'\x09'},
00041                          {'name':'frame_id',  'len':1,      'default':'\x01'},
00042                          {'name':'command',   'len':2,      'default':None},
00043                          {'name':'parameter', 'len':None,   'default':None}],
00044                     "remote_at":
00045                         [{'name':'id',              'len':1,        'default':'\x17'},
00046                          {'name':'frame_id',        'len':1,        'default':'\x00'},
00047                          # dest_addr_long is 8 bytes (64 bits), so use an unsigned long long
00048                          {'name':'dest_addr_long',  'len':8,        'default':struct.pack('>Q', 0)},
00049                          {'name':'dest_addr',       'len':2,        'default':'\xFF\xFE'},
00050                          {'name':'options',         'len':1,        'default':'\x02'},
00051                          {'name':'command',         'len':2,        'default':None},
00052                          {'name':'parameter',       'len':None,     'default':None}],
00053                     "tx":
00054                         [{'name':'id',              'len':1,        'default':'\x10'},
00055                          {'name':'frame_id',        'len':1,        'default':'\x01'},
00056                          {'name':'dest_addr_long',  'len':8,        'default':None},
00057                          {'name':'dest_addr',       'len':2,        'default':None},
00058                          {'name':'broadcast_radius','len':1,        'default':'\x00'},
00059                          {'name':'options',         'len':1,        'default':'\x00'},
00060                          {'name':'data',            'len':None,     'default':None}],
00061                     "tx_explicit":
00062                         [{'name':'id',              'len':1,        'default':'\x11'},
00063                          {'name':'frame_id',        'len':1,        'default':'\x00'},
00064                          {'name':'dest_addr_long',  'len':8,        'default':None},
00065                          {'name':'dest_addr',       'len':2,        'default':None},
00066                          {'name':'src_endpoint',    'len':1,        'default':None},
00067                          {'name':'dest_endpoint',   'len':1,        'default':None},
00068                          {'name':'cluster',         'len':1,        'default':None},
00069                          {'name':'profile',         'len':1,        'default':None},
00070                          {'name':'broadcast_radius','len':1,        'default':'\x00'},
00071                          {'name':'options',         'len':1,        'default':'\x00'},
00072                          {'name':'data',            'len':None,     'default':None}]
00073                     }
00074     
00075     # Packets which can be received from an XBee
00076     
00077     # Format: 
00078     #        {id byte received from XBee:
00079     #           {name: name of response
00080     #            structure:
00081     #                [ {'name': name of field, 'len':length of field}
00082     #                  ...
00083     #                  ]
00084     #            parse_as_io_samples:name of field to parse as io
00085     #           }
00086     #           ...
00087     #        }
00088     #
00089     api_responses = {"\x90":
00090                         {'name':'rx',
00091                          'structure':
00092                             [{'name':'source_addr_long','len':8},
00093                              {'name':'source_addr',     'len':2},
00094                              {'name':'options',         'len':1},
00095                              {'name':'rf_data',         'len':None}]},
00096                      "\x91":
00097                         {'name':'rx_explicit',
00098                          'structure':
00099                             [{'name':'source_addr_long','len':8},
00100                              {'name':'source_addr',     'len':2},
00101                              {'name':'source_endpoint', 'len':1},
00102                              {'name':'dest_endpoint',   'len':1},
00103                              {'name':'cluster',         'len':2},
00104                              {'name':'profile',         'len':2},
00105                              {'name':'options',         'len':1},
00106                              {'name':'rf_data',         'len':None}]},
00107                      "\x92": # Checked by GDR-parse_samples_header function appears to need update to support
00108                         {'name':'rx_io_data_long_addr',
00109                          'structure':
00110                             [{'name':'source_addr_long','len':8},
00111                              {'name':'source_addr',     'len':2},
00112                              {'name':'options',         'len':1},
00113                              {'name':'samples',         'len':None}],
00114                          'parse_as_io_samples':'samples'},
00115                      "\x8b":
00116                         {'name':'tx_status',
00117                          'structure':
00118                             [{'name':'frame_id',        'len':1},
00119                              {'name':'dest_addr',       'len':2},
00120                              {'name':'retries',         'len':1},
00121                              {'name':'deliver_status',  'len':1},
00122                              {'name':'discover_status', 'len':1}]},
00123                      "\x8a":
00124                         {'name':'status',
00125                          'structure':
00126                             [{'name':'status',      'len':1}]},
00127                      "\x88":
00128                         {'name':'at_response',
00129                          'structure':
00130                             [{'name':'frame_id',    'len':1},
00131                              {'name':'command',     'len':2},
00132                              {'name':'status',      'len':1},
00133                              {'name':'parameter',   'len':None}]},
00134                      "\x97": #Checked GDR (not sure about parameter, could be 4 bytes)
00135                         {'name':'remote_at_response',
00136                          'structure':
00137                             [{'name':'frame_id',        'len':1},
00138                              {'name':'source_addr_long','len':8},
00139                              {'name':'source_addr',     'len':2},
00140                              {'name':'command',         'len':2},
00141                              {'name':'status',          'len':1},
00142                              {'name':'parameter',       'len':None}]},
00143                      "\x95":
00144                         {'name':'node_id_indicator',
00145                          'structure':
00146                             [{'name':'sender_addr_long','len':8},
00147                              {'name':'sender_addr',     'len':2},
00148                              {'name':'options',         'len':1},
00149                              {'name':'source_addr',     'len':2},
00150                              {'name':'source_addr_long','len':8},
00151                              {'name':'node_id',         'len':'null_terminated'},
00152                              {'name':'parent_source_addr','len':2},
00153                              {'name':'device_type',     'len':1},
00154                              {'name':'source_event',    'len':1},
00155                              {'name':'digi_profile_id', 'len':2},
00156                              {'name':'manufacturer_id', 'len':2}]}
00157                      }
00158     
00159     def __init__(self, *args, **kwargs):
00160         # Call the super class constructor to save the serial port
00161         super(ZigBee, self).__init__(*args, **kwargs)
00162 
00163     def _parse_samples_header(self, io_bytes):
00164         """
00165         _parse_samples_header: binary data in XBee ZB IO data format ->
00166                         (int, [int ...], [int ...], int, int)
00167                         
00168         _parse_samples_header will read the first three bytes of the 
00169         binary data given and will return the number of samples which
00170         follow, a list of enabled digital inputs, a list of enabled
00171         analog inputs, the dio_mask, and the size of the header in bytes
00172 
00173         _parse_samples_header is overloaded here to support the additional
00174         IO lines offered by the XBee ZB
00175         """
00176         header_size = 4
00177 
00178         # number of samples (always 1?) is the first byte
00179         sample_count = ord(io_bytes[0])
00180         
00181         # bytes 1 and 2 are the DIO mask; bits 9 and 8 aren't used
00182         dio_mask = (ord(io_bytes[1]) << 8 | ord(io_bytes[2])) & 0x0E7F
00183         
00184         # byte 3 is the AIO mask
00185         aio_mask = ord(io_bytes[3])
00186         
00187         # sorted lists of enabled channels; value is position of bit in mask
00188         dio_chans = []
00189         aio_chans = []
00190         
00191         for i in range(0,13):
00192             if dio_mask & (1 << i):
00193                 dio_chans.append(i)
00194         
00195         dio_chans.sort()
00196         
00197         for i in range(0,8):
00198             if aio_mask & (1 << i):
00199                 aio_chans.append(i)
00200         
00201         aio_chans.sort()
00202         
00203         return (sample_count, dio_chans, aio_chans, dio_mask, header_size)


rosserial_xbee
Author(s): Adam Stambler
autogenerated on Fri Aug 28 2015 12:44:47