Project

General

Profile

Statistics
| Revision:

root / trunk / code / projects / unit_tests / xbee.c @ 1623

History | View | Annotate | Download (21.8 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
#define ROBOT
39
#define WL_DEBUG
40
#define WL_DEBUG_PRINT( s ) usb_puts( s )
41
#define WL_DEBUG_PRINT_INT( i ) usb_puti(i)
42

    
43
#ifndef ROBOT
44

    
45
#include <fcntl.h>
46
#include <unistd.h>
47
#include <pthread.h>
48
#include <errno.h>
49
#include <termios.h>
50

    
51
#else
52

    
53
#include <serial.h>
54
#include <avr/interrupt.h>
55

    
56
#endif
57

    
58
#include <stdio.h>
59
#include <stdlib.h>
60
#include <string.h>
61

    
62
#define XBEE_FRAME_START 0x7E
63
#define XBEE_GET_PACKET_TIMEOUT 1000
64

    
65
/*Frame Types*/
66
#define XBEE_FRAME_STATUS 0x8A
67
#define XBEE_FRAME_AT_COMMAND 0x08
68
#define XBEE_FRAME_AT_COMMAND_RESPONSE 0x88
69
#define XBEE_FRAME_TX_REQUEST_64 0x00
70
#define XBEE_FRAME_TX_REQUEST_16 0x01
71
#define XBEE_FRAME_TX_STATUS XBEE_TX_STATUS
72
#define XBEE_FRAME_RX_64 0x80
73
#define XBEE_FRAME_RX_16 XBEE_RX
74

    
75
/*Internal Function Prototypes*/
76

    
77
/*I/O Functions*/
78
static int xbee_send(char* buf, int size);
79
static int xbee_send_string(char* c);
80

    
81
#ifndef ROBOT
82
static int xbee_read(char* buf, int size);
83
#endif
84

    
85
/*Command Mode Functions
86
 * Called during initialization.
87
 */
88
static int xbee_enter_command_mode(void);
89
static int xbee_exit_command_mode(void);
90
static int xbee_enter_api_mode(void);
91
static int xbee_exit_api_mode(void);
92
static int xbee_wait_for_string(char* s, int len);
93
static int xbee_wait_for_ok(void);
94

    
95
/*API Mode Functions*/
96

    
97
static int xbee_handle_packet(char* packet, int len);
98
static void xbee_handle_at_command_response(char* command, char result, char* extra, int extraLen);
99
static void xbee_handle_status(char status);
100
static int xbee_verify_checksum(char* packet, int len);
101
static char xbee_compute_checksum(char* packet, int len);
102
static int xbee_send_frame(char* buf, int len);
103
int xbee_send_read_at_command(char* command);
104
static int xbee_send_modify_at_command(char* command, char* value);
105

    
106
/*Global Variables*/
107

    
108
#ifndef ROBOT
109
static char* xbee_com_port = XBEE_PORT_DEFAULT;
110
static int xbee_stream;
111
static pthread_t* xbee_listen_thread;
112
#endif
113

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

    
124

    
125
//used to store packets as they are read
126
static char xbee_buf[PACKET_BUFFER_SIZE];
127
static int currentBufPos = 0;
128

    
129
//XBee status
130
static unsigned int xbee_panID = XBEE_PAN_DEFAULT;
131
static unsigned int xbee_pending_panID = XBEE_PAN_DEFAULT;
132
static int xbee_channel = XBEE_CHANNEL_DEFAULT;
133
static int xbee_pending_channel = XBEE_CHANNEL_DEFAULT;
134
static volatile unsigned int xbee_address = 0;
135

    
136
/*Function Implementations*/
137

    
138
#ifdef ROBOT
139

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

    
174
#else
175

    
176
// Computer code
177

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

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

    
201
                usleep(1000);
202
        }
203

    
204
        return NULL;
205
}
206

    
207
#endif
208

    
209
/**
210
 * Initializes the XBee library so that other functions may be used.
211
 **/
212
int xbee_lib_init()
213
{
214
        WL_DEBUG_PRINT("in xbee_init\n");
215
#ifdef ROBOT
216

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
372
        return 0;
373

    
374
#else
375

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

    
392
        //write was interrupted after writing ret bytes
393
        return xbee_send(buf + ret, size - ret);
394
#endif
395
}
396

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

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

    
415
        return 0;
416
}
417
#endif
418

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

    
428
        if (xbee_wait_for_ok() != 0) {
429
          return -1;
430
        }
431
          return 0;
432
}
433

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

    
443
        xbee_wait_for_ok();
444

    
445
        return 0;
446
}
447

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

    
458
        return 0;
459
}
460

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

    
470
        return 0;
471
}
472

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

    
481
/**
482
 * Delay until the specified string is received from
483
 * the XBee. Discards all other XBee data.
484
 *
485
 * ********* Robot often hangs here ****************
486
 *
487
 * @param s the string to receive
488
 * @param len the length of the string
489
 **/
490
static int xbee_wait_for_string(char* s, int len)
491
{
492
        char* curr = s;
493
        while (curr - s < len) {
494
    WL_DEBUG_PRINT("waiting for string\r\n");
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
 * Sends an AT command to read a parameter.
596
 *
597
 * @param command the AT command to send. For exmaple,
598
 * use ID to read the PAN ID and MY to return the XBee ID.
599
 * See the XBee reference guide for a complete listing.
600
 **/
601
int xbee_send_read_at_command(char* command)
602
{
603
        return xbee_send_modify_at_command(command, NULL);
604
}
605

    
606
/**
607
 * Sends the given AT command.
608
 *
609
 * @param command the AT command to send (e.g., MY, ID)
610
 * @param value the value to pass as a parameter
611
 * (or NULL if there is no parameter)
612
 **/
613
static int xbee_send_modify_at_command(char* command, char* value)
614
{
615
        char buf[16];
616
        int i;
617

    
618
        buf[0] = XBEE_FRAME_AT_COMMAND;
619
        buf[1] = 1;
620
        buf[2] = command[0];
621
        buf[3] = command[1];
622
        int valueLen = 0;
623
        if (value != NULL)
624
        {
625
                valueLen = strlen(value);
626
                if (valueLen > 8)
627
                {
628
                        WL_DEBUG_PRINT("AT Command too large.\r\n");
629
                        return -1;
630
                }
631

    
632
                for (i = 0; i < valueLen; i++) {
633
                        buf[4 + i] = value[i];
634
                }
635
        }
636

    
637
        return xbee_send_frame(buf, 4 + valueLen);
638
}
639

    
640
/**
641
 * Send the specified packet.
642
 *
643
 * @param packet the packet data to send
644
 * @param len the number of bytes in the packet
645
 *
646
 * @param dest the ID of the XBee to send the packet to,
647
 * or XBEE_BROADCAST to send the message to all robots
648
 * in the PAN.
649
 *
650
 * @param options a combination of the flags
651
 * XBEE_OPTIONS_NONE, XBEE_OPTIONS_DISABLE_RESPONSE and
652
 * XBEE_OPTIONS_BROADCAST_ALL_PANS
653
 *
654
 * @param frame the frame number to associate this packet
655
 * with. This will be used to identify the response when
656
 * the XBee alerts us as to whether or not our message
657
 * was received.
658
 **/
659
int xbee_send_packet(char* packet, int len, int dest, char options, char frame)
660
{
661
        char buf[5];
662
        char prefix[3];
663
        int i;
664
        unsigned char checksum = 0;
665

    
666
        if (len > 100)
667
        {
668
                WL_DEBUG_PRINT("Packet is too large.\r\n");
669
                return -1;
670
        }
671

    
672
        //data for sending request
673
        buf[0] = XBEE_FRAME_TX_REQUEST_16;
674
        buf[1] = frame;
675
        buf[2] = (dest >> 8) & 0xFF;
676
        buf[3] = dest & 0xFF;
677
        buf[4] = options;
678

    
679
        //packet prefix, do this here so we don't need an extra buffer
680
        prefix[0] = XBEE_FRAME_START;
681
        prefix[1] = ((5 + len) & 0xFF00) >> 8;
682
        prefix[2] = (5 + len) & 0xFF;
683

    
684
        for (i = 0; i < 5; i++)
685
                checksum += (unsigned char)buf[i];
686
        for (i = 0; i < len; i++)
687
                checksum += (unsigned char)packet[i];
688
        checksum = 0xFF - checksum;
689

    
690
        if (xbee_send(prefix, 3) != 0) {
691
                return -1;
692
        }
693

    
694
        if (xbee_send(buf, 5) != 0) {
695
                return -1;
696
        }
697

    
698
        if (xbee_send(packet, len) != 0) {
699
                return -1;
700
        }
701

    
702
        if (xbee_send((char*)&checksum, 1) != 0) {
703
                return -1;
704
        }
705

    
706
        return 0;
707
}
708

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

    
759
                if (buffer_first == XBEE_BUFFER_SIZE) {
760
                        buffer_first = 0;
761
                }
762
                xbee_buf[0] = XBEE_FRAME_START;
763
                currentBufPos++;
764
        }
765

    
766
        int len = -1;
767
        if (currentBufPos >= 3) {
768
                len = (int)xbee_buf[2] + ((int)xbee_buf[1] << 8);
769
        }
770

    
771
        while (len == -1 //packet length has not been read yet
772
                || currentBufPos < len + 4)
773
        {
774
                if (currentBufPos == 3)
775
                {
776
                        len = (int)xbee_buf[2] + ((int)xbee_buf[1] << 8);
777
                        if (len > 120)
778
                        {
779
                                WL_DEBUG_PRINT("Packet too large. Probably error in XBee transmission.\n");
780
                                currentBufPos = 0;
781
                                return -1;
782
                        }
783
                }
784

    
785
                // check if buffer is empty
786
                if (buffer_first == buffer_last) {
787
                        return -1;
788
                }
789
                xbee_buf[currentBufPos++] = arrival_buf[buffer_first++];
790
                if (buffer_first == XBEE_BUFFER_SIZE) {
791
                        buffer_first = 0;
792
                }
793
        }
794

    
795
        currentBufPos = 0;
796

    
797
        if (!xbee_verify_checksum(xbee_buf, len + 4))
798
        {
799
                WL_DEBUG_PRINT("XBee checksum failed.\r\n");
800
                return -1;
801
        }
802

    
803
        //we will take care of the packet
804
        
805
        ret = xbee_handle_packet(xbee_buf+3, len);
806
        if (ret == 1) {
807
                return 3;
808
        }
809
        
810
        if (dest == NULL) {
811
                return -1;
812
        }
813

    
814
        int i;
815
        for (i = 3; i < len + 3; i++) {
816
                dest[i - 3] = xbee_buf[i];
817
        }
818
        return len;
819
}
820

    
821
/**
822
 * Handles modem status packets.
823
 *
824
 * @param status the type of status packet received.
825
 **/
826
void xbee_handle_status(char status)
827
{
828
        switch (status)
829
        {
830
                case 0:
831
                        WL_DEBUG_PRINT("XBee hardware reset.\r\n");
832
                        break;
833
                case 1:
834
                        WL_DEBUG_PRINT("Watchdog timer reset.\r\n");
835
                        break;
836
                case 2:
837
                        WL_DEBUG_PRINT("Associated.\r\n");
838
                        break;
839
                case 3:
840
                        WL_DEBUG_PRINT("Disassociated.\r\n");
841
                        break;
842
                case 4:
843
                        WL_DEBUG_PRINT("Synchronization lost.\r\n");
844
                        break;
845
                case 5:
846
                        WL_DEBUG_PRINT("Coordinator realignment.\r\n");
847
                        break;
848
                case 6:
849
                        WL_DEBUG_PRINT("Coordinator started.\r\n");
850
                        break;
851
        }
852
}
853

    
854
/**
855
 * Handles AT command response packets.
856
 * @param command the two character AT command, e.g. MY or ID
857
 * @param result 0 for success, 1 for an error
858
 * @param extra the hex value of the requested register
859
 * @param extraLen the length in bytes of extra
860
 **/
861
static void xbee_handle_at_command_response(char* command, char result, char* extra, int extraLen)
862
{
863
        if (result == 1)
864
        {
865
                WL_DEBUG_PRINT("Error with AT");
866
                WL_DEBUG_PRINT(command);
867
                WL_DEBUG_PRINT(" packet.\r\n");
868
        }
869
        WL_DEBUG_PRINT("AT");
870
        WL_DEBUG_PRINT(command);
871
        WL_DEBUG_PRINT(" command was successful.\r\n");
872

    
873
        if (command[0] == 'I' && command[1] == 'D')
874
        {
875
                xbee_panID = xbee_pending_panID;
876
                WL_DEBUG_PRINT("PAN ID set to ");
877
                WL_DEBUG_PRINT_INT(xbee_panID);
878
                WL_DEBUG_PRINT(".\r\n");
879
                return;
880
        }
881

    
882
        if (command[0] == 'C' && command[1] == 'H')
883
        {
884
                xbee_channel = xbee_pending_channel;
885
                WL_DEBUG_PRINT("Channel set to ");
886
                WL_DEBUG_PRINT_INT(xbee_channel);
887
                WL_DEBUG_PRINT(".\r\n");
888
                return;
889
        }
890
  
891
  if (command[0] == 'N' && command[1] == 'D')
892
        {
893
                xbee_channel = xbee_pending_channel;
894
                WL_DEBUG_PRINT("extra=");
895
    WL_DEBUG_PRINT(extra);
896
                WL_DEBUG_PRINT("\r\n");
897
                return;
898
        }
899

    
900
        if (command[0] == 'M' && command[1] == 'Y' && extraLen != 0)
901
        {
902
                xbee_address = 0;
903
                int i;
904
                for (i = 0; i < extraLen; i++) {
905
                        xbee_address = (xbee_address << 8) + extra[i];
906
                }
907

    
908
                WL_DEBUG_PRINT("XBee address is ");
909
                WL_DEBUG_PRINT_INT(xbee_address);
910
                WL_DEBUG_PRINT(".\r\n");
911

    
912
                if (xbee_address == 0)
913
                {
914
                        WL_DEBUG_PRINT("XBee 16-bit address must be set using ATMY.\r\n");
915
                        #ifndef ROBOT
916
                        exit(0);
917
                        #endif
918
                }
919
        }
920
}
921

    
922
/**
923
 * Attempts to handle the packet if it is dealt with
924
 * by the library.
925
 * We will handle the following packet types:
926
 *    Modem Status
927
 *    AT Command Response
928
 *
929
 * @param packet the packet to handle
930
 * @param len the length of the packet
931
 *
932
 * @return 1 if we have handled the packet, 0 otherwise
933
 */
934
static int xbee_handle_packet(char* packet, int len)
935
{
936

    
937
        char command[3] = {1, 2, 3};
938
        if (len <= 0) //this should not happend
939
        {
940
                WL_DEBUG_PRINT("Non-positive packet length.\r\n");
941
                return 0;
942
        }
943

    
944
        switch ((unsigned char)packet[0]) //packet type
945
        {
946
                case XBEE_FRAME_STATUS:
947
                        xbee_handle_status(packet[1]);
948
                        return 1;
949
                case XBEE_FRAME_AT_COMMAND_RESPONSE:
950
                        command[0] = packet[2];
951
                        command[1] = packet[3];
952
                        command[2] = 0;
953
                        xbee_handle_at_command_response(command, packet[4], packet + 5, len - 5);
954
                        return 1;
955
        }
956
        return 0;
957
}
958

    
959
/**
960
 * Sets the personal area network id.
961
 *
962
 * @param id the new personal area network (PAN) id
963
 **/
964
int xbee_set_pan_id(int id)
965
{
966
        char s[3];
967
        s[0] = (id >> 8) & 0xFF;
968
        s[1] = id & 0xFF;
969
        s[2] = 0;
970
        xbee_pending_panID = id;
971
        return xbee_send_modify_at_command("ID", s);
972
}
973

    
974
/**
975
 * Get the PAN ID for the XBee.
976
 *
977
 * @return the personal area network id, or
978
 * XBEE_PAN_DEFAULT if it has not yet been set.
979
 **/
980
unsigned int xbee_get_pan_id()
981
{
982
        return xbee_panID;
983
}
984

    
985
/**
986
 * Set the channel the XBee is using.
987
 *
988
 * @param channel the channel the XBee will not use,
989
 * between 0x0B and 0x1A
990
 *
991
 * @see xbee_get_channel
992
 **/
993
int xbee_set_channel(int channel)
994
{
995
        if (channel < 0x0B || channel > 0x1A)
996
        {
997
                WL_DEBUG_PRINT("Channel out of range.\r\n");
998
                return -1;
999
        }
1000

    
1001
        char s[3];
1002
        s[0] = channel & 0xFF;
1003
        s[1] = 0;
1004
        xbee_pending_channel = channel;
1005

    
1006
        return xbee_send_modify_at_command("CH", s);
1007
}
1008

    
1009
/**
1010
 * Returns the channel which the XBee is currently using.
1011
 *
1012
 * @return the channel the XBee is using
1013
 *
1014
 * @see xbee_set_channel
1015
 **/
1016
int xbee_get_channel(void)
1017
{
1018
        return xbee_channel;
1019
}
1020

    
1021
/**
1022
 * Get the 16-bit address of the XBee.
1023
 * This is used to specify who to send messages to
1024
 * and who messages are from.
1025
 *
1026
 * @return the 16-bit address of the XBee.
1027
 **/
1028
unsigned int xbee_get_address()
1029
{
1030
        return xbee_address;
1031
}
1032

    
1033
#ifndef ROBOT
1034
void xbee_set_com_port(char* port)
1035
{
1036
        xbee_com_port = port;
1037
}
1038
#endif