Project

General

Profile

Statistics
| Revision:

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

History | View | Annotate | Download (24.8 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 uint8_t xbee_basic_buf[PACKET_BUFFER_SIZE];
116
static uint8_t xbee_other_buf[PACKET_BUFFER_SIZE];
117
static int currentBufPos = 0;
118
static uint8_t basic_buf_first = 0;        // beginning of first packet in basic buffer
119
static uint8_t basic_buf_last = 0;        // end of last packet in basic buffer
120
static uint8_t other_buf_first = 0; // beginning of first packet in other buffer
121
static uint8_t other_buf_last = 0;  // end of last packet in other buffer
122

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

    
130

    
131
/**@addtogroup xbee
132
 * @{ **/
133

    
134

    
135
/*Function Implementations*/
136

    
137
#ifdef ROBOT
138

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

    
173
#else
174

    
175
// Computer code
176

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

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

    
200
                usleep(1000);
201
        }
202

    
203
        return NULL;
204
}
205

    
206
#endif
207

    
208
/**
209
 * Initializes the XBee library so that other functions may be used.
210
 **/
211
int xbee_lib_init()
212
{
213
  if (xbee_init() != 0) {
214
    usb_puts("xbee_init error");
215
    return -1;
216
  }
217

    
218
        WL_DEBUG_PRINT("in xbee_init\n");
219
#ifdef ROBOT
220

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

    
246
        // set baud rate, etc. correctly
247
        struct termios options;
248

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

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

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

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

    
284
        WL_DEBUG_PRINT("Entering command mode.\r\n");
285

    
286
        if (xbee_enter_command_mode() != 0) {
287
    usb_puts("error entering command mode\r\n");
288
                return -1;
289
        }
290

    
291
        WL_DEBUG_PRINT("Entered command mode.\r\n");
292

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

    
352
  // enter command mode
353
  WL_DEBUG_PRINT("entering command mode 2\r\n");
354
  xbee_send_string("+++");
355
  xbee_wait_for_ok();
356
  WL_DEBUG_PRINT("entered command mode 2\r\n");
357
  
358
  if (xbee_enter_api_mode() != 0) {
359
    WL_DEBUG_PRINT("can't enter api mode\r\n");
360
                return -1;
361
        }
362

    
363
        WL_DEBUG_PRINT("Entered api mode.\r\n");
364

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

    
386
#ifndef ROBOT
387
        int i;
388
        for (i = 0; xbee_address == 0 && i < XBEE_GET_PACKET_TIMEOUT; i++) {
389
          ret = xbee_get_packet(NULL);
390

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

    
409
#ifndef ROBOT
410
        if (i == XBEE_GET_PACKET_TIMEOUT) { // We timed-out.
411

    
412
          WL_DEBUG_PRINT("xbee_get_packet timed out.\n");
413
          return -1;
414
        } else {
415
          return 0;
416
        }
417
#else
418
        return 0;
419
#endif
420
}
421

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

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

    
453
        return 0;
454

    
455
#else
456

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

    
473
        //write was interrupted after writing ret bytes
474
        return xbee_send(buf + ret, size - ret);
475
#endif
476
}
477

    
478
/**
479
 * Sends a string to the XBee.
480
 *
481
 * @param c the string to send to the XBEE
482
 **/
483
static int xbee_send_string(char* c)
484
{
485
        return xbee_send(c, strlen(c));
486
}
487

    
488
#ifndef ROBOT
489
static int xbee_read(char* buf, int size)
490
{
491
        if (read(xbee_stream, buf, size) == -1) {
492
                WL_DEBUG_PRINT("Failed to read from xbee.\r\n");
493
                return -1;
494
        }
495

    
496
        return 0;
497
}
498
#endif
499

    
500
/**
501
 * Enter into command mode.
502
 **/
503
static int xbee_enter_command_mode()
504
{
505
        if (xbee_send_string("+++") != 0) {
506
                return -1;
507
        }
508

    
509
        if (xbee_wait_for_ok() != 0) {
510
          return -1;
511
        }
512
          return 0;
513
}
514

    
515
/**
516
 * Exit from command mode.
517
 **/
518
static int xbee_exit_command_mode()
519
{
520
        if (xbee_send_string("ATCN\r") != 0) {
521
                return -1;
522
        }
523

    
524
        xbee_wait_for_ok();
525

    
526
        return 0;
527
}
528

    
529
/**
530
 * Enter API mode.
531
 **/
532
static int xbee_enter_api_mode()
533
{
534
        if (xbee_send_string("ATAP 1\r") != 0) {
535
                return -1;
536
        }
537
        xbee_wait_for_ok();
538

    
539
        return 0;
540
}
541

    
542
/**
543
 * Exit API mode.
544
 **/
545
static int xbee_exit_api_mode()
546
{
547
        if (xbee_send_modify_at_command("AP","0") != 0) {
548
                return -1;
549
        }
550

    
551
        return 0;
552
}
553

    
554
/**
555
 * Wait until the string "OK\r" is received from the XBee.
556
 **/
557
static int xbee_wait_for_ok()
558
{
559
        return xbee_wait_for_string("OK\r", 3);
560
}
561

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

    
587
                        if (c == *curr) {
588
                                curr++;
589
                        } else {
590
#ifndef ROBOT
591
                          //return -1; // Computer is less forgiving.
592
                          curr = s;
593
#else
594
                          curr = s;
595
#endif
596
                        }
597
                } // else buffer is empty.
598

    
599
#ifndef ROBOT
600
                usleep(100);
601
#endif
602
        }
603
  if (i >= 10000)
604
    return -1;
605

    
606
        return 0;
607
}
608

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

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

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

    
666
        if (xbee_send(prefix, 3) != 0) {
667
                return -1;
668
        }
669

    
670
        if (xbee_send(buf, len) != 0) {
671
                return -1;
672
        }
673

    
674
        if (xbee_send(&checksum, 1) != 0) {
675
                return -1;
676
        }
677

    
678
        return 0;
679
}
680

    
681
/**
682
 * Sends an AT command to read a parameter.
683
 *
684
 * @param command the AT command to send. For exmaple,
685
 * use ID to read the PAN ID and MY to return the XBee ID.
686
 * See the XBee reference guide for a complete listing.
687
 **/
688
int xbee_send_read_at_command(char* command)
689
{
690
        return xbee_send_modify_at_command(command, NULL);
691
}
692

    
693
/**
694
 * Sends the given AT command.
695
 *
696
 * @param command the AT command to send (e.g., MY, ID)
697
 * @param value the value to pass as a parameter
698
 * (or NULL if there is no parameter)
699
 **/
700
static int xbee_send_modify_at_command(char* command, char* value)
701
{
702
        char buf[16];
703
        int i;
704

    
705
        buf[0] = XBEE_FRAME_AT_COMMAND;
706
        buf[1] = 1;
707
        buf[2] = command[0];
708
        buf[3] = command[1];
709
        int valueLen = 0;
710
        if (value != NULL)
711
        {
712
                valueLen = strlen(value);
713
                if (valueLen > 8)
714
                {
715
                        WL_DEBUG_PRINT("AT Command too large.\r\n");
716
                        return -1;
717
                }
718

    
719
                for (i = 0; i < valueLen; i++) {
720
                        buf[4 + i] = value[i];
721
                }
722
        }
723

    
724
        return xbee_send_frame(buf, 4 + valueLen);
725
}
726

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

    
753
        if (len > 100)
754
        {
755
                WL_DEBUG_PRINT("Packet is too large.\r\n");
756
                return -1;
757
        }
758

    
759
        //data for sending request
760
        buf[0] = XBEE_FRAME_TX_REQUEST_16;
761
        buf[1] = frame;
762
        buf[2] = (dest >> 8) & 0xFF;
763
        buf[3] = dest & 0xFF;
764
        buf[4] = options;
765

    
766
        //packet prefix, do this here so we don't need an extra buffer
767
        prefix[0] = XBEE_FRAME_START;
768
        prefix[1] = ((5 + len) & 0xFF00) >> 8;
769
        prefix[2] = (5 + len) & 0xFF;
770

    
771
        for (i = 0; i < 5; i++)
772
                checksum += (unsigned char)buf[i];
773
        for (i = 0; i < len; i++)
774
                checksum += (unsigned char)packet[i];
775
        checksum = 0xFF - checksum;
776

    
777
        if (xbee_send(prefix, 3) != 0) {
778
                return -1;
779
        }
780

    
781
        if (xbee_send(buf, 5) != 0) {
782
                return -1;
783
        }
784

    
785
        if (xbee_send(packet, len) != 0) {
786
                return -1;
787
        }
788

    
789
        if (xbee_send((char*)&checksum, 1) != 0) {
790
                return -1;
791
        }
792

    
793
        return 0;
794
}
795

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

    
847
                if (buffer_first == XBEE_BUFFER_SIZE) {
848
                        buffer_first = 0;
849
                }
850
                xbee_buf[0] = XBEE_FRAME_START;
851
                currentBufPos++;
852
        }
853

    
854
        int len = -1;
855
        if (currentBufPos >= 3) {
856
                len = (int)xbee_buf[2] + ((int)xbee_buf[1] << 8);
857
        }
858

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

    
873
                // check if buffer is empty
874
                if (buffer_first == buffer_last) {
875
      WL_DEBUG_PRINT("Buffer empty 2\r\n");
876
                        return -1;
877
                }
878
                xbee_buf[currentBufPos++] = arrival_buf[buffer_first++];
879
                if (buffer_first == XBEE_BUFFER_SIZE) {
880
                        buffer_first = 0;
881
                }
882
        }
883

    
884
        currentBufPos = 0;
885

    
886
        if (!xbee_verify_checksum(xbee_buf, len + 4))
887
        {
888
                WL_DEBUG_PRINT("XBee checksum failed.\r\n");
889
                return -1;
890
        }
891

    
892
        //we will take care of the packet
893
        
894
        ret = xbee_handle_packet(xbee_buf+3, len);
895
        if (ret == 1) {
896
                return 3;
897
        } else if (ret == -1) {
898
    WL_DEBUG_PRINT("xbee_handle_packet returned -1\r\n");
899
    return -2;
900
  }
901
        
902
        if (dest == NULL) {
903
    WL_DEBUG_PRINT("dest buffer is null\r\n");
904
                return -1;
905
        }
906

    
907
        int i;
908
        for (i = 3; i < len + 3; i++) {
909
                dest[i - 3] = xbee_buf[i];
910
        }
911
        return len;
912
}
913

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

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

    
978
        if (command[0] == 'I' && command[1] == 'D')
979
        {
980
                xbee_panID = xbee_pending_panID;
981
                WL_DEBUG_PRINT("PAN ID set to ");
982
                WL_DEBUG_PRINT_INT(xbee_panID);
983
                WL_DEBUG_PRINT(".\r\n");
984
                return 0;
985
        }
986

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

    
1012
        if (command[0] == 'M' && command[1] == 'Y' && extraLen != 0)
1013
        {
1014
                xbee_address = 0;
1015
                int i;
1016
                for (i = 0; i < extraLen; i++) {
1017
                        xbee_address = (xbee_address << 8) + extra[i];
1018
                }
1019

    
1020
                WL_DEBUG_PRINT("XBee address is ");
1021
                WL_DEBUG_PRINT_INT(xbee_address);
1022
                WL_DEBUG_PRINT(".\r\n");
1023

    
1024
                if (xbee_address == 0)
1025
                {
1026
                        WL_DEBUG_PRINT("XBee 16-bit address must be set using ATMY.\r\n");
1027
                        #ifndef ROBOT
1028
                        exit(0);
1029
                        #endif
1030
                }
1031
        }
1032
  return 0;
1033
}
1034

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

    
1050
        char command[3] = {1, 2, 3};
1051
        if (len <= 0) //this should not happend
1052
        {
1053
                WL_DEBUG_PRINT("Non-positive packet length.\r\n");
1054
                return 0;
1055
        }
1056

    
1057
        switch ((unsigned char)packet[0]) //packet type
1058
        {
1059
                case XBEE_FRAME_STATUS:
1060
                        xbee_handle_status(packet[1]);
1061
                        return 1;
1062
                case XBEE_FRAME_AT_COMMAND_RESPONSE:
1063
                        command[0] = packet[2];
1064
                        command[1] = packet[3];
1065
                        command[2] = 0;
1066
                        if (xbee_handle_at_command_response(command, packet[4], packet + 5, len - 5) != 0)
1067
        return -1;
1068
      else
1069
        return 1;
1070
        }
1071
        return 0;
1072
}
1073

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

    
1089
/**
1090
 * Get the PAN ID for the XBee.
1091
 *
1092
 * @return the personal area network id, or
1093
 * XBEE_PAN_DEFAULT if it has not yet been set.
1094
 **/
1095
unsigned int xbee_get_pan_id()
1096
{
1097
        return xbee_panID;
1098
}
1099

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

    
1116
        char s[3];
1117
        s[0] = channel & 0xFF;
1118
        s[1] = 0;
1119
        xbee_pending_channel = channel;
1120

    
1121
        return xbee_send_modify_at_command("CH", s);
1122
}
1123

    
1124
/**
1125
 * Returns the channel which the XBee is currently using.
1126
 *
1127
 * @return the channel the XBee is using
1128
 *
1129
 * @see xbee_set_channel
1130
 **/
1131
int xbee_get_channel(void)
1132
{
1133
        return xbee_channel;
1134
}
1135

    
1136
/**
1137
 * Get the 16-bit address of the XBee.
1138
 * This is used to specify who to send messages to
1139
 * and who messages are from.
1140
 *
1141
 * @return the 16-bit address of the XBee.
1142
 **/
1143
unsigned int xbee_get_address()
1144
{
1145
        return xbee_address;
1146
}
1147

    
1148
#ifndef ROBOT
1149
void xbee_set_com_port(char* port)
1150
{
1151
        xbee_com_port = port;
1152
}
1153
#endif
1154

    
1155
/**@} **/ // end xbee group
1156