Project

General

Profile

Statistics
| Revision:

root / branches / autonomous_recharging / code / projects / libwireless / lib / xbee.c @ 767

History | View | Annotate | Download (24.4 KB)

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