Project

General

Profile

Statistics
| Revision:

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

History | View | Annotate | Download (25.9 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
/**@addtogroup xbee
63
 * @{ **/
64
 
65
/**@defgroup xbee_const xbee constants 
66
 * @{ **/
67
 
68
// TODO: move constants to xbee.h so they can be used publicly
69

    
70
/**@brief The port to use the XBee from on the computer. **/
71
#ifndef ROBOT
72
#define XBEE_PORT_DEFAULT "/dev/ttyUSB1"
73
#endif
74
 
75
/**@name xbee options
76
 * @{ **/
77
 
78
/**@brief Unset PAN, uses XBee default **/
79
#define XBEE_PAN_DEFAULT 0xFFFF
80
/**@brief Unset channel, uses XBee default **/
81
#define XBEE_CHANNEL_DEFAULT 0
82
/**@brief Broadcast to all robots in the PAN **/
83
#define XBEE_BROADCAST 0xFFFF
84
/**@brief No special options **/
85
#define XBEE_OPTIONS_NONE 0x00
86
/**@brief Do not receive a TX_STATUS message from this packet **/
87
#define XBEE_OPTIONS_DISABLE_RESPONSE 0x01
88
/**@brief Send the packet to all PANS **/
89
#define XBEE_OPTIONS_BROADCAST_ALL_PANS 0x04
90
/**@brief A transmit status packet **/
91
#define XBEE_TX_STATUS 0x89
92
/**@brief A packet received from another XBee **/
93
#define XBEE_RX 0x81
94

    
95
/**@}
96
 * @name xbee frame types
97
 * @{ **/
98

    
99
// TODO: add comments for all of these definitions
100
#define XBEE_FRAME_START 0x7E
101
#define XBEE_GET_PACKET_TIMEOUT 1000
102

    
103
/*Frame Types*/
104
#define XBEE_FRAME_STATUS 0x8A
105
#define XBEE_FRAME_AT_COMMAND 0x08
106
#define XBEE_FRAME_AT_COMMAND_RESPONSE 0x88
107
#define XBEE_FRAME_TX_REQUEST_64 0x00
108
#define XBEE_FRAME_TX_REQUEST_16 0x01
109
#define XBEE_FRAME_TX_STATUS XBEE_TX_STATUS
110
#define XBEE_FRAME_RX_64 0x80
111
#define XBEE_FRAME_RX_16 XBEE_RX
112

    
113
/** @} **/
114

    
115

    
116
// TODO: is this a good size?
117
/*Buffer sizes*/
118
#define XBEE_BUFFER_SIZE        128
119
#define PACKET_BUFFER_SIZE        108
120

    
121
/**@} **/ // end const group
122

    
123
/*Internal Function Prototypes*/
124

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

    
127
/*I/O Functions*/
128
static int xbee_send(char* buf, int size);
129
static int xbee_send_string(char* c);
130

    
131
#ifndef ROBOT
132
static int xbee_read(char* buf, int size);
133
#endif
134

    
135
/*Command Mode Functions
136
 * Called during initialization.
137
 */
138
static int xbee_enter_command_mode(void);
139
static int xbee_exit_command_mode(void);
140
static int xbee_enter_api_mode(void);
141
static int xbee_exit_api_mode(void);
142
static int xbee_wait_for_string(char* s, int len);
143
static int xbee_wait_for_ok(void);
144

    
145
/*API Mode Functions*/
146

    
147
static int xbee_handle_packet(char* packet, int len);
148
static int xbee_handle_at_command_response(char* command, char result, char* extra, int extraLen);
149
static void xbee_handle_status(char status);
150
static int xbee_verify_checksum(char* packet, int len);
151
static char xbee_compute_checksum(char* packet, int len);
152
static int xbee_send_frame(char* buf, int len);
153
int xbee_send_read_at_command(char* command);
154
static int xbee_send_modify_at_command(char* command, char* value);
155

    
156
/*Global Variables*/
157

    
158
#ifndef ROBOT
159
static char* xbee_com_port = XBEE_PORT_DEFAULT;
160
static int xbee_stream;
161
static pthread_t* xbee_listen_thread;
162
#endif
163

    
164
// TODO: clarify buffers, what they're used for, etc
165

    
166
// a buffer for data received from the XBee
167
char arrival_buf[XBEE_BUFFER_SIZE];
168
// location of last unread byte in buffer
169
volatile int buffer_last = 0;
170
// first unread byte in buffer
171
volatile int buffer_first = 0;
172

    
173

    
174
//used to store packets as they are read
175
static char xbee_buf[PACKET_BUFFER_SIZE];
176
static int currentBufPos = 0;
177

    
178
//XBee status
179
static unsigned int xbee_panID = XBEE_PAN_DEFAULT;
180
static unsigned int xbee_pending_panID = XBEE_PAN_DEFAULT;
181
static int xbee_channel = XBEE_CHANNEL_DEFAULT;
182
static int xbee_pending_channel = XBEE_CHANNEL_DEFAULT;
183
static volatile unsigned int xbee_address = 0;
184

    
185

    
186
/*Function Implementations*/
187

    
188
#ifdef ROBOT
189

    
190
/**
191
 * Interrupt for the robot. Adds bytes received from the xbee
192
 * to the buffer.
193
 **/
194
#ifndef FIREFLY
195
ISR(USART1_RX_vect)
196
{
197
        char c = UDR1;
198
        arrival_buf[buffer_last] = c;
199
        int t = buffer_last + 1;
200
        if (t == XBEE_BUFFER_SIZE)
201
                t = 0;
202
        if (t == buffer_first)
203
        {
204
                WL_DEBUG_PRINT("\nOut of space in buffer.\n");
205
        }
206
        buffer_last = t;
207
}
208
#else
209
SIGNAL(SIG_USART0_RECV)
210
{
211
        char c = UDR0;
212
        arrival_buf[buffer_last] = c;
213
        int t = buffer_last + 1;
214
        if (t == XBEE_BUFFER_SIZE)
215
                t = 0;
216
        if (t == buffer_first)
217
        {
218
                WL_DEBUG_PRINT("Out of space in buffer.\n");
219
        }
220
        buffer_last = t;
221
}
222
#endif
223

    
224
#else
225

    
226
// Computer code
227

    
228
/**
229
 * Thread that listens to the xbee.
230
 **/
231
static void* listen_to_xbee(void* x)
232
{
233
        char c;
234
        while (1)
235
        {
236
                if (xbee_read(&c, 1) != 0) {
237
                        WL_DEBUG_PRINT("xbee_read failed.\n");
238
                        return NULL;
239
                }
240

    
241
                arrival_buf[buffer_last] = c;
242
                int t = buffer_last + 1;
243
                if (t == XBEE_BUFFER_SIZE)
244
                        t = 0;
245
                if (t == buffer_first)
246
                {
247
                        WL_DEBUG_PRINT("Out of space in buffer.\n");
248
                }
249
                buffer_last = t;
250

    
251
                usleep(1000);
252
        }
253

    
254
        return NULL;
255
}
256

    
257
#endif
258

    
259
/**
260
 * Initializes the XBee library so that other functions may be used.
261
 **/
262
int xbee_lib_init()
263
{
264
  if (xbee_init() != 0) {
265
    usb_puts("xbee_init error");
266
    return -1;
267
  }
268

    
269
        WL_DEBUG_PRINT("in xbee_init\n");
270
#ifdef ROBOT
271

    
272
        //enable the receiving interrupt
273
#ifdef FIREFLY
274
        UCSR0B |= _BV(RXCIE) | _BV(RXEN);
275
#else
276
#ifdef BAYBOARD
277
        UCSR1B |= _BV(RXCIE1);
278
#else
279
        UCSR1B |= _BV(RXCIE);
280
#endif
281
#endif
282
        sei();
283
#else
284
        xbee_stream = open(xbee_com_port, O_RDWR);
285
        if (xbee_stream == -1/* || lockf(xbee_stream, F_TEST, 0) != 0*/)
286
        {
287
                WL_DEBUG_PRINT("Failed to open connection to XBee on port ");
288
                WL_DEBUG_PRINT_INT(xbee_com_port);
289
                WL_DEBUG_PRINT(".\n");
290
                return -1;
291
        } else {
292
          WL_DEBUG_PRINT("Successfully opened connection to XBee on port ");
293
                WL_DEBUG_PRINT_INT(xbee_com_port);
294
                WL_DEBUG_PRINT(".\n");
295
        }
296

    
297
        // set baud rate, etc. correctly
298
        struct termios options;
299

    
300
        tcgetattr(xbee_stream, &options);
301
        cfsetispeed(&options, B9600);
302
        cfsetospeed(&options, B9600);
303
        options.c_iflag &= ~ICRNL;
304
        options.c_oflag &= ~OCRNL;
305
        options.c_cflag |= (CLOCAL | CREAD);
306
        options.c_cflag &= ~PARENB;
307
        options.c_cflag &= ~CSTOPB;
308
        options.c_cflag &= ~CSIZE;
309
        options.c_cflag |= CS8;
310
        options.c_lflag &= ~ICANON;
311
        options.c_cc[VMIN] = 1;
312
        options.c_cc[VTIME] = 50;
313

    
314
        if (tcsetattr(xbee_stream, TCSANOW, &options))
315
        {
316
                WL_DEBUG_PRINT("Error setting attributes.\n");
317
                return -1;
318
        }
319

    
320
        xbee_listen_thread = (pthread_t*)malloc(sizeof(pthread_t));
321
        if (xbee_listen_thread == NULL)
322
        {
323
                WL_DEBUG_PRINT("Malloc failed.\n");
324
                return -1;
325
        }
326

    
327
        int ret = pthread_create(xbee_listen_thread, NULL, listen_to_xbee, NULL);
328
        if (ret)
329
        {
330
                WL_DEBUG_PRINT("Failed to create listener thread.\n");
331
                return -1;
332
        }
333
#endif
334

    
335
        WL_DEBUG_PRINT("Entering command mode.\r\n");
336

    
337
        if (xbee_enter_command_mode() != 0) {
338
    usb_puts("error entering command mode\r\n");
339
                return -1;
340
        }
341

    
342
        WL_DEBUG_PRINT("Entered command mode.\r\n");
343

    
344
  // reset baud rate
345
  WL_DEBUG_PRINT("Resetting Baud to ");
346
  WL_DEBUG_PRINT(XBEE_BAUD_STR);
347
  WL_DEBUG_PRINT("\r\n");
348
  
349
  // set baud on xbee
350
//#if (XBEE_BAUD == 250000)
351
#if (XBEE_BAUD == 115200)
352
  xbee_send_string("ATBD7\r\n");
353
#elif (XBEE_BAUD == 57600)
354
  xbee_send_string("ATBD6\r\n");
355
#elif (XBEE_BAUD == 38400)
356
  xbee_send_string("ATBD5\r\n");
357
#elif (XBEE_BAUD == 19200)
358
  xbee_send_string("ATBD4\r\n");
359
#elif (XBEE_BAUD == 9600)
360
  // already at this baud rate
361
  //xbee_send_string("ATBD3\r\n");
362
#else
363
  WL_DEBUG_PRINT("undefined baud rate\r\n");
364
#endif  
365
  // exit command mode
366
  xbee_wait_for_ok();
367
  WL_DEBUG_PRINT("got ok from baud reset\r\n");
368
  xbee_send_string("ATCN\r\n");
369
  xbee_wait_for_ok();
370
  WL_DEBUG_PRINT("got ok from exiting command mode\r\n");
371
  
372
  // set UART baud
373
#if (XBEE_BAUD == 250000)
374
  UBRR1H = 0x00;
375
  UBRR1L = 3;
376
  UCSR1A |= _BV(U2X1);
377
#elif (XBEE_BAUD == 115200)
378
  UBRR1H = 0x00;
379
  UBRR1L = 8;
380
  UCSR1A |= _BV(U2X1);
381
#elif (XBEE_BAUD == 57600)
382
  UBRR1H = 0x00;
383
  UBRR1L = 16;
384
  UCSR1A |= _BV(U2X1);
385
#elif (XBEE_BAUD == 38400)
386
  UBRR1H = 0x00;
387
  UBRR1L = 25;
388
  UCSR1A |= _BV(U2X1);
389
#elif (XBEE_BAUD == 19200)
390
  UBRR1H = 0x00;
391
  UBRR1L = 51;
392
  UCSR1A |= _BV(U2X1);
393
#elif (XBEE_BAUD == 9600)
394
  /* this is the default baud rate, so do nothing
395
  UBRR1H = 0x00;
396
  UBRR1L = 103;
397
  UCSR1A |= _BV(U2X1);*/
398
#else //Baud rate is defined in the header file, we should not get here
399
  return 0;
400
#endif
401
  delay_ms(50);
402

    
403
  // enter command mode
404
  WL_DEBUG_PRINT("entering command mode 2\r\n");
405
  xbee_send_string("+++");
406
  xbee_wait_for_ok();
407
  WL_DEBUG_PRINT("entered command mode 2\r\n");
408
  
409
  if (xbee_enter_api_mode() != 0) {
410
    WL_DEBUG_PRINT("can't enter api mode\r\n");
411
                return -1;
412
        }
413

    
414
        WL_DEBUG_PRINT("Entered api mode.\r\n");
415

    
416
        if (xbee_exit_command_mode() != 0) {
417
    WL_DEBUG_PRINT("can't exit command mode\r\n");
418
          return -1;
419
        }
420
        
421
        WL_DEBUG_PRINT("Left command mode.\r\n");
422
  
423
  // get MY address
424
        if (xbee_send_read_at_command("BD")) {
425
    WL_DEBUG_PRINT("can't send BD command\r\n");
426
                return -1;
427
        }
428
        WL_DEBUG_PRINT("Getting ATBD rate.\n");
429
  
430
  // get MY address
431
        if (xbee_send_read_at_command("MY")) {
432
    WL_DEBUG_PRINT("can't send my command\r\n");
433
                return -1;
434
        }
435
        WL_DEBUG_PRINT("Getting ATMY address.\n");
436

    
437
#ifndef ROBOT
438
        int i;
439
        for (i = 0; xbee_address == 0 && i < XBEE_GET_PACKET_TIMEOUT; i++) {
440
          ret = xbee_get_packet(NULL);
441

    
442
          usleep(1000);
443
          
444
/*           if (ret == -1) { */
445
/*             WL_DEBUG_PRINT("xbee_get_packet(NULL) failed.\n"); */
446
/*             return -1; */
447
/*           } */
448
        }
449
#else
450
        //wait to return until the address is set
451
  //TODO: this shouldn't wait indefinitely.  There should be some sort of reasonable timeout
452
  // so if the address is never set right, an error can be returned instead of having the
453
  // robot hang forever
454
        while (xbee_address == 0) {
455
          xbee_get_packet(NULL);
456
        }
457
#endif
458
        WL_DEBUG_PRINT("Got ATMY address.\n");
459

    
460
#ifndef ROBOT
461
        if (i == XBEE_GET_PACKET_TIMEOUT) { // We timed-out.
462

    
463
          WL_DEBUG_PRINT("xbee_get_packet timed out.\n");
464
          return -1;
465
        } else {
466
          return 0;
467
        }
468
#else
469
        return 0;
470
#endif
471
}
472

    
473
/**
474
 * Call when finished using the XBee library. This releases
475
 * all sued resources.
476
 **/
477
void xbee_terminate()
478
{
479
        #ifndef ROBOT
480
        pthread_cancel(*xbee_listen_thread);
481
    pthread_join(*xbee_listen_thread, NULL);
482
        free(xbee_listen_thread);
483
        lockf(xbee_stream, F_ULOCK, 0);
484
        close(xbee_stream);
485
  #else
486
  xbee_exit_api_mode();
487
        #endif
488
}
489

    
490
/**
491
 * Send a buffer buf of size bytes to the XBee.
492
 *
493
 * @param buf the buffer of data to send
494
 * @param size the number of bytes to send
495
 **/
496
static int xbee_send(char* buf, int size)
497
{
498
#ifdef ROBOT
499
        int i;
500
        for (i = 0; i < size; i++) {
501
                xbee_putc(buf[i]);
502
        }
503

    
504
        return 0;
505

    
506
#else
507

    
508
        int ret = write(xbee_stream, buf, size);
509
        //success
510
        if (ret == size)
511
                return 0;
512
        if (ret == -1)
513
        {
514
                //interrupted by system signal, probably timer interrupt.
515
                //just try again
516
                if (errno == 4)
517
                {
518
                        return xbee_send(buf, size);
519
                }
520
                WL_DEBUG_PRINT("Failed to write to xbee\r\n");
521
                return -1;
522
        }
523

    
524
        //write was interrupted after writing ret bytes
525
        return xbee_send(buf + ret, size - ret);
526
#endif
527
}
528

    
529
/**
530
 * Sends a string to the XBee.
531
 *
532
 * @param c the string to send to the XBEE
533
 **/
534
static int xbee_send_string(char* c)
535
{
536
        return xbee_send(c, strlen(c));
537
}
538

    
539
#ifndef ROBOT
540
static int xbee_read(char* buf, int size)
541
{
542
        if (read(xbee_stream, buf, size) == -1) {
543
                WL_DEBUG_PRINT("Failed to read from xbee.\r\n");
544
                return -1;
545
        }
546

    
547
        return 0;
548
}
549
#endif
550

    
551
/**
552
 * Enter into command mode.
553
 **/
554
static int xbee_enter_command_mode()
555
{
556
        if (xbee_send_string("+++") != 0) {
557
                return -1;
558
        }
559

    
560
        if (xbee_wait_for_ok() != 0) {
561
          return -1;
562
        }
563
          return 0;
564
}
565

    
566
/**
567
 * Exit from command mode.
568
 **/
569
static int xbee_exit_command_mode()
570
{
571
        if (xbee_send_string("ATCN\r") != 0) {
572
                return -1;
573
        }
574

    
575
        xbee_wait_for_ok();
576

    
577
        return 0;
578
}
579

    
580
/**
581
 * Enter API mode.
582
 **/
583
static int xbee_enter_api_mode()
584
{
585
        if (xbee_send_string("ATAP 1\r") != 0) {
586
                return -1;
587
        }
588
        xbee_wait_for_ok();
589

    
590
        return 0;
591
}
592

    
593
/**
594
 * Exit API mode.
595
 **/
596
static int xbee_exit_api_mode()
597
{
598
        if (xbee_send_modify_at_command("AP","0") != 0) {
599
                return -1;
600
        }
601

    
602
        return 0;
603
}
604

    
605
/**
606
 * Wait until the string "OK\r" is received from the XBee.
607
 **/
608
static int xbee_wait_for_ok()
609
{
610
        return xbee_wait_for_string("OK\r", 3);
611
}
612

    
613
/**
614
 * Delay until the specified string is received from
615
 * the XBee. Discards all other XBee data.
616
 *
617
 * ********* Robot often hangs here ****************
618
 *
619
 * @param s the string to receive
620
 * @param len the length of the string
621
 **/
622
static int xbee_wait_for_string(char* s, int len)
623
{
624
        char* curr = s;
625
  unsigned int i=0;
626
        while (curr - s < len) {
627
    WL_DEBUG_PRINT("waiting for string\r\n");
628
                // check if buffer is empty
629
                if (buffer_last != buffer_first) {
630
                        char c = arrival_buf[buffer_first++];
631
                        if (buffer_first == XBEE_BUFFER_SIZE) {
632
                                buffer_first = 0;
633
                        }
634
      WL_DEBUG_PRINT("buffer char|");
635
      WL_DEBUG_PRINT_CHAR(c);
636
      WL_DEBUG_PRINT("|\r\n");
637

    
638
                        if (c == *curr) {
639
                                curr++;
640
                        } else {
641
#ifndef ROBOT
642
                          //return -1; // Computer is less forgiving.
643
                          curr = s;
644
#else
645
                          curr = s;
646
#endif
647
                        }
648
                } // else buffer is empty.
649

    
650
#ifndef ROBOT
651
                usleep(100);
652
#endif
653
        }
654
  if (i >= 10000)
655
    return -1;
656

    
657
        return 0;
658
}
659

    
660
/**
661
 * Verifies that the packets checksum is correct.
662
 * (If the checksum is correct, the sum of the bytes
663
 * is 0xFF.)
664
 *
665
 * @param packet the packet received. This includes the first
666
 * three bytes, which are header information from the XBee.
667
 *
668
 * @param len The length of the packet received from the XBee
669
 *
670
 * @return 0 if the checksum is incorrect, nonzero
671
 * otherwise
672
 **/
673
int xbee_verify_checksum(char* packet, int len)
674
{
675
        unsigned char sum = 0;
676
        int i;
677
        for (i = 3; i < len; i++)
678
                sum += (unsigned char)packet[i];
679
        return sum == 0xFF;
680
}
681

    
682
/**
683
 * Returns the checksum of the given packet.
684
 *
685
 * @param buf the data for the packet to send
686
 * @param len the length of the packet in bytes
687
 *
688
 * @return the checksum of the packet, which will
689
 * become the last byte sent in the packet
690
 **/
691
char xbee_compute_checksum(char* buf, int len)
692
{
693
        int i;
694
        unsigned char sum = 0;
695
        for (i = 0; i < len; i++)
696
                sum += (unsigned char)buf[i];
697
        return 0xFF - sum;
698
}
699

    
700
/**
701
 * Adds header information and checksum to the given
702
 * packet and sends it. Header information includes
703
 * XBEE_FRAME_START and the packet length, as two bytes.
704
 *
705
 * @param buf the packet data
706
 * @param len the size in bytes of the packet data
707
 *
708
 **/
709
static int xbee_send_frame(char* buf, int len)
710
{
711
        char prefix[3];
712
        prefix[0] = XBEE_FRAME_START;
713
        prefix[1] = (len & 0xFF00) >> 8;
714
        prefix[2] = len & 0xFF;
715
        char checksum = xbee_compute_checksum(buf, len);
716

    
717
        if (xbee_send(prefix, 3) != 0) {
718
                return -1;
719
        }
720

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

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

    
729
        return 0;
730
}
731

    
732
/**
733
 * Sends an AT command to read a parameter.
734
 *
735
 * @param command the AT command to send. For exmaple,
736
 * use ID to read the PAN ID and MY to return the XBee ID.
737
 * See the XBee reference guide for a complete listing.
738
 **/
739
int xbee_send_read_at_command(char* command)
740
{
741
        return xbee_send_modify_at_command(command, NULL);
742
}
743

    
744
/**
745
 * Sends the given AT command.
746
 *
747
 * @param command the AT command to send (e.g., MY, ID)
748
 * @param value the value to pass as a parameter
749
 * (or NULL if there is no parameter)
750
 **/
751
static int xbee_send_modify_at_command(char* command, char* value)
752
{
753
        char buf[16];
754
        int i;
755

    
756
        buf[0] = XBEE_FRAME_AT_COMMAND;
757
        buf[1] = 1;
758
        buf[2] = command[0];
759
        buf[3] = command[1];
760
        int valueLen = 0;
761
        if (value != NULL)
762
        {
763
                valueLen = strlen(value);
764
                if (valueLen > 8)
765
                {
766
                        WL_DEBUG_PRINT("AT Command too large.\r\n");
767
                        return -1;
768
                }
769

    
770
                for (i = 0; i < valueLen; i++) {
771
                        buf[4 + i] = value[i];
772
                }
773
        }
774

    
775
        return xbee_send_frame(buf, 4 + valueLen);
776
}
777

    
778
/**
779
 * Send the specified packet.
780
 *
781
 * @param packet the packet data to send
782
 * @param len the number of bytes in the packet
783
 *
784
 * @param dest the ID of the XBee to send the packet to,
785
 * or XBEE_BROADCAST to send the message to all robots
786
 * in the PAN.
787
 *
788
 * @param options a combination of the flags
789
 * XBEE_OPTIONS_NONE, XBEE_OPTIONS_DISABLE_RESPONSE and
790
 * XBEE_OPTIONS_BROADCAST_ALL_PANS
791
 *
792
 * @param frame the frame number to associate this packet
793
 * with. This will be used to identify the response when
794
 * the XBee alerts us as to whether or not our message
795
 * was received.
796
 **/
797
int xbee_send_packet(char* packet, int len, int dest, char options, char frame)
798
{
799
        char buf[5];
800
        char prefix[3];
801
        int i;
802
        unsigned char checksum = 0;
803

    
804
        if (len > 100)
805
        {
806
                WL_DEBUG_PRINT("Packet is too large.\r\n");
807
                return -1;
808
        }
809

    
810
        //data for sending request
811
        buf[0] = XBEE_FRAME_TX_REQUEST_16;
812
        buf[1] = frame;
813
        buf[2] = (dest >> 8) & 0xFF;
814
        buf[3] = dest & 0xFF;
815
        buf[4] = options;
816

    
817
        //packet prefix, do this here so we don't need an extra buffer
818
        prefix[0] = XBEE_FRAME_START;
819
        prefix[1] = ((5 + len) & 0xFF00) >> 8;
820
        prefix[2] = (5 + len) & 0xFF;
821

    
822
        for (i = 0; i < 5; i++)
823
                checksum += (unsigned char)buf[i];
824
        for (i = 0; i < len; i++)
825
                checksum += (unsigned char)packet[i];
826
        checksum = 0xFF - checksum;
827

    
828
        if (xbee_send(prefix, 3) != 0) {
829
                return -1;
830
        }
831

    
832
        if (xbee_send(buf, 5) != 0) {
833
                return -1;
834
        }
835

    
836
        if (xbee_send(packet, len) != 0) {
837
                return -1;
838
        }
839

    
840
        if (xbee_send((char*)&checksum, 1) != 0) {
841
                return -1;
842
        }
843

    
844
        return 0;
845
}
846

    
847
/**
848
 * Reads a packet received from the XBee. This function
849
 * is non-blocking. The resulting packet is stored in dest.
850
 * Only returns transmission response packets and
851
 * received packets. The returned packet does not include
852
 * header information or the checksum. This method also
853
 * handles special packets dealt with by the XBee library,
854
 * and so should be called frequently while the XBee is in
855
 * use.<br><br>
856
 *
857
 * The first byte of the packet will be either
858
 * XBEE_TX_STATUS or XBEE_RX to indicated
859
 * a response to a sent message or a received message,
860
 * respectively.<br><br>
861
 *
862
 * For a status response packet:<br>
863
 * The first byte will be XBEE_TX_STATUS.<br>
864
 * The second byte will be the frame number.<br>
865
 * The third byte will be the result. 0 indicates success,
866
 * and nonzero indicates that an error ocurred in
867
 * transmitting the packet.<br><br>
868
 *
869
 * For a received packet:<br>
870
 * The first byte will be XBEE_RX.<br>
871
 * The second and third bytes will be the 16-bit
872
 * address of the packet's sender.<br>
873
 * The fourth byte is the signal strength.<br>
874
 * The fifth byte is 1 if the packet were sent to
875
 * a specific address, and 2 if it is a broadcast packet.<br><br>
876
 *
877
 * @param dest set to the packet data
878
 * @return the length of the packet, or -1 if no packet
879
 * is available
880
 **/
881
int xbee_get_packet(unsigned char* dest)
882
{
883
     int ret;
884
        //start reading a packet with XBEE_FRAME_START
885
        if (currentBufPos == 0)
886
        {
887
                do
888
                {
889
                        if (buffer_first == XBEE_BUFFER_SIZE)
890
                                buffer_first = 0;
891
                        // check if buffer is empty
892
                        if (buffer_first == buffer_last) {
893
        WL_DEBUG_PRINT("buffer empty\r\n");
894
                                return -1;
895
                        }
896
                } while (arrival_buf[buffer_first++] != XBEE_FRAME_START);
897

    
898
                if (buffer_first == XBEE_BUFFER_SIZE) {
899
                        buffer_first = 0;
900
                }
901
                xbee_buf[0] = XBEE_FRAME_START;
902
                currentBufPos++;
903
        }
904

    
905
        int len = -1;
906
        if (currentBufPos >= 3) {
907
                len = (int)xbee_buf[2] + ((int)xbee_buf[1] << 8);
908
        }
909

    
910
        while (len == -1 //packet length has not been read yet
911
                || currentBufPos < len + 4)
912
        {
913
                if (currentBufPos == 3)
914
                {
915
                        len = (int)xbee_buf[2] + ((int)xbee_buf[1] << 8);
916
                        if (len > 120)
917
                        {
918
                                WL_DEBUG_PRINT("Packet too large. Probably error in XBee transmission.\r\n");
919
                                currentBufPos = 0;
920
                                return -1;
921
                        }
922
                }
923

    
924
                // check if buffer is empty
925
                if (buffer_first == buffer_last) {
926
      WL_DEBUG_PRINT("Buffer empty 2\r\n");
927
                        return -1;
928
                }
929
                xbee_buf[currentBufPos++] = arrival_buf[buffer_first++];
930
                if (buffer_first == XBEE_BUFFER_SIZE) {
931
                        buffer_first = 0;
932
                }
933
        }
934

    
935
        currentBufPos = 0;
936

    
937
        if (!xbee_verify_checksum(xbee_buf, len + 4))
938
        {
939
                WL_DEBUG_PRINT("XBee checksum failed.\r\n");
940
                return -1;
941
        }
942

    
943
        //we will take care of the packet
944
        
945
        ret = xbee_handle_packet(xbee_buf+3, len);
946
        if (ret == 1) {
947
                return 3;
948
        } else if (ret == -1) {
949
    WL_DEBUG_PRINT("xbee_handle_packet returned -1\r\n");
950
    return -2;
951
  }
952
        
953
        if (dest == NULL) {
954
    WL_DEBUG_PRINT("dest buffer is null\r\n");
955
                return -1;
956
        }
957

    
958
        int i;
959
        for (i = 3; i < len + 3; i++) {
960
                dest[i - 3] = xbee_buf[i];
961
        }
962
        return len;
963
}
964

    
965
/**
966
 * Handles modem status packets.
967
 *
968
 * @param status the type of status packet received.
969
 **/
970
void xbee_handle_status(char status)
971
{
972
        switch (status)
973
        {
974
                case 0:
975
                        WL_DEBUG_PRINT("XBee hardware reset.\r\n");
976
                        break;
977
                case 1:
978
                        WL_DEBUG_PRINT("Watchdog timer reset.\r\n");
979
                        break;
980
                case 2:
981
                        WL_DEBUG_PRINT("Associated.\r\n");
982
                        break;
983
                case 3:
984
                        WL_DEBUG_PRINT("Disassociated.\r\n");
985
                        break;
986
                case 4:
987
                        WL_DEBUG_PRINT("Synchronization lost.\r\n");
988
                        break;
989
                case 5:
990
                        WL_DEBUG_PRINT("Coordinator realignment.\r\n");
991
                        break;
992
                case 6:
993
                        WL_DEBUG_PRINT("Coordinator started.\r\n");
994
                        break;
995
        }
996
}
997

    
998
/**
999
 * Handles AT command response packets.
1000
 * @param command the two character AT command, e.g. MY or ID
1001
 * @param result 0 for success, 1 for an error
1002
 * @param extra the hex value of the requested register
1003
 * @param extraLen the length in bytes of extra
1004
 **/
1005
static int xbee_handle_at_command_response(char* command, char result, char* extra, int extraLen)
1006
{
1007
        if (result == 1)
1008
        {
1009
                WL_DEBUG_PRINT("Error with AT");
1010
                WL_DEBUG_PRINT(command);
1011
                WL_DEBUG_PRINT(" packet. Result = ");
1012
    switch(result) {
1013
    case 1:
1014
      WL_DEBUG_PRINT("ERROR\r\n");
1015
      break;
1016
    case 2:
1017
      WL_DEBUG_PRINT("Invalid Command\r\n");
1018
      break;
1019
    case 3:
1020
      WL_DEBUG_PRINT("Invalid Parameter\r\n");
1021
      break;
1022
    }
1023
    return -1;
1024
        }
1025
        WL_DEBUG_PRINT("AT");
1026
        WL_DEBUG_PRINT(command);
1027
        WL_DEBUG_PRINT(" command was successful.\r\n");
1028

    
1029
        if (command[0] == 'I' && command[1] == 'D')
1030
        {
1031
                xbee_panID = xbee_pending_panID;
1032
                WL_DEBUG_PRINT("PAN ID set to ");
1033
                WL_DEBUG_PRINT_INT(xbee_panID);
1034
                WL_DEBUG_PRINT(".\r\n");
1035
                return 0;
1036
        }
1037

    
1038
        if (command[0] == 'C' && command[1] == 'H')
1039
        {
1040
                xbee_channel = xbee_pending_channel;
1041
                WL_DEBUG_PRINT("Channel set to ");
1042
                WL_DEBUG_PRINT_INT(xbee_channel);
1043
                WL_DEBUG_PRINT(".\r\n");
1044
                return 0;
1045
        }
1046
  
1047
  if (command[0] == 'N' && command[1] == 'D')
1048
        {
1049
                WL_DEBUG_PRINT("ND - extra=");
1050
    WL_DEBUG_PRINT(extra);
1051
                WL_DEBUG_PRINT("\r\n");
1052
                return 0;
1053
        }
1054
  
1055
   if (command[0] == 'B' && command[1] == 'D')
1056
        {
1057
                WL_DEBUG_PRINT("BD - extra=");
1058
    WL_DEBUG_PRINT(extra);
1059
                WL_DEBUG_PRINT("\r\n");
1060
                return 0;
1061
        }
1062

    
1063
        if (command[0] == 'M' && command[1] == 'Y' && extraLen != 0)
1064
        {
1065
                xbee_address = 0;
1066
                int i;
1067
                for (i = 0; i < extraLen; i++) {
1068
                        xbee_address = (xbee_address << 8) + extra[i];
1069
                }
1070

    
1071
                WL_DEBUG_PRINT("XBee address is ");
1072
                WL_DEBUG_PRINT_INT(xbee_address);
1073
                WL_DEBUG_PRINT(".\r\n");
1074

    
1075
                if (xbee_address == 0)
1076
                {
1077
                        WL_DEBUG_PRINT("XBee 16-bit address must be set using ATMY.\r\n");
1078
                        #ifndef ROBOT
1079
                        exit(0);
1080
                        #endif
1081
                }
1082
        }
1083
  return 0;
1084
}
1085

    
1086
/**
1087
 * Attempts to handle the packet if it is dealt with
1088
 * by the library.
1089
 * We will handle the following packet types:
1090
 *    Modem Status
1091
 *    AT Command Response
1092
 *
1093
 * @param packet the packet to handle
1094
 * @param len the length of the packet
1095
 *
1096
 * @return 1 if we have handled the packet, 0 otherwise
1097
 */
1098
static int xbee_handle_packet(char* packet, int len)
1099
{
1100

    
1101
        char command[3] = {1, 2, 3};
1102
        if (len <= 0) //this should not happend
1103
        {
1104
                WL_DEBUG_PRINT("Non-positive packet length.\r\n");
1105
                return 0;
1106
        }
1107

    
1108
        switch ((unsigned char)packet[0]) //packet type
1109
        {
1110
                case XBEE_FRAME_STATUS:
1111
                        xbee_handle_status(packet[1]);
1112
                        return 1;
1113
                case XBEE_FRAME_AT_COMMAND_RESPONSE:
1114
                        command[0] = packet[2];
1115
                        command[1] = packet[3];
1116
                        command[2] = 0;
1117
                        if (xbee_handle_at_command_response(command, packet[4], packet + 5, len - 5) != 0)
1118
        return -1;
1119
      else
1120
        return 1;
1121
        }
1122
        return 0;
1123
}
1124

    
1125
/**
1126
 * Sets the personal area network id.
1127
 *
1128
 * @param id the new personal area network (PAN) id
1129
 **/
1130
int xbee_set_pan_id(int id)
1131
{
1132
        char s[3];
1133
        s[0] = (id >> 8) & 0xFF;
1134
        s[1] = id & 0xFF;
1135
        s[2] = 0;
1136
        xbee_pending_panID = id;
1137
        return xbee_send_modify_at_command("ID", s);
1138
}
1139

    
1140
/**
1141
 * Get the PAN ID for the XBee.
1142
 *
1143
 * @return the personal area network id, or
1144
 * XBEE_PAN_DEFAULT if it has not yet been set.
1145
 **/
1146
unsigned int xbee_get_pan_id()
1147
{
1148
        return xbee_panID;
1149
}
1150

    
1151
/**
1152
 * Set the channel the XBee is using.
1153
 *
1154
 * @param channel the channel the XBee will not use,
1155
 * between 0x0B and 0x1A
1156
 *
1157
 * @see xbee_get_channel
1158
 **/
1159
int xbee_set_channel(int channel)
1160
{
1161
        if (channel < 0x0B || channel > 0x1A)
1162
        {
1163
                WL_DEBUG_PRINT("Channel out of range.\r\n");
1164
                return -1;
1165
        }
1166

    
1167
        char s[3];
1168
        s[0] = channel & 0xFF;
1169
        s[1] = 0;
1170
        xbee_pending_channel = channel;
1171

    
1172
        return xbee_send_modify_at_command("CH", s);
1173
}
1174

    
1175
/**
1176
 * Returns the channel which the XBee is currently using.
1177
 *
1178
 * @return the channel the XBee is using
1179
 *
1180
 * @see xbee_set_channel
1181
 **/
1182
int xbee_get_channel(void)
1183
{
1184
        return xbee_channel;
1185
}
1186

    
1187
/**
1188
 * Get the 16-bit address of the XBee.
1189
 * This is used to specify who to send messages to
1190
 * and who messages are from.
1191
 *
1192
 * @return the 16-bit address of the XBee.
1193
 **/
1194
unsigned int xbee_get_address()
1195
{
1196
        return xbee_address;
1197
}
1198

    
1199
#ifndef ROBOT
1200
void xbee_set_com_port(char* port)
1201
{
1202
        xbee_com_port = port;
1203
}
1204
#endif
1205

    
1206
/**@} **/ // end xbee group
1207