root / branches / wireless / code / projects / libwireless / xbee.c @ 1656
History | View | Annotate | Download (38 KB)
1 | 1576 | dsschult | /**
|
---|---|---|---|
2 | * Copyright (c) 2009 Colony Project
|
||
3 | *
|
||
4 | * Permission is hereby granted, free of charge, to any person
|
||
5 | * obtaining a copy of this software and associated documentation
|
||
6 | * files (the "Software"), to deal in the Software without
|
||
7 | * restriction, including without limitation the rights to use,
|
||
8 | * copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||
9 | * copies of the Software, and to permit persons to whom the
|
||
10 | * Software is furnished to do so, subject to the following
|
||
11 | * conditions:
|
||
12 | *
|
||
13 | * The above copyright notice and this permission notice shall be
|
||
14 | * included in all copies or substantial portions of the Software.
|
||
15 | *
|
||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||
17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||
18 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||
19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||
20 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||
21 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||
22 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||
23 | * OTHER DEALINGS IN THE SOFTWARE.
|
||
24 | **/
|
||
25 | |||
26 | /**
|
||
27 | * @file xbee.c
|
||
28 | * @brief XBee Interface
|
||
29 | *
|
||
30 | * Implementation of low level communication with the XBee in API mode.
|
||
31 | *
|
||
32 | * @author Colony Project, CMU Robotics Club
|
||
33 | **/
|
||
34 | 1642 | dsschult | #include <lights.h> |
35 | 1576 | dsschult | |
36 | 1601 | dsschult | #include <string.h> |
37 | 1642 | dsschult | #include <avr/io.h> |
38 | 1601 | dsschult | #include <avr/interrupt.h> |
39 | 1576 | dsschult | #include <time.h> |
40 | 1642 | dsschult | #include <wl_defs.h> |
41 | #include <wireless.h> |
||
42 | 1601 | dsschult | #include "xbee.h" |
43 | 1576 | dsschult | |
44 | |||
45 | 1601 | dsschult | /* Internal Function Prototypes */
|
46 | 1576 | dsschult | |
47 | 1601 | dsschult | /* I/O Functions */
|
48 | 1611 | dsschult | static int8_t xbee_send_string(uint8_t* c);
|
49 | 1576 | dsschult | |
50 | 1601 | dsschult | /* Command Mode Functions */
|
51 | 1611 | dsschult | static int8_t xbee_enter_command_mode(void); |
52 | static int8_t xbee_exit_command_mode(void); |
||
53 | static int8_t xbee_enter_api_mode(void); |
||
54 | static int8_t xbee_exit_api_mode(void); |
||
55 | static int8_t xbee_wait_for_string(uint8_t* s, uint16_t len);
|
||
56 | static int8_t xbee_wait_for_ok(void); |
||
57 | 1576 | dsschult | |
58 | 1601 | dsschult | /* API Mode Functions */
|
59 | 1616 | dsschult | //TODO: does this exist? static int8_t xbee_handle_packet(uint8_t* packet, uint16_t len);
|
60 | 1642 | dsschult | static int8_t xbee_handle_at_command_response(uint16_t command, uint8_t status, uint8_t len);
|
61 | 1609 | dsschult | static void xbee_handle_status(uint8_t status); |
62 | 1611 | dsschult | static int8_t xbee_verify_checksum(uint8_t* packet, uint16_t len);
|
63 | static uint8_t xbee_compute_checksum(uint8_t* packet, uint16_t len);
|
||
64 | static int8_t xbee_send_frame(uint8_t* buf, uint16_t len);
|
||
65 | int8_t xbee_send_read_at_command(uint8_t* command); |
||
66 | static int8_t xbee_send_modify_at_command(uint8_t* command, uint8_t* value, uint8_t len);
|
||
67 | 1576 | dsschult | |
68 | 1601 | dsschult | /* Buffer Manipulation Functions */
|
69 | int8_t xbee_basic_buf_add(uint8_t *ptr, uint8_t byte); |
||
70 | uint8_t xbee_basic_buf_get(uint8_t *ptr); |
||
71 | int8_t xbee_other_buf_add(uint8_t *ptr, uint8_t byte); |
||
72 | 1576 | dsschult | |
73 | 1616 | dsschult | /* private functions */
|
74 | int8_t check_last_receive(uint16_t source,uint8_t framenum); |
||
75 | inline uint8_t getStatus(uint8_t mask);
|
||
76 | inline void setStatus(uint8_t mask,uint8_t value); |
||
77 | 1576 | dsschult | |
78 | 1601 | dsschult | /*Global Variables*/
|
79 | 1576 | dsschult | |
80 | 1616 | dsschult | // last few packet sources and frame nums
|
81 | #define NUM_LAST_PACKETS 10 |
||
82 | struct {
|
||
83 | uint16_t source; |
||
84 | uint8_t framenum; |
||
85 | } lastPacket[NUM_LAST_PACKETS]; |
||
86 | |||
87 | 1591 | dsschult | // array for basic packets
|
88 | 1648 | dsschult | uint8_t xbee_basic_buf[PACKET_BUFFER_SIZE]; |
89 | 1591 | dsschult | |
90 | // beginning of first packet in basic buffer
|
||
91 | 1648 | dsschult | uint8_t basic_buf_first = 0xFF;
|
92 | 1591 | dsschult | |
93 | // byte after end of last packet in basic buffer (only access < basic_buf_last)
|
||
94 | // aka, the first free byte in basic buffer
|
||
95 | 1648 | dsschult | uint8_t basic_buf_last = 0;
|
96 | 1591 | dsschult | |
97 | // array for other packets
|
||
98 | 1648 | dsschult | uint8_t xbee_other_buf[PACKET_BUFFER_SIZE]; |
99 | 1576 | dsschult | |
100 | 1591 | dsschult | // beginning of first packet in other buffer
|
101 | 1648 | dsschult | uint8_t other_buf_first = 0xFF;
|
102 | 1591 | dsschult | |
103 | // byte after end of last packet in other buffer (only access < other_buf_last)
|
||
104 | // aka, the first free byte in other buffer
|
||
105 | 1648 | dsschult | uint8_t other_buf_last = 0;
|
106 | 1591 | dsschult | |
107 | 1600 | dsschult | // xbee status
|
108 | 1616 | dsschult | #define XBEE_API_OFF 0x00 |
109 | #define XBEE_API_ON 0x10 |
||
110 | #define XBEE_API_ESCAPE 0x20 |
||
111 | #define XBEE_API_MASK 0x30 |
||
112 | 1600 | dsschult | #define XBEE_COMMAND_WAIT 0x80 |
113 | #define XBEE_COMMAND_RESPONSE 0xC0 |
||
114 | 1616 | dsschult | #define XBEE_COMMAND_NONE 0x00 |
115 | #define XBEE_COMMAND_MASK 0xC0 |
||
116 | #define XBEE_NOT_INITD 0xF0 |
||
117 | #define LAST_PACKET_MASK 0x0F |
||
118 | uint8_t xbee_status = XBEE_NOT_INITD; |
||
119 | 1600 | dsschult | |
120 | // xbee command response (for PAN, channel, address, etc)
|
||
121 | 1642 | dsschult | static uint8_t xbee_command[8]; |
122 | 1600 | dsschult | |
123 | 1591 | dsschult | // external ack handler (wireless_send.c)
|
124 | 1648 | dsschult | extern void ackhandle(uint8_t num,uint8_t val); |
125 | 1591 | dsschult | |
126 | 1601 | dsschult | |
127 | 1642 | dsschult | |
128 | 1587 | dsschult | /**@addtogroup xbee
|
129 | * @{ **/
|
||
130 | |||
131 | 1576 | dsschult | /*Function Implementations*/
|
132 | |||
133 | /**
|
||
134 | * Interrupt for the robot. Adds bytes received from the xbee
|
||
135 | * to the buffer.
|
||
136 | **/
|
||
137 | 1624 | dsschult | |
138 | 1642 | dsschult | |
139 | 1576 | dsschult | #ifndef FIREFLY
|
140 | 1642 | dsschult | #define PORT UDR1
|
141 | #define FLAG (UCSR1A & (1<<RXC1)) |
||
142 | ISR(USART1_RX_vect) { |
||
143 | 1576 | dsschult | #else
|
144 | 1642 | dsschult | #define PORT UDR0
|
145 | #define FLAG (UCSR0A & (1<<RXC0)) |
||
146 | 1624 | dsschult | SIGNAL(SIG_USART0_RECV) |
147 | #endif
|
||
148 | 1591 | dsschult | // start of frame
|
149 | 1624 | dsschult | uint8_t apitype = PORT; // get frame start byte
|
150 | 1591 | dsschult | uint16_t i=0;
|
151 | uint16_t len=0;
|
||
152 | 1654 | dsschult | |
153 | /*WL_DEBUG_PRINT("in interrupt|status=");
|
||
154 | WL_DEBUG_PRINT_HEX(xbee_status);
|
||
155 | WL_DEBUG_PRINT("|frame_start=");
|
||
156 | WL_DEBUG_PRINT_HEX(apitype);
|
||
157 | |||
158 | if (getStatus(XBEE_API_MASK) == XBEE_API_OFF) {
|
||
159 | WL_DEBUG_PRINT("|API OFF");
|
||
160 | } else if (getStatus(XBEE_API_MASK) == XBEE_API_ON) {
|
||
161 | WL_DEBUG_PRINT("|API ON");
|
||
162 | } else {
|
||
163 | WL_DEBUG_PRINT("|API ERROR");
|
||
164 | }*/
|
||
165 | |||
166 | 1600 | dsschult | // check that we're in API mode
|
167 | 1616 | dsschult | if (getStatus(XBEE_API_MASK) == XBEE_API_OFF || apitype != XBEE_FRAME_START) {
|
168 | 1600 | dsschult | // not in API mode
|
169 | 1654 | dsschult | WL_DEBUG_PRINT("|api off branch");
|
170 | 1642 | dsschult | |
171 | 1616 | dsschult | if (getStatus(XBEE_COMMAND_MASK) == XBEE_COMMAND_WAIT) {
|
172 | 1600 | dsschult | // get rest of command and put in basic buf
|
173 | 1642 | dsschult | xbee_basic_buf[i] = apitype; |
174 | if (xbee_basic_buf[i++] != '\r') { |
||
175 | 1600 | dsschult | while(i < PACKET_BUFFER_SIZE) {
|
176 | if (FLAG) {
|
||
177 | xbee_basic_buf[i] = PORT; |
||
178 | if (xbee_basic_buf[i] == '\r') |
||
179 | break;
|
||
180 | 1642 | dsschult | i++; |
181 | 1600 | dsschult | } |
182 | } |
||
183 | } |
||
184 | 1654 | dsschult | WL_DEBUG_PRINT("got packet, len=");
|
185 | 1642 | dsschult | WL_DEBUG_PRINT_INT(i); |
186 | WL_DEBUG_PRINT("str=");
|
||
187 | 1624 | dsschult | WL_DEBUG_PRINT(xbee_basic_buf); |
188 | 1600 | dsschult | // signal handler that command response is done
|
189 | 1616 | dsschult | setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_RESPONSE); |
190 | 1600 | dsschult | } |
191 | 1624 | dsschult | WL_DEBUG_PRINT("return\r\n");
|
192 | 1600 | dsschult | return;
|
193 | 1624 | dsschult | } |
194 | 1654 | dsschult | //WL_DEBUG_PRINT("|api on branch");
|
195 | 1600 | dsschult | |
196 | 1591 | dsschult | // get length and type
|
197 | while(i<3) { |
||
198 | if (FLAG) {
|
||
199 | 1642 | dsschult | if (i==0) { |
200 | 1654 | dsschult | len |= PORT<<8;
|
201 | //WL_DEBUG_PRINT("|len_hi");
|
||
202 | 1642 | dsschult | } else if (i==1) { |
203 | 1591 | dsschult | len |= PORT; |
204 | 1654 | dsschult | //WL_DEBUG_PRINT("|len_lo");
|
205 | 1642 | dsschult | } else if (i==2) { |
206 | 1591 | dsschult | apitype = PORT; |
207 | 1654 | dsschult | //WL_DEBUG_PRINT("|GOT APITYPE");
|
208 | 1642 | dsschult | } |
209 | 1591 | dsschult | i++; |
210 | } |
||
211 | } |
||
212 | |||
213 | // do something based on the type
|
||
214 | i=1;
|
||
215 | switch(apitype) {
|
||
216 | 1611 | dsschult | case XBEE_FRAME_AT_COMMAND_RESPONSE: {
|
217 | 1591 | dsschult | // AT command response
|
218 | 1616 | dsschult | if (getStatus(XBEE_COMMAND_MASK) == XBEE_COMMAND_RESPONSE)
|
219 | 1642 | dsschult | return; // we're currently processing a command, so drop the incoming one ***** TODO: we need to read the whole length of the frame to do this right **** |
220 | 1591 | dsschult | uint16_t atcommand=0;
|
221 | uint8_t ptr=basic_buf_last; |
||
222 | while(i<len) {
|
||
223 | if (FLAG) {
|
||
224 | if (i==1) |
||
225 | apitype = PORT; // get frame id, but ignore it
|
||
226 | else if (i==2) |
||
227 | atcommand |= PORT<<8; // get command char1 |
||
228 | else if (i==3) |
||
229 | atcommand |= PORT; // get command char2
|
||
230 | else if (i==4) |
||
231 | apitype = PORT; // get status
|
||
232 | else {
|
||
233 | // put the command response on the basic buf temporarily
|
||
234 | 1600 | dsschult | if (xbee_basic_buf_add(&ptr,PORT) != 0) |
235 | 1591 | dsschult | break;
|
236 | } |
||
237 | i++; |
||
238 | } |
||
239 | 1642 | dsschult | } |
240 | // handle AT command
|
||
241 | WL_DEBUG_PRINT("i=");
|
||
242 | WL_DEBUG_PRINT_INT(i); |
||
243 | WL_DEBUG_PRINT("|len=");
|
||
244 | WL_DEBUG_PRINT_INT(len); |
||
245 | WL_DEBUG_PRINT("|status:");
|
||
246 | WL_DEBUG_PRINT_INT(apitype); |
||
247 | WL_DEBUG_PRINT("|atcommand:");
|
||
248 | WL_DEBUG_PRINT_CHAR((uint8_t)(atcommand>>8));
|
||
249 | WL_DEBUG_PRINT_CHAR((uint8_t)(atcommand&0xFF));
|
||
250 | WL_DEBUG_PRINT("|buf=");
|
||
251 | uint8_t ptr2 = basic_buf_last; |
||
252 | for(uint8_t j=0;j<i;j++) |
||
253 | WL_DEBUG_PRINT_HEX(xbee_basic_buf_get(&ptr2)); |
||
254 | WL_DEBUG_PRINT("|\r\n");
|
||
255 | xbee_handle_at_command_response(atcommand,apitype,len-5); // TODO: rewrite function |
||
256 | 1611 | dsschult | break; }
|
257 | case XBEE_FRAME_TX_STATUS: {
|
||
258 | 1591 | dsschult | // TX status
|
259 | 1609 | dsschult | uint8_t frame_id = 0;
|
260 | 1591 | dsschult | while(i<len) {
|
261 | if (FLAG) {
|
||
262 | if (i==1) |
||
263 | 1609 | dsschult | frame_id = PORT; |
264 | 1591 | dsschult | else {
|
265 | 1609 | dsschult | ackhandle(frame_id,PORT); // handle the status
|
266 | 1591 | dsschult | break;
|
267 | } |
||
268 | i++; |
||
269 | } |
||
270 | } |
||
271 | 1611 | dsschult | break; }
|
272 | case XBEE_FRAME_RX_64: {
|
||
273 | 1591 | dsschult | // receive a packet with 64bit address
|
274 | 1611 | dsschult | break; } // TODO: implement this (even if we don't use it) |
275 | case XBEE_FRAME_RX_16: {
|
||
276 | 1591 | dsschult | // receive a packet with 16bit address
|
277 | uint16_t source = 0;
|
||
278 | uint8_t framenum = 0;
|
||
279 | uint8_t group = 0;
|
||
280 | uint8_t ptr=basic_buf_last; |
||
281 | while(i<len) {
|
||
282 | if (FLAG) {
|
||
283 | if (i==1) |
||
284 | source |= PORT<<8; // get source hi byte |
||
285 | else if (i==2) |
||
286 | source |= PORT; // get source lo byte
|
||
287 | else if (i==3) |
||
288 | apitype = PORT; // get RSSI, and ignore
|
||
289 | else if (i==4) |
||
290 | apitype = PORT; // get options, and ignore
|
||
291 | else if (i==5) { |
||
292 | framenum = PORT; // get the frame number
|
||
293 | 1616 | dsschult | if (check_last_receive(source,framenum) != WL_SUCCESS) {
|
294 | 1591 | dsschult | // we've already received this frame
|
295 | ptr = 0xFF; // signal to skip processing |
||
296 | break;
|
||
297 | } |
||
298 | } |
||
299 | else if (i==6) { |
||
300 | group = PORT; // get group number
|
||
301 | if (group == 0) { |
||
302 | ptr = basic_buf_last+1;
|
||
303 | // add source to buffer
|
||
304 | 1600 | dsschult | if (xbee_basic_buf_add(&ptr,(uint8_t)((source&0xFF00)>>8)) != 0) |
305 | 1591 | dsschult | break;
|
306 | 1600 | dsschult | if (xbee_basic_buf_add(&ptr,(uint8_t)(source&0x00FF)) != 0) |
307 | 1591 | dsschult | break;
|
308 | } else {
|
||
309 | ptr = other_buf_last+1;
|
||
310 | 1600 | dsschult | // add source and group to buffer
|
311 | if (xbee_other_buf_add(&ptr,group) != 0) |
||
312 | 1591 | dsschult | break;
|
313 | 1600 | dsschult | if (xbee_other_buf_add(&ptr,(uint8_t)((source&0xFF00)>>8)) != 0) |
314 | 1591 | dsschult | break;
|
315 | 1600 | dsschult | if (xbee_other_buf_add(&ptr,(uint8_t)(source&0x00FF)) != 0) |
316 | 1591 | dsschult | break;
|
317 | } |
||
318 | } |
||
319 | 1600 | dsschult | else { // TODO: handle escaped characters supported by APIv2 |
320 | 1591 | dsschult | // put packet data on the correct buffer
|
321 | 1600 | dsschult | if (group == 0 && xbee_basic_buf_add(&ptr,PORT) != 0) |
322 | break;
|
||
323 | else if (xbee_other_buf_add(&ptr,PORT) != 0) |
||
324 | break;
|
||
325 | 1591 | dsschult | } |
326 | i++; |
||
327 | } |
||
328 | } |
||
329 | 1600 | dsschult | if (ptr != 0xFF && i > 6) { |
330 | 1591 | dsschult | if (group == 0) { |
331 | xbee_basic_buf[basic_buf_last] = i-6; // set length |
||
332 | basic_buf_last = ptr; |
||
333 | } |
||
334 | else {
|
||
335 | xbee_other_buf[other_buf_last] = i-6; // set length |
||
336 | // check if we have a high priority group
|
||
337 | for(;;)
|
||
338 | if (HIGH_PRIORITY) {
|
||
339 | // handle receive now
|
||
340 | ptr = 0xFF;
|
||
341 | break;
|
||
342 | } |
||
343 | if (ptr != 0xFF) { |
||
344 | // handle receive later
|
||
345 | other_buf_last = ptr; |
||
346 | } |
||
347 | } |
||
348 | } |
||
349 | 1611 | dsschult | break; }
|
350 | 1642 | dsschult | default:
|
351 | 1654 | dsschult | WL_DEBUG_PRINT("|BAD APITYPE");
|
352 | 1600 | dsschult | } // end of switch statement
|
353 | while (1) { |
||
354 | if (FLAG) {
|
||
355 | apitype = PORT; // get checksum, and ignore
|
||
356 | break;
|
||
357 | } |
||
358 | 1591 | dsschult | } |
359 | 1654 | dsschult | WL_DEBUG_PRINT("|interrupt - return\r\n");
|
360 | 1624 | dsschult | } // end of interrupt
|
361 | 1576 | dsschult | |
362 | 1642 | dsschult | |
363 | 1600 | dsschult | /* adds a byte to the basic buffer */
|
364 | int8_t xbee_basic_buf_add(uint8_t *ptr, uint8_t byte) { |
||
365 | if (*ptr == basic_buf_first) {
|
||
366 | // buffer full
|
||
367 | 1654 |