root / branches / wireless / code / projects / libwireless / xbee.c @ 1601
History | View | Annotate | Download (26.1 KB)
1 |
/**
|
---|---|
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 |
|
35 |
#include <string.h> |
36 |
#include <avr/interrupt.h> |
37 |
#include <time.h> |
38 |
#include <serial.h> // TODO: integrate serial xbee functions into this file |
39 |
#include "wl_defs.h" |
40 |
#include "xbee.h" |
41 |
|
42 |
|
43 |
/* Internal Function Prototypes */
|
44 |
|
45 |
// TODO: convert all int references to int16_t syntax (see stdint.h)
|
46 |
|
47 |
/* I/O Functions */
|
48 |
static int8_t xbee_send(uint8_t* buf, uint16_t size);
|
49 |
static int8_t xbee_send_string(unsigned char* c); |
50 |
|
51 |
/* Command Mode Functions */
|
52 |
static int xbee_enter_command_mode(void); |
53 |
static int xbee_exit_command_mode(void); |
54 |
static int xbee_enter_api_mode(void); |
55 |
static int xbee_exit_api_mode(void); |
56 |
static int xbee_wait_for_string(char* s, int len); |
57 |
static int xbee_wait_for_ok(void); |
58 |
|
59 |
/* API Mode Functions */
|
60 |
static int xbee_handle_packet(uint8_t* packet, uint16_t len); |
61 |
static int xbee_handle_at_command_response(uint16_t command, uint8_t result, uint8_t len); |
62 |
static int xbee_handle_at_command_response(uint16_t command, uint8_t result, uint8_t len); |
63 |
static void xbee_handle_status(char status); |
64 |
static int xbee_verify_checksum(char* packet, int len); |
65 |
static char xbee_compute_checksum(char* packet, int len); |
66 |
static int xbee_send_frame(char* buf, int len); |
67 |
int xbee_send_read_at_command(char* command); |
68 |
static int xbee_send_modify_at_command(char* command, char* value); |
69 |
|
70 |
/* Buffer Manipulation Functions */
|
71 |
int8_t xbee_basic_buf_add(uint8_t *ptr, uint8_t byte); |
72 |
uint8_t xbee_basic_buf_get(uint8_t *ptr); |
73 |
int8_t xbee_other_buf_add(uint8_t *ptr, uint8_t byte); |
74 |
|
75 |
|
76 |
/*Global Variables*/
|
77 |
|
78 |
// array for basic packets
|
79 |
static uint8_t xbee_basic_buf[PACKET_BUFFER_SIZE];
|
80 |
|
81 |
// beginning of first packet in basic buffer
|
82 |
static uint8_t basic_buf_first = 0; |
83 |
|
84 |
// byte after end of last packet in basic buffer (only access < basic_buf_last)
|
85 |
// aka, the first free byte in basic buffer
|
86 |
static uint8_t basic_buf_last = 0; |
87 |
|
88 |
// array for other packets
|
89 |
static uint8_t xbee_other_buf[PACKET_BUFFER_SIZE];
|
90 |
|
91 |
// beginning of first packet in other buffer
|
92 |
static uint8_t other_buf_first = 0; |
93 |
|
94 |
// byte after end of last packet in other buffer (only access < other_buf_last)
|
95 |
// aka, the first free byte in other buffer
|
96 |
static uint8_t other_buf_last = 0; |
97 |
|
98 |
|
99 |
// xbee status
|
100 |
#define XBEE_API_OFF 0x0 |
101 |
#define XBEE_API_ON 0x1 |
102 |
#define XBEE_API_ESCAPE 0x2 |
103 |
#define XBEE_NORMAL 0x00 |
104 |
#define XBEE_COMMAND_WAIT 0x80 |
105 |
#define XBEE_COMMAND_RESPONSE 0xC0 |
106 |
static uint8_t xbee_status = XBEE_API_OFF|XBEE_NORMAL;
|
107 |
|
108 |
// xbee command response (for PAN, channel, address, etc)
|
109 |
static uint8_t xbee_command[4]; |
110 |
|
111 |
// external ack handler (wireless_send.c)
|
112 |
extern void ackhandle(uint8_t num,uint8_t val); |
113 |
|
114 |
|
115 |
/**@addtogroup xbee
|
116 |
* @{ **/
|
117 |
|
118 |
/*Function Implementations*/
|
119 |
|
120 |
/**
|
121 |
* Interrupt for the robot. Adds bytes received from the xbee
|
122 |
* to the buffer.
|
123 |
**/
|
124 |
#ifndef FIREFLY
|
125 |
#define PORT UDR1
|
126 |
#define FLAG RXC1
|
127 |
ISR(USART1_RX_vect) |
128 |
#else
|
129 |
#define PORT UDR0
|
130 |
#define FLAG RXC0
|
131 |
SIGNAL(SIG_USART0_RECV) |
132 |
#endif
|
133 |
{ |
134 |
// start of frame
|
135 |
uint8_t apitype = PORT; // get frame start byte
|
136 |
uint16_t i=0;
|
137 |
uint16_t len=0;
|
138 |
|
139 |
// check that we're in API mode
|
140 |
if (xbee_status&0x03 == XBEE_API_OFF || apitype != XBEE_FRAME_START) { |
141 |
// not in API mode
|
142 |
if (xbee_status&0xC0) == XBEE_COMMAND_WAIT) { |
143 |
// get rest of command and put in basic buf
|
144 |
xbee_basic_buf[0] = apitype;
|
145 |
if (xbee_basic_buf[i] != '\r') { |
146 |
while(i < PACKET_BUFFER_SIZE) {
|
147 |
if (FLAG) {
|
148 |
xbee_basic_buf[i] = PORT; |
149 |
if (xbee_basic_buf[i] == '\r') |
150 |
break;
|
151 |
} |
152 |
} |
153 |
} |
154 |
// signal handler that command response is done
|
155 |
xbee_status = (xbee_status&0x3F)|XBEE_COMMAND_RESPONSE;
|
156 |
} |
157 |
return;
|
158 |
} |
159 |
|
160 |
// get length and type
|
161 |
while(i<3) { |
162 |
if (FLAG) {
|
163 |
if (i==0) |
164 |
len |= PORT<<8;
|
165 |
else if (i==1) |
166 |
len |= PORT; |
167 |
else if (i==2) |
168 |
apitype = PORT; |
169 |
i++; |
170 |
} |
171 |
} |
172 |
|
173 |
// do something based on the type
|
174 |
i=1;
|
175 |
switch(apitype) {
|
176 |
case XBEE_FRAME_AT_COMMAND_RESPONSE:
|
177 |
// AT command response
|
178 |
if (xbee_status&0xC0 == XBEE_COMMAND_RESPONSE) |
179 |
return; // we're currently processing a command, so drop the incoming one |
180 |
uint16_t atcommand=0;
|
181 |
uint8_t ptr=basic_buf_last; |
182 |
while(i<len) {
|
183 |
if (FLAG) {
|
184 |
if (i==1) |
185 |
apitype = PORT; // get frame id, but ignore it
|
186 |
else if (i==2) |
187 |
atcommand |= PORT<<8; // get command char1 |
188 |
else if (i==3) |
189 |
atcommand |= PORT; // get command char2
|
190 |
else if (i==4) |
191 |
apitype = PORT; // get status
|
192 |
else {
|
193 |
// put the command response on the basic buf temporarily
|
194 |
if (xbee_basic_buf_add(&ptr,PORT) != 0) |
195 |
break;
|
196 |
} |
197 |
i++; |
198 |
} |
199 |
} |
200 |
// handle AT command
|
201 |
xbee_handle_at_command_response(atcommand,apitype,i-5); // TODO: rewrite function |
202 |
break;
|
203 |
case XBEE_FRAME_TX_STATUS:
|
204 |
// TX status
|
205 |
uint8_t frameid=0;
|
206 |
while(i<len) {
|
207 |
if (FLAG) {
|
208 |
if (i==1) |
209 |
frameid = PORT; |
210 |
else {
|
211 |
ackhandle(frameid,PORT); // handle the status
|
212 |
break;
|
213 |
} |
214 |
i++; |
215 |
} |
216 |
} |
217 |
break;
|
218 |
case XBEE_FRAME_RX_64:
|
219 |
// receive a packet with 64bit address
|
220 |
break; // TODO: implement this (even if we don't use it) |
221 |
case XBEE_FRAME_RX_16:
|
222 |
// receive a packet with 16bit address
|
223 |
uint16_t source = 0;
|
224 |
uint8_t framenum = 0;
|
225 |
uint8_t group = 0;
|
226 |
uint8_t ptr=basic_buf_last; |
227 |
while(i<len) {
|
228 |
if (FLAG) {
|
229 |
if (i==1) |
230 |
source |= PORT<<8; // get source hi byte |
231 |
else if (i==2) |
232 |
source |= PORT; // get source lo byte
|
233 |
else if (i==3) |
234 |
apitype = PORT; // get RSSI, and ignore
|
235 |
else if (i==4) |
236 |
apitype = PORT; // get options, and ignore
|
237 |
else if (i==5) { |
238 |
framenum = PORT; // get the frame number
|
239 |
if (check_last_receive(source,framenum) != 0) { // TODO: write function |
240 |
// we've already received this frame
|
241 |
ptr = 0xFF; // signal to skip processing |
242 |
break;
|
243 |
} |
244 |
} |
245 |
else if (i==6) { |
246 |
group = PORT; // get group number
|
247 |
if (group == 0) { |
248 |
ptr = basic_buf_last+1;
|
249 |
// add source to buffer
|
250 |
if (xbee_basic_buf_add(&ptr,(uint8_t)((source&0xFF00)>>8)) != 0) |
251 |
break;
|
252 |
if (xbee_basic_buf_add(&ptr,(uint8_t)(source&0x00FF)) != 0) |
253 |
break;
|
254 |
} else {
|
255 |
ptr = other_buf_last+1;
|
256 |
// add source and group to buffer
|
257 |
if (xbee_other_buf_add(&ptr,group) != 0) |
258 |
break;
|
259 |
if (xbee_other_buf_add(&ptr,(uint8_t)((source&0xFF00)>>8)) != 0) |
260 |
break;
|
261 |
if (xbee_other_buf_add(&ptr,(uint8_t)(source&0x00FF)) != 0) |
262 |
break;
|
263 |
} |
264 |
} |
265 |
else { // TODO: handle escaped characters supported by APIv2 |
266 |
// put packet data on the correct buffer
|
267 |
if (group == 0 && xbee_basic_buf_add(&ptr,PORT) != 0) |
268 |
break;
|
269 |
else if (xbee_other_buf_add(&ptr,PORT) != 0) |
270 |
break;
|
271 |
} |
272 |
i++; |
273 |
} |
274 |
} |
275 |
if (ptr != 0xFF && i > 6) { |
276 |
if (group == 0) { |
277 |
xbee_basic_buf[basic_buf_last] = i-6; // set length |
278 |
basic_buf_last = ptr; |
279 |
} |
280 |
else {
|
281 |
xbee_other_buf[other_buf_last] = i-6; // set length |
282 |
// check if we have a high priority group
|
283 |
for(;;)
|
284 |
if (HIGH_PRIORITY) {
|
285 |
// handle receive now
|
286 |
ptr = 0xFF;
|
287 |
break;
|
288 |
} |
289 |
if (ptr != 0xFF) { |
290 |
// handle receive later
|
291 |
other_buf_last = ptr; |
292 |
} |
293 |
} |
294 |
} |
295 |
break;
|
296 |
} // end of switch statement
|
297 |
while (1) { |
298 |
if (FLAG) {
|
299 |
apitype = PORT; // get checksum, and ignore
|
300 |
break;
|
301 |
} |
302 |
} |
303 |
} // end of interrupt
|
304 |
|
305 |
|
306 |
|
307 |
/* adds a byte to the basic buffer */
|
308 |
int8_t xbee_basic_buf_add(uint8_t *ptr, uint8_t byte) { |
309 |
if (*ptr == basic_buf_first) {
|
310 |
// buffer full
|
311 |
WL_DEBUG_PRINT("basic buffer full\r\n");
|
312 |
return -1; |
313 |
} |
314 |
xbee_basic_buf[(*ptr)++] = byte); |
315 |
if (*ptr == PACKET_BUFFER_SIZE)
|
316 |
*ptr = 0;
|
317 |
return 0; |
318 |
} |
319 |
/* gets a byte from the basic buffer */
|
320 |
uint8_t xbee_basic_buf_get(uint8_t *ptr) { |
321 |
uint8_t byte = xbee_basic_buf[(*ptr)++]; |
322 |
if (*ptr == PACKET_BUFFER_SIZE)
|
323 |
*ptr = 0;
|
324 |
return byte;
|
325 |
} |
326 |
/* adds a byte to the other buffer */
|
327 |
int8_t xbee_other_buf_add(uint8_t *ptr, uint8_t byte) { |
328 |
if (*ptr == other_buf_first) {
|
329 |
// buffer full
|
330 |
WL_DEBUG_PRINT("other buffer full\r\n");
|
331 |
return -1; |
332 |
} |
333 |
xbee_other_buf[(*ptr)++] = byte; |
334 |
if (ptr == PACKET_BUFFER_SIZE)
|
335 |
*ptr = 0;
|
336 |
return 0; |
337 |
} |
338 |
|
339 |
|
340 |
/**
|
341 |
* Initializes the XBee library so that other functions may be used.
|
342 |
**/
|
343 |
int8_t xbee_lib_init() |
344 |
{ |
345 |
// do serial.c xbee init TODO: merge this into xbee.c
|
346 |
if (xbee_init() != 0) { |
347 |
usb_puts("xbee_init error");
|
348 |
return WL_ERROR_INIT_FAILED;
|
349 |
} |
350 |
|
351 |
WL_DEBUG_PRINT("in xbee_init\n");
|
352 |
|
353 |
//enable the receiving interrupt
|
354 |
#ifdef FIREFLY
|
355 |
UCSR0B |= _BV(RXCIE) | _BV(RXEN); |
356 |
#else
|
357 |
#ifdef BAYBOARD
|
358 |
UCSR1B |= _BV(RXCIE1); |
359 |
#else
|
360 |
UCSR1B |= _BV(RXCIE); |
361 |
#endif
|
362 |
#endif
|
363 |
sei(); |
364 |
|
365 |
WL_DEBUG_PRINT("Entering command mode.\r\n");
|
366 |
if (xbee_enter_command_mode() != 0) { |
367 |
usb_puts("error entering command mode\r\n");
|
368 |
return -1; |
369 |
} |
370 |
WL_DEBUG_PRINT("Entered command mode.\r\n");
|
371 |
|
372 |
// reset baud rate
|
373 |
WL_DEBUG_PRINT("Resetting Baud to ");
|
374 |
WL_DEBUG_PRINT(XBEE_BAUD_STR); |
375 |
WL_DEBUG_PRINT("\r\n");
|
376 |
|
377 |
// set baud on xbee
|
378 |
#if (XBEE_BAUD == 115200) |
379 |
xbee_send_string("ATBD7\r");
|
380 |
#elif (XBEE_BAUD == 57600) |
381 |
xbee_send_string("ATBD6\r");
|
382 |
#elif (XBEE_BAUD == 38400) |
383 |
xbee_send_string("ATBD5\r");
|
384 |
#elif (XBEE_BAUD == 19200) |
385 |
xbee_send_string("ATBD4\r");
|
386 |
#elif (XBEE_BAUD == 9600) |
387 |
// already at this baud rate
|
388 |
//xbee_send_string("ATBD3\r\n");
|
389 |
#else
|
390 |
WL_DEBUG_PRINT("undefined baud rate\r\n");
|
391 |
return WL_ERROR_BAUD;
|
392 |
#endif
|
393 |
// exit command mode
|
394 |
xbee_wait_for_ok(); |
395 |
WL_DEBUG_PRINT("got ok from baud reset\r\n");
|
396 |
xbee_send_string("ATCN\r");
|
397 |
xbee_wait_for_ok(); |
398 |
WL_DEBUG_PRINT("got ok from exiting command mode\r\n");
|
399 |
|
400 |
// set UART baud
|
401 |
#if (XBEE_BAUD == 115200) |
402 |
UBRR1H = 0x00;
|
403 |
UBRR1L = 8;
|
404 |
UCSR1A |= _BV(U2X1); |
405 |
#elif (XBEE_BAUD == 57600) |
406 |
UBRR1H = 0x00;
|
407 |
UBRR1L = 16;
|
408 |
UCSR1A |= _BV(U2X1); |
409 |
#elif (XBEE_BAUD == 38400) |
410 |
UBRR1H = 0x00;
|
411 |
UBRR1L = 25;
|
412 |
UCSR1A |= _BV(U2X1); |
413 |
#elif (XBEE_BAUD == 19200) |
414 |
UBRR1H = 0x00;
|
415 |
UBRR1L = 51;
|
416 |
UCSR1A |= _BV(U2X1); |
417 |
#elif (XBEE_BAUD == 9600) |
418 |
/* this is the default baud rate, so do nothing
|
419 |
UBRR1H = 0x00;
|
420 |
UBRR1L = 103;
|
421 |
UCSR1A |= _BV(U2X1);*/
|
422 |
#else
|
423 |
WL_DEBUG_PRINT("undefined baud rate\r\n");
|
424 |
return WL_ERROR_BUAD;
|
425 |
#endif
|
426 |
delay_ms(50);
|
427 |
|
428 |
// enter command mode
|
429 |
WL_DEBUG_PRINT("entering command mode 2\r\n");
|
430 |
xbee_send_string("+++");
|
431 |
xbee_wait_for_ok(); |
432 |
WL_DEBUG_PRINT("entered command mode 2\r\n");
|
433 |
|
434 |
if (xbee_enter_api_mode() != 0) { |
435 |
WL_DEBUG_PRINT("can't enter api mode\r\n");
|
436 |
return -1; |
437 |
} |
438 |
|
439 |
WL_DEBUG_PRINT("Entered api mode.\r\n");
|
440 |
|
441 |
if (xbee_exit_command_mode() != 0) { |
442 |
WL_DEBUG_PRINT("can't exit command mode\r\n");
|
443 |
return -1; |
444 |
} |
445 |
|
446 |
WL_DEBUG_PRINT("Left command mode.\r\n");
|
447 |
|
448 |
// TODO: we should set the MY address to the robot address from eeprom
|
449 |
|
450 |
return WL_SUCCESS;
|
451 |
} |
452 |
|
453 |
/**
|
454 |
* Call when finished using the XBee library.
|
455 |
**/
|
456 |
void xbee_terminate()
|
457 |
{ |
458 |
xbee_exit_api_mode(); |
459 |
} |
460 |
|
461 |
/**
|
462 |
* Send a buffer buf of size bytes to the XBee.
|
463 |
*
|
464 |
* @param buf the buffer of data to send
|
465 |
* @param size the number of bytes to send
|
466 |
**/
|
467 |
static int8_t xbee_send(uint8_t* buf, uint16_t size)
|
468 |
{ |
469 |
while(--size > 0) |
470 |
if (xbee_putc(buf[i]) != WL_SUCCESS)
|
471 |
return WL_ERROR_SEND;
|
472 |
} |
473 |
if (xbee_putc(buf[0]) != WL_SUCCESS) |
474 |
return WL_ERROR_SEND;
|
475 |
|
476 |
return WL_SUCCESS;
|
477 |
} |
478 |
|
479 |
/**
|
480 |
* Sends a string to the XBee.
|
481 |
*
|
482 |
* @param c the string to send to the XBEE
|
483 |
**/
|
484 |
static int8_t xbee_send_string(unsigned char* c) |
485 |
{ |
486 |
return xbee_send(c, strlen(c));
|
487 |
} |
488 |
|
489 |
|
490 |
/**
|
491 |
* Enter into command mode.
|
492 |
**/
|
493 |
static int8_t xbee_enter_command_mode()
|
494 |
{ |
495 |
if (xbee_send_string("+++") != WL_SUCCESS) { |
496 |
return WL_ERROR_XBEE_COMMAND;
|
497 |
} |
498 |
|
499 |
if (xbee_wait_for_ok() != WL_SUCCESS) {
|
500 |
return WL_ERROR_XBEE_COMMAND;
|
501 |
} |
502 |
|
503 |
return WL_SUCCESS;
|
504 |
} |
505 |
|
506 |
/**
|
507 |
* Exit from command mode.
|
508 |
**/
|
509 |
static int8_t xbee_exit_command_mode()
|
510 |
{ |
511 |
if (xbee_send_string("ATCN\r") != 0) { |
512 |
return -1; |
513 |
} |
514 |
|
515 |
xbee_wait_for_ok(); |
516 |
|
517 |
return 0; |
518 |
} |
519 |
|
520 |
/**
|
521 |
* Enter API mode.
|
522 |
**/
|
523 |
static int xbee_enter_api_mode() |
524 |
{ |
525 |
if (xbee_send_string("ATAP 1\r") != 0) { |
526 |
return -1; |
527 |
} |
528 |
xbee_wait_for_ok(); |
529 |
|
530 |
xbee_status = (xbee_status&0xFC)|XBEE_API_ON;
|
531 |
|
532 |
return 0; |
533 |
} |
534 |
|
535 |
/**
|
536 |
* Enter API mode 2.
|
537 |
**/
|
538 |
static int xbee_enter_api_mode2() |
539 |
{ |
540 |
if (xbee_send_string("ATAP 2\r") != 0) { |
541 |
return -1; |
542 |
} |
543 |
xbee_wait_for_ok(); |
544 |
|
545 |
xbee_status = (xbee_status&0xFC)|XBEE_API_ESCAPE;
|
546 |
|
547 |
return 0; |
548 |
} |
549 |
|
550 |
/**
|
551 |
* Exit API mode.
|
552 |
**/
|
553 |
static int xbee_exit_api_mode() |
554 |
{ |
555 |
if (xbee_send_modify_at_command("AP","0") != 0) { |
556 |
return -1; |
557 |
} |
558 |
|
559 |
xbee_status = (xbee_status&0xFC)|XBEE_API_OFF;
|
560 |
|
561 |
return 0; |
562 |
} |
563 |
|
564 |
/**
|
565 |
* Wait until the string "OK\r" is received from the XBee.
|
566 |
**/
|
567 |
static int xbee_wait_for_ok() |
568 |
{ |
569 |
return xbee_wait_for_string("OK\r", 3); |
570 |
} |
571 |
|
572 |
/**
|
573 |
* Delay until the specified string is received from
|
574 |
* the XBee. Discards all other XBee data.
|
575 |
*
|
576 |
* ********* Robot often hangs here ****************
|
577 |
*
|
578 |
* @param s the string to receive
|
579 |
* @param len the length of the string
|
580 |
**/
|
581 |
static int8_t xbee_wait_for_string(char* s, int len) |
582 |
{ |
583 |
uint8_t i=0;
|
584 |
if (xbee_status&0x03 == XBEE_API_OFF) { |
585 |
// wait until the response is received (only wait 1 second)
|
586 |
while(xbee_status&0xC0 != XBEE_COMMAND_RESPONSE && i++ < 1000) { |
587 |
delay_us(1);
|
588 |
} |
589 |
// check response
|
590 |
if (i >= 1000 || memcmp(s,xbee_basic_buf,len) != 0) { |
591 |
// bad response
|
592 |
WL_DEBUG_PRINT("Bad response when waiting for string ");
|
593 |
WL_DEBUG_PRINT(s); |
594 |
WL_DEBUG_PRINT("\r\n");
|
595 |
return -1; |
596 |
} |
597 |
|
598 |
// clear response
|
599 |
xbee_status = xbee_status&0x3F;
|
600 |
} |
601 |
|
602 |
return 0; |
603 |
} |
604 |
|
605 |
/**
|
606 |
* Delay until we receive a command response.
|
607 |
* (either OK\r or some actual value)
|
608 |
*
|
609 |
* Only works when not in API mode
|
610 |
*
|
611 |
* @param s the string to store the response in
|
612 |
* @param len the length of the string
|
613 |
*/
|
614 |
static int8_t xbee_wait_for_response(char* s, int len) { |
615 |
uint8_t i=0;
|
616 |
if (xbee_status&0x03 == XBEE_API_OFF) { |
617 |
// wait until the response is received (only wait 1 second)
|
618 |
while(xbee_status&0xC0 != XBEE_COMMAND_RESPONSE && i++ < 1000) { |
619 |
delay_us(1);
|
620 |
} |
621 |
// check response
|
622 |
if (i >= 1000) |
623 |
return -1; |
624 |
} else {
|
625 |
i=strcspn(xbee_basic_buf,"\r");
|
626 |
if (i<PACKET_BUFFER_SIZE) {
|
627 |
memcpy(s,xbee_basic_buf,i); |
628 |
xbee_status = xbee_status&0x3F; // clear response |
629 |
return 0; |
630 |
} |
631 |
else
|
632 |
return -1; |
633 |
} |
634 |
} |
635 |
// TODO: do something for API mode
|
636 |
|
637 |
return 0; |
638 |
} |
639 |
|
640 |
/** TODO: since we don't use this, do we need it?
|
641 |
*
|
642 |
* Verifies that the packets checksum is correct.
|
643 |
* (If the checksum is correct, the sum of the bytes
|
644 |
* is 0xFF.)
|
645 |
*
|
646 |
* @param packet the packet received. This includes the first
|
647 |
* three bytes, which are header information from the XBee.
|
648 |
*
|
649 |
* @param len The length of the packet received from the XBee
|
650 |
*
|
651 |
* @return 0 if the checksum is incorrect, nonzero
|
652 |
* otherwise
|
653 |
**/
|
654 |
uint8_t xbee_verify_checksum(uint8_t* packet, uint16_t len) |
655 |
{ |
656 |
uint8_t sum = 0;
|
657 |
while(--len > 0) { |
658 |
sum += packet[len]; |
659 |
} |
660 |
sum += packet[0];
|
661 |
return (sum == 0xFF); |
662 |
} |
663 |
|
664 |
/**
|
665 |
* Returns the checksum of the given packet.
|
666 |
*
|
667 |
* @param buf the data for the packet to send
|
668 |
* @param len the length of the packet in bytes
|
669 |
*
|
670 |
* @return the checksum of the packet, which will
|
671 |
* become the last byte sent in the packet
|
672 |
**/
|
673 |
char xbee_compute_checksum(uint8_t* buf, uint16_t len)
|
674 |
{ |
675 |
uint8_t sum = 0;
|
676 |
while(--len > 0) { |
677 |
sum += buf[len]; |
678 |
} |
679 |
sum += buf[0];
|
680 |
return 0xFF - sum; |
681 |
} |
682 |
|
683 |
/**
|
684 |
* Adds header information and checksum to the given
|
685 |
* packet and sends it. Header information includes
|
686 |
* XBEE_FRAME_START and the packet length, as two bytes.
|
687 |
*
|
688 |
* @param buf the packet data
|
689 |
* @param len the size in bytes of the packet data
|
690 |
*
|
691 |
**/
|
692 |
static int8_t xbee_send_frame(uint8_t* buf, uint16_t len)
|
693 |
{ |
694 |
uint8_t prefix[3];
|
695 |
prefix[0] = XBEE_FRAME_START;
|
696 |
prefix[1] = (len & 0xFF00) >> 8; |
697 |
prefix[2] = len & 0x00FF; |
698 |
uint8_t checksum = xbee_compute_checksum(buf, len); |
699 |
|
700 |
if (xbee_send(prefix, 3) != 0) { |
701 |
return WL_ERROR_SEND;
|
702 |
} |
703 |
|
704 |
if (xbee_send(buf, len) != 0) { |
705 |
return WL_ERROR_SEND;
|
706 |
} |
707 |
|
708 |
if (xbee_send(&checksum, 1) != 0) { |
709 |
return WL_ERROR_SEND;
|
710 |
} |
711 |
|
712 |
return WL_SUCCESS;
|
713 |
} |
714 |
|
715 |
/**
|
716 |
* Sends an AT command to read a parameter.
|
717 |
*
|
718 |
* @param command the AT command to send. For exmaple,
|
719 |
* use ID to read the PAN ID and MY to return the XBee ID.
|
720 |
* See the XBee reference guide for a complete listing.
|
721 |
**/
|
722 |
int8_t xbee_send_read_at_command(uint8_t* command) |
723 |
{ |
724 |
return xbee_send_modify_at_command(command, NULL, 0); |
725 |
} |
726 |
|
727 |
/**
|
728 |
* Sends the given AT command.
|
729 |
*
|
730 |
* @param command the AT command to send (e.g., MY, ID)
|
731 |
* @param value the value to pass as a parameter
|
732 |
* (or NULL if there is no parameter)
|
733 |
**/
|
734 |
static int8_t xbee_send_modify_at_command(uint8_t* command, uint8_t* value, uint8_t len)
|
735 |
{ |
736 |
uint8_t buf[12];
|
737 |
|
738 |
buf[0] = XBEE_FRAME_AT_COMMAND;
|
739 |
buf[1] = 1; |
740 |
buf[2] = command[0]; |
741 |
buf[3] = command[1]; |
742 |
if (value != NULL) |
743 |
{ |
744 |
if (len > 8) |
745 |
{ |
746 |
WL_DEBUG_PRINT("AT Command too large.\r\n");
|
747 |
return WL_ERROR_ARGUMENT;
|
748 |
} |
749 |
memcpy(buf+4,value,len);
|
750 |
} |
751 |
|
752 |
return xbee_send_frame(buf, 4 + len); |
753 |
} |
754 |
|
755 |
/**
|
756 |
* Send the specified packet.
|
757 |
*
|
758 |
* @param packet the packet data to send
|
759 |
* @param len the number of bytes in the packet
|
760 |
*
|
761 |
* @param dest the ID of the XBee to send the packet to,
|
762 |
* or XBEE_BROADCAST to send the message to all robots
|
763 |
* in the PAN.
|
764 |
*
|
765 |
* @param options a combination of the flags
|
766 |
* XBEE_OPTIONS_NONE, XBEE_OPTIONS_DISABLE_RESPONSE and
|
767 |
* XBEE_OPTIONS_BROADCAST_ALL_PANS
|
768 |
*
|
769 |
* @param frame the frame number to associate this packet
|
770 |
* with. This will be used to identify the response when
|
771 |
* the XBee alerts us as to whether or not our message
|
772 |
* was received.
|
773 |
**/
|
774 |
int xbee_send_packet(char* packet, int len, int dest, char options, char frame) |
775 |
{ |
776 |
char buf[5]; |
777 |
char prefix[3]; |
778 |
int i;
|
779 |
unsigned char checksum = 0; |
780 |
|
781 |
if (len > 100) |
782 |
{ |
783 |
WL_DEBUG_PRINT("Packet is too large.\r\n");
|
784 |
return -1; |
785 |
} |
786 |
|
787 |
//data for sending request
|
788 |
buf[0] = XBEE_FRAME_TX_REQUEST_16;
|
789 |
buf[1] = frame;
|
790 |
buf[2] = (dest >> 8) & 0xFF; |
791 |
buf[3] = dest & 0xFF; |
792 |
buf[4] = options;
|
793 |
|
794 |
//packet prefix, do this here so we don't need an extra buffer
|
795 |
prefix[0] = XBEE_FRAME_START;
|
796 |
prefix[1] = ((5 + len) & 0xFF00) >> 8; |
797 |
prefix[2] = (5 + len) & 0xFF; |
798 |
|
799 |
for (i = 0; i < 5; i++) |
800 |
checksum += (unsigned char)buf[i]; |
801 |
for (i = 0; i < len; i++) |
802 |
checksum += (unsigned char)packet[i]; |
803 |
checksum = 0xFF - checksum;
|
804 |
|
805 |
if (xbee_send(prefix, 3) != 0) { |
806 |
return -1; |
807 |
} |
808 |
|
809 |
if (xbee_send(buf, 5) != 0) { |
810 |
return -1; |
811 |
} |
812 |
|
813 |
if (xbee_send(packet, len) != 0) { |
814 |
return -1; |
815 |
} |
816 |
|
817 |
if (xbee_send((char*)&checksum, 1) != 0) { |
818 |
return -1; |
819 |
} |
820 |
|
821 |
return 0; |
822 |
} |
823 |
|
824 |
/**
|
825 |
* Handles modem status packets.
|
826 |
*
|
827 |
* @param status the type of status packet received.
|
828 |
**/
|
829 |
void xbee_handle_status(char status) |
830 |
{ |
831 |
switch (status)
|
832 |
{ |
833 |
case 0: |
834 |
WL_DEBUG_PRINT("XBee hardware reset.\r\n");
|
835 |
break;
|
836 |
case 1: |
837 |
WL_DEBUG_PRINT("Watchdog timer reset.\r\n");
|
838 |
break;
|
839 |
case 2: |
840 |
WL_DEBUG_PRINT("Associated.\r\n");
|
841 |
break;
|
842 |
case 3: |
843 |
WL_DEBUG_PRINT("Disassociated.\r\n");
|
844 |
break;
|
845 |
case 4: |
846 |
WL_DEBUG_PRINT("Synchronization lost.\r\n");
|
847 |
break;
|
848 |
case 5: |
849 |
WL_DEBUG_PRINT("Coordinator realignment.\r\n");
|
850 |
break;
|
851 |
case 6: |
852 |
WL_DEBUG_PRINT("Coordinator started.\r\n");
|
853 |
break;
|
854 |
} |
855 |
} |
856 |
|
857 |
/**
|
858 |
* Handles AT command response packets.
|
859 |
* @param command the two character AT command, e.g. MY or ID
|
860 |
* @param result 0 for success, 1 for an error
|
861 |
* @param len the length in bytes of extra
|
862 |
**/
|
863 |
static int8_t xbee_handle_at_command_response(uint16_t command, uint8_t result, uint8_t len)
|
864 |
{ |
865 |
if (result == 1) |
866 |
{ |
867 |
WL_DEBUG_PRINT("Error with AT");
|
868 |
WL_DEBUG_PRINT(command); |
869 |
WL_DEBUG_PRINT(" packet. Result = ");
|
870 |
switch(result) {
|
871 |
case 1: |
872 |
WL_DEBUG_PRINT("ERROR\r\n");
|
873 |
break;
|
874 |
case 2: |
875 |
WL_DEBUG_PRINT("Invalid Command\r\n");
|
876 |
break;
|
877 |
case 3: |
878 |
WL_DEBUG_PRINT("Invalid Parameter\r\n");
|
879 |
break;
|
880 |
} |
881 |
return WL_SUCCESS;
|
882 |
} |
883 |
WL_DEBUG_PRINT("AT");
|
884 |
WL_DEBUG_PRINT(command); |
885 |
WL_DEBUG_PRINT(" command was successful.\r\n");
|
886 |
|
887 |
// TODO: program more command responses here (ND, etc)
|
888 |
switch(command) {
|
889 |
case ('I'<<8)+'D': // PAN |
890 |
case ('C'<<8)+'H': // channel |
891 |
case ('M'<<8)+'Y': // address |
892 |
// copy command to handler
|
893 |
xbee_command[0] = (command&0xFF00)>>8; |
894 |
xbee_command[1] = command&0x00FF; |
895 |
result = basic_buf_last; |
896 |
for(command=2;command<len+2;command++) |
897 |
xbee_command[command] = xbee_basic_buf_get(&result); |
898 |
break;
|
899 |
default:
|
900 |
WL_DEBUG_PRINT("unknown AT command");
|
901 |
} |
902 |
|
903 |
// signal handler that command response is done
|
904 |
xbee_status = (xbee_status&0x3F)|XBEE_COMMAND_RESPONSE;
|
905 |
|
906 |
return WL_SUCCESS;
|
907 |
} |
908 |
|
909 |
/**
|
910 |
* Sets the personal area network id.
|
911 |
*
|
912 |
* @param id the new personal area network (PAN) id
|
913 |
**/
|
914 |
int8_t xbee_set_pan_id(uint16_t id) |
915 |
{ |
916 |
if (xbee_status&0xC0 == XBEE_COMMAND_WAIT |
917 |
|| xbee_status&0xC0 == XBEE_COMMAND_RESPONSE)
|
918 |
return WL_ERROR_XBEE_COMMAND; // can't do command right now |
919 |
|
920 |
int16_t i=0;
|
921 |
// change status to command wait
|
922 |
xbee_status = (xbee_status&0x3F)|XBEE_COMMAND_WAIT;
|
923 |
xbee_send_modify_at_command("ID",id); // send command to set the channel |
924 |
// wait for up to 30 ms
|
925 |
while(xbee_status&0xC0 != XBEE_COMMAND_RESPONSE && i++ < 10000) { |
926 |
delay_us(1); // wait 3us |
927 |
} |
928 |
if (i < 1000 && xbee_command[0] == 'O' && xbee_command[1] == 'K') { |
929 |
i = WL_SUCCESS; |
930 |
else
|
931 |
i = WL_ERROR_XBEE_COMMAND; // set error code
|
932 |
xbee_status = xbee_status&0x3F; // reset status |
933 |
return (int8_t)i; // return |
934 |
} |
935 |
|
936 |
/**
|
937 |
* Get the PAN ID for the XBee.
|
938 |
*
|
939 |
* @return the personal area network id, or
|
940 |
* XBEE_PAN_DEFAULT if it has not yet been set.
|
941 |
**/
|
942 |
uint16_t xbee_get_pan_id() |
943 |
{ |
944 |
if (xbee_status&0xC0 == XBEE_COMMAND_WAIT |
945 |
|| xbee_status&0xC0 == XBEE_COMMAND_RESPONSE)
|
946 |
return WL_ERROR_XBEE_COMMAND_16BIT; // can't do command right now |
947 |
|
948 |
uint16_t i=0;
|
949 |
// change status to command wait
|
950 |
xbee_status = (xbee_status&0x3F)|XBEE_COMMAND_WAIT;
|
951 |
xbee_send_read_at_command("ID"); // send command to get the PAN |
952 |
// wait for up to 30 ms
|
953 |
while(xbee_status&0xC0 != XBEE_COMMAND_RESPONSE && i++ < 10000) { |
954 |
delay_us(1); // wait 3us |
955 |
} |
956 |
if (i < 1000 && xbee_command[0] == 'I' && xbee_command[1] == 'D') { |
957 |
i = (xbee_command[2]<<8)|xbee_command[3]; // get PAN |
958 |
else
|
959 |
i = WL_ERROR_XBEE_COMMAND_16BIT; // set error code
|
960 |
xbee_status = xbee_status&0x3F; // reset status |
961 |
return i; // return |
962 |
} |
963 |
|
964 |
/**
|
965 |
* Set the channel the XBee is using.
|
966 |
*
|
967 |
* @param channel the channel the XBee will not use,
|
968 |
* between 0x0B and 0x1A
|
969 |
*
|
970 |
* @see xbee_get_channel
|
971 |
**/
|
972 |
int8_t xbee_set_channel(uint8_t channel) |
973 |
{ |
974 |
if (channel < 0x0B || channel > 0x1A) |
975 |
{ |
976 |
WL_DEBUG_PRINT("Channel out of range.\r\n");
|
977 |
return -1; |
978 |
} |
979 |
|
980 |
if (xbee_status&0xC0 == XBEE_COMMAND_WAIT |
981 |
|| xbee_status&0xC0 == XBEE_COMMAND_RESPONSE)
|
982 |
return WL_ERROR_XBEE_COMMAND; // can't do command right now |
983 |
|
984 |
int16_t i=0;
|
985 |
// change status to command wait
|
986 |
xbee_status = (xbee_status&0x3F)|XBEE_COMMAND_WAIT;
|
987 |
xbee_send_modify_at_command("CH",channel); // send command to set the channel |
988 |
// wait for up to 30 ms
|
989 |
while(xbee_status&0xC0 != XBEE_COMMAND_RESPONSE && i++ < 10000) { |
990 |
delay_us(1); // wait 3us |
991 |
} |
992 |
if (i < 1000 && xbee_command[0] == 'O' && xbee_command[1] == 'K') { |
993 |
i = WL_SUCCESS; |
994 |
else
|
995 |
i = WL_ERROR_XBEE_COMMAND; // set error code
|
996 |
xbee_status = xbee_status&0x3F; // reset status |
997 |
return (int8_t)i; // return |
998 |
} |
999 |
|
1000 |
/**
|
1001 |
* Returns the channel which the XBee is currently using.
|
1002 |
*
|
1003 |
* @return the channel the XBee is using
|
1004 |
*
|
1005 |
* @see xbee_set_channel
|
1006 |
**/
|
1007 |
int8_t xbee_get_channel(void)
|
1008 |
{ |
1009 |
if (xbee_status&0xC0 == XBEE_COMMAND_WAIT |
1010 |
|| xbee_status&0xC0 == XBEE_COMMAND_RESPONSE)
|
1011 |
return WL_ERROR_XBEE_COMMAND; // can't do command right now |
1012 |
|
1013 |
int16_t i=0;
|
1014 |
// change status to command wait
|
1015 |
xbee_status = (xbee_status&0x3F)|XBEE_COMMAND_WAIT;
|
1016 |
xbee_send_read_at_command("ID"); // send command to get the channel |
1017 |
// wait for up to 30 ms
|
1018 |
while(xbee_status&0xC0 != XBEE_COMMAND_RESPONSE && i++ < 10000) { |
1019 |
delay_us(1); // wait 3us |
1020 |
} |
1021 |
if (i < 1000 && xbee_command[0] == 'C' && xbee_command[1] == 'H') { |
1022 |
i = xbee_command[2]; // get channel |
1023 |
else
|
1024 |
i = WL_ERROR_XBEE_COMMAND; // set error code
|
1025 |
xbee_status = xbee_status&0x3F; // reset status |
1026 |
return i; // return |
1027 |
} |
1028 |
|
1029 |
/**
|
1030 |
* Get the 16-bit address of the XBee.
|
1031 |
* This is used to specify who to send messages to
|
1032 |
* and who messages are from.
|
1033 |
*
|
1034 |
* @return the 16-bit address of the XBee.
|
1035 |
**/
|
1036 |
uint16_t xbee_get_address(void)
|
1037 |
{ |
1038 |
if (xbee_status&0xC0 == XBEE_COMMAND_WAIT |
1039 |
|| xbee_status&0xC0 == XBEE_COMMAND_RESPONSE)
|
1040 |
return WL_ERROR_XBEE_COMMAND_16BIT; // can't do command right now |
1041 |
|
1042 |
uint16_t i=0;
|
1043 |
// change status to command wait
|
1044 |
xbee_status = (xbee_status&0x3F)|XBEE_COMMAND_WAIT;
|
1045 |
xbee_send_read_at_command("MY"); // send command to get the address |
1046 |
// wait for up to 30 ms
|
1047 |
while(xbee_status&0xC0 != XBEE_COMMAND_RESPONSE && i++ < 10000) { |
1048 |
delay_us(1); // wait 3us |
1049 |
} |
1050 |
if (i < 1000 && xbee_command[0] == 'M' && xbee_command[1] == 'Y') { |
1051 |
i = (xbee_command[2]<<8)+xbee_command[3]; // get address |
1052 |
else
|
1053 |
i = WL_ERROR_XBEE_COMMAND_16BIT; // set error code
|
1054 |
xbee_status = xbee_status&0x3F; // reset status |
1055 |
return i; // return |
1056 |
} |
1057 |
|
1058 |
/**@} **/ // end xbee group |
1059 |
|