Project

General

Profile

Statistics
| Revision:

root / branches / autonomous_recharging / code / projects / libwireless / lib / xbee.c @ 668

History | View | Annotate | Download (22.8 KB)

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

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

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

    
38
#ifndef ROBOT
39

    
40
#include <fcntl.h>
41
#include <unistd.h>
42
#include <pthread.h>
43
#include <errno.h>
44
#include <termios.h>
45

    
46
#else
47

    
48
#include <serial.h>
49
#include <avr/interrupt.h>
50

    
51
#endif
52

    
53
#include <stdio.h>
54
#include <stdlib.h>
55
#include <string.h>
56

    
57
#define XBEE_FRAME_START 0x7E
58
#define XBEE_GET_PACKET_TIMEOUT 1000
59

    
60
/*Frame Types*/
61
#define XBEE_FRAME_STATUS 0x8A
62
#define XBEE_FRAME_AT_COMMAND 0x08
63
#define XBEE_FRAME_AT_COMMAND_RESPONSE 0x88
64
#define XBEE_FRAME_TX_REQUEST_64 0x00
65
#define XBEE_FRAME_TX_REQUEST_16 0x01
66
#define XBEE_FRAME_TX_STATUS XBEE_TX_STATUS
67
#define XBEE_FRAME_RX_64 0x80
68
#define XBEE_FRAME_RX_16 XBEE_RX
69

    
70
/*Internal Function Prototypes*/
71

    
72
/*I/O Functions*/
73
static int xbee_send(char* buf, int size);
74
static int xbee_send_string(char* c);
75

    
76
#ifndef ROBOT
77
static int xbee_read(char* buf, int size);
78
#endif
79

    
80
/*Command Mode Functions
81
 * Called during initialization.
82
 */
83
static int xbee_enter_command_mode(void);
84
static int xbee_exit_command_mode(void);
85
static int xbee_enter_api_mode(void);
86
static int xbee_exit_api_mode(void);
87
static int xbee_wait_for_string(char* s, int len);
88
static int xbee_wait_for_ok(void);
89

    
90
/*API Mode Functions*/
91

    
92
static int xbee_handle_packet(char* packet, int len);
93
static void xbee_handle_at_command_response(char* command, char result, char* extra, int extraLen);
94
static void xbee_handle_status(char status);
95
static int xbee_verify_checksum(char* packet, int len);
96
static char xbee_compute_checksum(char* packet, int len);
97
static int xbee_send_frame(char* buf, int len);
98
static int xbee_send_read_at_command(char* command);
99
static int xbee_send_modify_at_command(char* command, char* value);
100

    
101
/*Global Variables*/
102

    
103
#ifndef ROBOT
104
static char* xbee_com_port = XBEE_PORT_DEFAULT;
105
static int xbee_stream;
106
static pthread_t* xbee_listen_thread;
107
#endif
108

    
109
// TODO: is this a good size?
110
#define XBEE_BUFFER_SIZE        256
111
// a buffer for data received from the XBee
112
char arrival_buf[XBEE_BUFFER_SIZE];
113
// location of last unread byte in buffer
114
volatile int buffer_last = 0;
115
// first unread byte in buffer
116
volatile int buffer_first = 0;
117

    
118

    
119
//used to store packets as they are read
120
static char xbee_buf[128];
121
static int currentBufPos = 0;
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
void printHex(char * s, int len) {
131
  int i;
132
  for (i = 0; i < len; i++) {
133
    printf("0x%x ", (int)(s[i]));
134
  }
135
  printf("\n");
136
}
137

    
138

    
139
/*Function Implementations*/
140

    
141
#ifdef ROBOT
142

    
143
/**
144
 * Interrupt for the robot. Adds bytes received from the xbee
145
 * to the buffer.
146
 **/
147
#ifdef FIREFLY
148
SIGNAL(SIG_USART0_RECV)
149
{
150
        char c = UDR0;
151
        arrival_buf[buffer_last] = c;
152
        int t = buffer_last + 1;
153
        if (t == XBEE_BUFFER_SIZE)
154
                t = 0;
155
        if (t == buffer_first)
156
        {
157
                WL_DEBUG_PRINT("Out of space in buffer.\n");
158
        }
159
        buffer_last = t;
160
}
161
#else
162
#ifdef BAYBOARD
163
// TODO: interrupt handler for bayboard, should be similar to above and below
164
#else
165
ISR(USART1_RX_vect)
166
{
167
        char c = UDR1;
168
        arrival_buf[buffer_last] = c;
169
        int t = buffer_last + 1;
170
        if (t == XBEE_BUFFER_SIZE)
171
                t = 0;
172
        if (t == buffer_first)
173
        {
174
                WL_DEBUG_PRINT("Out of space in buffer.\n");
175
        }
176
        buffer_last = t;
177
}
178
#endif
179
#endif
180

    
181
#else
182

    
183
// Computer code
184

    
185
/**
186
 * Thread that listens to the xbee.
187
 **/
188
static void* listen_to_xbee(void* x)
189
{
190
        char c;
191
        while (1)
192
        {
193
                if (xbee_read(&c, 1) != 0) {
194
                        fprintf(stderr, "xbee_read failed.\n");
195
                        return NULL;
196
                }
197
                
198
                //DEBUGGING PRINT
199
                //printf("interrupt: %c (%d)\n", c, (int)c);
200
                arrival_buf[buffer_last] = c;
201
                int t = buffer_last + 1;
202
                if (t == XBEE_BUFFER_SIZE)
203
                        t = 0;
204
                if (t == buffer_first)
205
                {
206
                        WL_DEBUG_PRINT("Out of space in buffer.\n");
207
                }
208
                buffer_last = t;
209

    
210
                usleep(1000);
211
        }
212

    
213
        return NULL;
214
}
215

    
216
#endif
217

    
218
/**
219
 * Initializes the XBee library so that other functions may be used.
220
 **/
221
int xbee_lib_init()
222
{
223
        arrival_buf[0] = 'A';
224
        arrival_buf[1] = 'A';
225
        arrival_buf[2] = 'A';
226
#ifdef ROBOT
227

    
228
        //enable the receiving interrupt
229
#ifdef FIREFLY
230
        UCSR0B |= _BV(RXCIE) | _BV(RXEN);
231
#else
232
#ifdef BAYBOARD
233
//TODO: enable the receiving interrupt on the bayboard
234
#else
235
        UCSR1B |= _BV(RXCIE);
236
#endif
237
#endif
238
        sei();
239
#else
240
        printf("Connecting to port %s.\n", xbee_com_port);
241
        xbee_stream = open(xbee_com_port, O_RDWR);
242
        if (xbee_stream == -1/* || lockf(xbee_stream, F_TEST, 0) != 0*/)
243
        {
244
                printf("Failed to open connection to XBee on port %s\r\n", xbee_com_port);
245
                return -1;
246
        } else {
247
          printf("Successfully opened connection to XBee on port %s\r\n", xbee_com_port);
248
        }
249

    
250
        // set baud rate, etc. correctly
251
        struct termios options;
252

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

    
267
        if (tcsetattr(xbee_stream, TCSANOW, &options))
268
        {
269
                fprintf(stderr, "Error setting attributes.\n");
270
                return -1;
271
        } else {
272
          //printf("Successfully set termios attributes.\n");
273
        }
274

    
275
        //lockf(xbee_stream, F_LOCK, 0);
276

    
277
        xbee_listen_thread = (pthread_t*)malloc(sizeof(pthread_t));
278
        if (xbee_listen_thread == NULL)
279
        {
280
                fprintf(stderr, "%s: Malloc failed.\n", __FUNCTION__);
281
                return -1;
282
        }
283

    
284
        int ret = pthread_create(xbee_listen_thread, NULL, listen_to_xbee, NULL);
285
        if (ret)
286
        {
287
                fprintf(stderr, "Failed to create listener thread.\r\n");
288
                return -1;
289
        } else {
290
          //printf("Successfully created listener thread.\n");
291
        }
292
#endif
293

    
294
        //DEBUGGING PRINT
295
        //printf("about to call xbee_enter_command_mode\n");
296

    
297
        if (xbee_enter_command_mode() != 0) {
298
#ifndef ROBOT
299
          printf("Error returned from xbee_enter_command_mode\n");
300
#endif
301
                return -1;
302
        }
303

    
304
        //DEBUGGING PRINT
305
        //printf("about to call xbee_enter_api_mode\n");
306

    
307
        if (xbee_enter_api_mode() != 0) {
308
#ifndef ROBOT
309
          printf("Error returned from xbee_enter_api_mode\n");
310
#endif
311
                return -1;
312
        }
313

    
314
        //DEBUGGING PRINT
315
        //printf("about to call xbee_exit_command_mode\n");
316

    
317
        if (xbee_exit_command_mode() != 0) {
318
#ifndef ROBOT
319
          printf("Error returned from xbee_exit_command_mode\n");
320
#endif
321
                return -1;
322
        }
323

    
324
        //DEBUGGING PRINT
325
        //printf("about to call xbee_send_read_at_command\n");
326

    
327
        if (xbee_send_read_at_command("MY")) {
328
#ifndef ROBOT
329
          printf("Error returned from xbee_send_read_at_command\n");
330
#endif
331
                return -1;
332
        }
333

    
334
#ifndef ROBOT
335
        //printf("About to enter while loop to get xbee_address.\n");
336
        int i;
337
        for (i = 0; xbee_address == 0 && i < XBEE_GET_PACKET_TIMEOUT; i++) {
338
          ret = xbee_get_packet(NULL);
339

    
340
          usleep(1000);
341

    
342
          if (ret == -1) {
343
                //printf("xbee_get_packet(NULL) failed.\n");
344
                return -1;
345
          }
346
        }
347

    
348
        //        printf("After exiting while loop to get xbee_address.\n");
349
#else
350
        //wait to return until the address is set
351
        while (xbee_address == 0) {
352
          xbee_get_packet(NULL);
353
        }
354
#endif
355

    
356
#ifndef ROBOT
357
        if (i == XBEE_GET_PACKET_TIMEOUT) { // We timed-out.
358

    
359
          printf("xbee_get_packet timed out.\n");
360
          return -1;
361
        } else {
362
          return 0;
363
        }
364
#else
365
        return 0;
366
#endif
367
}
368

    
369
/**
370
 * Call when finished using the XBee library. This releases
371
 * all sued resources.
372
 **/
373
void xbee_terminate()
374
{
375
        #ifndef ROBOT
376
        pthread_cancel(*xbee_listen_thread);
377
        free(xbee_listen_thread);
378
        lockf(xbee_stream, F_ULOCK, 0);
379
        close(xbee_stream);
380
        #endif
381
}
382

    
383
/**
384
 * Send a buffer buf of size bytes to the XBee.
385
 *
386
 * @param buf the buffer of data to send
387
 * @param size the number of bytes to send
388
 **/
389
static int xbee_send(char* buf, int size)
390
{
391
#ifdef ROBOT
392
        int i;
393
        for (i = 0; i < size; i++) {
394
                xbee_putc(buf[i]);
395
        }
396

    
397
        return 0;
398

    
399
#else
400
        //DEBUGGING PRINT
401
        //printf("in xbee_send ");
402
        //printHex(buf, size);
403

    
404
        int ret = write(xbee_stream, buf, size);
405
        //success
406
        if (ret == size)
407
                return 0;
408
        if (ret == -1)
409
        {
410
                //interrupted by system signal, probably timer interrupt.
411
                //just try again
412
                if (errno == 4)
413
                {
414
                        return xbee_send(buf, size);
415
                }
416
                printf("Failed to write to xbee, error %i.\r\n", errno);
417
                return -1;
418
        }
419

    
420
        //write was interrupted after writing ret bytes
421
        return xbee_send(buf + ret, size - ret);
422
#endif
423
}
424

    
425
/**
426
 * Sends a string to the XBee.
427
 *
428
 * @param c the string to send to the XBEE
429
 **/
430
static int xbee_send_string(char* c)
431
{
432
        return xbee_send(c, strlen(c));
433
}
434

    
435
#ifndef ROBOT
436
static int xbee_read(char* buf, int size)
437
{
438
        if (read(xbee_stream, buf, size) == -1) {
439
                printf("Failed to read from xbee.\r\n");
440
                return -1;
441
        }
442

    
443
        return 0;
444
}
445
#endif
446

    
447
/**
448
 * Enter into command mode.
449
 **/
450
static int xbee_enter_command_mode()
451
{
452
        if (xbee_send_string("+++") != 0) {
453
                return -1;
454
        }
455

    
456
#ifndef ROBOT
457
        //        printf("In xbee_enter_command_mode about to call xbee_wait_for_ok()\n");
458
#endif
459

    
460
        if (xbee_wait_for_ok() != 0) {
461
#ifndef ROBOT
462
          printf("xbee_wait_for_ok failed.\n");
463
#endif
464
          return -1;
465
        } else {
466
          return 0;
467
        }
468
}
469

    
470
/**
471
 * Exit from command mode.
472
 **/
473
static int xbee_exit_command_mode()
474
{
475
        if (xbee_send_string("ATCN\r") != 0) {
476
                return -1;
477
        }
478

    
479
        xbee_wait_for_ok();
480

    
481
        return 0;
482
}
483

    
484
/**
485
 * Enter API mode.
486
 **/
487
static int xbee_enter_api_mode()
488
{
489
        if (xbee_send_string("ATAP 1\r") != 0) {
490
                return -1;
491
        }
492
        xbee_wait_for_ok();
493

    
494
        return 0;
495
}
496

    
497
/**
498
 * Exit API mode. (warning - does not check for response)
499
 **/
500
static int xbee_exit_api_mode()
501
{
502
        return xbee_send_string("ATAP 0\r");
503
}
504

    
505
/**
506
 * Wait until the string "OK\r" is received from the XBee.
507
 **/
508
static int xbee_wait_for_ok()
509
{
510
  //DEBUGGING PRINT
511
  //printf("\tin xbee_wait_for_ok\n");
512
        return xbee_wait_for_string("OK\r", 3);
513
}
514

    
515
/**
516
 * Delay until the specified string is received from
517
 * the XBee. Discards all other XBee data.
518
 *
519
 * @param s the string to receive
520
 * @param len the length of the string
521
 **/
522
static int xbee_wait_for_string(char* s, int len)
523
{
524
  //DEBUGGING PRINT
525
  //printf("\t in xbee_wait_for_string\n");
526

    
527
#ifndef ROBOT
528
  //printf("In xbee_wait_for_string.\n");
529
#endif
530

    
531
        char* curr = s;
532
        while (curr - s < len) {
533
                // check if buffer is empty
534
                if (buffer_last != buffer_first) {
535
                        char c = arrival_buf[buffer_first++];
536
                        if (buffer_first == XBEE_BUFFER_SIZE) {
537
                                buffer_first = 0;
538
                        }
539

    
540
                        //DEBUGGING PRINT
541
                        //printf("\t\t c is %c (%d)\n", c, (int)c);
542

    
543
                        if (c == *curr) {
544
                                curr++;
545
                        } else {
546
#ifndef ROBOT
547
                          //return -1; // Computer is less forgiving.
548
                          curr = s;
549
#else
550
                          curr = s;
551
#endif
552
                        }
553
                } // else buffer is empty.
554

    
555
#ifndef ROBOT
556
                usleep(100);
557
#endif
558
        }
559

    
560
        return 0;
561
}
562

    
563
/**
564
 * Verifies that the packets checksum is correct.
565
 * (If the checksum is correct, the sum of the bytes
566
 * is 0xFF.)
567
 *
568
 * @param packet the packet received. This includes the first
569
 * three bytes, which are header information from the XBee.
570
 *
571
 * @param len The length of the packet received from the XBee
572
 *
573
 * @return 0 if the checksum is incorrect, nonzero
574
 * otherwise
575
 **/
576
int xbee_verify_checksum(char* packet, int len)
577
{
578
        unsigned char sum = 0;
579
        int i;
580
        for (i = 3; i < len; i++)
581
                sum += (unsigned char)packet[i];
582
        return sum == 0xFF;
583
}
584

    
585
/**
586
 * Returns the checksum of the given packet.
587
 *
588
 * @param buf the data for the packet to send
589
 * @param len the length of the packet in bytes
590
 *
591
 * @return the checksum of the packet, which will
592
 * become the last byte sent in the packet
593
 **/
594
char xbee_compute_checksum(char* buf, int len)
595
{
596
        int i;
597
        unsigned char sum = 0;
598
        for (i = 0; i < len; i++)
599
                sum += (unsigned char)buf[i];
600
        return 0xFF - sum;
601
}
602

    
603
/**
604
 * Adds header information and checksum to the given
605
 * packet and sends it. Header information includes
606
 * XBEE_FRAME_START and the packet length, as two bytes.
607
 *
608
 * @param buf the packet data
609
 * @param len the size in bytes of the packet data
610
 *
611
 **/
612
static int xbee_send_frame(char* buf, int len)
613
{
614
        //printf("in %s and len is %d\n", __FUNCTION__, len);
615

    
616
        char prefix[3];
617
        prefix[0] = XBEE_FRAME_START;
618
        prefix[1] = (len & 0xFF00) >> 8;
619
        prefix[2] = len & 0xFF;
620
        char checksum = xbee_compute_checksum(buf, len);
621

    
622
        if (xbee_send(prefix, 3) != 0) {
623
                return -1;
624
        }
625

    
626
        if (xbee_send(buf, len) != 0) {
627
                return -1;
628
        }
629

    
630
        if (xbee_send(&checksum, 1) != 0) {
631
                return -1;
632
        }
633

    
634
        return 0;
635
}
636

    
637
/**
638
 * Sends an AT command to read a parameter.
639
 *
640
 * @param command the AT command to send. For exmaple,
641
 * use ID to read the PAN ID and MY to return the XBee ID.
642
 * See the XBee reference guide for a complete listing.
643
 **/
644
static int xbee_send_read_at_command(char* command)
645
{
646
        return xbee_send_modify_at_command(command, NULL);
647
}
648

    
649
/**
650
 * Sends the given AT command.
651
 *
652
 * @param command the AT command to send (e.g., MY, ID)
653
 * @param value the value to pass as a parameter
654
 * (or NULL if there is no parameter)
655
 **/
656
static int xbee_send_modify_at_command(char* command, char* value)
657
{
658
        //printf("in %s with command %s and value %s\n", __FUNCTION__, command, value);
659

    
660
        char buf[16];
661
        int i;
662

    
663
        buf[0] = XBEE_FRAME_AT_COMMAND;
664
        buf[1] = 1;
665
        buf[2] = command[0];
666
        buf[3] = command[1];
667
        int valueLen = 0;
668
        if (value != NULL)
669
        {
670
                valueLen = strlen(value);
671
                if (valueLen > 8)
672
                {
673
                        WL_DEBUG_PRINT("AT Command too large.\r\n");
674
                        return -1;
675
                }
676

    
677
                for (i = 0; i < valueLen; i++) {
678
                        buf[4 + i] = value[i];
679
                }
680
        }
681

    
682
        return xbee_send_frame(buf, 4 + valueLen);
683
}
684

    
685
/**
686
 * Send the specified packet.
687
 *
688
 * @param packet the packet data to send
689
 * @param len the number of bytes in the packet
690
 *
691
 * @param dest the ID of the XBee to send the packet to,
692
 * or XBEE_BROADCAST to send the message to all robots
693
 * in the PAN.
694
 *
695
 * @param options a combination of the flags
696
 * XBEE_OPTIONS_NONE, XBEE_OPTIONS_DISABLE_RESPONSE and
697
 * XBEE_OPTIONS_BROADCAST_ALL_PANS
698
 *
699
 * @param frame the frame number to associate this packet
700
 * with. This will be used to identify the response when
701
 * the XBee alerts us as to whether or not our message
702
 * was received.
703
 **/
704
int xbee_send_packet(char* packet, int len, int dest, char options, char frame)
705
{
706
        char buf[5];
707
        char prefix[3];
708
        int i;
709
        unsigned char checksum = 0;
710

    
711
        if (len > 100)
712
        {
713
                WL_DEBUG_PRINT("Packet is too large.\r\n");
714
                return -1;
715
        }
716

    
717
        //data for sending request
718
        buf[0] = XBEE_FRAME_TX_REQUEST_16;
719
        buf[1] = frame;
720
        buf[2] = (dest >> 8) & 0xFF;
721
        buf[3] = dest & 0xFF;
722
        buf[4] = options;
723

    
724
        //packet prefix, do this here so we don't need an extra buffer
725
        prefix[0] = XBEE_FRAME_START;
726
        prefix[1] = ((5 + len) & 0xFF00) >> 8;
727
        prefix[2] = (5 + len) & 0xFF;
728

    
729
        for (i = 0; i < 5; i++)
730
                checksum += (unsigned char)buf[i];
731
        for (i = 0; i < len; i++)
732
                checksum += (unsigned char)packet[i];
733
        checksum = 0xFF - checksum;
734

    
735
        if (xbee_send(prefix, 3) != 0) {
736
                return -1;
737
        }
738

    
739
        if (xbee_send(buf, 5) != 0) {
740
                return -1;
741
        }
742

    
743
        if (xbee_send(packet, len) != 0) {
744
                return -1;
745
        }
746

    
747
        if (xbee_send((char*)&checksum, 1) != 0) {
748
                return -1;
749
        }
750

    
751
        return 0;
752
}
753

    
754
/**
755
 * Reads a packet received from the XBee. This function
756
 * is non-blocking. The resulting packet is stored in dest.
757
 * Only returns transmission response packets and
758
 * received packets. The returned packet does not include
759
 * header information or the checksum. This method also
760
 * handles special packets dealt with by the XBee library,
761
 * and so should be called frequently while the XBee is in
762
 * use.<br><br>
763
 *
764
 * The first byte of the packet will be either
765
 * XBEE_TX_STATUS or XBEE_RX to indicated
766
 * a response to a sent message or a received message,
767
 * respectively.<br><br>
768
 *
769
 * For a status response packet:<br>
770
 * The first byte will be XBEE_TX_STATUS.<br>
771
 * The second byte will be the frame number.<br>
772
 * The third byte will be the result. 0 indicates success,
773
 * and nonzero indicates that an error ocurred in
774
 * transmitting the packet.<br><br>
775
 *
776
 * For a received packet:<br>
777
 * The first byte will be XBEE_RX.<br>
778
 * The second and third bytes will be the 16-bit
779
 * address of the packet's sender.<br>
780
 * The fourth byte is the signal strength.<br>
781
 * The fifth byte is 1 if the packet were sent to
782
 * a specific address, and 2 if it is a broadcast packet.<br><br>
783
 *
784
 * @param dest set to the packet data
785
 * @return the length of the packet, or -1 if no packet
786
 * is available
787
 **/
788
int xbee_get_packet(unsigned char* dest)
789
{
790
        //start reading a packet with XBEE_FRAME_START
791
        if (currentBufPos == 0)
792
        {
793
                do
794
                {
795
                        if (buffer_first == XBEE_BUFFER_SIZE)
796
                                buffer_first = 0;
797
                        // check if buffer is empty
798
                        if (buffer_first == buffer_last) {
799
                                return 0;
800
                        }
801
                } while (arrival_buf[buffer_first++] != XBEE_FRAME_START);
802

    
803
                if (buffer_first == XBEE_BUFFER_SIZE) {
804
                        buffer_first = 0;
805
                }
806
                xbee_buf[0] = XBEE_FRAME_START;
807
                currentBufPos++;
808
        }
809

    
810
        int len = -1;
811
        if (currentBufPos >= 3) {
812
                len = (int)xbee_buf[2] + ((int)xbee_buf[1] << 8);
813
        }
814

    
815
        while (len == -1 //packet length has not been read yet
816
                || currentBufPos < len + 4)
817
        {
818
                if (currentBufPos == 3)
819
                {
820
                        len = (int)xbee_buf[2] + ((int)xbee_buf[1] << 8);
821
                        if (len > 120)
822
                        {
823
                                WL_DEBUG_PRINT("Packet too large. Probably error in XBee transmission.\n");
824
                                currentBufPos = 0;
825
                                return -1;
826
                        }
827
                }
828

    
829
                // check if buffer is empty
830
                if (buffer_first == buffer_last) {
831
                        return 0;
832
                }
833
                xbee_buf[currentBufPos++] = arrival_buf[buffer_first++];
834
                if (buffer_first == XBEE_BUFFER_SIZE) {
835
                        buffer_first = 0;
836
                }
837
        }
838

    
839
        currentBufPos = 0;
840

    
841
        if (!xbee_verify_checksum(xbee_buf, len + 4))
842
        {
843
                WL_DEBUG_PRINT("XBee checksum failed.\r\n");
844
                return -1;
845
        }
846

    
847
        //we will take care of the packet
848
        if (xbee_handle_packet(xbee_buf + 3, len) != 0) {
849
                return 0;
850
        }
851

    
852
        if (dest == NULL) {
853
                return 0;
854
        }
855

    
856
        int i;
857
        for (i = 3; i < len + 3; i++) {
858
                dest[i - 3] = xbee_buf[i];
859
        }
860

    
861
        return len;
862
}
863

    
864
/**
865
 * Handles modem status packets.
866
 *
867
 * @param status the type of status packet received.
868
 **/
869
void xbee_handle_status(char status)
870
{
871
        switch (status)
872
        {
873
                case 0:
874
                        WL_DEBUG_PRINT("XBee hardware reset.\r\n");
875
                        break;
876
                case 1:
877
                        WL_DEBUG_PRINT("Watchdog timer reset.\r\n");
878
                        break;
879
                case 2:
880
                        WL_DEBUG_PRINT("Associated.\r\n");
881
                        break;
882
                case 3:
883
                        WL_DEBUG_PRINT("Disassociated.\r\n");
884
                        break;
885
                case 4:
886
                        WL_DEBUG_PRINT("Synchronization lost.\r\n");
887
                        break;
888
                case 5:
889
                        WL_DEBUG_PRINT("Coordinator realignment.\r\n");
890
                        break;
891
                case 6:
892
                        WL_DEBUG_PRINT("Coordinator started.\r\n");
893
                        break;
894
        }
895
}
896

    
897
/**
898
 * Handles AT command response packets.
899
 * @param command the two character AT command, e.g. MY or ID
900
 * @param result 0 for success, 1 for an error
901
 * @param extra the hex value of the requested register
902
 * @param extraLen the length in bytes of extra
903
 **/
904
static void xbee_handle_at_command_response(char* command, char result, char* extra, int extraLen)
905
{
906
        if (result == 1)
907
        {
908
                WL_DEBUG_PRINT("Error with AT");
909
                WL_DEBUG_PRINT(command);
910
                WL_DEBUG_PRINT(" packet.\r\n");
911
        }
912
        WL_DEBUG_PRINT("AT");
913
        WL_DEBUG_PRINT(command);
914
        WL_DEBUG_PRINT(" command was successful.\r\n");
915

    
916
        if (command[0] == 'I' && command[1] == 'D')
917
        {
918
                xbee_panID = xbee_pending_panID;
919
                WL_DEBUG_PRINT("PAN ID set to ");
920
                WL_DEBUG_PRINT_INT(xbee_panID);
921
                WL_DEBUG_PRINT(".\r\n");
922
                return;
923
        }
924

    
925
        if (command[0] == 'C' && command[1] == 'H')
926
        {
927
                xbee_channel = xbee_pending_channel;
928
                WL_DEBUG_PRINT("Channel set to ");
929
                WL_DEBUG_PRINT_INT(xbee_channel);
930
                WL_DEBUG_PRINT(".\r\n");
931
                return;
932
        }
933

    
934
        if (command[0] == 'M' && command[1] == 'Y' && extraLen != 0)
935
        {
936
//                                                        printf("reading xbee_address\n");
937

    
938
                xbee_address = 0;
939
                int i;
940
                for (i = 0; i < extraLen; i++) {
941
                        xbee_address = (xbee_address << 8) + extra[i];
942
                }
943
//                                                        printf("xbee address is: %d\n", xbee_address);
944

    
945
                WL_DEBUG_PRINT("XBee address is ");
946
                WL_DEBUG_PRINT_INT(xbee_address);
947
                WL_DEBUG_PRINT(".\r\n");
948

    
949
                if (xbee_address == 0)
950
                {
951
                  printf("XBee 16-bit address must be set using ATMY.\r\n");
952
                        WL_DEBUG_PRINT("XBee 16-bit address must be set using ATMY.\r\n");
953
                        exit(0);
954
                }
955
        }
956
}
957

    
958
/**
959
 * Attempts to handle the packet if it is dealt with
960
 * by the library.
961
 * We will handle the following packet types:
962
 *    Modem Status
963
 *    AT Command Response
964
 *
965
 * @param packet the packet to handle
966
 * @param len the length of the packet
967
 *
968
 * @return 1 if we have handled the packet, 0 otherwise
969
 */
970
static int xbee_handle_packet(char* packet, int len)
971
{
972
  //DEBUGGING PRINT
973
  //printf("xbee_handle_packet: ");
974
  //printHex(packet, len);
975

    
976
        char command[3] = {1, 2, 3};
977
        if (len <= 0) //this should not happend
978
        {
979
                WL_DEBUG_PRINT("Non-positive packet length.\r\n");
980
                return 0;
981
        }
982

    
983
        switch ((unsigned char)packet[0]) //packet type
984
        {
985
                case XBEE_FRAME_STATUS:
986
                        xbee_handle_status(packet[1]);
987
                        return 1;
988
                case XBEE_FRAME_AT_COMMAND_RESPONSE:
989
                        //printf("in XBEE_FRAME_AT_COMMAND_RESPONSE case\n");
990
                        command[0] = packet[2];
991
                        command[1] = packet[3];
992
                        command[2] = 0;
993
                        xbee_handle_at_command_response(command, packet[4], packet + 5, len - 5);
994
                        return 1;
995
        }
996
        return 0;
997
}
998

    
999
/**
1000
 * Sets the personal area network id.
1001
 *
1002
 * @param id the new personal area network (PAN) id
1003
 **/
1004
int xbee_set_pan_id(int id)
1005
{
1006
        char s[3];
1007
        s[0] = (id >> 8) & 0xFF;
1008
        s[1] = id & 0xFF;
1009
        s[2] = 0;
1010
        xbee_pending_panID = id;
1011
        return xbee_send_modify_at_command("ID", s);
1012
}
1013

    
1014
/**
1015
 * Get the PAN ID for the XBee.
1016
 *
1017
 * @return the personal area network id, or
1018
 * XBEE_PAN_DEFAULT if it has not yet been set.
1019
 **/
1020
unsigned int xbee_get_pan_id()
1021
{
1022
        return xbee_panID;
1023
}
1024

    
1025
/**
1026
 * Set the channel the XBee is using.
1027
 *
1028
 * @param channel the channel the XBee will not use,
1029
 * between 0x0B and 0x1A
1030
 *
1031
 * @see xbee_get_channel
1032
 **/
1033
int xbee_set_channel(int channel)
1034
{
1035
        if (channel < 0x0B || channel > 0x1A)
1036
        {
1037
                WL_DEBUG_PRINT("Channel out of range.\r\n");
1038
                return -1;
1039
        }
1040

    
1041
        char s[3];
1042
        s[0] = channel & 0xFF;
1043
        s[1] = 0;
1044
        xbee_pending_channel = channel;
1045

    
1046
        return xbee_send_modify_at_command("CH", s);
1047
}
1048

    
1049
/**
1050
 * Returns the channel which the XBee is currently using.
1051
 *
1052
 * @return the channel the XBee is using
1053
 *
1054
 * @see xbee_set_channel
1055
 **/
1056
int xbee_get_channel(void)
1057
{
1058
        return xbee_channel;
1059
}
1060

    
1061
/**
1062
 * Get the 16-bit address of the XBee.
1063
 * This is used to specify who to send messages to
1064
 * and who messages are from.
1065
 *
1066
 * @return the 16-bit address of the XBee.
1067
 **/
1068
unsigned int xbee_get_address()
1069
{
1070
        return xbee_address;
1071
}
1072

    
1073
#ifndef ROBOT
1074
void xbee_set_com_port(char* port)
1075
{
1076
        xbee_com_port = port;
1077
}
1078
#endif