Project

General

Profile

Statistics
| Revision:

root / trunk / code / lib / src / libwireless / xbee.c @ 738

History | View | Annotate | Download (21.7 KB)

1
/**
2
 * Copyright (c) 2007 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 Brian Coltin, Colony Project, CMU Robotics Club
33
 **/
34

    
35
#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
#include <termios.h>
45

    
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
#define XBEE_GET_PACKET_TIMEOUT 1000
59

    
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
static int xbee_send(char* buf, int size);
74
static int xbee_send_string(char* c);
75

    
76
#ifndef ROBOT
77
static int xbee_read(char* buf, int size);
78
#endif
79

    
80
/*Command Mode Functions
81
 * Called during initialization.
82
 */
83
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
static int xbee_wait_for_string(char* s, int len);
88
static int xbee_wait_for_ok(void);
89

    
90
/*API Mode Functions*/
91

    
92
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

    
101
/*Global Variables*/
102

    
103
#ifndef ROBOT
104
static char* xbee_com_port = XBEE_PORT_DEFAULT;
105
static int xbee_stream;
106
static pthread_t* xbee_listen_thread;
107
#endif
108

    
109
// TODO: is this a good size?
110
#define XBEE_BUFFER_SIZE        128
111
#define PACKET_BUFFER_SIZE        108
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

    
119

    
120
//used to store packets as they are read
121
static char xbee_buf[PACKET_BUFFER_SIZE];
122
static int currentBufPos = 0;
123

    
124
//XBee status
125
static unsigned int xbee_panID = XBEE_PAN_DEFAULT;
126
static unsigned int xbee_pending_panID = XBEE_PAN_DEFAULT;
127
static int xbee_channel = XBEE_CHANNEL_DEFAULT;
128
static int xbee_pending_channel = XBEE_CHANNEL_DEFAULT;
129
static volatile unsigned int xbee_address = 0;
130

    
131
/*Function Implementations*/
132

    
133
#ifdef ROBOT
134

    
135
/**
136
 * Interrupt for the robot. Adds bytes received from the xbee
137
 * to the buffer.
138
 **/
139
#ifndef FIREFLY
140
ISR(USART1_RX_vect)
141
{
142
        char c = UDR1;
143
        arrival_buf[buffer_last] = c;
144
        int t = buffer_last + 1;
145
        if (t == XBEE_BUFFER_SIZE)
146
                t = 0;
147
        if (t == buffer_first)
148
        {
149
                WL_DEBUG_PRINT("\nOut of space in buffer.\n");
150
        }
151
        buffer_last = t;
152
}
153
#else
154
SIGNAL(SIG_USART0_RECV)
155
{
156
        char c = UDR0;
157
        arrival_buf[buffer_last] = c;
158
        int t = buffer_last + 1;
159
        if (t == XBEE_BUFFER_SIZE)
160
                t = 0;
161
        if (t == buffer_first)
162
        {
163
                WL_DEBUG_PRINT("Out of space in buffer.\n");
164
        }
165
        buffer_last = t;
166
}
167
#endif
168

    
169
#else
170

    
171
// Computer code
172

    
173
/**
174
 * Thread that listens to the xbee.
175
 **/
176
static void* listen_to_xbee(void* x)
177
{
178
        char c;
179
        while (1)
180
        {
181
                if (xbee_read(&c, 1) != 0) {
182
                        WL_DEBUG_PRINT("xbee_read failed.\n");
183
                        return NULL;
184
                }
185

    
186
                arrival_buf[buffer_last] = c;
187
                int t = buffer_last + 1;
188
                if (t == XBEE_BUFFER_SIZE)
189
                        t = 0;
190
                if (t == buffer_first)
191
                {
192
                        WL_DEBUG_PRINT("Out of space in buffer.\n");
193
                }
194
                buffer_last = t;
195

    
196
                usleep(1000);
197
        }
198

    
199
        return NULL;
200
}
201

    
202
#endif
203

    
204
/**
205
 * Initializes the XBee library so that other functions may be used.
206
 **/
207
int xbee_lib_init()
208
{
209
#ifdef ROBOT
210

    
211
        //enable the receiving interrupt
212
#ifdef FIREFLY
213
        UCSR0B |= _BV(RXCIE) | _BV(RXEN);
214
#else
215
        UCSR1B |= _BV(RXCIE);
216
#endif
217
        sei();
218
#else
219
        xbee_stream = open(xbee_com_port, O_RDWR);
220
        if (xbee_stream == -1/* || lockf(xbee_stream, F_TEST, 0) != 0*/)
221
        {
222
                WL_DEBUG_PRINT("Failed to open connection to XBee on port ");
223
                WL_DEBUG_PRINT_INT(xbee_com_port);
224
                WL_DEBUG_PRINT(".\n");
225
                return -1;
226
        } else {
227
          WL_DEBUG_PRINT("Successfully opened connection to XBee on port ");
228
                WL_DEBUG_PRINT_INT(xbee_com_port);
229
                WL_DEBUG_PRINT(".\n");
230
        }
231

    
232
        // set baud rate, etc. correctly
233
        struct termios options;
234

    
235
        tcgetattr(xbee_stream, &options);
236
        cfsetispeed(&options, B9600);
237
        cfsetospeed(&options, B9600);
238
        options.c_iflag &= ~ICRNL;
239
        options.c_oflag &= ~OCRNL;
240
        options.c_cflag |= (CLOCAL | CREAD);
241
        options.c_cflag &= ~PARENB;
242
        options.c_cflag &= ~CSTOPB;
243
        options.c_cflag &= ~CSIZE;
244
        options.c_cflag |= CS8;
245
        options.c_lflag &= ~ICANON;
246
        options.c_cc[VMIN] = 1;
247
        options.c_cc[VTIME] = 50;
248

    
249
        if (tcsetattr(xbee_stream, TCSANOW, &options))
250
        {
251
                WL_DEBUG_PRINT("Error setting attributes.\n");
252
                return -1;
253
        }
254

    
255
        xbee_listen_thread = (pthread_t*)malloc(sizeof(pthread_t));
256
        if (xbee_listen_thread == NULL)
257
        {
258
                WL_DEBUG_PRINT("Malloc failed.\n");
259
                return -1;
260
        }
261

    
262
        int ret = pthread_create(xbee_listen_thread, NULL, listen_to_xbee, NULL);
263
        if (ret)
264
        {
265
                WL_DEBUG_PRINT("Failed to create listener thread.\n");
266
                return -1;
267
        }
268
#endif
269

    
270

    
271
        if (xbee_enter_command_mode() != 0) {
272
                return -1;
273
        }
274

    
275
        if (xbee_enter_api_mode() != 0) {
276
                return -1;
277
        }
278

    
279
        if (xbee_exit_command_mode() != 0) {
280
                return -1;
281
        }
282

    
283
        if (xbee_send_read_at_command("MY")) {
284
                return -1;
285
        }
286

    
287
#ifndef ROBOT
288
        int i;
289
        for (i = 0; xbee_address == 0 && i < XBEE_GET_PACKET_TIMEOUT; i++) {
290
          ret = xbee_get_packet(NULL);
291

    
292
          usleep(1000);
293

    
294
          if (ret == -1) {
295
            WL_DEBUG_PRINT("xbee_get_packet(NULL) failed.\n");
296
            return -1;
297
          }
298
        }
299
#else
300
        //wait to return until the address is set
301
  //TODO: this shouldn't wait indefinitely.  There should be some sort of reasonable timeout
302
  // so if the address is never set right, an error can be returned instead of having the
303
  // robot hang forever
304
        while (xbee_address == 0) {
305
          xbee_get_packet(NULL);
306
        }
307
#endif
308

    
309
#ifndef ROBOT
310
        if (i == XBEE_GET_PACKET_TIMEOUT) { // We timed-out.
311

    
312
          WL_DEBUG_PRINT("xbee_get_packet timed out.\n");
313
          return -1;
314
        } else {
315
          return 0;
316
        }
317
#else
318
        return 0;
319
#endif
320
}
321

    
322
/**
323
 * Call when finished using the XBee library. This releases
324
 * all sued resources.
325
 **/
326
void xbee_terminate()
327
{
328
        #ifndef ROBOT
329
        pthread_cancel(*xbee_listen_thread);
330
        free(xbee_listen_thread);
331
        lockf(xbee_stream, F_ULOCK, 0);
332
        close(xbee_stream);
333
        #endif
334
}
335

    
336
/**
337
 * Send a buffer buf of size bytes to the XBee.
338
 *
339
 * @param buf the buffer of data to send
340
 * @param size the number of bytes to send
341
 **/
342
static int xbee_send(char* buf, int size)
343
{
344
#ifdef ROBOT
345
        int i;
346
        for (i = 0; i < size; i++) {
347
                xbee_putc(buf[i]);
348
        }
349

    
350
        return 0;
351

    
352
#else
353

    
354
        int ret = write(xbee_stream, buf, size);
355
        //success
356
        if (ret == size)
357
                return 0;
358
        if (ret == -1)
359
        {
360
                //interrupted by system signal, probably timer interrupt.
361
                //just try again
362
                if (errno == 4)
363
                {
364
                        return xbee_send(buf, size);
365
                }
366
                WL_DEBUG_PRINT("Failed to write to xbee, error %i.\r\n", errno);
367
                return -1;
368
        }
369

    
370
        //write was interrupted after writing ret bytes
371
        return xbee_send(buf + ret, size - ret);
372
#endif
373
}
374

    
375
/**
376
 * Sends a string to the XBee.
377
 *
378
 * @param c the string to send to the XBEE
379
 **/
380
//TODO: this function is so simple, it *may* be beneficial to inline this function.  testing of if
381
// it reduces code size or not should be done to be sure.
382
static int xbee_send_string(char* c)
383
{
384
        return xbee_send(c, strlen(c));
385
}
386

    
387
#ifndef ROBOT
388
static int xbee_read(char* buf, int size)
389
{
390
        if (read(xbee_stream, buf, size) == -1) {
391
                WL_DEBUG_PRINT("Failed to read from xbee.\r\n");
392
                return -1;
393
        }
394

    
395
        return 0;
396
}
397
#endif
398

    
399
/**
400
 * Enter into command mode.
401
 **/
402
static int xbee_enter_command_mode()
403
{
404
        if (xbee_send_string("+++") != 0) {
405
                return -1;
406
        }
407

    
408
        if (xbee_wait_for_ok() != 0) {
409
          return -1;
410
        }
411
          return 0;
412
}
413

    
414
/**
415
 * Exit from command mode.
416
 **/
417
static int xbee_exit_command_mode()
418
{
419
        if (xbee_send_string("ATCN\r") != 0) {
420
                return -1;
421
        }
422

    
423
        xbee_wait_for_ok();
424

    
425
        return 0;
426
}
427

    
428
/**
429
 * Enter API mode.
430
 **/
431
static int xbee_enter_api_mode()
432
{
433
        if (xbee_send_string("ATAP 1\r") != 0) {
434
                return -1;
435
        }
436
        xbee_wait_for_ok();
437

    
438
        return 0;
439
}
440

    
441
/**
442
 * Wait until the string "OK\r" is received from the XBee.
443
 **/
444
//TODO: this function is so simple, it *may* be beneficial to inline this function.  testing of if
445
// it reduces code size or not should be done to be sure.
446
static int xbee_wait_for_ok()
447
{
448
        return xbee_wait_for_string("OK\r", 3);
449
}
450

    
451
/**
452
 * Delay until the specified string is received from
453
 * the XBee. Discards all other XBee data.
454
 *
455
 * @param s the string to receive
456
 * @param len the length of the string
457
 **/
458
static int xbee_wait_for_string(char* s, int len)
459
{
460
        char* curr = s;
461
        while (curr - s < len) {
462
                // check if buffer is empty
463
                if (buffer_last != buffer_first) {
464
                        char c = arrival_buf[buffer_first++];
465
                        if (buffer_first == XBEE_BUFFER_SIZE) {
466
                                buffer_first = 0;
467
                        }
468

    
469
                        if (c == *curr) {
470
                                curr++;
471
                        } else {
472
#ifndef ROBOT
473
                          //return -1; // Computer is less forgiving.
474
                          curr = s;
475
#else
476
                          curr = s;
477
#endif
478
                        }
479
                } // else buffer is empty.
480

    
481
#ifndef ROBOT
482
                usleep(100);
483
#endif
484
        }
485

    
486
        return 0;
487
}
488

    
489
/**
490
 * Verifies that the packets checksum is correct.
491
 * (If the checksum is correct, the sum of the bytes
492
 * is 0xFF.)
493
 *
494
 * @param packet the packet received. This includes the first
495
 * three bytes, which are header information from the XBee.
496
 *
497
 * @param len The length of the packet received from the XBee
498
 *
499
 * @return 0 if the checksum is incorrect, nonzero
500
 * otherwise
501
 **/
502
int xbee_verify_checksum(char* packet, int len)
503
{
504
        unsigned char sum = 0;
505
        int i;
506
        for (i = 3; i < len; i++)
507
                sum += (unsigned char)packet[i];
508
        return sum == 0xFF;
509
}
510

    
511
/**
512
 * Returns the checksum of the given packet.
513
 *
514
 * @param buf the data for the packet to send
515
 * @param len the length of the packet in bytes
516
 *
517
 * @return the checksum of the packet, which will
518
 * become the last byte sent in the packet
519
 **/
520
char xbee_compute_checksum(char* buf, int len)
521
{
522
        int i;
523
        unsigned char sum = 0;
524
        for (i = 0; i < len; i++)
525
                sum += (unsigned char)buf[i];
526
        return 0xFF - sum;
527
}
528

    
529
/**
530
 * Adds header information and checksum to the given
531
 * packet and sends it. Header information includes
532
 * XBEE_FRAME_START and the packet length, as two bytes.
533
 *
534
 * @param buf the packet data
535
 * @param len the size in bytes of the packet data
536
 *
537
 **/
538
static int xbee_send_frame(char* buf, int len)
539
{
540
        char prefix[3];
541
        prefix[0] = XBEE_FRAME_START;
542
        prefix[1] = (len & 0xFF00) >> 8;
543
        prefix[2] = len & 0xFF;
544
        char checksum = xbee_compute_checksum(buf, len);
545

    
546
        if (xbee_send(prefix, 3) != 0) {
547
                return -1;
548
        }
549

    
550
        if (xbee_send(buf, len) != 0) {
551
                return -1;
552
        }
553

    
554
        if (xbee_send(&checksum, 1) != 0) {
555
                return -1;
556
        }
557

    
558
        return 0;
559
}
560

    
561
/**
562
 * Sends an AT command to read a parameter.
563
 *
564
 * @param command the AT command to send. For exmaple,
565
 * use ID to read the PAN ID and MY to return the XBee ID.
566
 * See the XBee reference guide for a complete listing.
567
 **/
568
//TODO: this function is so simple, it *may* be beneficial to inline this function.  testing of if
569
// it reduces code size or not should be done to be sure.
570
static int xbee_send_read_at_command(char* command)
571
{
572
        return xbee_send_modify_at_command(command, NULL);
573
}
574

    
575
/**
576
 * Sends the given AT command.
577
 *
578
 * @param command the AT command to send (e.g., MY, ID)
579
 * @param value the value to pass as a parameter
580
 * (or NULL if there is no parameter)
581
 **/
582
static int xbee_send_modify_at_command(char* command, char* value)
583
{
584
        char buf[16];
585
        int i;
586

    
587
        buf[0] = XBEE_FRAME_AT_COMMAND;
588
        buf[1] = 1;
589
        buf[2] = command[0];
590
        buf[3] = command[1];
591
        int valueLen = 0;
592
        if (value != NULL)
593
        {
594
                valueLen = strlen(value);
595
                if (valueLen > 8)
596
                {
597
                        WL_DEBUG_PRINT("AT Command too large.\r\n");
598
                        return -1;
599
                }
600

    
601
                for (i = 0; i < valueLen; i++) {
602
                        buf[4 + i] = value[i];
603
                }
604
        }
605

    
606
        return xbee_send_frame(buf, 4 + valueLen);
607
}
608

    
609
/**
610
 * Send the specified packet.
611
 *
612
 * @param packet the packet data to send
613
 * @param len the number of bytes in the packet
614
 *
615
 * @param dest the ID of the XBee to send the packet to,
616
 * or XBEE_BROADCAST to send the message to all robots
617
 * in the PAN.
618
 *
619
 * @param options a combination of the flags
620
 * XBEE_OPTIONS_NONE, XBEE_OPTIONS_DISABLE_RESPONSE and
621
 * XBEE_OPTIONS_BROADCAST_ALL_PANS
622
 *
623
 * @param frame the frame number to associate this packet
624
 * with. This will be used to identify the response when
625
 * the XBee alerts us as to whether or not our message
626
 * was received.
627
 **/
628
int xbee_send_packet(char* packet, int len, int dest, char options, char frame)
629
{
630
        char buf[5];
631
        char prefix[3];
632
        int i;
633
        unsigned char checksum = 0;
634

    
635
        if (len > 100)
636
        {
637
                WL_DEBUG_PRINT("Packet is too large.\r\n");
638
                return -1;
639
        }
640

    
641
        //data for sending request
642
        buf[0] = XBEE_FRAME_TX_REQUEST_16;
643
        buf[1] = frame;
644
        buf[2] = (dest >> 8) & 0xFF;
645
        buf[3] = dest & 0xFF;
646
        buf[4] = options;
647

    
648
        //packet prefix, do this here so we don't need an extra buffer
649
        prefix[0] = XBEE_FRAME_START;
650
        prefix[1] = ((5 + len) & 0xFF00) >> 8;
651
        prefix[2] = (5 + len) & 0xFF;
652

    
653
        for (i = 0; i < 5; i++)
654
                checksum += (unsigned char)buf[i];
655
        for (i = 0; i < len; i++)
656
                checksum += (unsigned char)packet[i];
657
        checksum = 0xFF - checksum;
658

    
659
        if (xbee_send(prefix, 3) != 0) {
660
                return -1;
661
        }
662

    
663
        if (xbee_send(buf, 5) != 0) {
664
                return -1;
665
        }
666

    
667
        if (xbee_send(packet, len) != 0) {
668
                return -1;
669
        }
670

    
671
        if (xbee_send((char*)&checksum, 1) != 0) {
672
                return -1;
673
        }
674

    
675
        return 0;
676
}
677

    
678
/**
679
 * Reads a packet received from the XBee. This function
680
 * is non-blocking. The resulting packet is stored in dest.
681
 * Only returns transmission response packets and
682
 * received packets. The returned packet does not include
683
 * header information or the checksum. This method also
684
 * handles special packets dealt with by the XBee library,
685
 * and so should be called frequently while the XBee is in
686
 * use.<br><br>
687
 *
688
 * The first byte of the packet will be either
689
 * XBEE_TX_STATUS or XBEE_RX to indicated
690
 * a response to a sent message or a received message,
691
 * respectively.<br><br>
692
 *
693
 * For a status response packet:<br>
694
 * The first byte will be XBEE_TX_STATUS.<br>
695
 * The second byte will be the frame number.<br>
696
 * The third byte will be the result. 0 indicates success,
697
 * and nonzero indicates that an error ocurred in
698
 * transmitting the packet.<br><br>
699
 *
700
 * For a received packet:<br>
701
 * The first byte will be XBEE_RX.<br>
702
 * The second and third bytes will be the 16-bit
703
 * address of the packet's sender.<br>
704
 * The fourth byte is the signal strength.<br>
705
 * The fifth byte is 1 if the packet were sent to
706
 * a specific address, and 2 if it is a broadcast packet.<br><br>
707
 *
708
 * @param dest set to the packet data
709
 * @return the length of the packet, or -1 if no packet
710
 * is available
711
 **/
712
int xbee_get_packet(unsigned char* dest)
713
{
714
        //start reading a packet with XBEE_FRAME_START
715
        if (currentBufPos == 0)
716
        {
717
                do
718
                {
719
                        if (buffer_first == XBEE_BUFFER_SIZE)
720
                                buffer_first = 0;
721
                        // check if buffer is empty
722
                        if (buffer_first == buffer_last) {
723
                                return 0;
724
                        }
725
                } while (arrival_buf[buffer_first++] != XBEE_FRAME_START);
726

    
727
                if (buffer_first == XBEE_BUFFER_SIZE) {
728
                        buffer_first = 0;
729
                }
730
                xbee_buf[0] = XBEE_FRAME_START;
731
                currentBufPos++;
732
        }
733

    
734
        int len = -1;
735
        if (currentBufPos >= 3) {
736
                len = (int)xbee_buf[2] + ((int)xbee_buf[1] << 8);
737
        }
738

    
739
        while (len == -1 //packet length has not been read yet
740
                || currentBufPos < len + 4)
741
        {
742
                if (currentBufPos == 3)
743
                {
744
                        len = (int)xbee_buf[2] + ((int)xbee_buf[1] << 8);
745
                        if (len > 120)
746
                        {
747
                                WL_DEBUG_PRINT("Packet too large. Probably error in XBee transmission.\n");
748
                                currentBufPos = 0;
749
                                return -1;
750
                        }
751
                }
752

    
753
                // check if buffer is empty
754
                if (buffer_first == buffer_last) {
755
                        return 0;
756
                }
757
                xbee_buf[currentBufPos++] = arrival_buf[buffer_first++];
758
                if (buffer_first == XBEE_BUFFER_SIZE) {
759
                        buffer_first = 0;
760
                }
761
        }
762

    
763
        currentBufPos = 0;
764

    
765
        if (!xbee_verify_checksum(xbee_buf, len + 4))
766
        {
767
                WL_DEBUG_PRINT("XBee checksum failed.\r\n");
768
                return -1;
769
        }
770

    
771
        //we will take care of the packet
772
        if (xbee_handle_packet(xbee_buf + 3, len) != 0) {
773
                return 0;
774
        }
775

    
776
        if (dest == NULL) {
777
                return 0;
778
        }
779

    
780
        int i;
781
        for (i = 3; i < len + 3; i++) {
782
                dest[i - 3] = xbee_buf[i];
783
        }
784

    
785
        return len;
786
}
787

    
788
/**
789
 * Handles modem status packets.
790
 *
791
 * @param status the type of status packet received.
792
 **/
793
void xbee_handle_status(char status)
794
{
795
        switch (status)
796
        {
797
                case 0:
798
                        WL_DEBUG_PRINT("XBee hardware reset.\r\n");
799
                        break;
800
                case 1:
801
                        WL_DEBUG_PRINT("Watchdog timer reset.\r\n");
802
                        break;
803
                case 2:
804
                        WL_DEBUG_PRINT("Associated.\r\n");
805
                        break;
806
                case 3:
807
                        WL_DEBUG_PRINT("Disassociated.\r\n");
808
                        break;
809
                case 4:
810
                        WL_DEBUG_PRINT("Synchronization lost.\r\n");
811
                        break;
812
                case 5:
813
                        WL_DEBUG_PRINT("Coordinator realignment.\r\n");
814
                        break;
815
                case 6:
816
                        WL_DEBUG_PRINT("Coordinator started.\r\n");
817
                        break;
818
        }
819
}
820

    
821
/**
822
 * Handles AT command response packets.
823
 * @param command the two character AT command, e.g. MY or ID
824
 * @param result 0 for success, 1 for an error
825
 * @param extra the hex value of the requested register
826
 * @param extraLen the length in bytes of extra
827
 **/
828
static void xbee_handle_at_command_response(char* command, char result, char* extra, int extraLen)
829
{
830
        if (result == 1)
831
        {
832
                WL_DEBUG_PRINT("Error with AT");
833
                WL_DEBUG_PRINT(command);
834
                WL_DEBUG_PRINT(" packet.\r\n");
835
        }
836
        WL_DEBUG_PRINT("AT");
837
        WL_DEBUG_PRINT(command);
838
        WL_DEBUG_PRINT(" command was successful.\r\n");
839

    
840
        if (command[0] == 'I' && command[1] == 'D')
841
        {
842
                xbee_panID = xbee_pending_panID;
843
                WL_DEBUG_PRINT("PAN ID set to ");
844
                WL_DEBUG_PRINT_INT(xbee_panID);
845
                WL_DEBUG_PRINT(".\r\n");
846
                return;
847
        }
848

    
849
        if (command[0] == 'C' && command[1] == 'H')
850
        {
851
                xbee_channel = xbee_pending_channel;
852
                WL_DEBUG_PRINT("Channel set to ");
853
                WL_DEBUG_PRINT_INT(xbee_channel);
854
                WL_DEBUG_PRINT(".\r\n");
855
                return;
856
        }
857

    
858
        if (command[0] == 'M' && command[1] == 'Y' && extraLen != 0)
859
        {
860
                xbee_address = 0;
861
                int i;
862
                for (i = 0; i < extraLen; i++) {
863
                        xbee_address = (xbee_address << 8) + extra[i];
864
                }
865

    
866
                WL_DEBUG_PRINT("XBee address is ");
867
                WL_DEBUG_PRINT_INT(xbee_address);
868
                WL_DEBUG_PRINT(".\r\n");
869

    
870
                if (xbee_address == 0)
871
                {
872
                        WL_DEBUG_PRINT("XBee 16-bit address must be set using ATMY.\r\n");
873
                        #ifndef ROBOT
874
                        exit(0);
875
                        #endif
876
                }
877
        }
878
}
879

    
880
/**
881
 * Attempts to handle the packet if it is dealt with
882
 * by the library.
883
 * We will handle the following packet types:
884
 *    Modem Status
885
 *    AT Command Response
886
 *
887
 * @param packet the packet to handle
888
 * @param len the length of the packet
889
 *
890
 * @return 1 if we have handled the packet, 0 otherwise
891
 */
892
static int xbee_handle_packet(char* packet, int len)
893
{
894

    
895
        char command[3] = {1, 2, 3};
896
        if (len <= 0) //this should not happend
897
        {
898
                WL_DEBUG_PRINT("Non-positive packet length.\r\n");
899
                return 0;
900
        }
901

    
902
        switch ((unsigned char)packet[0]) //packet type
903
        {
904
                case XBEE_FRAME_STATUS:
905
                        xbee_handle_status(packet[1]);
906
                        return 1;
907
                case XBEE_FRAME_AT_COMMAND_RESPONSE:
908
                        command[0] = packet[2];
909
                        command[1] = packet[3];
910
                        command[2] = 0;
911
                        xbee_handle_at_command_response(command, packet[4], packet + 5, len - 5);
912
                        return 1;
913
        }
914
        return 0;
915
}
916

    
917
/**
918
 * Sets the personal area network id.
919
 *
920
 * @param id the new personal area network (PAN) id
921
 **/
922
int xbee_set_pan_id(int id)
923
{
924
        char s[3];
925
        s[0] = (id >> 8) & 0xFF;
926
        s[1] = id & 0xFF;
927
        s[2] = 0;
928
        xbee_pending_panID = id;
929
        return xbee_send_modify_at_command("ID", s);
930
}
931

    
932
/**
933
 * Get the PAN ID for the XBee.
934
 *
935
 * @return the personal area network id, or
936
 * XBEE_PAN_DEFAULT if it has not yet been set.
937
 **/
938
//TODO: this function is so simple, it *may* be beneficial to inline this function.  testing of if
939
// it reduces code size or not should be done to be sure.
940
unsigned int xbee_get_pan_id()
941
{
942
        return xbee_panID;
943
}
944

    
945
/**
946
 * Set the channel the XBee is using.
947
 *
948
 * @param channel the channel the XBee will not use,
949
 * between 0x0B and 0x1A
950
 *
951
 * @see xbee_get_channel
952
 **/
953
int xbee_set_channel(int channel)
954
{
955
        if (channel < 0x0B || channel > 0x1A)
956
        {
957
                WL_DEBUG_PRINT("Channel out of range.\r\n");
958
                return -1;
959
        }
960

    
961
        char s[3];
962
        s[0] = channel & 0xFF;
963
        s[1] = 0;
964
        xbee_pending_channel = channel;
965

    
966
        return xbee_send_modify_at_command("CH", s);
967
}
968

    
969
/**
970
 * Returns the channel which the XBee is currently using.
971
 *
972
 * @return the channel the XBee is using
973
 *
974
 * @see xbee_set_channel
975
 **/
976
//TODO: this function is so simple, it *may* be beneficial to inline this function.  testing of if
977
// it reduces code size or not should be done to be sure.
978
int xbee_get_channel(void)
979
{
980
        return xbee_channel;
981
}
982

    
983
/**
984
 * Get the 16-bit address of the XBee.
985
 * This is used to specify who to send messages to
986
 * and who messages are from.
987
 *
988
 * @return the 16-bit address of the XBee.
989
 **/
990
//TODO: this function is so simple, it *may* be beneficial to inline this function.  testing of if
991
// it reduces code size or not should be done to be sure.
992
unsigned int xbee_get_address()
993
{
994
        return xbee_address;
995
}
996

    
997
#ifndef ROBOT
998
void xbee_set_com_port(char* port)
999
{
1000
        xbee_com_port = port;
1001
}
1002
#endif