Project

General

Profile

Statistics
| Revision:

root / branches / wireless / code / projects / libwireless / lib / xbee.c @ 1494

History | View | Annotate | Download (21.9 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
#include <stdio.h>
46
#include <stdlib.h>
47

    
48
#else
49

    
50
#include <serial.h>
51
#include <avr/interrupt.h>
52
#include <util/delay.h>
53

    
54
#endif
55

    
56
#include <string.h>
57

    
58
#define XBEE_FRAME_START 0x7E
59
#define XBEE_GET_PACKET_TIMEOUT 1000
60

    
61
/*Frame Types*/
62
#define XBEE_FRAME_STATUS 0x8A
63
#define XBEE_FRAME_AT_COMMAND 0x08
64
#define XBEE_FRAME_AT_COMMAND_RESPONSE 0x88
65
#define XBEE_FRAME_TX_REQUEST_64 0x00
66
#define XBEE_FRAME_TX_REQUEST_16 0x01
67
#define XBEE_FRAME_TX_STATUS XBEE_TX_STATUS
68
#define XBEE_FRAME_RX_64 0x80
69
#define XBEE_FRAME_RX_16 XBEE_RX
70

    
71
/*Internal Function Prototypes*/
72

    
73
/*I/O Functions*/
74
static int xbee_send(char* buf, int size);
75
static int xbee_send_string(char* c);
76

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

    
81
/*Command Mode Functions
82
 * Called during initialization.
83
 */
84
static int xbee_enter_command_mode(void);
85
static int xbee_exit_command_mode(void);
86
static int xbee_enter_api_mode(void);
87
static int xbee_exit_api_mode(void);
88
static int xbee_wait_for_string(char* s, int len);
89
static int xbee_wait_for_ok(void);
90

    
91
/*API Mode Functions*/
92

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

    
102
/*Global Variables*/
103

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

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

    
120

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

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

    
132
/*Function Implementations*/
133

    
134
#ifdef ROBOT
135

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

    
170
#else
171

    
172
// Computer code
173

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

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

    
197
                usleep(1000);
198
        }
199

    
200
        return NULL;
201
}
202

    
203
#endif
204

    
205
/**
206
 * Initializes the XBee library so that other functions may be used.
207
 **/
208
int xbee_lib_init()
209
{
210
        WL_DEBUG_PRINT("in xbee_init\n");
211
#ifdef ROBOT
212
  // enable basic xbee serial communications
213
  xbee_init();
214

    
215
        // enable the receiving interrupt for USART1
216
#ifdef FIREFLY
217
        UCSR0B |= _BV(RXCIE) | _BV(RXEN);
218
#else
219
#ifdef BAYBOARD
220
        UCSR1B |= _BV(RXCIE1);
221
#else
222
  // dragonfly register 
223
        UCSR1B |= _BV(RXCIE);
224
#endif
225
#endif
226
        sei();
227
#else
228
  // this is computer only code
229
  
230
        xbee_stream = open(xbee_com_port, O_RDWR);
231
        if (xbee_stream == -1/* || lockf(xbee_stream, F_TEST, 0) != 0*/)
232
        {
233
                WL_DEBUG_PRINT("Failed to open connection to XBee on port ");
234
                WL_DEBUG_PRINT_INT(xbee_com_port);
235
                WL_DEBUG_PRINT(".\n");
236
                return -1;
237
        } else {
238
          WL_DEBUG_PRINT("Successfully opened connection to XBee on port ");
239
                WL_DEBUG_PRINT_INT(xbee_com_port);
240
                WL_DEBUG_PRINT(".\n");
241
        }
242

    
243
        // set baud rate, etc. correctly
244
        struct termios options;
245

    
246
        tcgetattr(xbee_stream, &options);
247
        cfsetispeed(&options, B9600);
248
        cfsetospeed(&options, B9600);
249
        options.c_iflag &= ~ICRNL;
250
        options.c_oflag &= ~OCRNL;
251
        options.c_cflag |= (CLOCAL | CREAD);
252
        options.c_cflag &= ~PARENB;
253
        options.c_cflag &= ~CSTOPB;
254
        options.c_cflag &= ~CSIZE;
255
        options.c_cflag |= CS8;
256
        options.c_lflag &= ~ICANON;
257
        options.c_cc[VMIN] = 1;
258
        options.c_cc[VTIME] = 50;
259

    
260
        if (tcsetattr(xbee_stream, TCSANOW, &options))
261
        {
262
                WL_DEBUG_PRINT("Error setting attributes.\n");
263
                return -1;
264
        }
265

    
266
        xbee_listen_thread = (pthread_t*)malloc(sizeof(pthread_t));
267
        if (xbee_listen_thread == NULL)
268
        {
269
                WL_DEBUG_PRINT("Malloc failed.\n");
270
                return -1;
271
        }
272

    
273
        int ret = pthread_create(xbee_listen_thread, NULL, listen_to_xbee, NULL);
274
        if (ret)
275
        {
276
                WL_DEBUG_PRINT("Failed to create listener thread.\n");
277
                return -1;
278
        }
279
#endif
280

    
281
        WL_DEBUG_PRINT("Entering command mode.\n");
282

    
283
        if (xbee_enter_command_mode() != 0) {
284
                return -1;
285
        }
286

    
287
        WL_DEBUG_PRINT("Entered command mode.\n");
288

    
289
        if (xbee_enter_api_mode() != 0) {
290
                return -1;
291
        }
292

    
293
        WL_DEBUG_PRINT("Entered api mode.\n");
294

    
295
        if (xbee_exit_command_mode() != 0) {
296
             return -1;
297
        }
298
        
299
        WL_DEBUG_PRINT("Left command mode.\n");
300

    
301
        if (xbee_send_read_at_command("MY")) {
302
                return -1;
303
        }
304
        WL_DEBUG_PRINT("Getting ATMY address.\n");
305

    
306
#ifndef ROBOT
307
        int i;
308
        for (i = 0; xbee_address == 0 && i < XBEE_GET_PACKET_TIMEOUT; i++) {
309
          ret = xbee_get_packet(NULL);
310

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

    
329
#ifndef ROBOT
330
        if (i == XBEE_GET_PACKET_TIMEOUT) { // We timed-out.
331

    
332
          WL_DEBUG_PRINT("xbee_get_packet timed out.\n");
333
          return -1;
334
        } else {
335
    
336
    
337
          return 0;
338
        }
339
#else
340
        return 0;
341
#endif
342
}
343

    
344
/**
345
 * Call when finished using the XBee library. This releases
346
 * all sued resources.
347
 **/
348
void xbee_terminate()
349
{
350
        #ifndef ROBOT
351
        pthread_cancel(*xbee_listen_thread);
352
    pthread_join(*xbee_listen_thread, NULL);
353
        free(xbee_listen_thread);
354
        lockf(xbee_stream, F_ULOCK, 0);
355
        close(xbee_stream);
356
  #else
357
  xbee_exit_api_mode();
358
        #endif
359
}
360

    
361
/**
362
 * Send a buffer buf of size bytes to the XBee.
363
 *
364
 * @param buf the buffer of data to send
365
 * @param size the number of bytes to send
366
 **/
367
static int xbee_send(char* buf, int size)
368
{
369
#ifdef ROBOT
370
        int i;
371
        for (i = 0; i < size; i++) {
372
                xbee_putc(buf[i]);
373
        }
374

    
375
        return 0;
376

    
377
#else
378

    
379
        int ret = write(xbee_stream, buf, size);
380
        //success
381
        if (ret == size)
382
                return 0;
383
        if (ret == -1)
384
        {
385
                //interrupted by system signal, probably timer interrupt.
386
                //just try again
387
                if (errno == 4)
388
                {
389
                        return xbee_send(buf, size);
390
                }
391
                WL_DEBUG_PRINT("Failed to write to xbee\r\n");
392
                return -1;
393
        }
394

    
395
        //write was interrupted after writing ret bytes
396
        return xbee_send(buf + ret, size - ret);
397
#endif
398
}
399

    
400
/**
401
 * Sends a string to the XBee.
402
 *
403
 * @param c the string to send to the XBEE
404
 **/
405
static int xbee_send_string(char* c)
406
{
407
        return xbee_send(c, strlen(c));
408
}
409

    
410
#ifndef ROBOT
411
static int xbee_read(char* buf, int size)
412
{
413
        if (read(xbee_stream, buf, size) == -1) {
414
                WL_DEBUG_PRINT("Failed to read from xbee.\r\n");
415
                return -1;
416
        }
417

    
418
        return 0;
419
}
420
#endif
421

    
422
/**
423
 * Enter into command mode.
424
 **/
425
static int xbee_enter_command_mode()
426
{
427
        if (xbee_send_string("+++") != 0) {
428
                return -1;
429
        }
430

    
431
        if (xbee_wait_for_ok() != 0) {
432
          return -1;
433
        }
434
          return 0;
435
}
436

    
437
/**
438
 * Exit from command mode.
439
 **/
440
static int xbee_exit_command_mode()
441
{
442
        if (xbee_send_string("ATCN\r") != 0) {
443
                return -1;
444
        }
445

    
446
        xbee_wait_for_ok();
447

    
448
        return 0;
449
}
450

    
451
/**
452
 * Enter API mode.
453
 **/
454
static int xbee_enter_api_mode()
455
{
456
        if (xbee_send_string("ATAP 1\r") != 0) {
457
                return -1;
458
        }
459
        xbee_wait_for_ok();
460

    
461
        return 0;
462
}
463

    
464
/**
465
 * Exit API mode.
466
 **/
467
static int xbee_exit_api_mode()
468
{
469
        if (xbee_send_modify_at_command("AP","0") != 0) {
470
                return -1;
471
        }
472

    
473
        return 0;
474
}
475

    
476
/**
477
 * Wait until the string "OK\r" is received from the XBee.
478
 **/
479
static int xbee_wait_for_ok()
480
{
481
        return xbee_wait_for_string("OK\r", 3);
482
}
483

    
484
/**
485
 * Delay until the specified string is received from
486
 * the XBee. Discards all other XBee data.
487
 *
488
 * @param s the string to receive
489
 * @param len the length of the string
490
 **/
491
static int xbee_wait_for_string(char* s, int len)
492
{
493
        char* curr = s;
494
        while (curr - s < len) {
495
                // check if buffer is empty
496
                if (buffer_last != buffer_first) {
497
                        char c = arrival_buf[buffer_first++];
498
                        if (buffer_first == XBEE_BUFFER_SIZE) {
499
                                buffer_first = 0;
500
                        }
501

    
502
                        if (c == *curr) {
503
                                curr++;
504
                        } else {
505
#ifndef ROBOT
506
                          //return -1; // Computer is less forgiving.
507
                          curr = s;
508
#else
509
                          curr = s;
510
#endif
511
                        }
512
                } // else buffer is empty.
513

    
514
#ifndef ROBOT
515
                usleep(100);
516
#endif
517
        }
518

    
519
        return 0;
520
}
521

    
522
/**
523
 * Verifies that the packets checksum is correct.
524
 * (If the checksum is correct, the sum of the bytes
525
 * is 0xFF.)
526
 *
527
 * @param packet the packet received. This includes the first
528
 * three bytes, which are header information from the XBee.
529
 *
530
 * @param len The length of the packet received from the XBee
531
 *
532
 * @return 0 if the checksum is incorrect, nonzero
533
 * otherwise
534
 **/
535
int xbee_verify_checksum(char* packet, int len)
536
{
537
        unsigned char sum = 0;
538
        int i;
539
        for (i = 3; i < len; i++)
540
                sum += (unsigned char)packet[i];
541
        return sum == 0xFF;
542
}
543

    
544
/**
545
 * Returns the checksum of the given packet.
546
 *
547
 * @param buf the data for the packet to send
548
 * @param len the length of the packet in bytes
549
 *
550
 * @return the checksum of the packet, which will
551
 * become the last byte sent in the packet
552
 **/
553
char xbee_compute_checksum(char* buf, int len)
554
{
555
        int i;
556
        unsigned char sum = 0;
557
        for (i = 0; i < len; i++)
558
                sum += (unsigned char)buf[i];
559
        return 0xFF - sum;
560
}
561

    
562
/**
563
 * Adds header information and checksum to the given
564
 * packet and sends it. Header information includes
565
 * XBEE_FRAME_START and the packet length, as two bytes.
566
 *
567
 * @param buf the packet data
568
 * @param len the size in bytes of the packet data
569
 *
570
 **/
571
static int xbee_send_frame(char* buf, int len)
572
{
573
        char prefix[3];
574
        prefix[0] = XBEE_FRAME_START;
575
        prefix[1] = (len & 0xFF00) >> 8;
576
        prefix[2] = len & 0xFF;
577
        char checksum = xbee_compute_checksum(buf, len);
578

    
579
        if (xbee_send(prefix, 3) != 0) {
580
                return -1;
581
        }
582

    
583
        if (xbee_send(buf, len) != 0) {
584
                return -1;
585
        }
586

    
587
        if (xbee_send(&checksum, 1) != 0) {
588
                return -1;
589
        }
590

    
591
        return 0;
592
}
593

    
594
/**
595
 * Resets the XBee Modem (including baud rate when on robot)
596
 * 
597
 * Used for launching bootloader
598
 **/
599
int xbee_reset(void)
600
{
601
#ifdef ROBOT
602
        xbee_send_modify_at_command("BD", "3");
603
#endif
604
        xbee_send_read_at_command("FR");
605
    // delay 150 ms to wait for reset
606
#ifndef ROBOT
607
        usleep(150000);
608
#else
609
        _delay_ms(150);
610
#endif
611

    
612
        return 0;
613
}
614

    
615
/**
616
 * Sends an AT command to read a parameter.
617
 *
618
 * @param command the AT command to send. For exmaple,
619
 * use ID to read the PAN ID and MY to return the XBee ID.
620
 * See the XBee reference guide for a complete listing.
621
 **/
622
static int xbee_send_read_at_command(char* command)
623
{
624
        return xbee_send_modify_at_command(command, NULL);
625
}
626

    
627
/**
628
 * Sends the given AT command.
629
 *
630
 * @param command the AT command to send (e.g., MY, ID)
631
 * @param value the value to pass as a parameter
632
 * (or NULL if there is no parameter)
633
 **/
634
static int xbee_send_modify_at_command(char* command, char* value)
635
{
636
        char buf[16];
637
        int i;
638

    
639
        buf[0] = XBEE_FRAME_AT_COMMAND;
640
        buf[1] = 1;
641
        buf[2] = command[0];
642
        buf[3] = command[1];
643
        int valueLen = 0;
644
        if (value != NULL)
645
        {
646
                valueLen = strlen(value);
647
                if (valueLen > 8)
648
                {
649
                        WL_DEBUG_PRINT("AT Command too large.\r\n");
650
                        return -1;
651
                }
652

    
653
                for (i = 0; i < valueLen; i++) {
654
                        buf[4 + i] = value[i];
655
                }
656
        }
657

    
658
        return xbee_send_frame(buf, 4 + valueLen);
659
}
660

    
661
/**
662
 * Send the specified packet.
663
 *
664
 * @param packet the packet data to send
665
 * @param len the number of bytes in the packet
666
 *
667
 * @param dest the ID of the XBee to send the packet to,
668
 * or XBEE_BROADCAST to send the message to all robots
669
 * in the PAN.
670
 *
671
 * @param options a combination of the flags
672
 * XBEE_OPTIONS_NONE, XBEE_OPTIONS_DISABLE_RESPONSE and
673
 * XBEE_OPTIONS_BROADCAST_ALL_PANS
674
 *
675
 * @param frame the frame number to associate this packet
676
 * with. This will be used to identify the response when
677
 * the XBee alerts us as to whether or not our message
678
 * was received.
679
 **/
680
int xbee_send_packet(char* packet, int len, int dest, char options, char frame)
681
{
682
        char buf[5];
683
        char prefix[3];
684
        int i;
685
        unsigned char checksum = 0;
686

    
687
        if (len > 100)
688
        {
689
                WL_DEBUG_PRINT("Packet is too large.\r\n");
690
                return -1;
691
        }
692

    
693
        //data for sending request
694
        buf[0] = XBEE_FRAME_TX_REQUEST_16;
695
        buf[1] = frame;
696
        buf[2] = (dest >> 8) & 0xFF;
697
        buf[3] = dest & 0xFF;
698
        buf[4] = options;
699

    
700
        //packet prefix, do this here so we don't need an extra buffer
701
        prefix[0] = XBEE_FRAME_START;
702
        prefix[1] = ((5 + len) & 0xFF00) >> 8;
703
        prefix[2] = (5 + len) & 0xFF;
704

    
705
        for (i = 0; i < 5; i++)
706
                checksum += (unsigned char)buf[i];
707
        for (i = 0; i < len; i++)
708
                checksum += (unsigned char)packet[i];
709
        checksum = 0xFF - checksum;
710

    
711
        if (xbee_send(prefix, 3) != 0) {
712
                return -1;
713
        }
714

    
715
        if (xbee_send(buf, 5) != 0) {
716
                return -1;
717
        }
718

    
719
        if (xbee_send(packet, len) != 0) {
720
                return -1;
721
        }
722

    
723
        if (xbee_send((char*)&checksum, 1) != 0) {
724
                return -1;
725
        }
726

    
727
        return 0;
728
}
729

    
730
/**
731
 * Reads a packet received from the XBee. This function
732
 * is non-blocking. The resulting packet is stored in dest.
733
 * Only returns transmission response packets and
734
 * received packets. The returned packet does not include
735
 * header information or the checksum. This method also
736
 * handles special packets dealt with by the XBee library,
737
 * and so should be called frequently while the XBee is in
738
 * use.<br><br>
739
 *
740
 * The first byte of the packet will be either
741
 * XBEE_TX_STATUS or XBEE_RX to indicated
742
 * a response to a sent message or a received message,
743
 * respectively.<br><br>
744
 *
745
 * For a status response packet:<br>
746
 * The first byte will be XBEE_TX_STATUS.<br>
747
 * The second byte will be the frame number.<br>
748
 * The third byte will be the result. 0 indicates success,
749
 * and nonzero indicates that an error ocurred in
750
 * transmitting the packet.<br><br>
751
 *
752
 * For a received packet:<br>
753
 * The first byte will be XBEE_RX.<br>
754
 * The second and third bytes will be the 16-bit
755
 * address of the packet's sender.<br>
756
 * The fourth byte is the signal strength.<br>
757
 * The fifth byte is 1 if the packet were sent to
758
 * a specific address, and 2 if it is a broadcast packet.<br><br>
759
 *
760
 * @param dest set to the packet data
761
 * @return the length of the packet, or -1 if no packet
762
 * is available
763
 **/
764
int xbee_get_packet(unsigned char* dest)
765
{
766
     int ret;
767
        //start reading a packet with XBEE_FRAME_START
768
        if (currentBufPos == 0)
769
        {
770
                do
771
                {
772
                        if (buffer_first == XBEE_BUFFER_SIZE)
773
                                buffer_first = 0;
774
                        // check if buffer is empty
775
                        if (buffer_first == buffer_last) {
776
                                return -1;
777
                        }
778
                } while (arrival_buf[buffer_first++] != XBEE_FRAME_START);
779

    
780
                if (buffer_first == XBEE_BUFFER_SIZE) {
781
                        buffer_first = 0;
782
                }
783
                xbee_buf[0] = XBEE_FRAME_START;
784
                currentBufPos++;
785
        }
786

    
787
        int len = -1;
788
        if (currentBufPos >= 3) {
789
                len = (int)xbee_buf[2] + ((int)xbee_buf[1] << 8);
790
        }
791

    
792
        while (len == -1 //packet length has not been read yet
793
                || currentBufPos < len + 4)
794
        {
795
                if (currentBufPos == 3)
796
                {
797
                        len = (int)xbee_buf[2] + ((int)xbee_buf[1] << 8);
798
                        if (len > 120)
799
                        {
800
                                WL_DEBUG_PRINT("Packet too large. Probably error in XBee transmission.\n");
801
                                currentBufPos = 0;
802
                                return -1;
803
                        }
804
                }
805

    
806
                // check if buffer is empty
807
                if (buffer_first == buffer_last) {
808
                        return -1;
809
                }
810
                xbee_buf[currentBufPos++] = arrival_buf[buffer_first++];
811
                if (buffer_first == XBEE_BUFFER_SIZE) {
812
                        buffer_first = 0;
813
                }
814
        }
815

    
816
        currentBufPos = 0;
817

    
818
        if (!xbee_verify_checksum(xbee_buf, len + 4))
819
        {
820
                WL_DEBUG_PRINT("XBee checksum failed.\r\n");
821
                return -1;
822
        }
823

    
824
        //we will take care of the packet
825
        
826
        ret = xbee_handle_packet(xbee_buf+3, len);
827
        if (ret == 1) {
828
                return 3;
829
        }
830
        
831
        if (dest == NULL) {
832
                return -1;
833
        }
834

    
835
        int i;
836
        for (i = 3; i < len + 3; i++) {
837
                dest[i - 3] = xbee_buf[i];
838
        }
839
        return len;
840
}
841

    
842
/**
843
 * Handles modem status packets.
844
 *
845
 * @param status the type of status packet received.
846
 **/
847
void xbee_handle_status(char status)
848
{
849
        switch (status)
850
        {
851
                case 0:
852
                        WL_DEBUG_PRINT("XBee hardware reset.\r\n");
853
                        break;
854
                case 1:
855
                        WL_DEBUG_PRINT("Watchdog timer reset.\r\n");
856
                        break;
857
                case 2:
858
                        WL_DEBUG_PRINT("Associated.\r\n");
859
                        break;
860
                case 3:
861
                        WL_DEBUG_PRINT("Disassociated.\r\n");
862
                        break;
863
                case 4:
864
                        WL_DEBUG_PRINT("Synchronization lost.\r\n");
865
                        break;
866
                case 5:
867
                        WL_DEBUG_PRINT("Coordinator realignment.\r\n");
868
                        break;
869
                case 6:
870
                        WL_DEBUG_PRINT("Coordinator started.\r\n");
871
                        break;
872
        }
873
}
874

    
875
/**
876
 * Handles AT command response packets.
877
 * @param command the two character AT command, e.g. MY or ID
878
 * @param result 0 for success, 1 for an error
879
 * @param extra the hex value of the requested register
880
 * @param extraLen the length in bytes of extra
881
 **/
882
static void xbee_handle_at_command_response(char* command, char result, char* extra, int extraLen)
883
{
884
        if (result == 1)
885
        {
886
                WL_DEBUG_PRINT("Error with AT");
887
                WL_DEBUG_PRINT(command);
888
                WL_DEBUG_PRINT(" packet.\r\n");
889
        }
890
        WL_DEBUG_PRINT("AT");
891
        WL_DEBUG_PRINT(command);
892
        WL_DEBUG_PRINT(" command was successful.\r\n");
893

    
894
        if (command[0] == 'I' && command[1] == 'D')
895
        {
896
                xbee_panID = xbee_pending_panID;
897
                WL_DEBUG_PRINT("PAN ID set to ");
898
                WL_DEBUG_PRINT_INT(xbee_panID);
899
                WL_DEBUG_PRINT(".\r\n");
900
                return;
901
        }
902

    
903
        if (command[0] == 'C' && command[1] == 'H')
904
        {
905
                xbee_channel = xbee_pending_channel;
906
                WL_DEBUG_PRINT("Channel set to ");
907
                WL_DEBUG_PRINT_INT(xbee_channel);
908
                WL_DEBUG_PRINT(".\r\n");
909
                return;
910
        }
911

    
912
        if (command[0] == 'M' && command[1] == 'Y' && extraLen != 0)
913
        {
914
                xbee_address = 0;
915
                int i;
916
                for (i = 0; i < extraLen; i++) {
917
                        xbee_address = (xbee_address << 8) + extra[i];
918
                }
919

    
920
                WL_DEBUG_PRINT("XBee address is ");
921
                WL_DEBUG_PRINT_INT(xbee_address);
922
                WL_DEBUG_PRINT(".\r\n");
923

    
924
                if (xbee_address == 0)
925
                {
926
                        WL_DEBUG_PRINT("XBee 16-bit address must be set using ATMY.\r\n");
927
                        #ifndef ROBOT
928
                        exit(0);
929
                        #endif
930
                }
931
        }
932
}
933

    
934
/**
935
 * Attempts to handle the packet if it is dealt with
936
 * by the library.
937
 * We will handle the following packet types:
938
 *    Modem Status
939
 *    AT Command Response
940
 *
941
 * @param packet the packet to handle
942
 * @param len the length of the packet
943
 *
944
 * @return 1 if we have handled the packet, 0 otherwise
945
 */
946
static int xbee_handle_packet(char* packet, int len)
947
{
948

    
949
        char command[3] = {1, 2, 3};
950
        if (len <= 0) //this should not happend
951
        {
952
                WL_DEBUG_PRINT("Non-positive packet length.\r\n");
953
                return 0;
954
        }
955

    
956
        switch ((unsigned char)packet[0]) //packet type
957
        {
958
                case XBEE_FRAME_STATUS:
959
                        xbee_handle_status(packet[1]);
960
                        return 1;
961
                case XBEE_FRAME_AT_COMMAND_RESPONSE:
962
                        command[0] = packet[2];
963
                        command[1] = packet[3];
964
                        command[2] = 0;
965
                        xbee_handle_at_command_response(command, packet[4], packet + 5, len - 5);
966
                        return 1;
967
        }
968
        return 0;
969
}
970

    
971
/**
972
 * Sets the personal area network id.
973
 *
974
 * @param id the new personal area network (PAN) id
975
 **/
976
int xbee_set_pan_id(int id)
977
{
978
        char s[3];
979
        s[0] = (id >> 8) & 0xFF;
980
        s[1] = id & 0xFF;
981
        s[2] = 0;
982
        xbee_pending_panID = id;
983
        return xbee_send_modify_at_command("ID", s);
984
}
985

    
986
/**
987
 * Get the PAN ID for the XBee.
988
 *
989
 * @return the personal area network id, or
990
 * XBEE_PAN_DEFAULT if it has not yet been set.
991
 **/
992
unsigned int xbee_get_pan_id()
993
{
994
        return xbee_panID;
995
}
996

    
997
/**
998
 * Set the channel the XBee is using.
999
 *
1000
 * @param channel the channel the XBee will not use,
1001
 * between 0x0B and 0x1A
1002
 *
1003
 * @see xbee_get_channel
1004
 **/
1005
int xbee_set_channel(int channel)
1006
{
1007
        if (channel < 0x0B || channel > 0x1A)
1008
        {
1009
                WL_DEBUG_PRINT("Channel out of range.\r\n");
1010
                return -1;
1011
        }
1012

    
1013
        char s[3];
1014
        s[0] = channel & 0xFF;
1015
        s[1] = 0;
1016
        xbee_pending_channel = channel;
1017

    
1018
        return xbee_send_modify_at_command("CH", s);
1019
}
1020

    
1021
/**
1022
 * Returns the channel which the XBee is currently using.
1023
 *
1024
 * @return the channel the XBee is using
1025
 *
1026
 * @see xbee_set_channel
1027
 **/
1028
int xbee_get_channel(void)
1029
{
1030
        return xbee_channel;
1031
}
1032

    
1033
/**
1034
 * Get the 16-bit address of the XBee.
1035
 * This is used to specify who to send messages to
1036
 * and who messages are from.
1037
 *
1038
 * @return the 16-bit address of the XBee.
1039
 **/
1040
unsigned int xbee_get_address()
1041
{
1042
        return xbee_address;
1043
}
1044

    
1045
#ifndef ROBOT
1046
void xbee_set_com_port(char* port)
1047
{
1048
        xbee_com_port = port;
1049
}
1050
#endif