1 '''
2 Support for the TelosB / Tmote Sky platforms, and close clones.
3
4 Utilizes the GoodFET firmware with CCSPI application, and the GoodFET client code.
5 '''
6
7 import os
8 import time
9 import struct
10 import time
11 from datetime import datetime, date, timedelta
12 from kbutils import KBCapabilities, makeFCS
13 from GoodFETCCSPI import GoodFETCCSPI
14
15 CC2420_REG_SYNC = 0x14
16
19 '''
20 Instantiates the KillerBee class for our TelosB/TmoteSky running GoodFET firmware.
21 @type dev: String
22 @param dev: Serial device identifier (ex /dev/ttyUSB0)
23 @return: None
24 @rtype: None
25 '''
26 self._channel = None
27 self.handle = None
28 self.dev = dev
29
30 os.environ["board"] = "telosb"
31 self.handle = GoodFETCCSPI()
32 self.handle.serInit(port=self.dev)
33 self.handle.setup()
34
35 self.__stream_open = False
36 self.capabilities = KBCapabilities()
37 self.__set_capabilities()
38
40 self.handle.serClose()
41 self.handle = None
42
44 return self.capabilities.check(capab)
46 return self.capabilities.getlist()
60
61
62
64 '''
65 Returns device information in a list identifying the device.
66 @rtype: List
67 @return: List of 3 strings identifying device.
68 '''
69 return [self.dev, "TelosB/Tmote", ""]
70
71
73 '''
74 Turns the sniffer on such that pnext() will start returning observed
75 data. Will set the command mode to Air Capture if it is not already
76 set.
77 @type channel: Integer
78 @param channel: Sets the channel, optional
79 @rtype: None
80 '''
81 self.capabilities.require(KBCapabilities.SNIFF)
82
83 self.handle.RF_promiscuity(1);
84 self.handle.RF_autocrc(0);
85
86 if channel != None:
87 self.set_channel(channel)
88
89 self.handle.CC_RFST_RX();
90
91
92 self.__stream_open = True
93
94
96 '''
97 Turns the sniffer off, freeing the hardware for other functions. It is
98 not necessary to call this function before closing the interface with
99 close().
100 @rtype: None
101 '''
102
103 self.__stream_open = False
104
105
107 '''
108 Sets the radio interface to the specifid channel (limited to 2.4 GHz channels 11-26)
109 @type channel: Integer
110 @param channel: Sets the channel, optional
111 @rtype: None
112 '''
113 self.capabilities.require(KBCapabilities.SETCHAN)
114
115 if channel >= 11 or channel <= 26:
116 self._channel = channel
117 self.handle.RF_setchan(channel)
118 else:
119 raise Exception('Invalid channel')
120
121
122 - def inject(self, packet, channel=None, count=1, delay=0):
123 '''
124 Injects the specified packet contents.
125 @type packet: String
126 @param packet: Packet contents to transmit, without FCS.
127 @type channel: Integer
128 @param channel: Sets the channel, optional
129 @type count: Integer
130 @param count: Transmits a specified number of frames, def=1
131 @type delay: Float
132 @param delay: Delay between each frame, def=1
133 @rtype: None
134 '''
135 self.capabilities.require(KBCapabilities.INJECT)
136
137 if len(packet) < 1:
138 raise Exception('Empty packet')
139 if len(packet) > 125:
140 raise Exception('Packet too long')
141
142 if channel != None:
143 self.set_channel(channel)
144
145 self.handle.RF_autocrc(1)
146 for pnum in range(0, count):
147 gfready = [ord(x) for x in packet]
148 gfready.insert(0, len(gfready)+2)
149 self.handle.RF_txpacket(gfready)
150
151 time.sleep(0.01)
152
153
154
155 - def pnext(self, timeout=100):
156 '''
157 Returns a dictionary containing packet data, else None.
158 @type timeout: Integer
159 @param timeout: Timeout to wait for packet reception in usec
160 @rtype: List
161 @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 ]
162 '''
163 if self.__stream_open == False:
164 self.sniffer_on()
165
166 packet = None;
167 start = datetime.now()
168
169 while (packet is None and (start + timedelta(microseconds=timeout) > datetime.now())):
170 packet = self.handle.RF_rxpacket()
171 rssi = self.handle.RF_getrssi()
172
173 if packet is None:
174 return None
175
176 frame = packet[1:]
177 if frame[-2:] == makeFCS(frame[:-2]): validcrc = True
178 else: validcrc = False
179
180
181 result = {0:frame, 1:validcrc, 2:rssi, 'bytes':frame, 'validcrc':validcrc, 'rssi':rssi, 'location':None}
182 result['dbm'] = rssi - 45
183 result['datetime'] = datetime.combine(date.today(), (datetime.now()).time())
184 return result
185
186 - def ping(self, da, panid, sa, channel=None):
187 '''
188 Not yet implemented.
189 @return: None
190 @rtype: None
191 '''
192 raise Exception('Not yet implemented')
193
209
211 '''Set the register controlling the 802.15.4 PHY sync byte.'''
212 self.capabilities.require(KBCapabilities.SET_SYNC)
213 if (sync >> 16) > 0:
214 raise Exception("Sync word (%x) must be 2-bytes or less." % sync)
215 return self.handle.poke(CC2420_REG_SYNC, sync)
216
218 '''
219 Not yet implemented.
220 @return: None
221 @rtype: None
222 '''
223
224 raise Exception('Not yet implemented')
225