Project

General

Profile

Statistics
| Revision:

root / trunk / code / projects / libwireless / lib / xbee.c @ 717

History | View | Annotate | Download (24.3 KB)

1 242 bcoltin
/**
2
 * Copyright (c) 2007 Colony Project
3 409 emarinel
 *
4 242 bcoltin
 * 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 409 emarinel
 *
13 242 bcoltin
 * The above copyright notice and this permission notice shall be
14
 * included in all copies or substantial portions of the Software.
15 409 emarinel
 *
16 242 bcoltin
 * 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 Brian Coltin, Colony Project, CMU Robotics Club
33
 **/
34
35 17 bcoltin
#include "xbee.h"
36
#include "wl_defs.h"
37
38
#ifndef ROBOT
39
40
#include <fcntl.h>
41
#include <unistd.h>
42
#include <pthread.h>
43
#include <errno.h>
44 309 emarinel
#include <termios.h>
45 17 bcoltin
46
#else
47
48
#include <serial.h>
49
#include <avr/interrupt.h>
50
51
#endif
52
53
#include <stdio.h>
54
#include <stdlib.h>
55
#include <string.h>
56
57
#define XBEE_FRAME_START 0x7E
58 581 jknichel
#define XBEE_GET_PACKET_TIMEOUT 1000
59 17 bcoltin
60
/*Frame Types*/
61
#define XBEE_FRAME_STATUS 0x8A
62
#define XBEE_FRAME_AT_COMMAND 0x08
63
#define XBEE_FRAME_AT_COMMAND_RESPONSE 0x88
64
#define XBEE_FRAME_TX_REQUEST_64 0x00
65
#define XBEE_FRAME_TX_REQUEST_16 0x01
66
#define XBEE_FRAME_TX_STATUS XBEE_TX_STATUS
67
#define XBEE_FRAME_RX_64 0x80
68
#define XBEE_FRAME_RX_16 XBEE_RX
69
70
/*Internal Function Prototypes*/
71
72
/*I/O Functions*/
73 397 emarinel
static int xbee_send(char* buf, int size);
74 418 emarinel
static int xbee_send_string(char* c);
75 17 bcoltin
76
#ifndef ROBOT
77 418 emarinel
static int xbee_read(char* buf, int size);
78 17 bcoltin
#endif
79
80
/*Command Mode Functions
81
 * Called during initialization.
82
 */
83 418 emarinel
static int xbee_enter_command_mode(void);
84
static int xbee_exit_command_mode(void);
85
static int xbee_enter_api_mode(void);
86
static int xbee_exit_api_mode(void);
87 581 jknichel
static int xbee_wait_for_string(char* s, int len);
88
static int xbee_wait_for_ok(void);
89 17 bcoltin
90
/*API Mode Functions*/
91
92 418 emarinel
static int xbee_handle_packet(char* packet, int len);
93
static void xbee_handle_at_command_response(char* command, char result, char* extra, int extraLen);
94
static void xbee_handle_status(char status);
95
static int xbee_verify_checksum(char* packet, int len);
96
static char xbee_compute_checksum(char* packet, int len);
97
static int xbee_send_frame(char* buf, int len);
98
static int xbee_send_read_at_command(char* command);
99
static int xbee_send_modify_at_command(char* command, char* value);
100 17 bcoltin
101
/*Global Variables*/
102
103
#ifndef ROBOT
104 399 emarinel
static char* xbee_com_port = XBEE_PORT_DEFAULT;
105
static int xbee_stream;
106
static pthread_t* xbee_listen_thread;
107 17 bcoltin
#endif
108
109 336 bcoltin
// TODO: is this a good size?
110 717 jknichel
//TODO: does this buffer size need to be so large?  we have constrained memory, so this should be as small as feasibly possible
111 336 bcoltin
#define XBEE_BUFFER_SIZE        256
112
// a buffer for data received from the XBee
113
char arrival_buf[XBEE_BUFFER_SIZE];
114
// location of last unread byte in buffer
115
volatile int buffer_last = 0;
116
// first unread byte in buffer
117
volatile int buffer_first = 0;
118 17 bcoltin
119 336 bcoltin
120 17 bcoltin
//used to store packets as they are read
121 717 jknichel
122
//TODO: does this need to be 128?  can it be smaller to save memory?
123
//TODO: this shouldn't be hardcoded as 128.  it should be a define.
124 418 emarinel
static char xbee_buf[128];
125
static int currentBufPos = 0;
126 17 bcoltin
127
//XBee status
128 418 emarinel
static unsigned int xbee_panID = XBEE_PAN_DEFAULT;
129
static unsigned int xbee_pending_panID = XBEE_PAN_DEFAULT;
130
static int xbee_channel = XBEE_CHANNEL_DEFAULT;
131
static int xbee_pending_channel = XBEE_CHANNEL_DEFAULT;
132 581 jknichel
static volatile unsigned int xbee_address = 0;
133 17 bcoltin
134 717 jknichel
//TODO: this is only needed for the computer side, right?  I'm going to put #ifndef ROBOT around it to remove it from robot code
135
#ifndef ROBOT
136 613 jknichel
void printHex(char * s, int len) {
137
  int i;
138
  for (i = 0; i < len; i++) {
139
    printf("0x%x ", (int)(s[i]));
140
  }
141
  printf("\n");
142
}
143 717 jknichel
#endif
144 613 jknichel
145
146 17 bcoltin
/*Function Implementations*/
147
148
#ifdef ROBOT
149
150
/**
151
 * Interrupt for the robot. Adds bytes received from the xbee
152 336 bcoltin
 * to the buffer.
153 17 bcoltin
 **/
154 86 bcoltin
#ifndef FIREFLY
155 346 bcoltin
ISR(USART1_RX_vect)
156
{
157
        char c = UDR1;
158
        arrival_buf[buffer_last] = c;
159
        int t = buffer_last + 1;
160
        if (t == XBEE_BUFFER_SIZE)
161
                t = 0;
162
        if (t == buffer_first)
163
        {
164
                WL_DEBUG_PRINT("Out of space in buffer.\n");
165
        }
166
        buffer_last = t;
167 17 bcoltin
}
168 86 bcoltin
#else
169 346 bcoltin
SIGNAL(SIG_USART0_RECV)
170
{
171
        char c = UDR0;
172
        arrival_buf[buffer_last] = c;
173
        int t = buffer_last + 1;
174
        if (t == XBEE_BUFFER_SIZE)
175
                t = 0;
176
        if (t == buffer_first)
177
        {
178
                WL_DEBUG_PRINT("Out of space in buffer.\n");
179
        }
180
        buffer_last = t;
181 86 bcoltin
}
182
#endif
183 17 bcoltin
184
#else
185
186 418 emarinel
// Computer code
187
188 17 bcoltin
/**
189
 * Thread that listens to the xbee.
190
 **/
191 418 emarinel
static void* listen_to_xbee(void* x)
192 346 bcoltin
{
193
        char c;
194
        while (1)
195
        {
196 418 emarinel
                if (xbee_read(&c, 1) != 0) {
197
                        fprintf(stderr, "xbee_read failed.\n");
198
                        return NULL;
199
                }
200 717 jknichel
201 613 jknichel
                //DEBUGGING PRINT
202
                //printf("interrupt: %c (%d)\n", c, (int)c);
203 346 bcoltin
                arrival_buf[buffer_last] = c;
204
                int t = buffer_last + 1;
205
                if (t == XBEE_BUFFER_SIZE)
206
                        t = 0;
207
                if (t == buffer_first)
208
                {
209
                        WL_DEBUG_PRINT("Out of space in buffer.\n");
210
                }
211
                buffer_last = t;
212 409 emarinel
213
                usleep(1000);
214 346 bcoltin
        }
215 418 emarinel
216
        return NULL;
217 17 bcoltin
}
218
219
#endif
220
221
/**
222
 * Initializes the XBee library so that other functions may be used.
223
 **/
224 399 emarinel
int xbee_lib_init()
225 346 bcoltin
{
226
        arrival_buf[0] = 'A';
227
        arrival_buf[1] = 'A';
228
        arrival_buf[2] = 'A';
229 581 jknichel
#ifdef ROBOT
230 17 bcoltin
231 346 bcoltin
        //enable the receiving interrupt
232 412 emarinel
#ifdef FIREFLY
233 346 bcoltin
        UCSR0B |= _BV(RXCIE) | _BV(RXEN);
234 412 emarinel
#else
235 346 bcoltin
        UCSR1B |= _BV(RXCIE);
236 412 emarinel
#endif
237 346 bcoltin
        sei();
238 412 emarinel
#else
239 346 bcoltin
        printf("Connecting to port %s.\n", xbee_com_port);
240
        xbee_stream = open(xbee_com_port, O_RDWR);
241
        if (xbee_stream == -1/* || lockf(xbee_stream, F_TEST, 0) != 0*/)
242
        {
243
                printf("Failed to open connection to XBee on port %s\r\n", xbee_com_port);
244
                return -1;
245 581 jknichel
        } else {
246
          printf("Successfully opened connection to XBee on port %s\r\n", xbee_com_port);
247 346 bcoltin
        }
248 409 emarinel
249 346 bcoltin
        // set baud rate, etc. correctly
250
        struct termios options;
251 309 emarinel
252 346 bcoltin
        tcgetattr(xbee_stream, &options);
253
        cfsetispeed(&options, B9600);
254
        cfsetospeed(&options, B9600);
255
        options.c_iflag &= ~ICRNL;
256
        options.c_oflag &= ~OCRNL;
257
        options.c_cflag |= (CLOCAL | CREAD);
258
        options.c_cflag &= ~PARENB;
259
        options.c_cflag &= ~CSTOPB;
260
        options.c_cflag &= ~CSIZE;
261
        options.c_cflag |= CS8;
262
        options.c_lflag &= ~ICANON;
263
        options.c_cc[VMIN] = 1;
264
        options.c_cc[VTIME] = 50;
265 309 emarinel
266 346 bcoltin
        if (tcsetattr(xbee_stream, TCSANOW, &options))
267
        {
268
                fprintf(stderr, "Error setting attributes.\n");
269
                return -1;
270 581 jknichel
        } else {
271
          //printf("Successfully set termios attributes.\n");
272 346 bcoltin
        }
273 309 emarinel
274 346 bcoltin
        //lockf(xbee_stream, F_LOCK, 0);
275 409 emarinel
276
        xbee_listen_thread = (pthread_t*)malloc(sizeof(pthread_t));
277 346 bcoltin
        if (xbee_listen_thread == NULL)
278
        {
279
                fprintf(stderr, "%s: Malloc failed.\n", __FUNCTION__);
280
                return -1;
281
        }
282 409 emarinel
283
        int ret = pthread_create(xbee_listen_thread, NULL, listen_to_xbee, NULL);
284 346 bcoltin
        if (ret)
285
        {
286
                fprintf(stderr, "Failed to create listener thread.\r\n");
287
                return -1;
288 581 jknichel
        } else {
289
          //printf("Successfully created listener thread.\n");
290 346 bcoltin
        }
291 412 emarinel
#endif
292 409 emarinel
293 613 jknichel
        //DEBUGGING PRINT
294
        //printf("about to call xbee_enter_command_mode\n");
295
296 418 emarinel
        if (xbee_enter_command_mode() != 0) {
297 581 jknichel
#ifndef ROBOT
298
          printf("Error returned from xbee_enter_command_mode\n");
299
#endif
300 418 emarinel
                return -1;
301
        }
302 409 emarinel
303 613 jknichel
        //DEBUGGING PRINT
304
        //printf("about to call xbee_enter_api_mode\n");
305
306 418 emarinel
        if (xbee_enter_api_mode() != 0) {
307 581 jknichel
#ifndef ROBOT
308
          printf("Error returned from xbee_enter_api_mode\n");
309
#endif
310 418 emarinel
                return -1;
311
        }
312
313 613 jknichel
        //DEBUGGING PRINT
314
        //printf("about to call xbee_exit_command_mode\n");
315
316 418 emarinel
        if (xbee_exit_command_mode() != 0) {
317 581 jknichel
#ifndef ROBOT
318
          printf("Error returned from xbee_exit_command_mode\n");
319
#endif
320 418 emarinel
                return -1;
321
        }
322
323 613 jknichel
        //DEBUGGING PRINT
324
        //printf("about to call xbee_send_read_at_command\n");
325
326 418 emarinel
        if (xbee_send_read_at_command("MY")) {
327 581 jknichel
#ifndef ROBOT
328
          printf("Error returned from xbee_send_read_at_command\n");
329
#endif
330 418 emarinel
                return -1;
331
        }
332
333 581 jknichel
#ifndef ROBOT
334
        //printf("About to enter while loop to get xbee_address.\n");
335
        int i;
336
        for (i = 0; xbee_address == 0 && i < XBEE_GET_PACKET_TIMEOUT; i++) {
337
          ret = xbee_get_packet(NULL);
338
339
          usleep(1000);
340
341
          if (ret == -1) {
342
            printf("xbee_get_packet(NULL) failed.\n");
343
            return -1;
344
          }
345
        }
346
347
        //        printf("After exiting while loop to get xbee_address.\n");
348
#else
349 346 bcoltin
        //wait to return until the address is set
350 717 jknichel
  //TODO: this shouldn't wait indefinitely.  There should be some sort of reasonable timeout
351
  // so if the address is never set right, an error can be returned instead of having the
352
  // robot hang forever
353 581 jknichel
        while (xbee_address == 0) {
354
          xbee_get_packet(NULL);
355
        }
356
#endif
357 309 emarinel
358 581 jknichel
#ifndef ROBOT
359
        if (i == XBEE_GET_PACKET_TIMEOUT) { // We timed-out.
360
361
          printf("xbee_get_packet timed out.\n");
362
          return -1;
363
        } else {
364
          return 0;
365
        }
366
#else
367 346 bcoltin
        return 0;
368 581 jknichel
#endif
369 17 bcoltin
}
370
371
/**
372
 * Call when finished using the XBee library. This releases
373
 * all sued resources.
374
 **/
375 346 bcoltin
void xbee_terminate()
376
{
377
        #ifndef ROBOT
378
        pthread_cancel(*xbee_listen_thread);
379
        free(xbee_listen_thread);
380
        lockf(xbee_stream, F_ULOCK, 0);
381
        close(xbee_stream);
382
        #endif
383 17 bcoltin
}
384
385
/**
386
 * Send a buffer buf of size bytes to the XBee.
387 409 emarinel
 *
388 17 bcoltin
 * @param buf the buffer of data to send
389
 * @param size the number of bytes to send
390
 **/
391 418 emarinel
static int xbee_send(char* buf, int size)
392 346 bcoltin
{
393 418 emarinel
#ifdef ROBOT
394 346 bcoltin
        int i;
395 418 emarinel
        for (i = 0; i < size; i++) {
396 346 bcoltin
                xbee_putc(buf[i]);
397 418 emarinel
        }
398
399
        return 0;
400
401
#else
402 613 jknichel
        //DEBUGGING PRINT
403
        //printf("in xbee_send ");
404
        //printHex(buf, size);
405 418 emarinel
406 346 bcoltin
        int ret = write(xbee_stream, buf, size);
407
        //success
408
        if (ret == size)
409 397 emarinel
                return 0;
410 346 bcoltin
        if (ret == -1)
411
        {
412
                //interrupted by system signal, probably timer interrupt.
413
                //just try again
414
                if (errno == 4)
415
                {
416 397 emarinel
                        return xbee_send(buf, size);
417 346 bcoltin
                }
418
                printf("Failed to write to xbee, error %i.\r\n", errno);
419 397 emarinel
                return -1;
420 346 bcoltin
        }
421 17 bcoltin
422 346 bcoltin
        //write was interrupted after writing ret bytes
423 418 emarinel
        return xbee_send(buf + ret, size - ret);
424
#endif
425 17 bcoltin
}
426
427
/**
428
 * Sends a string to the XBee.
429
 *
430
 * @param c the string to send to the XBEE
431
 **/
432 717 jknichel
//TODO: this function is so simple, it *may* be beneficial to inline this function.  testing of if
433
// it reduces code size or not should be done to be sure.
434 418 emarinel
static int xbee_send_string(char* c)
435 346 bcoltin
{
436 418 emarinel
        return xbee_send(c, strlen(c));
437 17 bcoltin
}
438
439
#ifndef ROBOT
440 418 emarinel
static int xbee_read(char* buf, int size)
441 346 bcoltin
{
442 418 emarinel
        if (read(xbee_stream, buf, size) == -1) {
443 346 bcoltin
                printf("Failed to read from xbee.\r\n");
444 418 emarinel
                return -1;
445
        }
446
447
        return 0;
448 17 bcoltin
}
449
#endif
450
451
/**
452
 * Enter into command mode.
453
 **/
454 418 emarinel
static int xbee_enter_command_mode()
455 346 bcoltin
{
456 418 emarinel
        if (xbee_send_string("+++") != 0) {
457
                return -1;
458
        }
459
460 581 jknichel
#ifndef ROBOT
461
        //        printf("In xbee_enter_command_mode about to call xbee_wait_for_ok()\n");
462
#endif
463 418 emarinel
464 581 jknichel
        if (xbee_wait_for_ok() != 0) {
465
#ifndef ROBOT
466
          printf("xbee_wait_for_ok failed.\n");
467
#endif
468
          return -1;
469
        } else {
470
          return 0;
471
        }
472 17 bcoltin
}
473
474
/**
475
 * Exit from command mode.
476
 **/
477 418 emarinel
static int xbee_exit_command_mode()
478 346 bcoltin
{
479 418 emarinel
        if (xbee_send_string("ATCN\r") != 0) {
480
                return -1;
481
        }
482
483 346 bcoltin
        xbee_wait_for_ok();
484 418 emarinel
485
        return 0;
486 17 bcoltin
}
487
488
/**
489
 * Enter API mode.
490
 **/
491 418 emarinel
static int xbee_enter_api_mode()
492 346 bcoltin
{
493 418 emarinel
        if (xbee_send_string("ATAP 1\r") != 0) {
494
                return -1;
495
        }
496 346 bcoltin
        xbee_wait_for_ok();
497 418 emarinel
498
        return 0;
499 17 bcoltin
}
500
501
/**
502 309 emarinel
 * Exit API mode. (warning - does not check for response)
503
 **/
504 717 jknichel
//TODO: this function is so simple, it *may* be beneficial to inline this function.  testing of if
505
// it reduces code size or not should be done to be sure.
506 418 emarinel
static int xbee_exit_api_mode()
507 346 bcoltin
{
508 418 emarinel
        return xbee_send_string("ATAP 0\r");
509 309 emarinel
}
510
511
/**
512 17 bcoltin
 * Wait until the string "OK\r" is received from the XBee.
513
 **/
514 717 jknichel
//TODO: this function is so simple, it *may* be beneficial to inline this function.  testing of if
515
// it reduces code size or not should be done to be sure.
516 581 jknichel
static int xbee_wait_for_ok()
517 346 bcoltin
{
518 613 jknichel
  //DEBUGGING PRINT
519
  //printf("\tin xbee_wait_for_ok\n");
520 581 jknichel
        return xbee_wait_for_string("OK\r", 3);
521 17 bcoltin
}
522
523
/**
524
 * Delay until the specified string is received from
525
 * the XBee. Discards all other XBee data.
526
 *
527
 * @param s the string to receive
528
 * @param len the length of the string
529
 **/
530 581 jknichel
static int xbee_wait_for_string(char* s, int len)
531 346 bcoltin
{
532 613 jknichel
  //DEBUGGING PRINT
533
  //printf("\t in xbee_wait_for_string\n");
534
535 581 jknichel
#ifndef ROBOT
536
  //printf("In xbee_wait_for_string.\n");
537
#endif
538
539 412 emarinel
        char* curr = s;
540
        while (curr - s < len) {
541
                // check if buffer is empty
542
                if (buffer_last != buffer_first) {
543
                        char c = arrival_buf[buffer_first++];
544
                        if (buffer_first == XBEE_BUFFER_SIZE) {
545
                                buffer_first = 0;
546
                        }
547 409 emarinel
548 613 jknichel
                        //DEBUGGING PRINT
549
                        //printf("\t\t c is %c (%d)\n", c, (int)c);
550
551 412 emarinel
                        if (c == *curr) {
552
                                curr++;
553
                        } else {
554 581 jknichel
#ifndef ROBOT
555 613 jknichel
                          //return -1; // Computer is less forgiving.
556
                          curr = s;
557 581 jknichel
#else
558
                          curr = s;
559
#endif
560 412 emarinel
                        }
561 581 jknichel
                } // else buffer is empty.
562 409 emarinel
563 412 emarinel
#ifndef ROBOT
564 581 jknichel
                usleep(100);
565 412 emarinel
#endif
566
        }
567 581 jknichel
568
        return 0;
569 17 bcoltin
}
570
571
/**
572
 * Verifies that the packets checksum is correct.
573
 * (If the checksum is correct, the sum of the bytes
574
 * is 0xFF.)
575
 *
576
 * @param packet the packet received. This includes the first
577
 * three bytes, which are header information from the XBee.
578
 *
579
 * @param len The length of the packet received from the XBee
580
 *
581
 * @return 0 if the checksum is incorrect, nonzero
582
 * otherwise
583
 **/
584 346 bcoltin
int xbee_verify_checksum(char* packet, int len)
585
{
586
        unsigned char sum = 0;
587
        int i;
588
        for (i = 3; i < len; i++)
589
                sum += (unsigned char)packet[i];
590
        return sum == 0xFF;
591 17 bcoltin
}
592
593
/**
594
 * Returns the checksum of the given packet.
595
 *
596
 * @param buf the data for the packet to send
597
 * @param len the length of the packet in bytes
598
 *
599
 * @return the checksum of the packet, which will
600
 * become the last byte sent in the packet
601
 **/
602 346 bcoltin
char xbee_compute_checksum(char* buf, int len)
603
{
604
        int i;
605
        unsigned char sum = 0;
606
        for (i = 0; i < len; i++)
607
                sum += (unsigned char)buf[i];
608
        return 0xFF - sum;
609 17 bcoltin
}
610
611
/**
612
 * Adds header information and checksum to the given
613
 * packet and sends it. Header information includes
614
 * XBEE_FRAME_START and the packet length, as two bytes.
615
 *
616
 * @param buf the packet data
617
 * @param len the size in bytes of the packet data
618
 *
619
 **/
620 418 emarinel
static int xbee_send_frame(char* buf, int len)
621 346 bcoltin
{
622 613 jknichel
  printf("in %s and len is %d\n", __FUNCTION__, len);
623
624 346 bcoltin
        char prefix[3];
625
        prefix[0] = XBEE_FRAME_START;
626
        prefix[1] = (len & 0xFF00) >> 8;
627
        prefix[2] = len & 0xFF;
628
        char checksum = xbee_compute_checksum(buf, len);
629 418 emarinel
630
        if (xbee_send(prefix, 3) != 0) {
631
                return -1;
632
        }
633 581 jknichel
634 418 emarinel
        if (xbee_send(buf, len) != 0) {
635
                return -1;
636
        }
637
638
        if (xbee_send(&checksum, 1) != 0) {
639
                return -1;
640
        }
641
642
        return 0;
643 17 bcoltin
}
644
645
/**
646
 * Sends an AT command to read a parameter.
647
 *
648
 * @param command the AT command to send. For exmaple,
649
 * use ID to read the PAN ID and MY to return the XBee ID.
650
 * See the XBee reference guide for a complete listing.
651
 **/
652 717 jknichel
//TODO: this function is so simple, it *may* be beneficial to inline this function.  testing of if
653
// it reduces code size or not should be done to be sure.
654 418 emarinel
static int xbee_send_read_at_command(char* command)
655 346 bcoltin
{
656 418 emarinel
        return xbee_send_modify_at_command(command, NULL);
657 17 bcoltin
}
658
659
/**
660
 * Sends the given AT command.
661
 *
662
 * @param command the AT command to send (e.g., MY, ID)
663
 * @param value the value to pass as a parameter
664
 * (or NULL if there is no parameter)
665
 **/
666 418 emarinel
static int xbee_send_modify_at_command(char* command, char* value)
667 346 bcoltin
{
668 613 jknichel
  printf("in %s with command %s and value %s\n", __FUNCTION__, command, value);
669
670 346 bcoltin
        char buf[16];
671
        int i;
672 409 emarinel
673 346 bcoltin
        buf[0] = XBEE_FRAME_AT_COMMAND;
674
        buf[1] = 1;
675
        buf[2] = command[0];
676
        buf[3] = command[1];
677
        int valueLen = 0;
678
        if (value != NULL)
679
        {
680
                valueLen = strlen(value);
681
                if (valueLen > 8)
682
                {
683
                        WL_DEBUG_PRINT("AT Command too large.\r\n");
684 418 emarinel
                        return -1;
685 346 bcoltin
                }
686 418 emarinel
687
                for (i = 0; i < valueLen; i++) {
688 346 bcoltin
                        buf[4 + i] = value[i];
689 418 emarinel
                }
690 346 bcoltin
        }
691 418 emarinel
692
        return xbee_send_frame(buf, 4 + valueLen);
693 17 bcoltin
}
694
695
/**
696
 * Send the specified packet.
697 409 emarinel
 *
698 17 bcoltin
 * @param packet the packet data to send
699
 * @param len the number of bytes in the packet
700 409 emarinel
 *
701 17 bcoltin
 * @param dest the ID of the XBee to send the packet to,
702
 * or XBEE_BROADCAST to send the message to all robots
703
 * in the PAN.
704 409 emarinel
 *
705 17 bcoltin
 * @param options a combination of the flags
706 409 emarinel
 * XBEE_OPTIONS_NONE, XBEE_OPTIONS_DISABLE_RESPONSE and
707 17 bcoltin
 * XBEE_OPTIONS_BROADCAST_ALL_PANS
708
 *
709
 * @param frame the frame number to associate this packet
710
 * with. This will be used to identify the response when
711
 * the XBee alerts us as to whether or not our message
712
 * was received.
713
 **/
714 397 emarinel
int xbee_send_packet(char* packet, int len, int dest, char options, char frame)
715 346 bcoltin
{
716
        char buf[5];
717
        char prefix[3];
718
        int i;
719
        unsigned char checksum = 0;
720 17 bcoltin
721 346 bcoltin
        if (len > 100)
722
        {
723
                WL_DEBUG_PRINT("Packet is too large.\r\n");
724 397 emarinel
                return -1;
725 346 bcoltin
        }
726 17 bcoltin
727 346 bcoltin
        //data for sending request
728
        buf[0] = XBEE_FRAME_TX_REQUEST_16;
729
        buf[1] = frame;
730
        buf[2] = (dest >> 8) & 0xFF;
731
        buf[3] = dest & 0xFF;
732
        buf[4] = options;
733 17 bcoltin
734 346 bcoltin
        //packet prefix, do this here so we don't need an extra buffer
735
        prefix[0] = XBEE_FRAME_START;
736
        prefix[1] = ((5 + len) & 0xFF00) >> 8;
737
        prefix[2] = (5 + len) & 0xFF;
738 17 bcoltin
739 346 bcoltin
        for (i = 0; i < 5; i++)
740
                checksum += (unsigned char)buf[i];
741
        for (i = 0; i < len; i++)
742
                checksum += (unsigned char)packet[i];
743
        checksum = 0xFF - checksum;
744 397 emarinel
745
        if (xbee_send(prefix, 3) != 0) {
746
                return -1;
747
        }
748
749
        if (xbee_send(buf, 5) != 0) {
750
                return -1;
751
        }
752
753
        if (xbee_send(packet, len) != 0) {
754
                return -1;
755
        }
756
757
        if (xbee_send((char*)&checksum, 1) != 0) {
758
                return -1;
759
        }
760
761
        return 0;
762 17 bcoltin
}
763
764
/**
765
 * Reads a packet received from the XBee. This function
766
 * is non-blocking. The resulting packet is stored in dest.
767
 * Only returns transmission response packets and
768
 * received packets. The returned packet does not include
769
 * header information or the checksum. This method also
770
 * handles special packets dealt with by the XBee library,
771
 * and so should be called frequently while the XBee is in
772
 * use.<br><br>
773
 *
774
 * The first byte of the packet will be either
775
 * XBEE_TX_STATUS or XBEE_RX to indicated
776 409 emarinel
 * a response to a sent message or a received message,
777 17 bcoltin
 * respectively.<br><br>
778
 *
779
 * For a status response packet:<br>
780
 * The first byte will be XBEE_TX_STATUS.<br>
781
 * The second byte will be the frame number.<br>
782
 * The third byte will be the result. 0 indicates success,
783 409 emarinel
 * and nonzero indicates that an error ocurred in
784 17 bcoltin
 * transmitting the packet.<br><br>
785
 *
786
 * For a received packet:<br>
787
 * The first byte will be XBEE_RX.<br>
788
 * The second and third bytes will be the 16-bit
789
 * address of the packet's sender.<br>
790
 * The fourth byte is the signal strength.<br>
791
 * The fifth byte is 1 if the packet were sent to
792
 * a specific address, and 2 if it is a broadcast packet.<br><br>
793 409 emarinel
 *
794 17 bcoltin
 * @param dest set to the packet data
795
 * @return the length of the packet, or -1 if no packet
796
 * is available
797
 **/
798 346 bcoltin
int xbee_get_packet(unsigned char* dest)
799
{
800
        //start reading a packet with XBEE_FRAME_START
801
        if (currentBufPos == 0)
802
        {
803
                do
804
                {
805
                        if (buffer_first == XBEE_BUFFER_SIZE)
806
                                buffer_first = 0;
807
                        // check if buffer is empty
808 581 jknichel
                        if (buffer_first == buffer_last) {
809
                                return 0;
810
                        }
811 418 emarinel
                } while (arrival_buf[buffer_first++] != XBEE_FRAME_START);
812
813
                if (buffer_first == XBEE_BUFFER_SIZE) {
814
                        buffer_first = 0;
815 346 bcoltin
                }
816
                xbee_buf[0] = XBEE_FRAME_START;
817
                currentBufPos++;
818
        }
819 17 bcoltin
820 346 bcoltin
        int len = -1;
821 418 emarinel
        if (currentBufPos >= 3) {
822 346 bcoltin
                len = (int)xbee_buf[2] + ((int)xbee_buf[1] << 8);
823 418 emarinel
        }
824 409 emarinel
825 346 bcoltin
        while (len == -1 //packet length has not been read yet
826 418 emarinel
                || currentBufPos < len + 4)
827 346 bcoltin
        {
828
                if (currentBufPos == 3)
829
                {
830
                        len = (int)xbee_buf[2] + ((int)xbee_buf[1] << 8);
831
                        if (len > 120)
832
                        {
833
                                WL_DEBUG_PRINT("Packet too large. Probably error in XBee transmission.\n");
834
                                currentBufPos = 0;
835
                                return -1;
836
                        }
837
                }
838 418 emarinel
839 346 bcoltin
                // check if buffer is empty
840 418 emarinel
                if (buffer_first == buffer_last) {
841 581 jknichel
                        return 0;
842 418 emarinel
                }
843 346 bcoltin
                xbee_buf[currentBufPos++] = arrival_buf[buffer_first++];
844 418 emarinel
                if (buffer_first == XBEE_BUFFER_SIZE) {
845 346 bcoltin
                        buffer_first = 0;
846 418 emarinel
                }
847 346 bcoltin
        }
848 409 emarinel
849 17 bcoltin
        currentBufPos = 0;
850 409 emarinel
851 346 bcoltin
        if (!xbee_verify_checksum(xbee_buf, len + 4))
852
        {
853
                WL_DEBUG_PRINT("XBee checksum failed.\r\n");
854
                return -1;
855
        }
856 17 bcoltin
857 346 bcoltin
        //we will take care of the packet
858 581 jknichel
        if (xbee_handle_packet(xbee_buf + 3, len) != 0) {
859
                return 0;
860 418 emarinel
        }
861 409 emarinel
862 418 emarinel
        if (dest == NULL) {
863 581 jknichel
                return 0;
864 418 emarinel
        }
865 409 emarinel
866 346 bcoltin
        int i;
867 418 emarinel
        for (i = 3; i < len + 3; i++) {
868 346 bcoltin
                dest[i - 3] = xbee_buf[i];
869 418 emarinel
        }
870
871 346 bcoltin
        return len;
872 17 bcoltin
}
873
874
/**
875
 * Handles modem status packets.
876
 *
877
 * @param status the type of status packet received.
878
 **/
879 346 bcoltin
void xbee_handle_status(char status)
880
{
881
        switch (status)
882
        {
883
                case 0:
884
                        WL_DEBUG_PRINT("XBee hardware reset.\r\n");
885
                        break;
886
                case 1:
887
                        WL_DEBUG_PRINT("Watchdog timer reset.\r\n");
888
                        break;
889
                case 2:
890
                        WL_DEBUG_PRINT("Associated.\r\n");
891
                        break;
892
                case 3:
893
                        WL_DEBUG_PRINT("Disassociated.\r\n");
894
                        break;
895
                case 4:
896
                        WL_DEBUG_PRINT("Synchronization lost.\r\n");
897
                        break;
898
                case 5:
899
                        WL_DEBUG_PRINT("Coordinator realignment.\r\n");
900
                        break;
901
                case 6:
902
                        WL_DEBUG_PRINT("Coordinator started.\r\n");
903
                        break;
904
        }
905 17 bcoltin
}
906
907
/**
908
 * Handles AT command response packets.
909
 * @param command the two character AT command, e.g. MY or ID
910
 * @param result 0 for success, 1 for an error
911
 * @param extra the hex value of the requested register
912
 * @param extraLen the length in bytes of extra
913
 **/
914 418 emarinel
static void xbee_handle_at_command_response(char* command, char result, char* extra, int extraLen)
915 346 bcoltin
{
916
        if (result == 1)
917
        {
918
                WL_DEBUG_PRINT("Error with AT");
919
                WL_DEBUG_PRINT(command);
920
                WL_DEBUG_PRINT(" packet.\r\n");
921
        }
922
        WL_DEBUG_PRINT("AT");
923
        WL_DEBUG_PRINT(command);
924
        WL_DEBUG_PRINT(" command was successful.\r\n");
925 409 emarinel
926 346 bcoltin
        if (command[0] == 'I' && command[1] == 'D')
927
        {
928
                xbee_panID = xbee_pending_panID;
929
                WL_DEBUG_PRINT("PAN ID set to ");
930
                WL_DEBUG_PRINT_INT(xbee_panID);
931
                WL_DEBUG_PRINT(".\r\n");
932
                return;
933
        }
934 60 bcoltin
935 346 bcoltin
        if (command[0] == 'C' && command[1] == 'H')
936
        {
937
                xbee_channel = xbee_pending_channel;
938
                WL_DEBUG_PRINT("Channel set to ");
939
                WL_DEBUG_PRINT_INT(xbee_channel);
940
                WL_DEBUG_PRINT(".\r\n");
941
                return;
942
        }
943 409 emarinel
944 346 bcoltin
        if (command[0] == 'M' && command[1] == 'Y' && extraLen != 0)
945
        {
946 418 emarinel
//                                                        printf("reading xbee_address\n");
947 581 jknichel
948 346 bcoltin
                xbee_address = 0;
949
                int i;
950 418 emarinel
                for (i = 0; i < extraLen; i++) {
951 346 bcoltin
                        xbee_address = (xbee_address << 8) + extra[i];
952 418 emarinel
                }
953
//                                                        printf("xbee address is: %d\n", xbee_address);
954 17 bcoltin
955 346 bcoltin
                WL_DEBUG_PRINT("XBee address is ");
956
                WL_DEBUG_PRINT_INT(xbee_address);
957
                WL_DEBUG_PRINT(".\r\n");
958 17 bcoltin
959 346 bcoltin
                if (xbee_address == 0)
960
                {
961 613 jknichel
                  printf("XBee 16-bit address must be set using ATMY.\r\n");
962 346 bcoltin
                        WL_DEBUG_PRINT("XBee 16-bit address must be set using ATMY.\r\n");
963
                        exit(0);
964
                }
965
        }
966 17 bcoltin
}
967
968
/**
969
 * Attempts to handle the packet if it is dealt with
970
 * by the library.
971
 * We will handle the following packet types:
972
 *    Modem Status
973
 *    AT Command Response
974
 *
975
 * @param packet the packet to handle
976
 * @param len the length of the packet
977 409 emarinel
 *
978 17 bcoltin
 * @return 1 if we have handled the packet, 0 otherwise
979
 */
980 418 emarinel
static int xbee_handle_packet(char* packet, int len)
981 346 bcoltin
{
982 613 jknichel
  //DEBUGGING PRINT
983
  //printf("xbee_handle_packet: ");
984
  //printHex(packet, len);
985
986 346 bcoltin
        char command[3] = {1, 2, 3};
987
        if (len <= 0) //this should not happend
988
        {
989
                WL_DEBUG_PRINT("Non-positive packet length.\r\n");
990
                return 0;
991
        }
992 409 emarinel
993 346 bcoltin
        switch ((unsigned char)packet[0]) //packet type
994
        {
995
                case XBEE_FRAME_STATUS:
996
                        xbee_handle_status(packet[1]);
997
                        return 1;
998
                case XBEE_FRAME_AT_COMMAND_RESPONSE:
999 613 jknichel
                  printf("in XBEE_FRAME_AT_COMMAND_RESPONSE case\n");
1000 346 bcoltin
                        command[0] = packet[2];
1001
                        command[1] = packet[3];
1002
                        command[2] = 0;
1003 418 emarinel
                        xbee_handle_at_command_response(command, packet[4], packet + 5, len - 5);
1004 346 bcoltin
                        return 1;
1005
        }
1006
        return 0;
1007 17 bcoltin
}
1008
1009
/**
1010
 * Sets the personal area network id.
1011
 *
1012
 * @param id the new personal area network (PAN) id
1013
 **/
1014 418 emarinel
int xbee_set_pan_id(int id)
1015 346 bcoltin
{
1016
        char s[3];
1017
        s[0] = (id >> 8) & 0xFF;
1018
        s[1] = id & 0xFF;
1019
        s[2] = 0;
1020
        xbee_pending_panID = id;
1021 418 emarinel
        return xbee_send_modify_at_command("ID", s);
1022 17 bcoltin
}
1023
1024
/**
1025
 * Get the PAN ID for the XBee.
1026 409 emarinel
 *
1027 17 bcoltin
 * @return the personal area network id, or
1028
 * XBEE_PAN_DEFAULT if it has not yet been set.
1029
 **/
1030 717 jknichel
//TODO: this function is so simple, it *may* be beneficial to inline this function.  testing of if
1031
// it reduces code size or not should be done to be sure.
1032 346 bcoltin
unsigned int xbee_get_pan_id()
1033
{
1034
        return xbee_panID;
1035 17 bcoltin
}
1036
1037
/**
1038 60 bcoltin
 * Set the channel the XBee is using.
1039
 *
1040 409 emarinel
 * @param channel the channel the XBee will not use,
1041 60 bcoltin
 * between 0x0B and 0x1A
1042
 *
1043
 * @see xbee_get_channel
1044
 **/
1045 418 emarinel
int xbee_set_channel(int channel)
1046 346 bcoltin
{
1047
        if (channel < 0x0B || channel > 0x1A)
1048
        {
1049
                WL_DEBUG_PRINT("Channel out of range.\r\n");
1050 418 emarinel
                return -1;
1051 346 bcoltin
        }
1052 418 emarinel
1053 346 bcoltin
        char s[3];
1054
        s[0] = channel & 0xFF;
1055
        s[1] = 0;
1056
        xbee_pending_channel = channel;
1057 418 emarinel
1058
        return xbee_send_modify_at_command("CH", s);
1059 60 bcoltin
}
1060
1061
/**
1062
 * Returns the channel which the XBee is currently using.
1063
 *
1064
 * @return the channel the XBee is using
1065
 *
1066
 * @see xbee_set_channel
1067
 **/
1068 717 jknichel
//TODO: this function is so simple, it *may* be beneficial to inline this function.  testing of if
1069
// it reduces code size or not should be done to be sure.
1070 346 bcoltin
int xbee_get_channel(void)
1071
{
1072
        return xbee_channel;
1073 60 bcoltin
}
1074
1075
/**
1076 17 bcoltin
 * Get the 16-bit address of the XBee.
1077
 * This is used to specify who to send messages to
1078
 * and who messages are from.
1079
 *
1080
 * @return the 16-bit address of the XBee.
1081
 **/
1082 717 jknichel
//TODO: this function is so simple, it *may* be beneficial to inline this function.  testing of if
1083
// it reduces code size or not should be done to be sure.
1084 346 bcoltin
unsigned int xbee_get_address()
1085
{
1086
        return xbee_address;
1087 17 bcoltin
}
1088
1089 203 justin
#ifndef ROBOT
1090 346 bcoltin
void xbee_set_com_port(char* port)
1091
{
1092
        xbee_com_port = port;
1093 203 justin
}
1094
#endif