root / branches / wireless / code / projects / unit_tests / xbee.c.bak @ 1935
History | View | Annotate | Download (38.8 KB)
1 | 1624 | 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 | #include <lights.h> |
||
35 | |||
36 | #include <string.h> |
||
37 | 1625 | dsschult | #include <avr/io.h> |
38 | 1624 | dsschult | #include <avr/interrupt.h> |
39 | #include <time.h> |
||
40 | #include <wl_defs.h> |
||
41 | #include <wireless.h> |
||
42 | #include "xbee.h" |
||
43 | |||
44 | |||
45 | /* Internal Function Prototypes */ |
||
46 | |||
47 | /* I/O Functions */ |
||
48 | static int8_t xbee_send_string(uint8_t* c); |
||
49 | |||
50 | /* Command Mode Functions */ |
||
51 | 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 | |||
58 | /* API Mode Functions */ |
||
59 | //TODO: does this exist? static int8_t xbee_handle_packet(uint8_t* packet, uint16_t len); |
||
60 | 1638 | dsschult | static int8_t xbee_handle_at_command_response(uint16_t command, uint8_t status, uint8_t len); |
61 | 1624 | dsschult | static void xbee_handle_status(uint8_t status); |
62 | 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 | |||
68 | /* 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 | |||
73 | /* 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 | |||
78 | /*Global Variables*/ |
||
79 | |||
80 | // 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 | // array for basic packets |
||
88 | static uint8_t xbee_basic_buf[PACKET_BUFFER_SIZE]; |
||
89 | |||
90 | // beginning of first packet in basic buffer |
||
91 | 1638 | dsschult | static uint8_t basic_buf_first = 0xFF; |
92 | 1624 | 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 | static uint8_t basic_buf_last = 0; |
||
96 | |||
97 | // array for other packets |
||
98 | static uint8_t xbee_other_buf[PACKET_BUFFER_SIZE]; |
||
99 | |||
100 | // beginning of first packet in other buffer |
||
101 | 1638 | dsschult | static uint8_t other_buf_first = 0xFF; |
102 | 1624 | 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 | static uint8_t other_buf_last = 0; |
||
106 | |||
107 | // xbee status |
||
108 | #define XBEE_API_OFF 0x00 |
||
109 | #define XBEE_API_ON 0x10 |
||
110 | #define XBEE_API_ESCAPE 0x20 |
||
111 | #define XBEE_API_MASK 0x30 |
||
112 | #define XBEE_COMMAND_WAIT 0x80 |
||
113 | #define XBEE_COMMAND_RESPONSE 0xC0 |
||
114 | #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 | |||
120 | // xbee command response (for PAN, channel, address, etc) |
||
121 | 1638 | dsschult | static uint8_t xbee_command[8]; |
122 | 1624 | dsschult | |
123 | // external ack handler (wireless_send.c) |
||
124 | void ackhandle(uint8_t num,uint8_t val) { return; } // disabled |
||
125 | |||
126 | // message buffer |
||
127 | uint8_t message[100]; |
||
128 | |||
129 | |||
130 | /**@addtogroup xbee |
||
131 | * @{ **/ |
||
132 | |||
133 | /*Function Implementations*/ |
||
134 | |||
135 | /** |
||
136 | * Interrupt for the robot. Adds bytes received from the xbee |
||
137 | * to the buffer. |
||
138 | **/ |
||
139 | |||
140 | |||
141 | 1638 | dsschult | #ifndef FIREFLY |
142 | 1624 | dsschult | #define PORT UDR1 |
143 | 1638 | dsschult | #define FLAG (UCSR1A & (1<<RXC1)) |
144 | 1625 | dsschult | ISR(USART1_RX_vect) { |
145 | 1638 | dsschult | #else |
146 | #define PORT UDR0 |
||
147 | #define FLAG (UCSR0A & (1<<RXC0)) |
||
148 | SIGNAL(SIG_USART0_RECV) |
||
149 | #endif |
||
150 | 1624 | dsschult | // start of frame |
151 | uint8_t apitype = PORT; // get frame start byte |
||
152 | uint16_t i=0; |
||
153 | uint16_t len=0; |
||
154 | |||
155 | 1638 | dsschult | /*WL_DEBUG_PRINT("in interrupt|status="); |
156 | 1624 | dsschult | WL_DEBUG_PRINT_HEX(xbee_status); |
157 | 1628 | dsschult | WL_DEBUG_PRINT("|frame_start="); |
158 | WL_DEBUG_PRINT_HEX(apitype); |
||
159 | 1624 | dsschult | |
160 | 1633 | dsschult | if (getStatus(XBEE_API_MASK) == XBEE_API_OFF) { |
161 | WL_DEBUG_PRINT("|API OFF"); |
||
162 | } else if (getStatus(XBEE_API_MASK) == XBEE_API_ON) { |
||
163 | WL_DEBUG_PRINT("|API ON"); |
||
164 | } else { |
||
165 | WL_DEBUG_PRINT("|API ERROR"); |
||
166 | 1638 | dsschult | }*/ |
167 | 1633 | dsschult | |
168 | 1624 | dsschult | // check that we're in API mode |
169 | if (getStatus(XBEE_API_MASK) == XBEE_API_OFF || apitype != XBEE_FRAME_START) { |
||
170 | // not in API mode |
||
171 | 1633 | dsschult | WL_DEBUG_PRINT("|api off branch"); |
172 | 1638 | dsschult | |
173 | 1624 | dsschult | if (getStatus(XBEE_COMMAND_MASK) == XBEE_COMMAND_WAIT) { |
174 | // get rest of command and put in basic buf |
||
175 | 1625 | dsschult | xbee_basic_buf[i] = apitype; |
176 | if (xbee_basic_buf[i++] != '\r') { |
||
177 | 1624 | dsschult | while(i < PACKET_BUFFER_SIZE) { |
178 | if (FLAG) { |
||
179 | xbee_basic_buf[i] = PORT; |
||
180 | if (xbee_basic_buf[i] == '\r') |
||
181 | break; |
||
182 | 1638 | dsschult | i++; |
183 | 1624 | dsschult | } |
184 | } |
||
185 | } |
||
186 | 1625 | dsschult | WL_DEBUG_PRINT("got packet, len="); |
187 | WL_DEBUG_PRINT_INT(i); |
||
188 | WL_DEBUG_PRINT("str="); |
||
189 | 1624 | dsschult | WL_DEBUG_PRINT(xbee_basic_buf); |
190 | // signal handler that command response is done |
||
191 | setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_RESPONSE); |
||
192 | } |
||
193 | WL_DEBUG_PRINT("return\r\n"); |
||
194 | return; |
||
195 | } |
||
196 | 1638 | dsschult | //WL_DEBUG_PRINT("|api on branch"); |
197 | 1624 | dsschult | |
198 | // get length and type |
||
199 | 1638 | dsschult | char buf[100]; |
200 | uint8_t buf_pos = 18; |
||
201 | while(i<3) { |
||
202 | 1624 | dsschult | if (FLAG) { |
203 | 1633 | dsschult | if (i==0) { |
204 | 1624 | dsschult | len |= PORT<<8; |
205 | 1638 | dsschult | buf[0] = 'l'; |
206 | buf[1] = 'e'; |
||
207 | buf[2] = 'n'; |
||
208 | buf[3] = '_'; |
||
209 | buf[4] = 'h'; |
||
210 | buf[5] = 'i'; |
||
211 | buf[6] = '|'; |
||
212 | //WL_DEBUG_PRINT("|len_hi"); |
||
213 | 1633 | dsschult | } else if (i==1) { |
214 | 1624 | dsschult | len |= PORT; |
215 | 1638 | dsschult | buf[7] = 'l'; |
216 | buf[8] = 'e'; |
||
217 | buf[9] = 'n'; |
||
218 | buf[10] = '_'; |
||
219 | buf[11] = 'l'; |
||
220 | buf[12] = 'o'; |
||
221 | buf[13] = '|'; |
||
222 | //WL_DEBUG_PRINT("|len_lo"); |
||
223 | 1633 | dsschult | } else if (i==2) { |
224 | 1624 | dsschult | apitype = PORT; |
225 | 1638 | dsschult | buf[14] = 'a'; |
226 | buf[15] = 'p'; |
||
227 | buf[16] = 'i'; |
||
228 | buf[17] = '|'; |
||
229 | //WL_DEBUG_PRINT("|GOT APITYPE"); |
||
230 | 1633 | dsschult | } else { |
231 | 1638 | dsschult | buf[buf_pos++] = PORT; |
232 | //WL_DEBUG_PRINT("|GOT NEXT"); |
||
233 | 1628 | dsschult | } |
234 | 1624 | dsschult | i++; |
235 | } |
||
236 | } |
||
237 | |||
238 | // do something based on the type |
||
239 | i=1; |
||
240 | switch(apitype) { |
||
241 | case XBEE_FRAME_AT_COMMAND_RESPONSE: { |
||
242 | // AT command response |
||
243 | if (getStatus(XBEE_COMMAND_MASK) == XBEE_COMMAND_RESPONSE) |
||
244 | 1638 | 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 **** |
245 | 1624 | dsschult | uint16_t atcommand=0; |
246 | uint8_t ptr=basic_buf_last; |
||
247 | while(i<len) { |
||
248 | if (FLAG) { |
||
249 | if (i==1) |
||
250 | apitype = PORT; // get frame id, but ignore it |
||
251 | else if (i==2) |
||
252 | atcommand |= PORT<<8; // get command char1 |
||
253 | else if (i==3) |
||
254 | atcommand |= PORT; // get command char2 |
||
255 | else if (i==4) |
||
256 | apitype = PORT; // get status |
||
257 | else { |
||
258 | // put the command response on the basic buf temporarily |
||
259 | if (xbee_basic_buf_add(&ptr,PORT) != 0) |
||
260 | break; |
||
261 | } |
||
262 | i++; |
||
263 | } |
||
264 | 1638 | dsschult | } |
265 | // handle AT command |
||
266 | WL_DEBUG_PRINT("i="); |
||
267 | WL_DEBUG_PRINT_INT(i); |
||
268 | WL_DEBUG_PRINT("|len="); |
||
269 | WL_DEBUG_PRINT_INT(len); |
||
270 | WL_DEBUG_PRINT("|status:"); |
||
271 | WL_DEBUG_PRINT_INT(apitype); |
||
272 | WL_DEBUG_PRINT("|atcommand:"); |
||
273 | WL_DEBUG_PRINT_CHAR((uint8_t)(atcommand>>8)); |
||
274 | WL_DEBUG_PRINT_CHAR((uint8_t)(atcommand&0xFF)); |
||
275 | WL_DEBUG_PRINT("|buf="); |
||
276 | uint8_t ptr2 = basic_buf_last; |
||
277 | for(uint8_t j=0;j<i;j++) |
||
278 | WL_DEBUG_PRINT_HEX(xbee_basic_buf_get(&ptr2)); |
||
279 | WL_DEBUG_PRINT("|\r\n"); |
||
280 | xbee_handle_at_command_response(atcommand,apitype,len-5); // TODO: rewrite function |
||
281 | 1624 | dsschult | break; } |
282 | case XBEE_FRAME_TX_STATUS: { |
||
283 | // TX status |
||
284 | uint8_t frame_id = 0; |
||
285 | while(i<len) { |
||
286 | if (FLAG) { |
||
287 | if (i==1) |
||
288 | frame_id = PORT; |
||
289 | else { |
||
290 | ackhandle(frame_id,PORT); // handle the status |
||
291 | break; |
||
292 | } |
||
293 | i++; |
||
294 | } |
||
295 | } |
||
296 | break; } |
||
297 | case XBEE_FRAME_RX_64: { |
||
298 | // receive a packet with 64bit address |
||
299 | break; } // TODO: implement this (even if we don't use it) |
||
300 | case XBEE_FRAME_RX_16: { |
||
301 | // receive a packet with 16bit address |
||
302 | uint16_t source = 0; |
||
303 | uint8_t framenum = 0; |
||
304 | uint8_t group = 0; |
||
305 | uint8_t ptr=basic_buf_last; |
||
306 | while(i<len) { |
||
307 | if (FLAG) { |
||
308 | if (i==1) |
||
309 | source |= PORT<<8; // get source hi byte |
||
310 | else if (i==2) |
||
311 | source |= PORT; // get source lo byte |
||
312 | else if (i==3) |
||
313 | apitype = PORT; // get RSSI, and ignore |
||
314 | else if (i==4) |
||
315 | apitype = PORT; // get options, and ignore |
||
316 | else if (i==5) { |
||
317 | framenum = PORT; // get the frame number |
||
318 | if (check_last_receive(source,framenum) != WL_SUCCESS) { |
||
319 | // we've already received this frame |
||
320 | ptr = 0xFF; // signal to skip processing |
||
321 | break; |
||
322 | } |
||
323 | } |
||
324 | else if (i==6) { |
||
325 | group = PORT; // get group number |
||
326 | if (group == 0) { |
||
327 | ptr = basic_buf_last+1; |
||
328 | // add source to buffer |
||
329 | if (xbee_basic_buf_add(&ptr,(uint8_t)((source&0xFF00)>>8)) != 0) |
||
330 | break; |
||
331 | if (xbee_basic_buf_add(&ptr,(uint8_t)(source&0x00FF)) != 0) |
||
332 | break; |
||
333 | } else { |
||
334 | ptr = other_buf_last+1; |
||
335 | // add source and group to buffer |
||
336 | if (xbee_other_buf_add(&ptr,group) != 0) |
||
337 | break; |
||
338 | if (xbee_other_buf_add(&ptr,(uint8_t)((source&0xFF00)>>8)) != 0) |
||
339 | break; |
||
340 | if (xbee_other_buf_add(&ptr,(uint8_t)(source&0x00FF)) != 0) |
||
341 | break; |
||
342 | } |
||
343 | } |
||
344 | else { // TODO: handle escaped characters supported by APIv2 |
||
345 | // put packet data on the correct buffer |
||
346 | if (group == 0 && xbee_basic_buf_add(&ptr,PORT) != 0) |
||
347 | break; |
||
348 | else if (xbee_other_buf_add(&ptr,PORT) != 0) |
||
349 | break; |
||
350 | } |
||
351 | i++; |
||
352 | } |
||
353 | } |
||
354 | if (ptr != 0xFF && i > 6) { |
||
355 | if (group == 0) { |
||
356 | xbee_basic_buf[basic_buf_last] = i-6; // set length |
||
357 | basic_buf_last = ptr; |
||
358 | } |
||
359 | else { |
||
360 | xbee_other_buf[other_buf_last] = i-6; // set length |
||
361 | // check if we have a high priority group |
||
362 | for(;;) |
||
363 | if (HIGH_PRIORITY) { |
||
364 | // handle receive now |
||
365 | ptr = 0xFF; |
||
366 | break; |
||
367 | } |
||
368 | if (ptr != 0xFF) { |
||
369 | // handle receive later |
||
370 | other_buf_last = ptr; |
||
371 | } |
||
372 | } |
||
373 | } |
||
374 | break; } |
||
375 | 1628 | dsschult | default: |
376 | WL_DEBUG_PRINT("|BAD APITYPE"); |
||
377 | 1624 | dsschult | } // end of switch statement |
378 | while (1) { |
||
379 | if (FLAG) { |
||
380 | apitype = PORT; // get checksum, and ignore |
||
381 | break; |
||
382 | } |
||
383 | } |
||
384 | 1638 | dsschult | buf[buf_pos] = '\0'; |
385 | WL_DEBUG_PRINT("xbee_interrupt_api_mode|"); |
||
386 | WL_DEBUG_PRINT(buf); |
||
387 | WL_DEBUG_PRINT("|len="); |
||
388 | WL_DEBUG_PRINT_INT(len); |
||
389 | WL_DEBUG_PRINT("|apitype="); |
||
390 | WL_DEBUG_PRINT_HEX(apitype); |
||
391 | WL_DEBUG_PRINT("|return\r\n"); |
||
392 | 1624 | dsschult | } // end of interrupt |
393 | |||
394 | |||
395 | /* adds a byte to the basic buffer */ |
||
396 | int8_t xbee_basic_buf_add(uint8_t *ptr, uint8_t byte) { |
||
397 | if (*ptr == basic_buf_first) { |
||
398 | // buffer full |
||
399 | WL_DEBUG_PRINT("basic buffer full\r\n"); |
||
400 | return -1; |
||
401 | } |
||
402 | xbee_basic_buf[(*ptr)++] = byte; |
||
403 | if (*ptr == PACKET_BUFFER_SIZE) |
||
404 | *ptr = 0; |
||
405 | return 0; |
||
406 | } |
||
407 | /* gets a byte from the basic buffer */ |
||
408 | uint8_t xbee_basic_buf_get(uint8_t *ptr) { |
||
409 | uint8_t byte = xbee_basic_buf[(*ptr)++]; |
||
410 | if (*ptr == PACKET_BUFFER_SIZE) |
||
411 | *ptr = 0; |
||
412 | return byte; |
||
413 | } |
||
414 | /* adds a byte to the other buffer */ |
||
415 | int8_t xbee_other_buf_add(uint8_t *ptr, uint8_t byte) { |
||
416 | if (*ptr == other_buf_first) { |
||
417 | // buffer full |
||
418 | WL_DEBUG_PRINT("other buffer full\r\n"); |
||
419 | return -1; |
||
420 | } |
||
421 | xbee_other_buf[(*ptr)++] = byte; |
||
422 | if (*ptr == PACKET_BUFFER_SIZE) |
||
423 | *ptr = 0; |
||
424 | return 0; |
||
425 | } |
||
426 | |||
427 | /** |
||
428 | * Checks if packet is a duplicate |
||
429 | **/ |
||
430 | int8_t check_last_receive(uint16_t source,uint8_t framenum) { |
||
431 | uint8_t i=0; |
||
432 | for(;i<NUM_LAST_PACKETS;i++) { |
||
433 | if (lastPacket[i].source == source && lastPacket[i].framenum == framenum) |
||
434 | return -1; // duplicate packet, so return error |
||
435 | } |
||
436 | // save packet source and framenum |
||
437 | i=getStatus(LAST_PACKET_MASK); |
||
438 | lastPacket[i].source = source; |
||
439 | lastPacket[i].framenum = framenum; |
||
440 | if (++i>=NUM_LAST_PACKETS) |
||
441 | i = 0; |
||
442 | setStatus(LAST_PACKET_MASK,i); |
||
443 | return WL_SUCCESS; |
||
444 | } |
||
445 | |||
446 | /** status functions **/ |
||
447 | inline uint8_t getStatus(uint8_t mask) { return xbee_status&mask; } |
||
448 | 1628 | dsschult | void setStatus(uint8_t mask,uint8_t value) { xbee_status = ((xbee_status&(~mask))|value); } |
449 | 1624 | dsschult | |
450 | |||
451 | 1625 | dsschult | // test interrupt |
452 | /*ISR(USART1_RX_vect) { |
||
453 | WL_DEBUG_PRINT("in interrupt|"); |
||
454 | char c = UDR1; |
||
455 | WL_DEBUG_PRINT_HEX(c); |
||
456 | WL_DEBUG_PRINT("|in interrupt"); |
||
457 | }*/ |
||
458 | |||
459 | |||
460 | |||
461 | 1624 | dsschult | /** |
462 | * Initializes the XBee library so that other functions may be used. |
||
463 | **/ |
||
464 | int8_t xbee_init() |
||
465 | { |
||
466 | WL_DEBUG_PRINT("in xbee_init\r\n"); |
||
467 | |||
468 | if(getStatus(XBEE_NOT_INITD) != XBEE_NOT_INITD) { |
||
469 | return WL_ERROR_INIT_ALREADY_INITD; |
||
470 | } |
||
471 | |||
472 | 1628 | dsschult | // set status |
473 | setStatus(XBEE_NOT_INITD,XBEE_COMMAND_NONE); |
||
474 | |||
475 | 1624 | dsschult | // clear last packet buffer |
476 | for(int i=0;i<NUM_LAST_PACKETS;i++) |
||
477 | lastPacket[i].source = lastPacket[i].framenum = 0; |
||
478 | |||
479 | // Set startup baud rate of 9600 |
||
480 | // Set frame format: 8data, 1stop bit, asynchronous normal mode |
||
481 | // Enable receiver and transmitter and the receiving interrupt |
||
482 | 1638 | dsschult | #ifdef FIREFLY |
483 | 1624 | dsschult | UBRR0H = 0x00; |
484 | UBRR0L = 103; |
||
485 | 1638 | dsschult | UCSR0A |= (1<<U2X0); |
486 | 1624 | dsschult | UCSR0C |= (1<<UCSZ00) | (1<<UCSZ01); |
487 | UCSR0B |= (1<<RXEN0) | (1<<TXEN0) | (1<<RXCIE); |
||
488 | 1638 | dsschult | #else |
489 | // Bayboard or robot |
||
490 | 1624 | dsschult | UBRR1H = 0x00; // baud rate |
491 | UBRR1L = 103; // baud rate |
||
492 | 1625 | dsschult | UCSR1A |= (1<<U2X1); // double transmit speed |
493 | //Enable receiver and transmitter on USART1 |
||
494 | UCSR1B |= (1<<RXEN1)|(1<<TXEN1); |
||
495 | |||
496 | // Set frame format: 8data, 1stop bit, asynchronous normal mode |
||
497 | 1638 | dsschult | UCSR1C |= (1<<UCSZ10) | (1<<UCSZ11); |
498 | 1625 | dsschult | |
499 | UCSR1B |= (1<<RXCIE1); // enable receive, transmit (1<<RXCIE) |
||
500 | 1638 | dsschult | #endif |
501 | 1624 | dsschult | sei(); |
502 | 1625 | dsschult | |
503 | 1628 | dsschult | // enter command mode |
504 | 1625 | dsschult | WL_DEBUG_PRINT("entering command mode\r\n"); |
505 | xbee_send_string((uint8_t*)"+++"); |
||
506 | xbee_wait_for_ok(); |
||
507 | WL_DEBUG_PRINT("entered command mode\r\n"); |
||
508 | 1624 | dsschult | |
509 | |||
510 | // set baud on xbee |
||
511 | #if (XBEE_BAUD == 115200) |
||
512 | xbee_send_string((uint8_t*)"ATBD7\r"); |
||
513 | #elif (XBEE_BAUD == 57600) |
||
514 | xbee_send_string((uint8_t*)"ATBD6\r"); |
||
515 | #elif (XBEE_BAUD == 38400) |
||
516 | xbee_send_string((uint8_t*)"ATBD5\r"); |
||
517 | #elif (XBEE_BAUD == 19200) |
||
518 | xbee_send_string((uint8_t*)"ATBD4\r"); |
||
519 | #elif (XBEE_BAUD == 9600) |
||
520 | // already at this baud rate |
||
521 | 1625 | dsschult | xbee_send_string("ATBD3\r\n"); |
522 | 1624 | dsschult | #else |
523 | WL_DEBUG_PRINT("undefined baud rate\r\n"); |
||
524 | return WL_ERROR_BAUD; |
||
525 | #endif |
||
526 | // exit command mode |
||
527 | xbee_wait_for_ok(); |
||
528 | WL_DEBUG_PRINT("got ok from baud reset\r\n"); |
||
529 | xbee_send_string((uint8_t*)"ATCN\r"); |
||
530 | xbee_wait_for_ok(); |
||
531 | WL_DEBUG_PRINT("got ok from exiting command mode\r\n"); |
||
532 | |||
533 | // set UART baud |
||
534 | #ifdef FIREFLY |
||
535 | #if (XBEE_BAUD == 115200) |
||
536 | UBRR0H = 0x00; |
||
537 | UBRR0L = 8; |
||
538 | #elif (XBEE_BAUD == 57600) |
||
539 | UBRR0H = 0x00; |
||
540 | UBRR0L = 16; |
||
541 | #elif (XBEE_BAUD == 38400) |
||
542 | UBRR0H = 0x00; |
||
543 | UBRR0L = 25; |
||
544 | #elif (XBEE_BAUD == 19200) |
||
545 | UBRR0H = 0x00; |
||
546 | UBRR0L = 51; |
||
547 | #elif (XBEE_BAUD == 9600) |
||
548 | /* this is the default baud rate, so do nothing |
||
549 | UBRR0H = 0x00; |
||
550 | UBRR0L = 103;*/ |
||
551 | #else |
||
552 | WL_DEBUG_PRINT("undefined baud rate\r\n"); |
||
553 | return WL_ERROR_BUAD; |
||
554 | #endif |
||
555 | #else // Bayboard or robot |
||
556 | #if (XBEE_BAUD == 115200) |
||
557 | UBRR1H = 0x00; |
||
558 | UBRR1L = 8; |
||
559 | #elif (XBEE_BAUD == 57600) |
||
560 | UBRR1H = 0x00; |
||
561 | UBRR1L = 16; |
||
562 | #elif (XBEE_BAUD == 38400) |
||
563 | UBRR1H = 0x00; |
||
564 | UBRR1L = 25; |
||
565 | #elif (XBEE_BAUD == 19200) |
||
566 | UBRR1H = 0x00; |
||
567 | UBRR1L = 51; |
||
568 | #elif (XBEE_BAUD == 9600) |
||
569 | /* this is the default baud rate, so do nothing |
||
570 | UBRR1H = 0x00; |
||
571 | UBRR1L = 103;*/ |
||
572 | #else |
||
573 | WL_DEBUG_PRINT("undefined baud rate\r\n"); |
||
574 | return WL_ERROR_BUAD; |
||
575 | #endif |
||
576 | #endif |
||
577 | 1638 | dsschult | // wait half second for the baud change to stabalize |
578 | delay_ms(500); |
||
579 | 1624 | dsschult | |
580 | // enter command mode |
||
581 | WL_DEBUG_PRINT("entering command mode 2\r\n"); |
||
582 | xbee_send_string((uint8_t*)"+++"); |
||
583 | xbee_wait_for_ok(); |
||
584 | WL_DEBUG_PRINT("entered command mode 2\r\n"); |
||
585 | |||
586 | 1638 | dsschult | if (xbee_enter_api_mode() != 0) { |
587 | 1624 | dsschult | WL_DEBUG_PRINT("can't enter api mode\r\n"); |
588 | return -1; |
||
589 | 1638 | dsschult | } |
590 | /*xbee_send_string((uint8_t*)"ATAP 1\r"); |
||
591 | xbee_wait_for_ok();*/ |
||
592 | 1625 | dsschult | |
593 | 1638 | dsschult | /*WL_DEBUG_PRINT("Entered api mode.\r\n"); |
594 | 1624 | dsschult | |
595 | if (xbee_exit_command_mode() != 0) { |
||
596 | WL_DEBUG_PRINT("can't exit command mode\r\n"); |
||
597 | return -1; |
||
598 | } |
||
599 | 1625 | dsschult | setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_NONE); // clear status |
600 | 1624 | dsschult | |
601 | WL_DEBUG_PRINT("Left command mode.\r\n"); |
||
602 | |||
603 | 1628 | dsschult | WL_DEBUG_PRINT("before status="); |
604 | WL_DEBUG_PRINT_HEX(getStatus(0xFF)); |
||
605 | WL_DEBUG_PRINT("\r\n"); |
||
606 | |||
607 | 1638 | dsschult | setStatus(XBEE_API_MASK,XBEE_API_ON); // set status to API_ON (API mode 1)*/ |
608 | 1628 | dsschult | |
609 | 1638 | dsschult | #ifdef WL_DEBUG |
610 | 1633 | dsschult | if (getStatus(XBEE_API_MASK) == XBEE_API_OFF) { |
611 | WL_DEBUG_PRINT("|API OFF|"); |
||
612 | } else if (getStatus(XBEE_API_MASK) == XBEE_API_ON) { |
||
613 | WL_DEBUG_PRINT("|API ON|"); |
||
614 | } else { |
||
615 | WL_DEBUG_PRINT("|API ERROR|"); |
||
616 | } |
||
617 | 1638 | dsschult | #endif |
618 | 1633 | dsschult | |
619 | 1628 | dsschult | |
620 | 1633 | dsschult | // TODO: we should set the MY address to the robot address from eeprom |
621 | 1638 | dsschult | uint16_t i=0; |
622 | setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_WAIT); |
||
623 | 1642 | dsschult | uint16_t newmy = 0x9876; |
624 | if (xbee_send_modify_at_command((uint8_t*)"MY",&newmy,2) != WL_SUCCESS) { |
||
625 | 1633 | dsschult | WL_DEBUG_PRINT("setting MY address failed\r\n"); |
626 | } |
||
627 | 1638 | dsschult | // wait for up to 30 ms |
628 | while(getStatus(XBEE_COMMAND_MASK) != XBEE_COMMAND_RESPONSE && i++ < 10000) { |
||
629 | delay_us(1); // wait 3us |
||
630 | } |
||
631 | if (i < 1000 && xbee_command[0] == 'M' && xbee_command[1] == 'Y') { |
||
632 | WL_DEBUG_PRINT("setting MY address successful\r\n"); |
||
633 | } else |
||
634 | WL_DEBUG_PRINT("setting MY address failed\r\n"); |
||
635 | setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_NONE); // reset status |
||
636 | 1633 | dsschult | |
637 | 1638 | dsschult | |
638 | uint16_t address = xbee_get_address(); |
||
639 | if (address == WL_ERROR_XBEE_COMMAND_16BIT) { |
||
640 | 1624 | dsschult | WL_DEBUG_PRINT("getting MY address failed\r\n"); |
641 | } |
||
642 | 1638 | dsschult | WL_DEBUG_PRINT("MY address:"); |
643 | WL_DEBUG_PRINT_HEX((uint8_t)(address>>8)); |
||
644 | WL_DEBUG_PRINT_HEX((uint8_t)(address&0xFF)); |
||
645 | WL_DEBUG_PRINT("\r\n"); |
||
646 | 1624 | dsschult | |
647 | return WL_SUCCESS; |
||
648 | } |
||
649 | |||
650 | /** |
||
651 | * Call when finished using the XBee library. |
||
652 | **/ |
||
653 | int8_t xbee_terminate() |
||
654 | { |
||
655 | int ret=xbee_exit_api_mode(); |
||
656 | if (ret != WL_SUCCESS) { |
||
657 | WL_DEBUG_PRINT("xbee termination failed\r\n"); |
||
658 | WL_DEBUG_PRINT_INT(ret); |
||
659 | WL_DEBUG_PRINT("|\r\n"); |
||
660 | return WL_ERROR_TERMINATION_FAILED; |
||
661 | } |
||
662 | setStatus(XBEE_NOT_INITD,XBEE_NOT_INITD); // clean initd status |
||
663 | return WL_SUCCESS; |
||
664 | } |
||
665 | |||
666 | /** |
||
667 | * Sends a character to the XBee. |
||
668 | * |
||
669 | * @param c the byte to send |
||
670 | * @return 0 for success, nonzero for failure |
||
671 | **/ |
||
672 | int8_t xbee_putc(uint8_t c) { |
||
673 | |||
674 | // Wait until buffer is clear for sending |
||
675 | // Then load buffer with your character |
||
676 | |||
677 | 1638 | dsschult | /*WL_DEBUG_PRINT("xbee_putc:"); |
678 | 1625 | dsschult | WL_DEBUG_PRINT_HEX(c); |
679 | 1638 | dsschult | WL_DEBUG_PRINT("|\r\n");*/ |
680 | 1624 | dsschult | |
681 | 1638 | dsschult | #ifdef FIREFLY |
682 | 1624 | dsschult | loop_until_bit_is_set(UCSR0A, UDRE0); |
683 | UDR0 = c; |
||
684 | 1638 | dsschult | #else |
685 | 1624 | dsschult | loop_until_bit_is_set(UCSR1A, UDRE1); |
686 | UDR1 = c; |
||
687 | 1638 | dsschult | #endif |
688 | 1624 | dsschult | |
689 | return WL_SUCCESS; |
||
690 | } |
||
691 | |||
692 | /** |
||
693 | * Returns the first byte in the buffer received from xbee. |
||
694 | * This function blocks execution until a character has been |
||
695 | * received. xbee_init must be called before this function |
||
696 | * may be used. |
||
697 | * |
||
698 | * @return the first character in the xbee buffer, -1 on error |
||
699 | * |
||
700 | * @see xbee_init, xbee_getc_nb |
||
701 | **/ |
||
702 | int16_t xbee_getc(void) { |
||
703 | |||
704 | // Wait for the receive buffer to be filled |
||
705 | // Then read the receive buffer |
||
706 | #ifdef FIREFLY |
||
707 | loop_until_bit_is_set(UCSR0A, RXC0); |
||
708 | return UDR0; |
||
709 | #else |
||
710 | loop_until_bit_is_set(UCSR1A, RXC1); |
||
711 | return UDR1; |
||
712 | #endif |
||
713 | } |
||
714 | |||
715 | /** |
||
716 | * Non blocking version of xbee_getc. If a byte is present in the buffer, |
||
717 | * it is returned, otherwise -1 is returned immediately. xbee_init |
||
718 | * must be called before this function can be used. |
||
719 | * |
||
720 | * @param c The received byte. This will be set if a byte has been received. |
||
721 | * |
||
722 | * @return -1 If no byte is available, 0 otherwise, positive for error |
||
723 | * |
||
724 | * @see xbee_getc |
||
725 | **/ |
||
726 | int8_t xbee_getc_nb(uint8_t *c) { |
||
727 | |||
728 | // check if the receive buffer is filled |
||
729 | #ifdef FIREFLY |
||
730 | if (UCSR0A & (1<<RXC0)) { |
||
731 | (*c) = UDR0; |
||
732 | #else |
||
733 | if (UCSR1A & (1<<RXC1)) { |
||
734 | (*c) = UDR1; |
||
735 | #endif |
||
736 | return WL_SUCCESS; |
||
737 | } |
||
738 | return -1; // Return empty |
||
739 | } |
||
740 | |||
741 | /** |
||
742 | * Send a buffer buf of size bytes to the XBee. |
||
743 | * |
||
744 | * @param buf the buffer of data to send |
||
745 | * @param size the number of bytes to send |
||
746 | **/ |
||
747 | int8_t xbee_send(uint8_t* buf, uint16_t size) |
||
748 | { |
||
749 | uint16_t i=0; // check if we need this variable |
||
750 | while(i<size) { |
||
751 | if (xbee_putc(buf[i++]) != WL_SUCCESS) |
||
752 | return WL_ERROR_SEND; |
||
753 | } |
||
754 | |||
755 | return WL_SUCCESS; |
||
756 | } |
||
757 | |||
758 | /** |
||
759 | * Sends a string to the XBee. |
||
760 | * |
||
761 | * @param c the string to send to the XBEE |
||
762 | **/ |
||
763 | static int8_t xbee_send_string(uint8_t* c) |
||
764 | { |
||
765 | return xbee_send(c, strlen((char*)c)); |
||
766 | } |
||
767 | |||
768 | |||
769 | /** |
||
770 | * Enter into command mode. |
||
771 | **/ |
||
772 | static int8_t xbee_enter_command_mode(void) |
||
773 | { |
||
774 | if (xbee_send_string((uint8_t*)"+++") != WL_SUCCESS) { |
||
775 | return WL_ERROR_XBEE_COMMAND; |
||
776 | } |
||
777 | WL_DEBUG_PRINT("sent command +++|"); |
||
778 | |||
779 | if (xbee_wait_for_ok() != WL_SUCCESS) { |
||
780 | return WL_ERROR_XBEE_COMMAND; |
||
781 | } |
||
782 | WL_DEBUG_PRINT("got OK\r\n"); |
||
783 | |||
784 | return WL_SUCCESS; |
||
785 | } |
||
786 | |||
787 | /** |
||
788 | * Exit from command mode. |
||
789 | **/ |
||
790 | static int8_t xbee_exit_command_mode() |
||
791 | { |
||
792 | if (xbee_send_string((uint8_t*)"ATCN\r") != 0) { |
||
793 | return WL_ERROR_SEND; |
||
794 | } |
||
795 | 1638 | dsschult | if (xbee_wait_for_ok() != WL_SUCCESS) { |
796 | WL_DEBUG_PRINT("failed to exit command mode\r\n"); |
||
797 | return WL_ERROR_SEND; |
||
798 | } |
||
799 | 1624 | dsschult | |
800 | return WL_SUCCESS; |
||
801 | } |
||
802 | |||
803 | /** |
||
804 | * Enter API mode. |
||
805 | **/ |
||
806 | static int8_t xbee_enter_api_mode(void) { |
||
807 | if (xbee_send_string((uint8_t*)"ATAP 1\r") != 0) { |
||
808 | return WL_ERROR_SEND; |
||
809 | } |
||
810 | 1638 | dsschult | if (xbee_wait_for_ok() != WL_SUCCESS) { |
811 | 1624 | dsschult | WL_DEBUG_PRINT("failed to enter API mode\r\n"); |
812 | return WL_ERROR_SEND; |
||
813 | } |
||
814 | 1638 | dsschult | if (xbee_exit_command_mode() != WL_SUCCESS) { |
815 | WL_DEBUG_PRINT("failed to enter API mode\r\n"); |
||
816 | return WL_ERROR_SEND; |
||
817 | } |
||
818 | 1624 | dsschult | WL_DEBUG_PRINT("got OK after entering API mode\r\n"); |
819 | |||
820 | 1638 | dsschult | setStatus(XBEE_API_MASK,XBEE_API_ON); // set status |
821 | |||
822 | 1624 | dsschult | return WL_SUCCESS; |
823 | } |
||
824 | |||
825 | /** |
||
826 | * Enter API mode 2. |
||
827 | **/ |
||
828 | static int8_t xbee_enter_api_mode2(void) { |
||
829 | if (xbee_send_string((uint8_t*)"ATAP 2\r") != 0) { |
||
830 | return WL_ERROR_SEND; |
||
831 | } |
||
832 | 1638 | dsschult | if (xbee_wait_for_ok() != WL_SUCCESS) { |
833 | 1624 | dsschult | WL_DEBUG_PRINT("failed to enter API mode2\r\n"); |
834 | return WL_ERROR_SEND; |
||
835 | } |
||
836 | 1638 | dsschult | if (xbee_exit_command_mode() != WL_SUCCESS) { |
837 | WL_DEBUG_PRINT("failed to enter API mode2\r\n"); |
||
838 | return WL_ERROR_SEND; |
||
839 | } |
||
840 | 1624 | dsschult | WL_DEBUG_PRINT("got OK after entering API mode2\r\n"); |
841 | |||
842 | setStatus(XBEE_API_MASK,XBEE_API_ESCAPE); // set status |
||
843 | |||
844 | return WL_SUCCESS; |
||
845 | } |
||
846 | |||
847 | /** |
||
848 | * Exit API mode. |
||
849 | **/ |
||
850 | static int8_t xbee_exit_api_mode() |
||
851 | { |
||
852 | if (getStatus(XBEE_COMMAND_MASK) == XBEE_COMMAND_WAIT |
||
853 | || getStatus(XBEE_COMMAND_MASK) == XBEE_COMMAND_RESPONSE) |
||
854 | return WL_ERROR_XBEE_COMMAND; // can't do command right now |
||
855 | WL_DEBUG_PRINT("now exiting API mode\r\n"); |
||
856 | |||
857 | int16_t i=0; |
||
858 | // change status to command wait |
||
859 | setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_WAIT); |
||
860 | 1638 | dsschult | if (xbee_send_modify_at_command((uint8_t*)"AP",(uint8_t*)(&i),1) != WL_SUCCESS) { // send command |
861 | WL_DEBUG_PRINT("error sending AP 0 command\r\n"); |
||
862 | setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_NONE); // reset status |
||
863 | return WL_ERROR_XBEE_COMMAND; |
||
864 | } |
||
865 | 1624 | dsschult | // wait for up to 30 ms |
866 | while(getStatus(XBEE_COMMAND_MASK) != XBEE_COMMAND_RESPONSE && i++ < 10000) { |
||
867 | delay_us(1); // wait 3us |
||
868 | } |
||
869 | if (i < 1000 && xbee_command[0] == 'A' && xbee_command[1] == 'P') { |
||
870 | WL_DEBUG_PRINT("done exiting API mode\r\n"); |
||
871 | i = WL_SUCCESS; |
||
872 | } else { |
||
873 | WL_DEBUG_PRINT("failed to exit API mode\r\n"); |
||
874 | i = WL_ERROR_XBEE_COMMAND; // set error code |
||
875 | } |
||
876 | 1638 | dsschult | setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_NONE); // reset status |
877 | setStatus(XBEE_API_MASK,XBEE_API_OFF); |
||
878 | |||
879 | 1624 | dsschult | return (int8_t)i; // return |
880 | } |
||
881 | |||
882 | /** |
||
883 | * Wait until the string "OK\r" is received from the XBee. |
||
884 | **/ |
||
885 | static int8_t xbee_wait_for_ok() |
||
886 | { |
||
887 | 1638 | dsschult | //delay_ms(1000); |
888 | //return WL_SUCCESS; |
||
889 | return xbee_wait_for_string((uint8_t*)"OK", 2); |
||
890 | 1624 | dsschult | } |
891 | |||
892 | /** |
||
893 | * Delay until the specified string is received from |
||
894 | * the XBee. |
||
895 | * |
||
896 | * Only works when not in API mode |
||
897 | * |
||
898 | * @param s the string to receive |
||
899 | * @param len the length of the string |
||
900 | **/ |
||
901 | static int8_t xbee_wait_for_string(uint8_t* s, uint16_t len) |
||
902 | { |
||
903 | 1625 | dsschult | uint8_t i=0; |
904 | setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_WAIT); // set status flag |
||
905 | 1624 | dsschult | if (getStatus(XBEE_API_MASK) == XBEE_API_OFF) { |
906 | // wait until the response is received (only wait 1 second) |
||
907 | while(getStatus(XBEE_COMMAND_MASK) != XBEE_COMMAND_RESPONSE && i++ < 1000) { |
||
908 | delay_us(1); |
||
909 | } |
||
910 | // check response |
||
911 | if (i >= 1000 || memcmp(s,xbee_basic_buf,len) != 0) { |
||
912 | // bad response |
||
913 | WL_DEBUG_PRINT("Bad response when waiting for string "); |
||
914 | WL_DEBUG_PRINT(s); |
||
915 | WL_DEBUG_PRINT("\r\n"); |
||
916 | return -1; |
||
917 | } |
||
918 | |||
919 | setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_NONE); // clear status |
||
920 | } |
||
921 | |||
922 | 1638 | dsschult | WL_DEBUG_PRINT("done waiting for string.\r\n"); |
923 | 1624 | dsschult | |
924 | return 0; |
||
925 | } |
||
926 | |||
927 | /** |
||
928 | * Delay until we receive a command response. |
||
929 | 1638 | dsschult | * Then copy the response to S and set the len |
930 | 1624 | dsschult | * |
931 | * Only works when not in API mode |
||
932 | * |
||
933 | * @param s the string to store the response in |
||
934 | * @param len the length of the string |
||
935 | */ |
||
936 | static int8_t xbee_wait_for_response(uint8_t* s, int16_t len) { |
||
937 | uint8_t i=0; |
||
938 | if (getStatus(XBEE_API_MASK) == XBEE_API_OFF) { |
||
939 | // wait until the response is received (only wait 1 second) |
||
940 | while(getStatus(XBEE_COMMAND_MASK) != XBEE_COMMAND_RESPONSE && i++ < 1000) { |
||
941 | delay_us(1); |
||
942 | } |
||
943 | // check response |
||
944 | if (i >= 1000) { |
||
945 | return -1; |
||
946 | } else { |
||
947 | i=strcspn((char*)xbee_basic_buf,"\r"); |
||
948 | if (i<PACKET_BUFFER_SIZE) { |
||
949 | memcpy(s,xbee_basic_buf,i); |
||
950 | 1638 | dsschult | len = i; |
951 | 1624 | dsschult | setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_NONE); // clear response |
952 | return 0; |
||
953 | } |
||
954 | else |
||
955 | return -1; |
||
956 | } |
||
957 | } |
||
958 | // TODO: do something for API mode |
||
959 | |||
960 | return 0; |
||
961 | } |
||
962 | |||
963 | /** TODO: since we don't use this, do we need it? |
||
964 | * |
||
965 | * Verifies that the packets checksum is correct. |
||
966 | * (If the checksum is correct, the sum of the bytes |
||
967 | * is 0xFF.) |
||
968 | * |
||
969 | * @param packet the packet received. This includes the first |
||
970 | * three bytes, which are header information from the XBee. |
||
971 | * |
||
972 | * @param len The length of the packet received from the XBee |
||
973 | * |
||
974 | * @return 0 if the checksum is incorrect, nonzero |
||
975 | * otherwise |
||
976 | **/ |
||
977 | int8_t xbee_verify_checksum(uint8_t* packet, uint16_t len) |
||
978 | { |
||
979 | uint8_t sum = 0; |
||
980 | while(--len > 0) { |
||
981 | sum += packet[len]; |
||
982 | } |
||
983 | sum += packet[0]; |
||
984 | return (sum == 0xFF); |
||
985 | } |
||
986 | |||
987 | /** |
||
988 | * Returns the checksum of the given packet. |
||
989 | * |
||
990 | * @param buf the data for the packet to send |
||
991 | * @param len the length of the packet in bytes |
||
992 | * |
||
993 | * @return the checksum of the packet, which will |
||
994 | * become the last byte sent in the packet |
||
995 | **/ |
||
996 | uint8_t xbee_compute_checksum(uint8_t* buf, uint16_t len) |
||
997 | { |
||
998 | uint8_t sum = 0; |
||
999 | while(--len > 0) { |
||
1000 | sum += buf[len]; |
||
1001 | } |
||
1002 | sum += buf[0]; |
||
1003 | return 0xFF - sum; |
||
1004 | } |
||
1005 | |||
1006 | /** |
||
1007 | * Adds buf to the previous checksum total |
||
1008 | * |
||
1009 | * @param buf a byte buffer to add to the checksum |
||
1010 | * @param len the length of the buffer |
||
1011 | * @param sum the previous sum |
||
1012 | * |
||
1013 | * @return error code |
||
1014 | **/ |
||
1015 | int8_t xbee_checksum_add(uint8_t *buf, uint8_t len, uint8_t* sum) { |
||
1016 | if (buf == NULL || sum == NULL) |
||
1017 | return WL_ERROR_ARGUMENT; |
||
1018 | while(--len > 0) { |
||
1019 | *sum += buf[len]; |
||
1020 | } |
||
1021 | *sum += buf[0]; |
||
1022 | return WL_SUCCESS; |
||
1023 | } |
||
1024 | |||
1025 | |||
1026 | /** |
||
1027 | * Sends header information. Header information includes |
||
1028 | * XBEE_FRAME_START and the packet length, as two bytes. |
||
1029 | * |
||
1030 | * @param type the packet type |
||
1031 | * @param len the size in bytes of the packet data |
||
1032 | * |
||
1033 | **/ |
||
1034 | 1642 | dsschult | int8_t xbee_send_header(uint16_t len) |
1035 | 1624 | dsschult | { |
1036 | //packet prefix |
||
1037 | if (xbee_putc(XBEE_FRAME_START) != WL_SUCCESS) |
||
1038 | return WL_ERROR_SEND; |
||
1039 | if (xbee_putc((uint8_t)((len & 0xFF00) >> 8)) != WL_SUCCESS) |
||
1040 | return WL_ERROR_SEND; |
||
1041 | if (xbee_putc((uint8_t)(len & 0x00FF)) != WL_SUCCESS) |
||
1042 | return WL_ERROR_SEND; |
||
1043 | |||
1044 | return WL_SUCCESS; |
||
1045 | } |
||
1046 | |||
1047 | /** |
||
1048 | * Adds header information and checksum to the given |
||
1049 | * packet and sends it. Header information includes |
||
1050 | * XBEE_FRAME_START and the packet length, as two bytes. |
||
1051 | * |
||
1052 | * @param buf the packet data |
||
1053 | * @param len the size in bytes of the packet data |
||
1054 | * |
||
1055 | **/ |
||
1056 | static int8_t xbee_send_frame(uint8_t* buf, uint16_t len) |
||
1057 | { |
||
1058 | uint8_t checksum = xbee_compute_checksum(buf, len); |
||
1059 | |||
1060 | //packet prefix |
||
1061 | if (xbee_putc(XBEE_FRAME_START) != WL_SUCCESS) |
||
1062 | return WL_ERROR_SEND; |
||
1063 | 1638 | dsschult | if (xbee_putc((uint8_t)(len>>8)) != WL_SUCCESS) |
1064 | 1624 | dsschult | return WL_ERROR_SEND; |
1065 | 1638 | dsschult | if (xbee_putc((uint8_t)(len&0xFF)) != WL_SUCCESS) |
1066 | 1624 | dsschult | return WL_ERROR_SEND; |
1067 | |||
1068 | if (xbee_send(buf, len) != WL_SUCCESS) |
||
1069 | return WL_ERROR_SEND; |
||
1070 | |||
1071 | if (xbee_putc(checksum) != WL_SUCCESS) |
||
1072 | return WL_ERROR_SEND; |
||
1073 | |||
1074 | return WL_SUCCESS; |
||
1075 | } |
||
1076 | |||
1077 | /** |
||
1078 | * Sends an AT command to read a parameter. |
||
1079 | * |
||
1080 | * @param command the AT command to send. For exmaple, |
||
1081 | * use ID to read the PAN ID and MY to return the XBee ID. |
||
1082 | * See the XBee reference guide for a complete listing. |
||
1083 | **/ |
||
1084 | int8_t xbee_send_read_at_command(uint8_t* command) |
||
1085 | { |
||
1086 | return xbee_send_modify_at_command(command, NULL, 0); |
||
1087 | } |
||
1088 | |||
1089 | /** |
||
1090 | * Sends the given AT command. |
||
1091 | * |
||
1092 | * @param command the AT command to send (e.g., MY, ID) |
||
1093 | * @param value the value to pass as a parameter |
||
1094 | * (or NULL if there is no parameter) |
||
1095 | **/ |
||
1096 | static int8_t xbee_send_modify_at_command(uint8_t* command, uint8_t* value, uint8_t len) |
||
1097 | { |
||
1098 | uint8_t buf[12]; |
||
1099 | |||
1100 | buf[0] = XBEE_FRAME_AT_COMMAND; |
||
1101 | buf[1] = 1; |
||
1102 | buf[2] = command[0]; |
||
1103 | buf[3] = command[1]; |
||
1104 | if (value != NULL) |
||
1105 | { |
||
1106 | if (len > 8) |
||
1107 | { |
||
1108 | WL_DEBUG_PRINT("AT Command too large.\r\n"); |
||
1109 | return WL_ERROR_ARGUMENT; |
||
1110 | } |
||
1111 | memcpy(buf+4,value,len); |
||
1112 | } |
||
1113 | |||
1114 | return xbee_send_frame(buf, 4 + len); |
||
1115 | } |
||
1116 | |||
1117 | /** |
||
1118 | * Send the specified packet. |
||
1119 | * |
||
1120 | * @param packet the packet data to send |
||
1121 | * @param len the number of bytes in the packet |
||
1122 | * |
||
1123 | * @param dest the ID of the XBee to send the packet to, |
||
1124 | * or XBEE_BROADCAST to send the message to all robots |
||
1125 | * in the PAN. |
||
1126 | * |
||
1127 | * @param options a combination of the flags |
||
1128 | * XBEE_OPTIONS_NONE, XBEE_OPTIONS_DISABLE_RESPONSE and |
||
1129 | * XBEE_OPTIONS_BROADCAST_ALL_PANS |
||
1130 | * |
||
1131 | * @param frame the frame number to associate this packet |
||
1132 | * with. This will be used to identify the response when |
||
1133 | * the XBee alerts us as to whether or not our message |
||
1134 | * was received. |
||
1135 | **/ |
||
1136 | int8_t xbee_send_packet(uint8_t* packet, uint8_t len, uint16_t dest, uint8_t options, uint8_t frame) |
||
1137 | { |
||
1138 | uint8_t sum = XBEE_FRAME_TX_REQUEST_16; |
||
1139 | uint8_t i = 0; |
||
1140 | |||
1141 | if (len > 100) |
||
1142 | { |
||
1143 | WL_DEBUG_PRINT("Packet is too large.\r\n"); |
||
1144 | return WL_ERROR_ARGUMENT; |
||
1145 | } |
||
1146 | |||
1147 | // calculate checksum |
||
1148 | for(;i<len;i++) |
||
1149 | sum += packet[len]; |
||
1150 | sum += frame; |
||
1151 | sum += (dest&0xFF00) >> 8; |
||
1152 | sum += dest&0x00FF; |
||
1153 | sum += options; |
||
1154 | sum = 0xFF - sum; |
||
1155 | |||
1156 | //packet prefix |
||
1157 | if (xbee_putc(XBEE_FRAME_START) != WL_SUCCESS) |
||
1158 | return WL_ERROR_SEND; |
||
1159 | if (xbee_putc(0x00) != WL_SUCCESS) |
||
1160 | return WL_ERROR_SEND; |
||
1161 | if (xbee_putc(len+5) != WL_SUCCESS) |
||
1162 | return WL_ERROR_SEND; |
||
1163 | |||
1164 | //send header for TX request |
||
1165 | if (xbee_putc(XBEE_FRAME_TX_REQUEST_16) != WL_SUCCESS) |
||
1166 | return WL_ERROR_SEND; |
||
1167 | if (xbee_putc(frame) != WL_SUCCESS) |
||
1168 | return WL_ERROR_SEND; |
||
1169 | if (xbee_putc((uint8_t)((dest&0xFF00) >> 8)) != WL_SUCCESS) |
||
1170 | return WL_ERROR_SEND; |
||
1171 | if (xbee_putc((uint8_t)(dest&0x00FF)) != WL_SUCCESS) |
||
1172 | return WL_ERROR_SEND; |
||
1173 | if (xbee_putc(options) != WL_SUCCESS) |
||
1174 | return WL_ERROR_SEND; |
||
1175 | |||
1176 | // send packet |
||
1177 | if (xbee_send(packet, len) != WL_SUCCESS) |
||
1178 | return WL_ERROR_SEND; |
||
1179 | |||
1180 | // send checksum |
||
1181 | if (xbee_putc(sum) != WL_SUCCESS) |
||
1182 | return WL_ERROR_SEND; |
||
1183 | |||
1184 | return WL_SUCCESS; |
||
1185 | } |
||
1186 | |||
1187 | /** |
||
1188 | * Handles modem status packets. |
||
1189 | * |
||
1190 | * @param status the type of status packet received. |
||
1191 | **/ |
||
1192 | void xbee_handle_status(uint8_t status) |
||
1193 | { |
||
1194 | switch (status) |
||
1195 | { |
||
1196 | case 0: |
||
1197 | WL_DEBUG_PRINT("XBee hardware reset.\r\n"); |
||
1198 | break; |
||
1199 | case 1: |
||
1200 | WL_DEBUG_PRINT("Watchdog timer reset.\r\n"); |
||
1201 | break; |
||
1202 | case 2: |
||
1203 | WL_DEBUG_PRINT("Associated.\r\n"); |
||
1204 | break; |
||
1205 | case 3: |
||
1206 | WL_DEBUG_PRINT("Disassociated.\r\n"); |
||
1207 | break; |
||
1208 | case 4: |
||
1209 | WL_DEBUG_PRINT("Synchronization lost.\r\n"); |
||
1210 | break; |
||
1211 | case 5: |
||
1212 | WL_DEBUG_PRINT("Coordinator realignment.\r\n"); |
||
1213 | break; |
||
1214 | case 6: |
||
1215 | WL_DEBUG_PRINT("Coordinator started.\r\n"); |
||
1216 | break; |
||
1217 | } |
||
1218 | } |
||
1219 | |||
1220 | /** |
||
1221 | * Handles AT command response packets. |
||
1222 | * @param command the two character AT command, e.g. MY or ID |
||
1223 | * @param result 0 for success, 1 for an error |
||
1224 | * @param len the length in bytes of extra |
||
1225 | **/ |
||
1226 | 1638 | dsschult | static int8_t xbee_handle_at_command_response(uint16_t command, uint8_t status, uint8_t len) |
1227 | 1624 | dsschult | { |
1228 | 1638 | dsschult | WL_DEBUG_PRINT("HANDLE AT COMMAND\r\n"); |
1229 | if (status != 0) |
||
1230 | 1624 | dsschult | { |
1231 | WL_DEBUG_PRINT("Error with AT"); |
||
1232 | WL_DEBUG_PRINT(command); |
||
1233 | WL_DEBUG_PRINT(" packet. Result = "); |
||
1234 | 1638 | dsschult | switch(status) { |
1235 | 1624 | dsschult | case 1: |
1236 | WL_DEBUG_PRINT("ERROR\r\n"); |
||
1237 | break; |
||
1238 | case 2: |
||
1239 | WL_DEBUG_PRINT("Invalid Command\r\n"); |
||
1240 | break; |
||
1241 | case 3: |
||
1242 | WL_DEBUG_PRINT("Invalid Parameter\r\n"); |
||
1243 | break; |
||
1244 | } |
||
1245 | return WL_SUCCESS; |
||
1246 | } |
||
1247 | WL_DEBUG_PRINT("AT"); |
||
1248 | 1638 | dsschult | WL_DEBUG_PRINT_CHAR((uint8_t)(command>>8)); |
1249 | WL_DEBUG_PRINT_CHAR((uint8_t)(command)); |
||
1250 | WL_DEBUG_PRINT(" command is being handled\r\n"); |
||
1251 | 1624 | dsschult | |
1252 | // TODO: program more command responses here (ND, etc) |
||
1253 | switch(command) { |
||
1254 | case ('I'<<8)+'D': // PAN |
||
1255 | case ('C'<<8)+'H': // channel |
||
1256 | case ('M'<<8)+'Y': // address |
||
1257 | 1638 | dsschult | case ('A'<<8)+'P': // api mode |
1258 | 1624 | dsschult | // copy command to handler |
1259 | xbee_command[0] = (command&0xFF00)>>8; |
||
1260 | xbee_command[1] = command&0x00FF; |
||
1261 | 1638 | dsschult | uint8_t ptr = basic_buf_last; |
1262 | for(command=2;command<len+2;command++) { |
||
1263 | xbee_command[command] = xbee_basic_buf_get(&ptr); |
||
1264 | if (xbee_command[command] == '\r') |
||
1265 | break; // done with command |
||
1266 | WL_DEBUG_PRINT_HEX(xbee_command[command]); |
||
1267 | } |
||
1268 | xbee_command[command] = '\0'; |
||
1269 | WL_DEBUG_PRINT("len="); |
||
1270 | WL_DEBUG_PRINT_INT(len); |
||
1271 | WL_DEBUG_PRINT("ID,CH,or MY command result:"); |
||
1272 | WL_DEBUG_PRINT(xbee_command); |
||
1273 | WL_DEBUG_PRINT("\r\n"); |
||
1274 | 1624 | dsschult | break; |
1275 | default: |
||
1276 | WL_DEBUG_PRINT("unknown AT command"); |
||
1277 | } |
||
1278 | |||
1279 | // signal handler that command response is done |
||
1280 | 1638 | dsschult | setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_RESPONSE); |
1281 | 1624 | dsschult | |
1282 | return WL_SUCCESS; |
||
1283 | } |
||
1284 | |||
1285 | /** |
||
1286 | * Sets the personal area network id. |
||
1287 | * |
||
1288 | * @param id the new personal area network (PAN) id |
||
1289 | **/ |
||
1290 | 1642 | dsschult | int8_t xbee_set_pan(uint16_t id) |
1291 | 1624 | dsschult | { |
1292 | if (getStatus(XBEE_COMMAND_MASK) == XBEE_COMMAND_WAIT |
||
1293 | || getStatus(XBEE_COMMAND_MASK) == XBEE_COMMAND_RESPONSE) |
||
1294 | return WL_ERROR_XBEE_COMMAND; // can't do command right now |
||
1295 | |||
1296 | int16_t i=0; |
||
1297 | // change status to command wait |
||
1298 | setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_WAIT); |
||
1299 | xbee_send_modify_at_command((uint8_t*)"ID",(uint8_t*)(&id),2); // send command to set the channel |
||
1300 | // wait for up to 30 ms |
||
1301 | while(getStatus(XBEE_COMMAND_MASK) != XBEE_COMMAND_RESPONSE && i++ < 10000) { |
||
1302 | delay_us(1); // wait 3us |
||
1303 | } |
||
1304 | 1642 | dsschult | if (i < 1000 && xbee_command[0] == 'I' && xbee_command[1] == 'D') |
1305 | 1624 | dsschult | i = WL_SUCCESS; |
1306 | else |
||
1307 | i = WL_ERROR_XBEE_COMMAND; // set error code |
||
1308 | setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_NONE); // reset status |
||
1309 | return (int8_t)i; // return |
||
1310 | } |
||
1311 | |||
1312 | /** |
||
1313 | * Get the PAN ID for the XBee. |
||
1314 | * |
||
1315 | * @return the personal area network id, or |
||
1316 | * XBEE_PAN_DEFAULT if it has not yet been set. |
||
1317 | **/ |
||
1318 | 1642 | dsschult | uint16_t xbee_get_pan() |
1319 | 1624 | dsschult | { |
1320 | if (getStatus(XBEE_COMMAND_MASK) == XBEE_COMMAND_WAIT |
||
1321 | || getStatus(XBEE_COMMAND_MASK) == XBEE_COMMAND_RESPONSE) |
||
1322 | return WL_ERROR_XBEE_COMMAND_16BIT; // can't do command right now |
||
1323 | |||
1324 | uint16_t i=0; |
||
1325 | // change status to command wait |
||
1326 | setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_WAIT); |
||
1327 | xbee_send_read_at_command((uint8_t*)"ID"); // send command to get the PAN |
||
1328 | // wait for up to 30 ms |
||
1329 | while(getStatus(XBEE_COMMAND_MASK) != XBEE_COMMAND_RESPONSE && i++ < 10000) { |
||
1330 | delay_us(1); // wait 3us |
||
1331 | } |
||
1332 | if (i < 1000 && xbee_command[0] == 'I' && xbee_command[1] == 'D') |
||
1333 | 1642 | dsschult | i = xbee_command[2]|(xbee_command[3]<<8); // do ntoh16 coversion |
1334 | 1624 | dsschult | else |
1335 | i = WL_ERROR_XBEE_COMMAND_16BIT; // set error code |
||
1336 | setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_NONE); // reset status |
||
1337 | return i; // return |
||
1338 | } |
||
1339 | |||
1340 | /** |
||
1341 | * Set the channel the XBee is using. |
||
1342 | * |
||
1343 | * @param channel the channel the XBee will not use, |
||
1344 | * between 0x0B and 0x1A |
||
1345 | * |
||
1346 | * @see xbee_get_channel |
||
1347 | **/ |
||
1348 | int8_t xbee_set_channel(uint8_t channel) |
||
1349 | { |
||
1350 | if (channel < 0x0B || channel > 0x1A) |
||
1351 | { |
||
1352 | WL_DEBUG_PRINT("Channel out of range.\r\n"); |
||
1353 | 1642 | dsschult | return WL_ERROR_ARGUMENT; |
1354 | 1624 | dsschult | } |
1355 | |||
1356 | if (getStatus(XBEE_COMMAND_MASK) == XBEE_COMMAND_WAIT |
||
1357 | || getStatus(XBEE_COMMAND_MASK) == XBEE_COMMAND_RESPONSE) |
||
1358 | return WL_ERROR_XBEE_COMMAND; // can't do command right now |
||
1359 | |||
1360 | int16_t i=0; |
||
1361 | // change status to command wait |
||
1362 | setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_WAIT); |
||
1363 | xbee_send_modify_at_command((uint8_t*)"CH",&channel,1); // send command to set the channel |
||
1364 | // wait for up to 30 ms |
||
1365 | while(getStatus(XBEE_COMMAND_MASK) != XBEE_COMMAND_RESPONSE && i++ < 10000) { |
||
1366 | delay_us(1); // wait 3us |
||
1367 | } |
||
1368 | 1642 | dsschult | if (i < 1000 && xbee_command[0] == 'C' && xbee_command[1] == 'H') |
1369 | 1624 | dsschult | i = WL_SUCCESS; |
1370 | else |
||
1371 | i = WL_ERROR_XBEE_COMMAND; // set error code |
||
1372 | setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_NONE); // reset status |
||
1373 | return (int8_t)i; // return |
||
1374 | } |
||
1375 | |||
1376 | /** |
||
1377 | * Returns the channel which the XBee is currently using. |
||
1378 | * |
||
1379 | * @return the channel the XBee is using |
||
1380 | * |
||
1381 | * @see xbee_set_channel |
||
1382 | **/ |
||
1383 | int8_t xbee_get_channel(void) |
||
1384 | { |
||
1385 | if (getStatus(XBEE_COMMAND_MASK) == XBEE_COMMAND_WAIT |
||
1386 | || getStatus(XBEE_COMMAND_MASK) == XBEE_COMMAND_RESPONSE) |
||
1387 | return WL_ERROR_XBEE_COMMAND; // can't do command right now |
||
1388 | |||
1389 | int16_t i=0; |
||
1390 | // change status to command wait |
||
1391 | setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_WAIT); |
||
1392 | 1642 | dsschult | xbee_send_read_at_command((uint8_t*)"CH"); // send command to get the channel |
1393 | 1624 | dsschult | // wait for up to 30 ms |
1394 | while(getStatus(XBEE_COMMAND_MASK) != XBEE_COMMAND_RESPONSE && i++ < 10000) { |
||
1395 | delay_us(1); // wait 3us |
||
1396 | } |
||
1397 | if (i < 1000 && xbee_command[0] == 'C' && xbee_command[1] == 'H') |
||
1398 | 1642 | dsschult | i = (int8_t)xbee_command[2]; // get channel |
1399 | 1624 | dsschult | else |
1400 | i = WL_ERROR_XBEE_COMMAND; // set error code |
||
1401 | setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_NONE); // reset status |
||
1402 | return i; // return |
||
1403 | } |
||
1404 | |||
1405 | /** |
||
1406 | * Get the 16-bit address of the XBee. |
||
1407 | * This is used to specify who to send messages to |
||
1408 | * and who messages are from. |
||
1409 | * |
||
1410 | * @return the 16-bit address of the XBee. |
||
1411 | **/ |
||
1412 | uint16_t xbee_get_address(void) |
||
1413 | { |
||
1414 | if (getStatus(XBEE_COMMAND_MASK) == XBEE_COMMAND_WAIT |
||
1415 | || getStatus(XBEE_COMMAND_MASK) == XBEE_COMMAND_RESPONSE) |
||
1416 | return WL_ERROR_XBEE_COMMAND_16BIT; // can't do command right now |
||
1417 | |||
1418 | uint16_t i=0; |
||
1419 | 1628 | dsschult | // change status to command wait |
1420 | 1638 | dsschult | /*WL_DEBUG_PRINT("\r\nbefore status="); |
1421 | 1628 | dsschult | WL_DEBUG_PRINT_HEX(getStatus(0xFF)); |
1422 | 1638 | dsschult | WL_DEBUG_PRINT("\r\n");*/ |
1423 | 1633 | dsschult | setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_WAIT); |
1424 | 1638 | dsschult | /*if (getStatus(XBEE_API_MASK) == XBEE_API_OFF) { |
1425 | 1633 | dsschult | WL_DEBUG_PRINT("|API OFF|"); |
1426 | } else if (getStatus(XBEE_API_MASK) == XBEE_API_ON) { |
||
1427 | WL_DEBUG_PRINT("|API ON|"); |
||
1428 | } else { |
||
1429 | WL_DEBUG_PRINT("|API ERROR|"); |
||
1430 | } |
||
1431 | 1628 | dsschult | WL_DEBUG_PRINT("after status="); |
1432 | WL_DEBUG_PRINT_HEX(getStatus(0xFF)); |
||
1433 | 1638 | dsschult | WL_DEBUG_PRINT("\r\n");*/ |
1434 | 1624 | dsschult | xbee_send_read_at_command((uint8_t*)"MY"); // send command to get the address |
1435 | // wait for up to 30 ms |
||
1436 | while(getStatus(XBEE_COMMAND_MASK) != XBEE_COMMAND_RESPONSE && i++ < 10000) { |
||
1437 | delay_us(1); // wait 3us |
||
1438 | } |
||
1439 | 1638 | dsschult | |
1440 | if (i < 1000 && xbee_command[0] == 'M' && xbee_command[1] == 'Y') { |
||
1441 | 1642 | dsschult | i = xbee_command[2]|(xbee_command[3]<<8); // do ntoh16 coversion |
1442 | 1638 | dsschult | } else |
1443 | 1624 | dsschult | i = WL_ERROR_XBEE_COMMAND_16BIT; // set error code |
1444 | setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_NONE); // reset status |
||
1445 | 1638 | dsschult | WL_DEBUG_PRINT("get MY address\r\n"); |
1446 | 1624 | dsschult | return i; // return |
1447 | } |
||
1448 | |||
1449 | /**@} **/ // end xbee group |