Project

General

Profile

Statistics
| Revision:

root / branches / wireless / code / projects / oldlibwireless / lib / xbee.c @ 1624

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
                WL_DEBUG_PRINT("\nOut of space in buffer.\n");
144
        char c = UDR1;
145
        arrival_buf[buffer_last] = c;
146
        int t = buffer_last + 1;
147
        if (t == XBEE_BUFFER_SIZE)
148
                t = 0;
149
        if (t == buffer_first)
150
        {
151
                WL_DEBUG_PRINT("\nOut of space in buffer.\n");
152
        }
153
        buffer_last = t;
154
}
155
#else
156
SIGNAL(SIG_USART0_RECV)
157
{
158
        char c = UDR0;
159
        arrival_buf[buffer_last] = c;
160
        int t = buffer_last + 1;
161
        if (t == XBEE_BUFFER_SIZE)
162
                t = 0;
163
        if (t == buffer_first)
164
        {
165
                WL_DEBUG_PRINT("Out of space in buffer.\n");
166
        }
167
        buffer_last = t;
168
}
169
#endif
170

    
171
#else
172

    
173
// Computer code
174

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

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

    
198
                usleep(1000);
199
        }
200

    
201
        return NULL;
202
}
203

    
204
#endif
205

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
376
        return 0;
377

    
378
#else
379

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

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

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

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

    
419
        return 0;
420
}
421
#endif
422

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

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

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

    
447
        xbee_wait_for_ok();
448

    
449
        return 0;
450
}
451

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

    
462
        return 0;
463
}
464

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

    
474
        return 0;
475
}
476

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

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

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

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

    
520
        return 0;
521
}
522

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

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

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

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

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

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

    
592
        return 0;
593
}
594

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

    
613
        return 0;
614
}
615

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
728
        return 0;
729
}
730

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

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

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

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

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

    
817
        currentBufPos = 0;
818

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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