Project

General

Profile

Statistics
| Revision:

root / branches / wireless / code / projects / libwireless / xbee.c @ 1587

History | View | Annotate | Download (24.4 KB)

1
/**
2
 * Copyright (c) 2009 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 Colony Project, CMU Robotics Club
33
 **/
34

    
35
#include "xbee.h"
36
#include "wl_defs.h"
37
#include <time.h>
38

    
39
// TODO: separate robot and computer code into two xbee.c files
40

    
41
#ifndef ROBOT
42

    
43
#include <fcntl.h>
44
#include <unistd.h>
45
#include <pthread.h>
46
#include <errno.h>
47
#include <termios.h>
48

    
49
#else
50

    
51
#include <serial.h> // TODO: integrate serial xbee functions into this file
52
#include <avr/interrupt.h>
53

    
54
#endif
55

    
56
// TODO: do we really need stdio and stdlib in the robot code?
57
#include <stdio.h>
58
#include <stdlib.h>
59
#include <string.h>
60

    
61

    
62
/*Internal Function Prototypes*/
63

    
64
// TODO: convert all int references to int16_t syntax (see stdint.h)
65

    
66
/*I/O Functions*/
67
static int xbee_send(char* buf, int size);
68
static int xbee_send_string(char* c);
69

    
70
#ifndef ROBOT
71
static int xbee_read(char* buf, int size);
72
#endif
73

    
74
/*Command Mode Functions
75
 * Called during initialization.
76
 */
77
static int xbee_enter_command_mode(void);
78
static int xbee_exit_command_mode(void);
79
static int xbee_enter_api_mode(void);
80
static int xbee_exit_api_mode(void);
81
static int xbee_wait_for_string(char* s, int len);
82
static int xbee_wait_for_ok(void);
83

    
84
/*API Mode Functions*/
85

    
86
static int xbee_handle_packet(char* packet, int len);
87
static int xbee_handle_at_command_response(char* command, char result, char* extra, int extraLen);
88
static void xbee_handle_status(char status);
89
static int xbee_verify_checksum(char* packet, int len);
90
static char xbee_compute_checksum(char* packet, int len);
91
static int xbee_send_frame(char* buf, int len);
92
int xbee_send_read_at_command(char* command);
93
static int xbee_send_modify_at_command(char* command, char* value);
94

    
95
/*Global Variables*/
96

    
97
#ifndef ROBOT
98
static char* xbee_com_port = XBEE_PORT_DEFAULT;
99
static int xbee_stream;
100
static pthread_t* xbee_listen_thread;
101
#endif
102

    
103
// TODO: clarify buffers, what they're used for, etc
104

    
105
// a buffer for data received from the XBee
106
char arrival_buf[XBEE_BUFFER_SIZE];
107
// location of last unread byte in buffer
108
volatile int buffer_last = 0;
109
// first unread byte in buffer
110
volatile int buffer_first = 0;
111

    
112

    
113
//used to store packets as they are read
114
static char xbee_buf[PACKET_BUFFER_SIZE];
115
static int currentBufPos = 0;
116

    
117
//XBee status
118
static unsigned int xbee_panID = XBEE_PAN_DEFAULT;
119
static unsigned int xbee_pending_panID = XBEE_PAN_DEFAULT;
120
static int xbee_channel = XBEE_CHANNEL_DEFAULT;
121
static int xbee_pending_channel = XBEE_CHANNEL_DEFAULT;
122
static volatile unsigned int xbee_address = 0;
123

    
124

    
125
/**@addtogroup xbee
126
 * @{ **/
127

    
128

    
129
/*Function Implementations*/
130

    
131
#ifdef ROBOT
132

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

    
167
#else
168

    
169
// Computer code
170

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

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

    
194
                usleep(1000);
195
        }
196

    
197
        return NULL;
198
}
199

    
200
#endif
201

    
202
/**
203
 * Initializes the XBee library so that other functions may be used.
204
 **/
205
int xbee_lib_init()
206
{
207
  if (xbee_init() != 0) {
208
    usb_puts("xbee_init error");
209
    return -1;
210
  }
211

    
212
        WL_DEBUG_PRINT("in xbee_init\n");
213
#ifdef ROBOT
214

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

    
240
        // set baud rate, etc. correctly
241
        struct termios options;
242

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

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

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

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

    
278
        WL_DEBUG_PRINT("Entering command mode.\r\n");
279

    
280
        if (xbee_enter_command_mode() != 0) {
281
    usb_puts("error entering command mode\r\n");
282
                return -1;
283
        }
284

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

    
287
  // reset baud rate
288
  WL_DEBUG_PRINT("Resetting Baud to ");
289
  WL_DEBUG_PRINT(XBEE_BAUD_STR);
290
  WL_DEBUG_PRINT("\r\n");
291
  
292
  // set baud on xbee
293
//#if (XBEE_BAUD == 250000)
294
#if (XBEE_BAUD == 115200)
295
  xbee_send_string("ATBD7\r\n");
296
#elif (XBEE_BAUD == 57600)
297
  xbee_send_string("ATBD6\r\n");
298
#elif (XBEE_BAUD == 38400)
299
  xbee_send_string("ATBD5\r\n");
300
#elif (XBEE_BAUD == 19200)
301
  xbee_send_string("ATBD4\r\n");
302
#elif (XBEE_BAUD == 9600)
303
  // already at this baud rate
304
  //xbee_send_string("ATBD3\r\n");
305
#else
306
  WL_DEBUG_PRINT("undefined baud rate\r\n");
307
#endif  
308
  // exit command mode
309
  xbee_wait_for_ok();
310
  WL_DEBUG_PRINT("got ok from baud reset\r\n");
311
  xbee_send_string("ATCN\r\n");
312
  xbee_wait_for_ok();
313
  WL_DEBUG_PRINT("got ok from exiting command mode\r\n");
314
  
315
  // set UART baud
316
#if (XBEE_BAUD == 250000)
317
  UBRR1H = 0x00;
318
  UBRR1L = 3;
319
  UCSR1A |= _BV(U2X1);
320
#elif (XBEE_BAUD == 115200)
321
  UBRR1H = 0x00;
322
  UBRR1L = 8;
323
  UCSR1A |= _BV(U2X1);
324
#elif (XBEE_BAUD == 57600)
325
  UBRR1H = 0x00;
326
  UBRR1L = 16;
327
  UCSR1A |= _BV(U2X1);
328
#elif (XBEE_BAUD == 38400)
329
  UBRR1H = 0x00;
330
  UBRR1L = 25;
331
  UCSR1A |= _BV(U2X1);
332
#elif (XBEE_BAUD == 19200)
333
  UBRR1H = 0x00;
334
  UBRR1L = 51;
335
  UCSR1A |= _BV(U2X1);
336
#elif (XBEE_BAUD == 9600)
337
  /* this is the default baud rate, so do nothing
338
  UBRR1H = 0x00;
339
  UBRR1L = 103;
340
  UCSR1A |= _BV(U2X1);*/
341
#else //Baud rate is defined in the header file, we should not get here
342
  return 0;
343
#endif
344
  delay_ms(50);
345

    
346
  // enter command mode
347
  WL_DEBUG_PRINT("entering command mode 2\r\n");
348
  xbee_send_string("+++");
349
  xbee_wait_for_ok();
350
  WL_DEBUG_PRINT("entered command mode 2\r\n");
351
  
352
  if (xbee_enter_api_mode() != 0) {
353
    WL_DEBUG_PRINT("can't enter api mode\r\n");
354
                return -1;
355
        }
356

    
357
        WL_DEBUG_PRINT("Entered api mode.\r\n");
358

    
359
        if (xbee_exit_command_mode() != 0) {
360
    WL_DEBUG_PRINT("can't exit command mode\r\n");
361
          return -1;
362
        }
363
        
364
        WL_DEBUG_PRINT("Left command mode.\r\n");
365
  
366
  // get MY address
367
        if (xbee_send_read_at_command("BD")) {
368
    WL_DEBUG_PRINT("can't send BD command\r\n");
369
                return -1;
370
        }
371
        WL_DEBUG_PRINT("Getting ATBD rate.\n");
372
  
373
  // get MY address
374
        if (xbee_send_read_at_command("MY")) {
375
    WL_DEBUG_PRINT("can't send my command\r\n");
376
                return -1;
377
        }
378
        WL_DEBUG_PRINT("Getting ATMY address.\n");
379

    
380
#ifndef ROBOT
381
        int i;
382
        for (i = 0; xbee_address == 0 && i < XBEE_GET_PACKET_TIMEOUT; i++) {
383
          ret = xbee_get_packet(NULL);
384

    
385
          usleep(1000);
386
          
387
/*           if (ret == -1) { */
388
/*             WL_DEBUG_PRINT("xbee_get_packet(NULL) failed.\n"); */
389
/*             return -1; */
390
/*           } */
391
        }
392
#else
393
        //wait to return until the address is set
394
  //TODO: this shouldn't wait indefinitely.  There should be some sort of reasonable timeout
395
  // so if the address is never set right, an error can be returned instead of having the
396
  // robot hang forever
397
        while (xbee_address == 0) {
398
          xbee_get_packet(NULL);
399
        }
400
#endif
401
        WL_DEBUG_PRINT("Got ATMY address.\n");
402

    
403
#ifndef ROBOT
404
        if (i == XBEE_GET_PACKET_TIMEOUT) { // We timed-out.
405

    
406
          WL_DEBUG_PRINT("xbee_get_packet timed out.\n");
407
          return -1;
408
        } else {
409
          return 0;
410
        }
411
#else
412
        return 0;
413
#endif
414
}
415

    
416
/**
417
 * Call when finished using the XBee library. This releases
418
 * all sued resources.
419
 **/
420
void xbee_terminate()
421
{
422
        #ifndef ROBOT
423
        pthread_cancel(*xbee_listen_thread);
424
    pthread_join(*xbee_listen_thread, NULL);
425
        free(xbee_listen_thread);
426
        lockf(xbee_stream, F_ULOCK, 0);
427
        close(xbee_stream);
428
  #else
429
  xbee_exit_api_mode();
430
        #endif
431
}
432

    
433
/**
434
 * Send a buffer buf of size bytes to the XBee.
435
 *
436
 * @param buf the buffer of data to send
437
 * @param size the number of bytes to send
438
 **/
439
static int xbee_send(char* buf, int size)
440
{
441
#ifdef ROBOT
442
        int i;
443
        for (i = 0; i < size; i++) {
444
                xbee_putc(buf[i]);
445
        }
446

    
447
        return 0;
448

    
449
#else
450

    
451
        int ret = write(xbee_stream, buf, size);
452
        //success
453
        if (ret == size)
454
                return 0;
455
        if (ret == -1)
456
        {
457
                //interrupted by system signal, probably timer interrupt.
458
                //just try again
459
                if (errno == 4)
460
                {
461
                        return xbee_send(buf, size);
462
                }
463
                WL_DEBUG_PRINT("Failed to write to xbee\r\n");
464
                return -1;
465
        }
466

    
467
        //write was interrupted after writing ret bytes
468
        return xbee_send(buf + ret, size - ret);
469
#endif
470
}
471

    
472
/**
473
 * Sends a string to the XBee.
474
 *
475
 * @param c the string to send to the XBEE
476
 **/
477
static int xbee_send_string(char* c)
478
{
479
        return xbee_send(c, strlen(c));
480
}
481

    
482
#ifndef ROBOT
483
static int xbee_read(char* buf, int size)
484
{
485
        if (read(xbee_stream, buf, size) == -1) {
486
                WL_DEBUG_PRINT("Failed to read from xbee.\r\n");
487
                return -1;
488
        }
489

    
490
        return 0;
491
}
492
#endif
493

    
494
/**
495
 * Enter into command mode.
496
 **/
497
static int xbee_enter_command_mode()
498
{
499
        if (xbee_send_string("+++") != 0) {
500
                return -1;
501
        }
502

    
503
        if (xbee_wait_for_ok() != 0) {
504
          return -1;
505
        }
506
          return 0;
507
}
508

    
509
/**
510
 * Exit from command mode.
511
 **/
512
static int xbee_exit_command_mode()
513
{
514
        if (xbee_send_string("ATCN\r") != 0) {
515
                return -1;
516
        }
517

    
518
        xbee_wait_for_ok();
519

    
520
        return 0;
521
}
522

    
523
/**
524
 * Enter API mode.
525
 **/
526
static int xbee_enter_api_mode()
527
{
528
        if (xbee_send_string("ATAP 1\r") != 0) {
529
                return -1;
530
        }
531
        xbee_wait_for_ok();
532

    
533
        return 0;
534
}
535

    
536
/**
537
 * Exit API mode.
538
 **/
539
static int xbee_exit_api_mode()
540
{
541
        if (xbee_send_modify_at_command("AP","0") != 0) {
542
                return -1;
543
        }
544

    
545
        return 0;
546
}
547

    
548
/**
549
 * Wait until the string "OK\r" is received from the XBee.
550
 **/
551
static int xbee_wait_for_ok()
552
{
553
        return xbee_wait_for_string("OK\r", 3);
554
}
555

    
556
/**
557
 * Delay until the specified string is received from
558
 * the XBee. Discards all other XBee data.
559
 *
560
 * ********* Robot often hangs here ****************
561
 *
562
 * @param s the string to receive
563
 * @param len the length of the string
564
 **/
565
static int xbee_wait_for_string(char* s, int len)
566
{
567
        char* curr = s;
568
  unsigned int i=0;
569
        while (curr - s < len) {
570
    WL_DEBUG_PRINT("waiting for string\r\n");
571
                // check if buffer is empty
572
                if (buffer_last != buffer_first) {
573
                        char c = arrival_buf[buffer_first++];
574
                        if (buffer_first == XBEE_BUFFER_SIZE) {
575
                                buffer_first = 0;
576
                        }
577
      WL_DEBUG_PRINT("buffer char|");
578
      WL_DEBUG_PRINT_CHAR(c);
579
      WL_DEBUG_PRINT("|\r\n");
580

    
581
                        if (c == *curr) {
582
                                curr++;
583
                        } else {
584
#ifndef ROBOT
585
                          //return -1; // Computer is less forgiving.
586
                          curr = s;
587
#else
588
                          curr = s;
589
#endif
590
                        }
591
                } // else buffer is empty.
592

    
593
#ifndef ROBOT
594
                usleep(100);
595
#endif
596
        }
597
  if (i >= 10000)
598
    return -1;
599

    
600
        return 0;
601
}
602

    
603
/**
604
 * Verifies that the packets checksum is correct.
605
 * (If the checksum is correct, the sum of the bytes
606
 * is 0xFF.)
607
 *
608
 * @param packet the packet received. This includes the first
609
 * three bytes, which are header information from the XBee.
610
 *
611
 * @param len The length of the packet received from the XBee
612
 *
613
 * @return 0 if the checksum is incorrect, nonzero
614
 * otherwise
615
 **/
616
int xbee_verify_checksum(char* packet, int len)
617
{
618
        unsigned char sum = 0;
619
        int i;
620
        for (i = 3; i < len; i++)
621
                sum += (unsigned char)packet[i];
622
        return sum == 0xFF;
623
}
624

    
625
/**
626
 * Returns the checksum of the given packet.
627
 *
628
 * @param buf the data for the packet to send
629
 * @param len the length of the packet in bytes
630
 *
631
 * @return the checksum of the packet, which will
632
 * become the last byte sent in the packet
633
 **/
634
char xbee_compute_checksum(char* buf, int len)
635
{
636
        int i;
637
        unsigned char sum = 0;
638
        for (i = 0; i < len; i++)
639
                sum += (unsigned char)buf[i];
640
        return 0xFF - sum;
641
}
642

    
643
/**
644
 * Adds header information and checksum to the given
645
 * packet and sends it. Header information includes
646
 * XBEE_FRAME_START and the packet length, as two bytes.
647
 *
648
 * @param buf the packet data
649
 * @param len the size in bytes of the packet data
650
 *
651
 **/
652
static int xbee_send_frame(char* buf, int len)
653
{
654
        char prefix[3];
655
        prefix[0] = XBEE_FRAME_START;
656
        prefix[1] = (len & 0xFF00) >> 8;
657
        prefix[2] = len & 0xFF;
658
        char checksum = xbee_compute_checksum(buf, len);
659

    
660
        if (xbee_send(prefix, 3) != 0) {
661
                return -1;
662
        }
663

    
664
        if (xbee_send(buf, len) != 0) {
665
                return -1;
666
        }
667

    
668
        if (xbee_send(&checksum, 1) != 0) {
669
                return -1;
670
        }
671

    
672
        return 0;
673
}
674

    
675
/**
676
 * Sends an AT command to read a parameter.
677
 *
678
 * @param command the AT command to send. For exmaple,
679
 * use ID to read the PAN ID and MY to return the XBee ID.
680
 * See the XBee reference guide for a complete listing.
681
 **/
682
int xbee_send_read_at_command(char* command)
683
{
684
        return xbee_send_modify_at_command(command, NULL);
685
}
686

    
687
/**
688
 * Sends the given AT command.
689
 *
690
 * @param command the AT command to send (e.g., MY, ID)
691
 * @param value the value to pass as a parameter
692
 * (or NULL if there is no parameter)
693
 **/
694
static int xbee_send_modify_at_command(char* command, char* value)
695
{
696
        char buf[16];
697
        int i;
698

    
699
        buf[0] = XBEE_FRAME_AT_COMMAND;
700
        buf[1] = 1;
701
        buf[2] = command[0];
702
        buf[3] = command[1];
703
        int valueLen = 0;
704
        if (value != NULL)
705
        {
706
                valueLen = strlen(value);
707
                if (valueLen > 8)
708
                {
709
                        WL_DEBUG_PRINT("AT Command too large.\r\n");
710
                        return -1;
711
                }
712

    
713
                for (i = 0; i < valueLen; i++) {
714
                        buf[4 + i] = value[i];
715
                }
716
        }
717

    
718
        return xbee_send_frame(buf, 4 + valueLen);
719
}
720

    
721
/**
722
 * Send the specified packet.
723
 *
724
 * @param packet the packet data to send
725
 * @param len the number of bytes in the packet
726
 *
727
 * @param dest the ID of the XBee to send the packet to,
728
 * or XBEE_BROADCAST to send the message to all robots
729
 * in the PAN.
730
 *
731
 * @param options a combination of the flags
732
 * XBEE_OPTIONS_NONE, XBEE_OPTIONS_DISABLE_RESPONSE and
733
 * XBEE_OPTIONS_BROADCAST_ALL_PANS
734
 *
735
 * @param frame the frame number to associate this packet
736
 * with. This will be used to identify the response when
737
 * the XBee alerts us as to whether or not our message
738
 * was received.
739
 **/
740
int xbee_send_packet(char* packet, int len, int dest, char options, char frame)
741
{
742
        char buf[5];
743
        char prefix[3];
744
        int i;
745
        unsigned char checksum = 0;
746

    
747
        if (len > 100)
748
        {
749
                WL_DEBUG_PRINT("Packet is too large.\r\n");
750
                return -1;
751
        }
752

    
753
        //data for sending request
754
        buf[0] = XBEE_FRAME_TX_REQUEST_16;
755
        buf[1] = frame;
756
        buf[2] = (dest >> 8) & 0xFF;
757
        buf[3] = dest & 0xFF;
758
        buf[4] = options;
759

    
760
        //packet prefix, do this here so we don't need an extra buffer
761
        prefix[0] = XBEE_FRAME_START;
762
        prefix[1] = ((5 + len) & 0xFF00) >> 8;
763
        prefix[2] = (5 + len) & 0xFF;
764

    
765
        for (i = 0; i < 5; i++)
766
                checksum += (unsigned char)buf[i];
767
        for (i = 0; i < len; i++)
768
                checksum += (unsigned char)packet[i];
769
        checksum = 0xFF - checksum;
770

    
771
        if (xbee_send(prefix, 3) != 0) {
772
                return -1;
773
        }
774

    
775
        if (xbee_send(buf, 5) != 0) {
776
                return -1;
777
        }
778

    
779
        if (xbee_send(packet, len) != 0) {
780
                return -1;
781
        }
782

    
783
        if (xbee_send((char*)&checksum, 1) != 0) {
784
                return -1;
785
        }
786

    
787
        return 0;
788
}
789

    
790
/**
791
 * Reads a packet received from the XBee. This function
792
 * is non-blocking. The resulting packet is stored in dest.
793
 * Only returns transmission response packets and
794
 * received packets. The returned packet does not include
795
 * header information or the checksum. This method also
796
 * handles special packets dealt with by the XBee library,
797
 * and so should be called frequently while the XBee is in
798
 * use.<br><br>
799
 *
800
 * The first byte of the packet will be either
801
 * XBEE_TX_STATUS or XBEE_RX to indicated
802
 * a response to a sent message or a received message,
803
 * respectively.<br><br>
804
 *
805
 * For a status response packet:<br>
806
 * The first byte will be XBEE_TX_STATUS.<br>
807
 * The second byte will be the frame number.<br>
808
 * The third byte will be the result. 0 indicates success,
809
 * and nonzero indicates that an error ocurred in
810
 * transmitting the packet.<br><br>
811
 *
812
 * For a received packet:<br>
813
 * The first byte will be XBEE_RX.<br>
814
 * The second and third bytes will be the 16-bit
815
 * address of the packet's sender.<br>
816
 * The fourth byte is the signal strength.<br>
817
 * The fifth byte is 1 if the packet were sent to
818
 * a specific address, and 2 if it is a broadcast packet.<br><br>
819
 *
820
 * @param dest set to the packet data
821
 * @return the length of the packet, or -1 if no packet
822
 * is available
823
 **/
824
int xbee_get_packet(unsigned char* dest)
825
{
826
     int ret;
827
        //start reading a packet with XBEE_FRAME_START
828
        if (currentBufPos == 0)
829
        {
830
                do
831
                {
832
                        if (buffer_first == XBEE_BUFFER_SIZE)
833
                                buffer_first = 0;
834
                        // check if buffer is empty
835
                        if (buffer_first == buffer_last) {
836
        WL_DEBUG_PRINT("buffer empty\r\n");
837
                                return -1;
838
                        }
839
                } while (arrival_buf[buffer_first++] != XBEE_FRAME_START);
840

    
841
                if (buffer_first == XBEE_BUFFER_SIZE) {
842
                        buffer_first = 0;
843
                }
844
                xbee_buf[0] = XBEE_FRAME_START;
845
                currentBufPos++;
846
        }
847

    
848
        int len = -1;
849
        if (currentBufPos >= 3) {
850
                len = (int)xbee_buf[2] + ((int)xbee_buf[1] << 8);
851
        }
852

    
853
        while (len == -1 //packet length has not been read yet
854
                || currentBufPos < len + 4)
855
        {
856
                if (currentBufPos == 3)
857
                {
858
                        len = (int)xbee_buf[2] + ((int)xbee_buf[1] << 8);
859
                        if (len > 120)
860
                        {
861
                                WL_DEBUG_PRINT("Packet too large. Probably error in XBee transmission.\r\n");
862
                                currentBufPos = 0;
863
                                return -1;
864
                        }
865
                }
866

    
867
                // check if buffer is empty
868
                if (buffer_first == buffer_last) {
869
      WL_DEBUG_PRINT("Buffer empty 2\r\n");
870
                        return -1;
871
                }
872
                xbee_buf[currentBufPos++] = arrival_buf[buffer_first++];
873
                if (buffer_first == XBEE_BUFFER_SIZE) {
874
                        buffer_first = 0;
875
                }
876
        }
877

    
878
        currentBufPos = 0;
879

    
880
        if (!xbee_verify_checksum(xbee_buf, len + 4))
881
        {
882
                WL_DEBUG_PRINT("XBee checksum failed.\r\n");
883
                return -1;
884
        }
885

    
886
        //we will take care of the packet
887
        
888
        ret = xbee_handle_packet(xbee_buf+3, len);
889
        if (ret == 1) {
890
                return 3;
891
        } else if (ret == -1) {
892
    WL_DEBUG_PRINT("xbee_handle_packet returned -1\r\n");
893
    return -2;
894
  }
895
        
896
        if (dest == NULL) {
897
    WL_DEBUG_PRINT("dest buffer is null\r\n");
898
                return -1;
899
        }
900

    
901
        int i;
902
        for (i = 3; i < len + 3; i++) {
903
                dest[i - 3] = xbee_buf[i];
904
        }
905
        return len;
906
}
907

    
908
/**
909
 * Handles modem status packets.
910
 *
911
 * @param status the type of status packet received.
912
 **/
913
void xbee_handle_status(char status)
914
{
915
        switch (status)
916
        {
917
                case 0:
918
                        WL_DEBUG_PRINT("XBee hardware reset.\r\n");
919
                        break;
920
                case 1:
921
                        WL_DEBUG_PRINT("Watchdog timer reset.\r\n");
922
                        break;
923
                case 2:
924
                        WL_DEBUG_PRINT("Associated.\r\n");
925
                        break;
926
                case 3:
927
                        WL_DEBUG_PRINT("Disassociated.\r\n");
928
                        break;
929
                case 4:
930
                        WL_DEBUG_PRINT("Synchronization lost.\r\n");
931
                        break;
932
                case 5:
933
                        WL_DEBUG_PRINT("Coordinator realignment.\r\n");
934
                        break;
935
                case 6:
936
                        WL_DEBUG_PRINT("Coordinator started.\r\n");
937
                        break;
938
        }
939
}
940

    
941
/**
942
 * Handles AT command response packets.
943
 * @param command the two character AT command, e.g. MY or ID
944
 * @param result 0 for success, 1 for an error
945
 * @param extra the hex value of the requested register
946
 * @param extraLen the length in bytes of extra
947
 **/
948
static int xbee_handle_at_command_response(char* command, char result, char* extra, int extraLen)
949
{
950
        if (result == 1)
951
        {
952
                WL_DEBUG_PRINT("Error with AT");
953
                WL_DEBUG_PRINT(command);
954
                WL_DEBUG_PRINT(" packet. Result = ");
955
    switch(result) {
956
    case 1:
957
      WL_DEBUG_PRINT("ERROR\r\n");
958
      break;
959
    case 2:
960
      WL_DEBUG_PRINT("Invalid Command\r\n");
961
      break;
962
    case 3:
963
      WL_DEBUG_PRINT("Invalid Parameter\r\n");
964
      break;
965
    }
966
    return -1;
967
        }
968
        WL_DEBUG_PRINT("AT");
969
        WL_DEBUG_PRINT(command);
970
        WL_DEBUG_PRINT(" command was successful.\r\n");
971

    
972
        if (command[0] == 'I' && command[1] == 'D')
973
        {
974
                xbee_panID = xbee_pending_panID;
975
                WL_DEBUG_PRINT("PAN ID set to ");
976
                WL_DEBUG_PRINT_INT(xbee_panID);
977
                WL_DEBUG_PRINT(".\r\n");
978
                return 0;
979
        }
980

    
981
        if (command[0] == 'C' && command[1] == 'H')
982
        {
983
                xbee_channel = xbee_pending_channel;
984
                WL_DEBUG_PRINT("Channel set to ");
985
                WL_DEBUG_PRINT_INT(xbee_channel);
986
                WL_DEBUG_PRINT(".\r\n");
987
                return 0;
988
        }
989
  
990
  if (command[0] == 'N' && command[1] == 'D')
991
        {
992
                WL_DEBUG_PRINT("ND - extra=");
993
    WL_DEBUG_PRINT(extra);
994
                WL_DEBUG_PRINT("\r\n");
995
                return 0;
996
        }
997
  
998
   if (command[0] == 'B' && command[1] == 'D')
999
        {
1000
                WL_DEBUG_PRINT("BD - extra=");
1001
    WL_DEBUG_PRINT(extra);
1002
                WL_DEBUG_PRINT("\r\n");
1003
                return 0;
1004
        }
1005

    
1006
        if (command[0] == 'M' && command[1] == 'Y' && extraLen != 0)
1007
        {
1008
                xbee_address = 0;
1009
                int i;
1010
                for (i = 0; i < extraLen; i++) {
1011
                        xbee_address = (xbee_address << 8) + extra[i];
1012
                }
1013

    
1014
                WL_DEBUG_PRINT("XBee address is ");
1015
                WL_DEBUG_PRINT_INT(xbee_address);
1016
                WL_DEBUG_PRINT(".\r\n");
1017

    
1018
                if (xbee_address == 0)
1019
                {
1020
                        WL_DEBUG_PRINT("XBee 16-bit address must be set using ATMY.\r\n");
1021
                        #ifndef ROBOT
1022
                        exit(0);
1023
                        #endif
1024
                }
1025
        }
1026
  return 0;
1027
}
1028

    
1029
/**
1030
 * Attempts to handle the packet if it is dealt with
1031
 * by the library.
1032
 * We will handle the following packet types:
1033
 *    Modem Status
1034
 *    AT Command Response
1035
 *
1036
 * @param packet the packet to handle
1037
 * @param len the length of the packet
1038
 *
1039
 * @return 1 if we have handled the packet, 0 otherwise
1040
 */
1041
static int xbee_handle_packet(char* packet, int len)
1042
{
1043

    
1044
        char command[3] = {1, 2, 3};
1045
        if (len <= 0) //this should not happend
1046
        {
1047
                WL_DEBUG_PRINT("Non-positive packet length.\r\n");
1048
                return 0;
1049
        }
1050

    
1051
        switch ((unsigned char)packet[0]) //packet type
1052
        {
1053
                case XBEE_FRAME_STATUS:
1054
                        xbee_handle_status(packet[1]);
1055
                        return 1;
1056
                case XBEE_FRAME_AT_COMMAND_RESPONSE:
1057
                        command[0] = packet[2];
1058
                        command[1] = packet[3];
1059
                        command[2] = 0;
1060
                        if (xbee_handle_at_command_response(command, packet[4], packet + 5, len - 5) != 0)
1061
        return -1;
1062
      else
1063
        return 1;
1064
        }
1065
        return 0;
1066
}
1067

    
1068
/**
1069
 * Sets the personal area network id.
1070
 *
1071
 * @param id the new personal area network (PAN) id
1072
 **/
1073
int xbee_set_pan_id(int id)
1074
{
1075
        char s[3];
1076
        s[0] = (id >> 8) & 0xFF;
1077
        s[1] = id & 0xFF;
1078
        s[2] = 0;
1079
        xbee_pending_panID = id;
1080
        return xbee_send_modify_at_command("ID", s);
1081
}
1082

    
1083
/**
1084
 * Get the PAN ID for the XBee.
1085
 *
1086
 * @return the personal area network id, or
1087
 * XBEE_PAN_DEFAULT if it has not yet been set.
1088
 **/
1089
unsigned int xbee_get_pan_id()
1090
{
1091
        return xbee_panID;
1092
}
1093

    
1094
/**
1095
 * Set the channel the XBee is using.
1096
 *
1097
 * @param channel the channel the XBee will not use,
1098
 * between 0x0B and 0x1A
1099
 *
1100
 * @see xbee_get_channel
1101
 **/
1102
int xbee_set_channel(int channel)
1103
{
1104
        if (channel < 0x0B || channel > 0x1A)
1105
        {
1106
                WL_DEBUG_PRINT("Channel out of range.\r\n");
1107
                return -1;
1108
        }
1109

    
1110
        char s[3];
1111
        s[0] = channel & 0xFF;
1112
        s[1] = 0;
1113
        xbee_pending_channel = channel;
1114

    
1115
        return xbee_send_modify_at_command("CH", s);
1116
}
1117

    
1118
/**
1119
 * Returns the channel which the XBee is currently using.
1120
 *
1121
 * @return the channel the XBee is using
1122
 *
1123
 * @see xbee_set_channel
1124
 **/
1125
int xbee_get_channel(void)
1126
{
1127
        return xbee_channel;
1128
}
1129

    
1130
/**
1131
 * Get the 16-bit address of the XBee.
1132
 * This is used to specify who to send messages to
1133
 * and who messages are from.
1134
 *
1135
 * @return the 16-bit address of the XBee.
1136
 **/
1137
unsigned int xbee_get_address()
1138
{
1139
        return xbee_address;
1140
}
1141

    
1142
#ifndef ROBOT
1143
void xbee_set_com_port(char* port)
1144
{
1145
        xbee_com_port = port;
1146
}
1147
#endif
1148

    
1149
/**@} **/ // end xbee group
1150