Package killerbee :: Module dev_zigduino
[hide private]
[frames] | no frames]

Source Code for Module killerbee.dev_zigduino

  1  ''' 
  2  Support is currently only tested with Zigduino r1. 
  3  Zigduino support is contributed by neighbor bx. 
  4  If you can test with or can provide us a Zigduino r2 for testing, that would be great. 
  5   
  6  Items still TODO: 
  7      - sniffer_off() needs to instruct the firmware to stop sending packets 
  8      - calibrate the RSSI reading on the r2 hardware and adjust for it 
  9      - add jamming support 
 10  ''' 
 11   
 12  import os 
 13  import time 
 14  import struct 
 15  import time 
 16  from datetime import datetime, date, timedelta 
 17  from kbutils import KBCapabilities, makeFCS 
 18  from GoodFETatmel128 import GoodFETatmel128rfa1 
 19   
 20  ATMEL_REG_SYNC = 0x0B 
 21   
22 -class ZIGDUINO:
23 - def __init__(self, dev):
24 ''' 25 Instantiates the KillerBee class for Zigduino running GoodFET firmware. 26 @type dev: String 27 @param dev: Serial device identifier (ex /dev/ttyUSB0) 28 @return: None 29 @rtype: None 30 ''' 31 self._channel = None 32 self.handle = None 33 self.dev = dev 34 self.handle = GoodFETatmel128rfa1() 35 self.handle.serInit(port=self.dev) 36 self.handle.setup() 37 38 self.__stream_open = False 39 self.capabilities = KBCapabilities() 40 self.__set_capabilities()
41
42 - def close(self):
43 self.handle.serClose() 44 self.handle = None
45
46 - def check_capability(self, capab):
47 return self.capabilities.check(capab)
48
49 - def get_capabilities(self):
50 return self.capabilities.getlist()
51
52 - def __set_capabilities(self):
53 ''' 54 Sets the capability information appropriate for GoodFETAVR client and firmware. 55 @rtype: None 56 @return: None 57 ''' 58 self.capabilities.setcapab(KBCapabilities.FREQ_2400, True) 59 self.capabilities.setcapab(KBCapabilities.SNIFF, True) 60 self.capabilities.setcapab(KBCapabilities.SETCHAN, True) 61 self.capabilities.setcapab(KBCapabilities.INJECT, True) 62 #self.capabilities.setcapab(KBCapabilities.PHYJAM_REFLEX, True) 63 self.capabilities.setcapab(KBCapabilities.SET_SYNC, True)
64 65 # KillerBee expects the driver to implement this function
66 - def get_dev_info(self):
67 ''' 68 Returns device information in a list identifying the device. 69 @rtype: List 70 @return: List of 3 strings identifying device. 71 ''' 72 return [self.dev, "Zigduino", ""]
73 74 # KillerBee expects the driver to implement this function
75 - def sniffer_on(self, channel=None):
76 ''' 77 Turns the sniffer on such that pnext() will start returning observed 78 data. Will set the command mode to Air Capture if it is not already 79 set. 80 @type channel: Integer 81 @param channel: Sets the channel, optional 82 @rtype: None 83 ''' 84 self.capabilities.require(KBCapabilities.SNIFF) 85 86 if channel != None: 87 self.set_channel(channel) 88 89 #print "Sniffer started (listening as %010x on %i MHz)" % (self.handle.RF_getsmac(), self.handle.RF_getfreq()/10**6); 90 91 self.__stream_open = True
92 93 # KillerBee expects the driver to implement this function
94 - def sniffer_off(self):
95 ''' 96 Turns the sniffer off, freeing the hardware for other functions. It is 97 not necessary to call this function before closing the interface with 98 close(). 99 @rtype: None 100 ''' 101 #TODO actually have firmware stop sending us packets! 102 self.__stream_open = False
103 104 # KillerBee expects the driver to implement this function
105 - def set_channel(self, channel):
106 ''' 107 Sets the radio interface to the specifid channel (limited to 2.4 GHz channels 11-26) 108 @type channel: Integer 109 @param channel: Sets the channel, optional 110 @rtype: None 111 ''' 112 self.capabilities.require(KBCapabilities.SETCHAN) 113 114 if channel >= 11 or channel <= 26: 115 self._channel = channel 116 self.handle.RF_setchannel(channel) 117 else: 118 raise Exception('Invalid channel')
119 120 # KillerBee expects the driver to implement this function
121 - def inject(self, packet, channel=None, count=1, delay=0):
122 ''' 123 Injects the specified packet contents. 124 @type packet: String 125 @param packet: Packet contents to transmit, without FCS. 126 @type channel: Integer 127 @param channel: Sets the channel, optional 128 @type count: Integer 129 @param count: Transmits a specified number of frames, def=1 130 @type delay: Float 131 @param delay: Delay between each frame, def=1 132 @rtype: None 133 ''' 134 self.capabilities.require(KBCapabilities.INJECT) 135 136 if len(packet) < 1: 137 raise Exception('Empty packet') 138 if len(packet) > 125: # 127 - 2 to accommodate FCS 139 raise Exception('Packet too long') 140 141 if channel != None: 142 self.set_channel(channel) 143 self.handle.RF_autocrc(1) #let the radio add the CRC 144 for pnum in range(0, count): 145 gfready = [ord(x) for x in packet] #convert packet string to GoodFET expected integer format 146 gfready.insert(0, len(gfready)+2) #add a length that leaves room for CRC 147 self.handle.RF_txpacket(gfready) 148 time.sleep(delay)
149 150 # KillerBee expects the driver to implement this function
151 - def pnext(self, timeout=100):
152 ''' 153 Returns a dictionary containing packet data, else None. 154 @type timeout: Integer 155 @param timeout: Timeout to wait for packet reception in usec 156 @rtype: List 157 @return: Returns None is timeout expires and no packet received. When a packet is received, a dictionary is returned with the keys bytes (string of packet bytes), validcrc (boolean if a vaid CRC), rssi (unscaled RSSI), and location (may be set to None). For backwards compatibility, keys for 0,1,2 are provided such that it can be treated as if a list is returned, in the form [ String: packet contents | Bool: Valid CRC | Int: Unscaled RSSI ] 158 ''' 159 if self.__stream_open == False: 160 self.sniffer_on() #start sniffing 161 162 packet = None; 163 start = datetime.now() 164 while (packet is None and (start + timedelta(microseconds=timeout) > datetime.now())): 165 packet = self.handle.RF_rxpacket() 166 if packet is None: 167 return None 168 rssi = self.handle.RF_getrssi() #TODO calibrate 169 frame = packet 170 if frame[-2:] == makeFCS(frame[:-2]): validcrc = True 171 else: validcrc = False 172 #Return in a nicer dictionary format, so we don't have to reference by number indicies. 173 #Note that 0,1,2 indicies inserted twice for backwards compatibility. 174 result = {0:frame, 1:validcrc, 2:rssi, 'bytes':frame, 'validcrc':validcrc, 'rssi':rssi, 'location':None} 175 result['dbm'] = rssi - 45 #TODO tune specifically to the Tmote platform (does ext antenna need to different?) 176 result['datetime'] = datetime.combine(date.today(), (datetime.now()).time()) #TODO address timezones by going to UTC everywhere 177 return result
178
179 - def jammer_on(self, channel=None):
180 ''' 181 Not yet implemented. 182 @type channel: Integer 183 @param channel: Sets the channel, optional 184 @rtype: None 185 ''' 186 raise Exception('Not yet implemented')
187
188 - def set_sync(self, sync=0xA7):
189 '''Set the register controlling the 802.15.4 PHY sync byte.''' 190 self.capabilities.require(KBCapabilities.SET_SYNC) 191 if (sync >> 8) > 0: 192 raise Exception("Sync word (%x) must be 1 byte." % sync) 193 if (sync & 0x0F) == 0: 194 raise Exception("Least-significant nybble in sync (%x) cannot be 0." % sync) 195 return self.handle.poke(ATMEL_REG_SYNC, sync)
196
197 - def jammer_off(self, channel=None):
198 ''' 199 Not yet implemented. 200 @return: None 201 @rtype: None 202 ''' 203 #TODO implement 204 raise Exception('Not yet implemented')
205