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     
00026     
00027     
00028     
00029     
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                          
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     
00076     
00077     
00078     
00079     
00080     
00081     
00082     
00083     
00084     
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": 
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": 
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         
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         
00179         sample_count = ord(io_bytes[0])
00180         
00181         
00182         dio_mask = (ord(io_bytes[1]) << 8 | ord(io_bytes[2])) & 0x0E7F
00183         
00184         
00185         aio_mask = ord(io_bytes[3])
00186         
00187         
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)