Project

General

Profile

Statistics
| Revision:

root / branches / simulator / projects / libwireless / lib / xbee.c @ 1128

History | View | Annotate | Download (22 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
        WL_DEBUG_PRINT("in xbee_init\n");
210
#ifdef ROBOT
211

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

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

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

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

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

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

    
271
        WL_DEBUG_PRINT("Entering command mode.\n");
272

    
273
        if (xbee_enter_command_mode() != 0) {
274
                return -1;
275
        }
276

    
277
        WL_DEBUG_PRINT("Entered command mode.\n");
278

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

    
283
        WL_DEBUG_PRINT("Entered api mode.\n");
284

    
285
        if (xbee_exit_command_mode() != 0) {
286
                return -1;
287
        }
288

    
289
        WL_DEBUG_PRINT("Left command mode.\n");
290

    
291
        if (xbee_send_read_at_command("MY")) {
292
                return -1;
293
        }
294
        WL_DEBUG_PRINT("Getting ATMY address.\n");
295

    
296
#ifndef ROBOT
297
        int i;
298
        for (i = 0; xbee_address == 0 && i < XBEE_GET_PACKET_TIMEOUT; i++) {
299
          ret = xbee_get_packet(NULL);
300

    
301
          usleep(1000);
302

    
303
          if (ret == -1) {
304
            WL_DEBUG_PRINT("xbee_get_packet(NULL) failed.\n");
305
            return -1;
306
          }
307
        }
308
#else
309
        //wait to return until the address is set
310
  //TODO: this shouldn't wait indefinitely.  There should be some sort of reasonable timeout
311
  // so if the address is never set right, an error can be returned instead of having the
312
  // robot hang forever
313
        while (xbee_address == 0) {
314
          xbee_get_packet(NULL);
315
        }
316
#endif
317
        WL_DEBUG_PRINT("Got ATMY address.\n");
318

    
319
#ifndef ROBOT
320
        if (i == XBEE_GET_PACKET_TIMEOUT) { // We timed-out.
321

    
322
          WL_DEBUG_PRINT("xbee_get_packet timed out.\n");
323
          return -1;
324
        } else {
325
          return 0;
326
        }
327
#else
328
        return 0;
329
#endif
330
}
331

    
332
/**
333
 * Call when finished using the XBee library. This releases
334
 * all sued resources.
335
 **/
336
void xbee_terminate()
337
{
338
        #ifndef ROBOT
339
        pthread_cancel(*xbee_listen_thread);
340
        free(xbee_listen_thread);
341
        lockf(xbee_stream, F_ULOCK, 0);
342
        close(xbee_stream);
343
        #endif
344
}
345

    
346
/**
347
 * Send a buffer buf of size bytes to the XBee.
348
 *
349
 * @param buf the buffer of data to send
350
 * @param size the number of bytes to send
351
 **/
352
static int xbee_send(char* buf, int size)
353
{
354
#ifdef ROBOT
355
        int i;
356
        for (i = 0; i < size; i++) {
357
                xbee_putc(buf[i]);
358
        }
359

    
360
        return 0;
361

    
362
#else
363

    
364
        int ret = write(xbee_stream, buf, size);
365
        //success
366
        if (ret == size)
367
                return 0;
368
        if (ret == -1)
369
        {
370
                //interrupted by system signal, probably timer interrupt.
371
                //just try again
372
                if (errno == 4)
373
                {
374
                        return xbee_send(buf, size);
375
                }
376
                WL_DEBUG_PRINT("Failed to write to xbee\r\n");
377
                return -1;
378
        }
379

    
380
        //write was interrupted after writing ret bytes
381
        return xbee_send(buf + ret, size - ret);
382
#endif
383
}
384

    
385
/**
386
 * Sends a string to the XBee.
387
 *
388
 * @param c the string to send to the XBEE
389
 **/
390
//TODO: this function is so simple, it *may* be beneficial to inline this function.  testing of if
391
// it reduces code size or not should be done to be sure.
392
static int xbee_send_string(char* c)
393
{
394
        return xbee_send(c, strlen(c));
395
}
396

    
397
#ifndef ROBOT
398
static int xbee_read(char* buf, int size)
399
{
400
        if (read(xbee_stream, buf, size) == -1) {
401
                WL_DEBUG_PRINT("Failed to read from xbee.\r\n");
402
                return -1;
403
        }
404

    
405
        return 0;
406
}
407
#endif
408

    
409
/**
410
 * Enter into command mode.
411
 **/
412
static int xbee_enter_command_mode()
413
{
414
        if (xbee_send_string("+++") != 0) {
415
                return -1;
416
        }
417

    
418
        if (xbee_wait_for_ok() != 0) {
419
          return -1;
420
        }
421
          return 0;
422
}
423

    
424
/**
425
 * Exit from command mode.
426
 **/
427
static int xbee_exit_command_mode()
428
{
429
        if (xbee_send_string("ATCN\r") != 0) {
430
                return -1;
431
        }
432

    
433
        xbee_wait_for_ok();
434

    
435
        return 0;
436
}
437

    
438
/**
439
 * Enter API mode.
440
 **/
441
static int xbee_enter_api_mode()
442
{
443
        if (xbee_send_string("ATAP 1\r") != 0) {
444
                return -1;
445
        }
446
        xbee_wait_for_ok();
447

    
448
        return 0;
449
}
450

    
451
/**
452
 * Wait until the string "OK\r" is received from the XBee.
453
 **/
454
//TODO: this function is so simple, it *may* be beneficial to inline this function.  testing of if
455
// it reduces code size or not should be done to be sure.
456
static int xbee_wait_for_ok()
457
{
458
        return xbee_wait_for_string("OK\r", 3);
459
}
460

    
461
/**
462
 * Delay until the specified string is received from
463
 * the XBee. Discards all other XBee data.
464
 *
465
 * @param s the string to receive
466
 * @param len the length of the string
467
 **/
468
static int xbee_wait_for_string(char* s, int len)
469
{
470
        char* curr = s;
471
        while (curr - s < len) {
472
                // check if buffer is empty
473
                if (buffer_last != buffer_first) {
474
                        char c = arrival_buf[buffer_first++];
475
                        if (buffer_first == XBEE_BUFFER_SIZE) {
476
                                buffer_first = 0;
477
                        }
478

    
479
                        if (c == *curr) {
480
                                curr++;
481
                        } else {
482
#ifndef ROBOT
483
                          //return -1; // Computer is less forgiving.
484
                          curr = s;
485
#else
486
                          curr = s;
487
#endif
488
                        }
489
                } // else buffer is empty.
490

    
491
#ifndef ROBOT
492
                usleep(100);
493
#endif
494
        }
495

    
496
        return 0;
497
}
498

    
499
/**
500
 * Verifies that the packets checksum is correct.
501
 * (If the checksum is correct, the sum of the bytes
502
 * is 0xFF.)
503
 *
504
 * @param packet the packet received. This includes the first
505
 * three bytes, which are header information from the XBee.
506
 *
507
 * @param len The length of the packet received from the XBee
508
 *
509
 * @return 0 if the checksum is incorrect, nonzero
510
 * otherwise
511
 **/
512
int xbee_verify_checksum(char* packet, int len)
513
{
514
        unsigned char sum = 0;
515
        int i;
516
        for (i = 3; i < len; i++)
517
                sum += (unsigned char)packet[i];
518
        return sum == 0xFF;
519
}
520

    
521
/**
522
 * Returns the checksum of the given packet.
523
 *
524
 * @param buf the data for the packet to send
525
 * @param len the length of the packet in bytes
526
 *
527
 * @return the checksum of the packet, which will
528
 * become the last byte sent in the packet
529
 **/
530
char xbee_compute_checksum(char* buf, int len)
531
{
532
        int i;
533
        unsigned char sum = 0;
534
        for (i = 0; i < len; i++)
535
                sum += (unsigned char)buf[i];
536
        return 0xFF - sum;
537
}
538

    
539
/**
540
 * Adds header information and checksum to the given
541
 * packet and sends it. Header information includes
542
 * XBEE_FRAME_START and the packet length, as two bytes.
543
 *
544
 * @param buf the packet data
545
 * @param len the size in bytes of the packet data
546
 *
547
 **/
548
static int xbee_send_frame(char* buf, int len)
549
{
550
        char prefix[3];
551
        prefix[0] = XBEE_FRAME_START;
552
        prefix[1] = (len & 0xFF00) >> 8;
553
        prefix[2] = len & 0xFF;
554
        char checksum = xbee_compute_checksum(buf, len);
555

    
556
        if (xbee_send(prefix, 3) != 0) {
557
                return -1;
558
        }
559

    
560
        if (xbee_send(buf, len) != 0) {
561
                return -1;
562
        }
563

    
564
        if (xbee_send(&checksum, 1) != 0) {
565
                return -1;
566
        }
567

    
568
        return 0;
569
}
570

    
571
/**
572
 * Sends an AT command to read a parameter.
573
 *
574
 * @param command the AT command to send. For exmaple,
575
 * use ID to read the PAN ID and MY to return the XBee ID.
576
 * See the XBee reference guide for a complete listing.
577
 **/
578
//TODO: this function is so simple, it *may* be beneficial to inline this function.  testing of if
579
// it reduces code size or not should be done to be sure.
580
static int xbee_send_read_at_command(char* command)
581
{
582
        return xbee_send_modify_at_command(command, NULL);
583
}
584

    
585
/**
586
 * Sends the given AT command.
587
 *
588
 * @param command the AT command to send (e.g., MY, ID)
589
 * @param value the value to pass as a parameter
590
 * (or NULL if there is no parameter)
591
 **/
592
static int xbee_send_modify_at_command(char* command, char* value)
593
{
594
        char buf[16];
595
        int i;
596

    
597
        buf[0] = XBEE_FRAME_AT_COMMAND;
598
        buf[1] = 1;
599
        buf[2] = command[0];
600
        buf[3] = command[1];
601
        int valueLen = 0;
602
        if (value != NULL)
603
        {
604
                valueLen = strlen(value);
605
                if (valueLen > 8)
606
                {
607
                        WL_DEBUG_PRINT("AT Command too large.\r\n");
608
                        return -1;
609
                }
610

    
611
                for (i = 0; i < valueLen; i++) {
612
                        buf[4 + i] = value[i];
613
                }
614
        }
615

    
616
        return xbee_send_frame(buf, 4 + valueLen);
617
}
618

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

    
645
        if (len > 100)
646
        {
647
                WL_DEBUG_PRINT("Packet is too large.\r\n");
648
                return -1;
649
        }
650

    
651
        //data for sending request
652
        buf[0] = XBEE_FRAME_TX_REQUEST_16;
653
        buf[1] = frame;
654
        buf[2] = (dest >> 8) & 0xFF;
655
        buf[3] = dest & 0xFF;
656
        buf[4] = options;
657

    
658
        //packet prefix, do this here so we don't need an extra buffer
659
        prefix[0] = XBEE_FRAME_START;
660
        prefix[1] = ((5 + len) & 0xFF00) >> 8;
661
        prefix[2] = (5 + len) & 0xFF;
662

    
663
        for (i = 0; i < 5; i++)
664
                checksum += (unsigned char)buf[i];
665
        for (i = 0; i < len; i++)
666
                checksum += (unsigned char)packet[i];
667
        checksum = 0xFF - checksum;
668

    
669
        if (xbee_send(prefix, 3) != 0) {
670
                return -1;
671
        }
672

    
673
        if (xbee_send(buf, 5) != 0) {
674
                return -1;
675
        }
676

    
677
        if (xbee_send(packet, len) != 0) {
678
                return -1;
679
        }
680

    
681
        if (xbee_send((char*)&checksum, 1) != 0) {
682
                return -1;
683
        }
684

    
685
        return 0;
686
}
687

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

    
737
                if (buffer_first == XBEE_BUFFER_SIZE) {
738
                        buffer_first = 0;
739
                }
740
                xbee_buf[0] = XBEE_FRAME_START;
741
                currentBufPos++;
742
        }
743

    
744
        int len = -1;
745
        if (currentBufPos >= 3) {
746
                len = (int)xbee_buf[2] + ((int)xbee_buf[1] << 8);
747
        }
748

    
749
        while (len == -1 //packet length has not been read yet
750
                || currentBufPos < len + 4)
751
        {
752
                if (currentBufPos == 3)
753
                {
754
                        len = (int)xbee_buf[2] + ((int)xbee_buf[1] << 8);
755
                        if (len > 120)
756
                        {
757
                                WL_DEBUG_PRINT("Packet too large. Probably error in XBee transmission.\n");
758
                                currentBufPos = 0;
759
                                return -1;
760
                        }
761
                }
762

    
763
                // check if buffer is empty
764
                if (buffer_first == buffer_last) {
765
                        return 0;
766
                }
767
                xbee_buf[currentBufPos++] = arrival_buf[buffer_first++];
768
                if (buffer_first == XBEE_BUFFER_SIZE) {
769
                        buffer_first = 0;
770
                }
771
        }
772

    
773
        currentBufPos = 0;
774

    
775
        if (!xbee_verify_checksum(xbee_buf, len + 4))
776
        {
777
                WL_DEBUG_PRINT("XBee checksum failed.\r\n");
778
                return -1;
779
        }
780

    
781
        //we will take care of the packet
782
        if (xbee_handle_packet(xbee_buf + 3, len) != 0) {
783
                return 0;
784
        }
785

    
786
        if (dest == NULL) {
787
                return 0;
788
        }
789

    
790
        int i;
791
        for (i = 3; i < len + 3; i++) {
792
                dest[i - 3] = xbee_buf[i];
793
        }
794

    
795
        return len;
796
}
797

    
798
/**
799
 * Handles modem status packets.
800
 *
801
 * @param status the type of status packet received.
802
 **/
803
void xbee_handle_status(char status)
804
{
805
        switch (status)
806
        {
807
                case 0:
808
                        WL_DEBUG_PRINT("XBee hardware reset.\r\n");
809
                        break;
810
                case 1:
811
                        WL_DEBUG_PRINT("Watchdog timer reset.\r\n");
812
                        break;
813
                case 2:
814
                        WL_DEBUG_PRINT("Associated.\r\n");
815
                        break;
816
                case 3:
817
                        WL_DEBUG_PRINT("Disassociated.\r\n");
818
                        break;
819
                case 4:
820
                        WL_DEBUG_PRINT("Synchronization lost.\r\n");
821
                        break;
822
                case 5:
823
                        WL_DEBUG_PRINT("Coordinator realignment.\r\n");
824
                        break;
825
                case 6:
826
                        WL_DEBUG_PRINT("Coordinator started.\r\n");
827
                        break;
828
        }
829
}
830

    
831
/**
832
 * Handles AT command response packets.
833
 * @param command the two character AT command, e.g. MY or ID
834
 * @param result 0 for success, 1 for an error
835
 * @param extra the hex value of the requested register
836
 * @param extraLen the length in bytes of extra
837
 **/
838
static void xbee_handle_at_command_response(char* command, char result, char* extra, int extraLen)
839
{
840
        if (result == 1)
841
        {
842
                WL_DEBUG_PRINT("Error with AT");
843
                WL_DEBUG_PRINT(command);
844
                WL_DEBUG_PRINT(" packet.\r\n");
845
        }
846
        WL_DEBUG_PRINT("AT");
847
        WL_DEBUG_PRINT(command);
848
        WL_DEBUG_PRINT(" command was successful.\r\n");
849

    
850
        if (command[0] == 'I' && command[1] == 'D')
851
        {
852
                xbee_panID = xbee_pending_panID;
853
                WL_DEBUG_PRINT("PAN ID set to ");
854
                WL_DEBUG_PRINT_INT(xbee_panID);
855
                WL_DEBUG_PRINT(".\r\n");
856
                return;
857
        }
858

    
859
        if (command[0] == 'C' && command[1] == 'H')
860
        {
861
                xbee_channel = xbee_pending_channel;
862
                WL_DEBUG_PRINT("Channel set to ");
863
                WL_DEBUG_PRINT_INT(xbee_channel);
864
                WL_DEBUG_PRINT(".\r\n");
865
                return;
866
        }
867

    
868
        if (command[0] == 'M' && command[1] == 'Y' && extraLen != 0)
869
        {
870
                xbee_address = 0;
871
                int i;
872
                for (i = 0; i < extraLen; i++) {
873
                        xbee_address = (xbee_address << 8) + extra[i];
874
                }
875

    
876
                WL_DEBUG_PRINT("XBee address is ");
877
                WL_DEBUG_PRINT_INT(xbee_address);
878
                WL_DEBUG_PRINT(".\r\n");
879

    
880
                if (xbee_address == 0)
881
                {
882
                        WL_DEBUG_PRINT("XBee 16-bit address must be set using ATMY.\r\n");
883
                        #ifndef ROBOT
884
                        exit(0);
885
                        #endif
886
                }
887
        }
888
}
889

    
890
/**
891
 * Attempts to handle the packet if it is dealt with
892
 * by the library.
893
 * We will handle the following packet types:
894
 *    Modem Status
895
 *    AT Command Response
896
 *
897
 * @param packet the packet to handle
898
 * @param len the length of the packet
899
 *
900
 * @return 1 if we have handled the packet, 0 otherwise
901
 */
902
static int xbee_handle_packet(char* packet, int len)
903
{
904

    
905
        char command[3] = {1, 2, 3};
906
        if (len <= 0) //this should not happend
907
        {
908
                WL_DEBUG_PRINT("Non-positive packet length.\r\n");
909
                return 0;
910
        }
911

    
912
        switch ((unsigned char)packet[0]) //packet type
913
        {
914
                case XBEE_FRAME_STATUS:
915
                        xbee_handle_status(packet[1]);
916
                        return 1;
917
                case XBEE_FRAME_AT_COMMAND_RESPONSE:
918
                        command[0] = packet[2];
919
                        command[1] = packet[3];
920
                        command[2] = 0;
921
                        xbee_handle_at_command_response(command, packet[4], packet + 5, len - 5);
922
                        return 1;
923
        }
924
        return 0;
925
}
926

    
927
/**
928
 * Sets the personal area network id.
929
 *
930
 * @param id the new personal area network (PAN) id
931
 **/
932
int xbee_set_pan_id(int id)
933
{
934
        char s[3];
935
        s[0] = (id >> 8) & 0xFF;
936
        s[1] = id & 0xFF;
937
        s[2] = 0;
938
        xbee_pending_panID = id;
939
        return xbee_send_modify_at_command("ID", s);
940
}
941

    
942
/**
943
 * Get the PAN ID for the XBee.
944
 *
945
 * @return the personal area network id, or
946
 * XBEE_PAN_DEFAULT if it has not yet been set.
947
 **/
948
//TODO: this function is so simple, it *may* be beneficial to inline this function.  testing of if
949
// it reduces code size or not should be done to be sure.
950
unsigned int xbee_get_pan_id()
951
{
952
        return xbee_panID;
953
}
954

    
955
/**
956
 * Set the channel the XBee is using.
957
 *
958
 * @param channel the channel the XBee will not use,
959
 * between 0x0B and 0x1A
960
 *
961
 * @see xbee_get_channel
962
 **/
963
int xbee_set_channel(int channel)
964
{
965
        if (channel < 0x0B || channel > 0x1A)
966
        {
967
                WL_DEBUG_PRINT("Channel out of range.\r\n");
968
                return -1;
969
        }
970

    
971
        char s[3];
972
        s[0] = channel & 0xFF;
973
        s[1] = 0;
974
        xbee_pending_channel = channel;
975

    
976
        return xbee_send_modify_at_command("CH", s);
977
}
978

    
979
/**
980
 * Returns the channel which the XBee is currently using.
981
 *
982
 * @return the channel the XBee is using
983
 *
984
 * @see xbee_set_channel
985
 **/
986
//TODO: this function is so simple, it *may* be beneficial to inline this function.  testing of if
987
// it reduces code size or not should be done to be sure.
988
int xbee_get_channel(void)
989
{
990
        return xbee_channel;
991
}
992

    
993
/**
994
 * Get the 16-bit address of the XBee.
995
 * This is used to specify who to send messages to
996
 * and who messages are from.
997
 *
998
 * @return the 16-bit address of the XBee.
999
 **/
1000
//TODO: this function is so simple, it *may* be beneficial to inline this function.  testing of if
1001
// it reduces code size or not should be done to be sure.
1002
unsigned int xbee_get_address()
1003
{
1004
        return xbee_address;
1005
}
1006

    
1007
#ifndef ROBOT
1008
void xbee_set_com_port(char* port)
1009
{
1010
        xbee_com_port = port;
1011
}
1012
#endif