Project

General

Profile

Statistics
| Revision:

root / branches / wireless / code / behaviors / Wireless_Speed_test / xbee.c @ 1560

History | View | Annotate | Download (24.4 KB)

1
/**
2
 * Copyright (c) 2007 Colony Project
3
 *
4
 * Permission is hereby granted, free of charge, to any person
5
 * obtaining a copy of this software and associated documentation
6
 * files (the "Software"), to deal in the Software without
7
 * restriction, including without limitation the rights to use,
8
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
9
 * copies of the Software, and to permit persons to whom the
10
 * Software is furnished to do so, subject to the following
11
 * conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be
14
 * included in all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23
 * OTHER DEALINGS IN THE SOFTWARE.
24
 **/
25

    
26
/**
27
 * @file xbee.c
28
 * @brief XBee Interface
29
 *
30
 * Implementation of low level communication with the XBee in API mode.
31
 *
32
 * @author Brian Coltin, Colony Project, CMU Robotics Club
33
 **/
34

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

    
39
//#define ROBOT
40
//#define WL_DEBUG
41
//#define WL_DEBUG_PRINT( s ) usb_puts( s )
42
//#define WL_DEBUG_PRINT_INT( i ) usb_puti(i)
43

    
44
#ifndef ROBOT
45

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

    
52
#else
53

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

    
57
#endif
58

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

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

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

    
76
/*Internal Function Prototypes*/
77

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

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

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

    
96
/*API Mode Functions*/
97

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

    
107
/*Global Variables*/
108

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

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

    
125

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

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

    
137
/*Function Implementations*/
138

    
139
#ifdef ROBOT
140

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

    
175
#else
176

    
177
// Computer code
178

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

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

    
202
                usleep(1000);
203
        }
204

    
205
        return NULL;
206
}
207

    
208
#endif
209

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

    
220
        WL_DEBUG_PRINT("in xbee_init\n");
221
#ifdef ROBOT
222

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

    
248
        // set baud rate, etc. correctly
249
        struct termios options;
250

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

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

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

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

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

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

    
293
        WL_DEBUG_PRINT("Entered command mode.\r\n");
294

    
295
  // reset baud rate
296
  usb_puts("Resetting Baud to ");
297
  usb_puts(XBEE_BAUD_STR);
298
  usb_puts("\r\n");
299
  
300
  // set baud on xbee
301
#if (XBEE_BAUD == 115200)
302
  xbee_send_string("ATBD7\r");
303
#end if  
304
  // exit command mode
305
  xbee_wait_for_ok();
306
  xbee_send_string("ATCN\r");
307
  xbee_wait_for_ok();
308
  
309
  // set UART baud
310
#if (XBEE_BAUD == 250000)
311
  UBRR1H = 0x00;
312
  UBRR1L = 3;
313
  UCSR1A |= _BV(U2X1);
314
#elif (XBEE_BAUD == 115200)
315
  UBRR1H = 0x00;
316
  UBRR1L = 8;
317
  UCSR1A |= _BV(U2X1);
318
#elif (XBEE_BAUD == 57600)
319
  if (xbee_send_modify_at_command("BD","6")) {
320
                return -1;
321
        }
322
  UBRR1H = 0x00;
323
  UBRR1L = 16;
324
  UCSR1A |= _BV(U2X1);
325
#elif (XBEE_BAUD == 38400)
326
  if (xbee_send_modify_at_command("BD","5")) {
327
                return -1;
328
        }
329
  UBRR1H = 0x00;
330
  UBRR1L = 25;
331
  UCSR1A |= _BV(U2X1);
332
#elif (XBEE_BAUD == 19200)
333
  if (xbee_send_modify_at_command("BD","4")) {
334
                return -1;
335
        }
336
  UBRR1H = 0x00;
337
  UBRR1L = 51;
338
  UCSR1A |= _BV(U2X1);
339
#elif (XBEE_BAUD == 9600)
340
  /* this is the default baud rate, so do nothing
341
  if (xbee_send_modify_at_command("BD","3")) {
342
                return -1;
343
        }
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

    
351
  // enter command mode
352
  if (xbee_enter_command_mode() != 0) {
353
    usb_puts("error entering command mode after baud set\r\n");
354
                return -1;
355
        }
356
  
357
  if (xbee_enter_api_mode() != 0) {
358
    usb_puts("can't enter api mode\r\n");
359
                return -1;
360
        }
361

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

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

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

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

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

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

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

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

    
452
        return 0;
453

    
454
#else
455

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

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

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

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

    
495
        return 0;
496
}
497
#endif
498

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

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

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

    
523
        xbee_wait_for_ok();
524

    
525
        return 0;
526
}
527

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

    
538
        return 0;
539
}
540

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

    
550
        return 0;
551
}
552

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

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

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

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

    
605
        return 0;
606
}
607

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

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

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

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

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

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

    
677
        return 0;
678
}
679

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
792
        return 0;
793
}
794

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

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

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

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

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

    
883
        currentBufPos = 0;
884

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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