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
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
43 self.handle.serClose()
44 self.handle = None
45
47 return self.capabilities.check(capab)
48
50 return self.capabilities.getlist()
51
64
65
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
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
90
91 self.__stream_open = True
92
93
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
102 self.__stream_open = False
103
104
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
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:
139 raise Exception('Packet too long')
140
141 if channel != None:
142 self.set_channel(channel)
143 self.handle.RF_autocrc(1)
144 for pnum in range(0, count):
145 gfready = [ord(x) for x in packet]
146 gfready.insert(0, len(gfready)+2)
147 self.handle.RF_txpacket(gfready)
148 time.sleep(delay)
149
150
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()
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()
169 frame = packet
170 if frame[-2:] == makeFCS(frame[:-2]): validcrc = True
171 else: validcrc = False
172
173
174 result = {0:frame, 1:validcrc, 2:rssi, 'bytes':frame, 'validcrc':validcrc, 'rssi':rssi, 'location':None}
175 result['dbm'] = rssi - 45
176 result['datetime'] = datetime.combine(date.today(), (datetime.now()).time())
177 return result
178
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
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
198 '''
199 Not yet implemented.
200 @return: None
201 @rtype: None
202 '''
203
204 raise Exception('Not yet implemented')
205