Project

General

Profile

Statistics
| Revision:

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

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_wait_for_string(char* s, int len);
87
static int xbee_wait_for_ok(void);
88

    
89
/*API Mode Functions*/
90

    
91
static int xbee_handle_packet(char* packet, int len);
92
static void xbee_handle_at_command_response(char* command, char result, char* extra, int extraLen);
93
static void xbee_handle_status(char status);
94
static int xbee_verify_checksum(char* packet, int len);
95
static char xbee_compute_checksum(char* packet, int len);
96
static int xbee_send_frame(char* buf, int len);
97
static int xbee_send_read_at_command(char* command);
98
static int xbee_send_modify_at_command(char* command, char* value);
99

    
100
/*Global Variables*/
101

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

    
108
// TODO: is this a good size?
109
#define XBEE_BUFFER_SIZE        128
110
#define PACKET_BUFFER_SIZE        108
111
// a buffer for data received from the XBee
112
char arrival_buf[XBEE_BUFFER_SIZE];
113
// location of last unread byte in buffer
114
volatile int buffer_last = 0;
115
// first unread byte in buffer
116
volatile int buffer_first = 0;
117

    
118

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

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

    
130
/*Function Implementations*/
131

    
132
#ifdef ROBOT
133

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

    
168
#else
169

    
170
// Computer code
171

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

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

    
195
                usleep(1000);
196
        }
197

    
198
        return NULL;
199
}
200

    
201
#endif
202

    
203
/**
204
 * Initializes the XBee library so that other functions may be used.
205
 **/
206
int xbee_lib_init()
207
{
208
        WL_DEBUG_PRINT("in xbee_init\n");
209
#ifdef ROBOT
210

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

    
236
        // set baud rate, etc. correctly
237
        struct termios options;
238

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

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

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

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

    
274
        WL_DEBUG_PRINT("Entering command mode.\n");
275

    
276
        if (xbee_enter_command_mode() != 0) {
277
                return -1;
278
        }
279

    
280
        WL_DEBUG_PRINT("Entered command mode.\n");
281

    
282
        if (xbee_enter_api_mode() != 0) {
283
                return -1;
284
        }
285

    
286
        WL_DEBUG_PRINT("Entered api mode.\n");
287

    
288
        if (xbee_exit_command_mode() != 0) {
289
             return -1;
290
        }
291
        
292
        WL_DEBUG_PRINT("Left command mode.\n");
293

    
294
        if (xbee_send_read_at_command("MY")) {
295
                return -1;
296
        }
297
        WL_DEBUG_PRINT("Getting ATMY address.\n");
298

    
299
#ifndef ROBOT
300
        int i;
301
        for (i = 0; xbee_address == 0 && i < XBEE_GET_PACKET_TIMEOUT; i++) {
302
          ret = xbee_get_packet(NULL);
303

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

    
322
#ifndef ROBOT
323
        if (i == XBEE_GET_PACKET_TIMEOUT) { // We timed-out.
324

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

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

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

    
363
        return 0;
364

    
365
#else
366

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

    
383
        //write was interrupted after writing ret bytes
384
        return xbee_send(buf + ret, size - ret);
385
#endif
386
}
387

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

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

    
408
        return 0;
409
}
410
#endif
411

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

    
421
        if (xbee_wait_for_ok() != 0) {
422
          return -1;
423
        }
424
          return 0;
425
}
426

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

    
436
        xbee_wait_for_ok();
437

    
438
        return 0;
439
}
440

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

    
451
        return 0;
452
}
453

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

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

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

    
494
#ifndef ROBOT
495
                usleep(100);
496
#endif
497
        }
498

    
499
        return 0;
500
}
501

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

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

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

    
559
        if (xbee_send(prefix, 3) != 0) {
560
                return -1;
561
        }
562

    
563
        if (xbee_send(buf, len) != 0) {
564
                return -1;
565
        }
566

    
567
        if (xbee_send(&checksum, 1) != 0) {
568
                return -1;
569
        }
570

    
571
        return 0;
572
}
573

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

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

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

    
614
                for (i = 0; i < valueLen; i++) {
615
                        buf[4 + i] = value[i];
616
                }
617
        }
618

    
619
        return xbee_send_frame(buf, 4 + valueLen);
620
}
621

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

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

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

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

    
666
        for (i = 0; i < 5; i++)
667
                checksum += (unsigned char)buf[i];
668
        for (i = 0; i < len; i++)
669
                checksum += (unsigned char)packet[i];
670
        checksum = 0xFF - checksum;
671

    
672
        if (xbee_send(prefix, 3) != 0) {
673
                return -1;
674
        }
675

    
676
        if (xbee_send(buf, 5) != 0) {
677
                return -1;
678
        }
679

    
680
        if (xbee_send(packet, len) != 0) {
681
                return -1;
682
        }
683

    
684
        if (xbee_send((char*)&checksum, 1) != 0) {
685
                return -1;
686
        }
687

    
688
        return 0;
689
}
690

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

    
741
                if (buffer_first == XBEE_BUFFER_SIZE) {
742
                        buffer_first = 0;
743
                }
744
                xbee_buf[0] = XBEE_FRAME_START;
745
                currentBufPos++;
746
        }
747

    
748
        int len = -1;
749
        if (currentBufPos >= 3) {
750
                len = (int)xbee_buf[2] + ((int)xbee_buf[1] << 8);
751
        }
752

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

    
767
                // check if buffer is empty
768
                if (buffer_first == buffer_last) {
769
                        return -1;
770
                }
771
                xbee_buf[currentBufPos++] = arrival_buf[buffer_first++];
772
                if (buffer_first == XBEE_BUFFER_SIZE) {
773
                        buffer_first = 0;
774
                }
775
        }
776

    
777
        currentBufPos = 0;
778

    
779
        if (!xbee_verify_checksum(xbee_buf, len + 4))
780
        {
781
                WL_DEBUG_PRINT("XBee checksum failed.\r\n");
782
                return -1;
783
        }
784

    
785
        //we will take care of the packet
786
        
787
        ret = xbee_handle_packet(xbee_buf+3, len);
788
        if (ret == 1) {
789
                return 3;
790
        }
791
        
792
        if (dest == NULL) {
793
                return -1;
794
        }
795

    
796
        int i;
797
        for (i = 3; i < len + 3; i++) {
798
                dest[i - 3] = xbee_buf[i];
799
        }
800
        return len;
801
}
802

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

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

    
855
        if (command[0] == 'I' && command[1] == 'D')
856
        {
857
                xbee_panID = xbee_pending_panID;
858
                WL_DEBUG_PRINT("PAN ID set to ");
859
                WL_DEBUG_PRINT_INT(xbee_panID);
860
                WL_DEBUG_PRINT(".\r\n");
861
                return;
862
        }
863

    
864
        if (command[0] == 'C' && command[1] == 'H')
865
        {
866
                xbee_channel = xbee_pending_channel;
867
                WL_DEBUG_PRINT("Channel set to ");
868
                WL_DEBUG_PRINT_INT(xbee_channel);
869
                WL_DEBUG_PRINT(".\r\n");
870
                return;
871
        }
872

    
873
        if (command[0] == 'M' && command[1] == 'Y' && extraLen != 0)
874
        {
875
                xbee_address = 0;
876
                int i;
877
                for (i = 0; i < extraLen; i++) {
878
                        xbee_address = (xbee_address << 8) + extra[i];
879
                }
880

    
881
                WL_DEBUG_PRINT("XBee address is ");
882
                WL_DEBUG_PRINT_INT(xbee_address);
883
                WL_DEBUG_PRINT(".\r\n");
884

    
885
                if (xbee_address == 0)
886
                {
887
                        WL_DEBUG_PRINT("XBee 16-bit address must be set using ATMY.\r\n");
888
                        #ifndef ROBOT
889
                        exit(0);
890
                        #endif
891
                }
892
        }
893
}
894

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

    
910
        char command[3] = {1, 2, 3};
911
        if (len <= 0) //this should not happend
912
        {
913
                WL_DEBUG_PRINT("Non-positive packet length.\r\n");
914
                return 0;
915
        }
916

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

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

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

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

    
976
        char s[3];
977
        s[0] = channel & 0xFF;
978
        s[1] = 0;
979
        xbee_pending_channel = channel;
980

    
981
        return xbee_send_modify_at_command("CH", s);
982
}
983

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

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

    
1012
#ifndef ROBOT
1013
void xbee_set_com_port(char* port)
1014
{
1015
        xbee_com_port = port;
1016
}
1017
#endif