Project

General

Profile

Statistics
| Revision:

root / trunk / code / projects / libwireless / lib / xbee.c @ 581

History | View | Annotate | Download (21.6 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
/*Function Implementations*/
131

    
132
#ifdef ROBOT
133

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

    
168
#else
169

    
170
// Computer code
171

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

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

    
195
                usleep(1000);
196
        }
197

    
198
        return NULL;
199
}
200

    
201
#endif
202

    
203
/**
204
 * Initializes the XBee library so that other functions may be used.
205
 **/
206
int xbee_lib_init()
207
{
208
        arrival_buf[0] = 'A';
209
        arrival_buf[1] = 'A';
210
        arrival_buf[2] = 'A';
211
#ifdef ROBOT
212

    
213
        //enable the receiving interrupt
214
#ifdef FIREFLY
215
        UCSR0B |= _BV(RXCIE) | _BV(RXEN);
216
#else
217
        UCSR1B |= _BV(RXCIE);
218
#endif
219
        sei();
220
#else
221
        printf("Connecting to port %s.\n", xbee_com_port);
222
        xbee_stream = open(xbee_com_port, O_RDWR);
223
        if (xbee_stream == -1/* || lockf(xbee_stream, F_TEST, 0) != 0*/)
224
        {
225
                printf("Failed to open connection to XBee on port %s\r\n", xbee_com_port);
226
                return -1;
227
        } else {
228
          printf("Successfully opened connection to XBee on port %s\r\n", xbee_com_port);
229
        }
230

    
231
        // set baud rate, etc. correctly
232
        struct termios options;
233

    
234
        tcgetattr(xbee_stream, &options);
235
        cfsetispeed(&options, B9600);
236
        cfsetospeed(&options, B9600);
237
        options.c_iflag &= ~ICRNL;
238
        options.c_oflag &= ~OCRNL;
239
        options.c_cflag |= (CLOCAL | CREAD);
240
        options.c_cflag &= ~PARENB;
241
        options.c_cflag &= ~CSTOPB;
242
        options.c_cflag &= ~CSIZE;
243
        options.c_cflag |= CS8;
244
        options.c_lflag &= ~ICANON;
245
        options.c_cc[VMIN] = 1;
246
        options.c_cc[VTIME] = 50;
247

    
248
        if (tcsetattr(xbee_stream, TCSANOW, &options))
249
        {
250
                fprintf(stderr, "Error setting attributes.\n");
251
                return -1;
252
        } else {
253
          //printf("Successfully set termios attributes.\n");
254
        }
255

    
256
        //lockf(xbee_stream, F_LOCK, 0);
257

    
258
        xbee_listen_thread = (pthread_t*)malloc(sizeof(pthread_t));
259
        if (xbee_listen_thread == NULL)
260
        {
261
                fprintf(stderr, "%s: Malloc failed.\n", __FUNCTION__);
262
                return -1;
263
        }
264

    
265
        int ret = pthread_create(xbee_listen_thread, NULL, listen_to_xbee, NULL);
266
        if (ret)
267
        {
268
                fprintf(stderr, "Failed to create listener thread.\r\n");
269
                return -1;
270
        } else {
271
          //printf("Successfully created listener thread.\n");
272
        }
273
#endif
274

    
275
        if (xbee_enter_command_mode() != 0) {
276
#ifndef ROBOT
277
          printf("Error returned from xbee_enter_command_mode\n");
278
#endif
279
                return -1;
280
        }
281

    
282
        if (xbee_enter_api_mode() != 0) {
283
#ifndef ROBOT
284
          printf("Error returned from xbee_enter_api_mode\n");
285
#endif
286
                return -1;
287
        }
288

    
289
        if (xbee_exit_command_mode() != 0) {
290
#ifndef ROBOT
291
          printf("Error returned from xbee_exit_command_mode\n");
292
#endif
293
                return -1;
294
        }
295

    
296
        if (xbee_send_read_at_command("MY")) {
297
#ifndef ROBOT
298
          printf("Error returned from xbee_send_read_at_command\n");
299
#endif
300
                return -1;
301
        }
302

    
303
#ifndef ROBOT
304
        //printf("About to enter while loop to get xbee_address.\n");
305
        int i;
306
        for (i = 0; xbee_address == 0 && i < XBEE_GET_PACKET_TIMEOUT; i++) {
307
          ret = xbee_get_packet(NULL);
308

    
309
          usleep(1000);
310

    
311
          if (ret == -1) {
312
            printf("xbee_get_packet(NULL) failed.\n");
313
            return -1;
314
          }
315
        }
316

    
317
        //        printf("After exiting while loop to get xbee_address.\n");
318
#else
319
        //wait to return until the address is set
320
        while (xbee_address == 0) {
321
          xbee_get_packet(NULL);
322
        }
323
#endif
324

    
325
#ifndef ROBOT
326
        if (i == XBEE_GET_PACKET_TIMEOUT) { // We timed-out.
327

    
328
          printf("xbee_get_packet timed out.\n");
329
          return -1;
330
        } else {
331
          return 0;
332
        }
333
#else
334
        return 0;
335
#endif
336
}
337

    
338
/**
339
 * Call when finished using the XBee library. This releases
340
 * all sued resources.
341
 **/
342
void xbee_terminate()
343
{
344
        #ifndef ROBOT
345
        pthread_cancel(*xbee_listen_thread);
346
        free(xbee_listen_thread);
347
        lockf(xbee_stream, F_ULOCK, 0);
348
        close(xbee_stream);
349
        #endif
350
}
351

    
352
/**
353
 * Send a buffer buf of size bytes to the XBee.
354
 *
355
 * @param buf the buffer of data to send
356
 * @param size the number of bytes to send
357
 **/
358
static int xbee_send(char* buf, int size)
359
{
360
#ifdef ROBOT
361
        int i;
362
        for (i = 0; i < size; i++) {
363
                xbee_putc(buf[i]);
364
        }
365

    
366
        return 0;
367

    
368
#else
369

    
370
        int ret = write(xbee_stream, buf, size);
371
        //success
372
        if (ret == size)
373
                return 0;
374
        if (ret == -1)
375
        {
376
                //interrupted by system signal, probably timer interrupt.
377
                //just try again
378
                if (errno == 4)
379
                {
380
                        return xbee_send(buf, size);
381
                }
382
                printf("Failed to write to xbee, error %i.\r\n", errno);
383
                return -1;
384
        }
385

    
386
        //write was interrupted after writing ret bytes
387
        return xbee_send(buf + ret, size - ret);
388
#endif
389
}
390

    
391
/**
392
 * Sends a string to the XBee.
393
 *
394
 * @param c the string to send to the XBEE
395
 **/
396
static int xbee_send_string(char* c)
397
{
398
        return xbee_send(c, strlen(c));
399
}
400

    
401
#ifndef ROBOT
402
static int xbee_read(char* buf, int size)
403
{
404
        if (read(xbee_stream, buf, size) == -1) {
405
                printf("Failed to read from xbee.\r\n");
406
                return -1;
407
        }
408

    
409
        return 0;
410
}
411
#endif
412

    
413
/**
414
 * Enter into command mode.
415
 **/
416
static int xbee_enter_command_mode()
417
{
418
        if (xbee_send_string("+++") != 0) {
419
                return -1;
420
        }
421

    
422
#ifndef ROBOT
423
        //        printf("In xbee_enter_command_mode about to call xbee_wait_for_ok()\n");
424
#endif
425

    
426
        if (xbee_wait_for_ok() != 0) {
427
#ifndef ROBOT
428
          printf("xbee_wait_for_ok failed.\n");
429
#endif
430
          return -1;
431
        } else {
432
          return 0;
433
        }
434
}
435

    
436
/**
437
 * Exit from command mode.
438
 **/
439
static int xbee_exit_command_mode()
440
{
441
        if (xbee_send_string("ATCN\r") != 0) {
442
                return -1;
443
        }
444

    
445
        xbee_wait_for_ok();
446

    
447
        return 0;
448
}
449

    
450
/**
451
 * Enter API mode.
452
 **/
453
static int xbee_enter_api_mode()
454
{
455
        if (xbee_send_string("ATAP 1\r") != 0) {
456
                return -1;
457
        }
458
        xbee_wait_for_ok();
459

    
460
        return 0;
461
}
462

    
463
/**
464
 * Exit API mode. (warning - does not check for response)
465
 **/
466
static int xbee_exit_api_mode()
467
{
468
        return xbee_send_string("ATAP 0\r");
469
}
470

    
471
/**
472
 * Wait until the string "OK\r" is received from the XBee.
473
 **/
474
static int xbee_wait_for_ok()
475
{
476
        return xbee_wait_for_string("OK\r", 3);
477
}
478

    
479
/**
480
 * Delay until the specified string is received from
481
 * the XBee. Discards all other XBee data.
482
 *
483
 * @param s the string to receive
484
 * @param len the length of the string
485
 **/
486
static int xbee_wait_for_string(char* s, int len)
487
{
488
#ifndef ROBOT
489
  //printf("In xbee_wait_for_string.\n");
490
#endif
491

    
492
        char* curr = s;
493
        while (curr - s < len) {
494
                // check if buffer is empty
495
                if (buffer_last != buffer_first) {
496
                        char c = arrival_buf[buffer_first++];
497
                        if (buffer_first == XBEE_BUFFER_SIZE) {
498
                                buffer_first = 0;
499
                        }
500

    
501
                        if (c == *curr) {
502
                                curr++;
503
                        } else {
504
#ifndef ROBOT
505
                          return -1; // Computer is less forgiving.
506
#else
507
                          curr = s;
508
#endif
509
                        }
510
                } // else buffer is empty.
511

    
512
#ifndef ROBOT
513
                usleep(100);
514
#endif
515
        }
516

    
517
        return 0;
518
}
519

    
520
/**
521
 * Verifies that the packets checksum is correct.
522
 * (If the checksum is correct, the sum of the bytes
523
 * is 0xFF.)
524
 *
525
 * @param packet the packet received. This includes the first
526
 * three bytes, which are header information from the XBee.
527
 *
528
 * @param len The length of the packet received from the XBee
529
 *
530
 * @return 0 if the checksum is incorrect, nonzero
531
 * otherwise
532
 **/
533
int xbee_verify_checksum(char* packet, int len)
534
{
535
        unsigned char sum = 0;
536
        int i;
537
        for (i = 3; i < len; i++)
538
                sum += (unsigned char)packet[i];
539
        return sum == 0xFF;
540
}
541

    
542
/**
543
 * Returns the checksum of the given packet.
544
 *
545
 * @param buf the data for the packet to send
546
 * @param len the length of the packet in bytes
547
 *
548
 * @return the checksum of the packet, which will
549
 * become the last byte sent in the packet
550
 **/
551
char xbee_compute_checksum(char* buf, int len)
552
{
553
        int i;
554
        unsigned char sum = 0;
555
        for (i = 0; i < len; i++)
556
                sum += (unsigned char)buf[i];
557
        return 0xFF - sum;
558
}
559

    
560
/**
561
 * Adds header information and checksum to the given
562
 * packet and sends it. Header information includes
563
 * XBEE_FRAME_START and the packet length, as two bytes.
564
 *
565
 * @param buf the packet data
566
 * @param len the size in bytes of the packet data
567
 *
568
 **/
569
static int xbee_send_frame(char* buf, int len)
570
{
571
        char prefix[3];
572
        prefix[0] = XBEE_FRAME_START;
573
        prefix[1] = (len & 0xFF00) >> 8;
574
        prefix[2] = len & 0xFF;
575
        char checksum = xbee_compute_checksum(buf, len);
576

    
577
        if (xbee_send(prefix, 3) != 0) {
578
                return -1;
579
        }
580

    
581
        if (xbee_send(buf, len) != 0) {
582
                return -1;
583
        }
584

    
585
        if (xbee_send(&checksum, 1) != 0) {
586
                return -1;
587
        }
588

    
589
        return 0;
590
}
591

    
592
/**
593
 * Sends an AT command to read a parameter.
594
 *
595
 * @param command the AT command to send. For exmaple,
596
 * use ID to read the PAN ID and MY to return the XBee ID.
597
 * See the XBee reference guide for a complete listing.
598
 **/
599
static int xbee_send_read_at_command(char* command)
600
{
601
        return xbee_send_modify_at_command(command, NULL);
602
}
603

    
604
/**
605
 * Sends the given AT command.
606
 *
607
 * @param command the AT command to send (e.g., MY, ID)
608
 * @param value the value to pass as a parameter
609
 * (or NULL if there is no parameter)
610
 **/
611
static int xbee_send_modify_at_command(char* command, char* value)
612
{
613
        char buf[16];
614
        int i;
615

    
616
        buf[0] = XBEE_FRAME_AT_COMMAND;
617
        buf[1] = 1;
618
        buf[2] = command[0];
619
        buf[3] = command[1];
620
        int valueLen = 0;
621
        if (value != NULL)
622
        {
623
                valueLen = strlen(value);
624
                if (valueLen > 8)
625
                {
626
                        WL_DEBUG_PRINT("AT Command too large.\r\n");
627
                        return -1;
628
                }
629

    
630
                for (i = 0; i < valueLen; i++) {
631
                        buf[4 + i] = value[i];
632
                }
633
        }
634

    
635
        return xbee_send_frame(buf, 4 + valueLen);
636
}
637

    
638
/**
639
 * Send the specified packet.
640
 *
641
 * @param packet the packet data to send
642
 * @param len the number of bytes in the packet
643
 *
644
 * @param dest the ID of the XBee to send the packet to,
645
 * or XBEE_BROADCAST to send the message to all robots
646
 * in the PAN.
647
 *
648
 * @param options a combination of the flags
649
 * XBEE_OPTIONS_NONE, XBEE_OPTIONS_DISABLE_RESPONSE and
650
 * XBEE_OPTIONS_BROADCAST_ALL_PANS
651
 *
652
 * @param frame the frame number to associate this packet
653
 * with. This will be used to identify the response when
654
 * the XBee alerts us as to whether or not our message
655
 * was received.
656
 **/
657
int xbee_send_packet(char* packet, int len, int dest, char options, char frame)
658
{
659
        char buf[5];
660
        char prefix[3];
661
        int i;
662
        unsigned char checksum = 0;
663

    
664
        if (len > 100)
665
        {
666
                WL_DEBUG_PRINT("Packet is too large.\r\n");
667
                return -1;
668
        }
669

    
670
        //data for sending request
671
        buf[0] = XBEE_FRAME_TX_REQUEST_16;
672
        buf[1] = frame;
673
        buf[2] = (dest >> 8) & 0xFF;
674
        buf[3] = dest & 0xFF;
675
        buf[4] = options;
676

    
677
        //packet prefix, do this here so we don't need an extra buffer
678
        prefix[0] = XBEE_FRAME_START;
679
        prefix[1] = ((5 + len) & 0xFF00) >> 8;
680
        prefix[2] = (5 + len) & 0xFF;
681

    
682
        for (i = 0; i < 5; i++)
683
                checksum += (unsigned char)buf[i];
684
        for (i = 0; i < len; i++)
685
                checksum += (unsigned char)packet[i];
686
        checksum = 0xFF - checksum;
687

    
688
        if (xbee_send(prefix, 3) != 0) {
689
                return -1;
690
        }
691

    
692
        if (xbee_send(buf, 5) != 0) {
693
                return -1;
694
        }
695

    
696
        if (xbee_send(packet, len) != 0) {
697
                return -1;
698
        }
699

    
700
        if (xbee_send((char*)&checksum, 1) != 0) {
701
                return -1;
702
        }
703

    
704
        return 0;
705
}
706

    
707
/**
708
 * Reads a packet received from the XBee. This function
709
 * is non-blocking. The resulting packet is stored in dest.
710
 * Only returns transmission response packets and
711
 * received packets. The returned packet does not include
712
 * header information or the checksum. This method also
713
 * handles special packets dealt with by the XBee library,
714
 * and so should be called frequently while the XBee is in
715
 * use.<br><br>
716
 *
717
 * The first byte of the packet will be either
718
 * XBEE_TX_STATUS or XBEE_RX to indicated
719
 * a response to a sent message or a received message,
720
 * respectively.<br><br>
721
 *
722
 * For a status response packet:<br>
723
 * The first byte will be XBEE_TX_STATUS.<br>
724
 * The second byte will be the frame number.<br>
725
 * The third byte will be the result. 0 indicates success,
726
 * and nonzero indicates that an error ocurred in
727
 * transmitting the packet.<br><br>
728
 *
729
 * For a received packet:<br>
730
 * The first byte will be XBEE_RX.<br>
731
 * The second and third bytes will be the 16-bit
732
 * address of the packet's sender.<br>
733
 * The fourth byte is the signal strength.<br>
734
 * The fifth byte is 1 if the packet were sent to
735
 * a specific address, and 2 if it is a broadcast packet.<br><br>
736
 *
737
 * @param dest set to the packet data
738
 * @return the length of the packet, or -1 if no packet
739
 * is available
740
 **/
741
int xbee_get_packet(unsigned char* dest)
742
{
743
        //start reading a packet with XBEE_FRAME_START
744
        if (currentBufPos == 0)
745
        {
746
                do
747
                {
748
                        if (buffer_first == XBEE_BUFFER_SIZE)
749
                                buffer_first = 0;
750
                        // check if buffer is empty
751
                        if (buffer_first == buffer_last) {
752
                                return 0;
753
                        }
754
                } while (arrival_buf[buffer_first++] != XBEE_FRAME_START);
755

    
756
                if (buffer_first == XBEE_BUFFER_SIZE) {
757
                        buffer_first = 0;
758
                }
759
                xbee_buf[0] = XBEE_FRAME_START;
760
                currentBufPos++;
761
        }
762

    
763
        int len = -1;
764
        if (currentBufPos >= 3) {
765
                len = (int)xbee_buf[2] + ((int)xbee_buf[1] << 8);
766
        }
767

    
768
        while (len == -1 //packet length has not been read yet
769
                || currentBufPos < len + 4)
770
        {
771
                if (currentBufPos == 3)
772
                {
773
                        len = (int)xbee_buf[2] + ((int)xbee_buf[1] << 8);
774
                        if (len > 120)
775
                        {
776
                                WL_DEBUG_PRINT("Packet too large. Probably error in XBee transmission.\n");
777
                                currentBufPos = 0;
778
                                return -1;
779
                        }
780
                }
781

    
782
                // check if buffer is empty
783
                if (buffer_first == buffer_last) {
784
                        return 0;
785
                }
786
                xbee_buf[currentBufPos++] = arrival_buf[buffer_first++];
787
                if (buffer_first == XBEE_BUFFER_SIZE) {
788
                        buffer_first = 0;
789
                }
790
        }
791

    
792
        currentBufPos = 0;
793

    
794
        if (!xbee_verify_checksum(xbee_buf, len + 4))
795
        {
796
                WL_DEBUG_PRINT("XBee checksum failed.\r\n");
797
                return -1;
798
        }
799

    
800
        //we will take care of the packet
801
        if (xbee_handle_packet(xbee_buf + 3, len) != 0) {
802
                return 0;
803
        }
804

    
805
        if (dest == NULL) {
806
                return 0;
807
        }
808

    
809
        int i;
810
        for (i = 3; i < len + 3; i++) {
811
                dest[i - 3] = xbee_buf[i];
812
        }
813

    
814
        return len;
815
}
816

    
817
/**
818
 * Handles modem status packets.
819
 *
820
 * @param status the type of status packet received.
821
 **/
822
void xbee_handle_status(char status)
823
{
824
        switch (status)
825
        {
826
                case 0:
827
                        WL_DEBUG_PRINT("XBee hardware reset.\r\n");
828
                        break;
829
                case 1:
830
                        WL_DEBUG_PRINT("Watchdog timer reset.\r\n");
831
                        break;
832
                case 2:
833
                        WL_DEBUG_PRINT("Associated.\r\n");
834
                        break;
835
                case 3:
836
                        WL_DEBUG_PRINT("Disassociated.\r\n");
837
                        break;
838
                case 4:
839
                        WL_DEBUG_PRINT("Synchronization lost.\r\n");
840
                        break;
841
                case 5:
842
                        WL_DEBUG_PRINT("Coordinator realignment.\r\n");
843
                        break;
844
                case 6:
845
                        WL_DEBUG_PRINT("Coordinator started.\r\n");
846
                        break;
847
        }
848
}
849

    
850
/**
851
 * Handles AT command response packets.
852
 * @param command the two character AT command, e.g. MY or ID
853
 * @param result 0 for success, 1 for an error
854
 * @param extra the hex value of the requested register
855
 * @param extraLen the length in bytes of extra
856
 **/
857
static void xbee_handle_at_command_response(char* command, char result, char* extra, int extraLen)
858
{
859
        if (result == 1)
860
        {
861
                WL_DEBUG_PRINT("Error with AT");
862
                WL_DEBUG_PRINT(command);
863
                WL_DEBUG_PRINT(" packet.\r\n");
864
        }
865
        WL_DEBUG_PRINT("AT");
866
        WL_DEBUG_PRINT(command);
867
        WL_DEBUG_PRINT(" command was successful.\r\n");
868

    
869
        if (command[0] == 'I' && command[1] == 'D')
870
        {
871
                xbee_panID = xbee_pending_panID;
872
                WL_DEBUG_PRINT("PAN ID set to ");
873
                WL_DEBUG_PRINT_INT(xbee_panID);
874
                WL_DEBUG_PRINT(".\r\n");
875
                return;
876
        }
877

    
878
        if (command[0] == 'C' && command[1] == 'H')
879
        {
880
                xbee_channel = xbee_pending_channel;
881
                WL_DEBUG_PRINT("Channel set to ");
882
                WL_DEBUG_PRINT_INT(xbee_channel);
883
                WL_DEBUG_PRINT(".\r\n");
884
                return;
885
        }
886

    
887
        if (command[0] == 'M' && command[1] == 'Y' && extraLen != 0)
888
        {
889
//                                                        printf("reading xbee_address\n");
890

    
891
                xbee_address = 0;
892
                int i;
893
                for (i = 0; i < extraLen; i++) {
894
                        xbee_address = (xbee_address << 8) + extra[i];
895
                }
896
//                                                        printf("xbee address is: %d\n", xbee_address);
897

    
898
                WL_DEBUG_PRINT("XBee address is ");
899
                WL_DEBUG_PRINT_INT(xbee_address);
900
                WL_DEBUG_PRINT(".\r\n");
901

    
902
                if (xbee_address == 0)
903
                {
904
                        WL_DEBUG_PRINT("XBee 16-bit address must be set using ATMY.\r\n");
905
                        exit(0);
906
                }
907
        }
908
}
909

    
910
/**
911
 * Attempts to handle the packet if it is dealt with
912
 * by the library.
913
 * We will handle the following packet types:
914
 *    Modem Status
915
 *    AT Command Response
916
 *
917
 * @param packet the packet to handle
918
 * @param len the length of the packet
919
 *
920
 * @return 1 if we have handled the packet, 0 otherwise
921
 */
922
static int xbee_handle_packet(char* packet, int len)
923
{
924
        char command[3] = {1, 2, 3};
925
        if (len <= 0) //this should not happend
926
        {
927
                WL_DEBUG_PRINT("Non-positive packet length.\r\n");
928
                return 0;
929
        }
930

    
931
        switch ((unsigned char)packet[0]) //packet type
932
        {
933
                case XBEE_FRAME_STATUS:
934
                        xbee_handle_status(packet[1]);
935
                        return 1;
936
                case XBEE_FRAME_AT_COMMAND_RESPONSE:
937
                        command[0] = packet[2];
938
                        command[1] = packet[3];
939
                        command[2] = 0;
940
                        xbee_handle_at_command_response(command, packet[4], packet + 5, len - 5);
941
                        return 1;
942
        }
943
        return 0;
944
}
945

    
946
/**
947
 * Sets the personal area network id.
948
 *
949
 * @param id the new personal area network (PAN) id
950
 **/
951
int xbee_set_pan_id(int id)
952
{
953
        char s[3];
954
        s[0] = (id >> 8) & 0xFF;
955
        s[1] = id & 0xFF;
956
        s[2] = 0;
957
        xbee_pending_panID = id;
958
        return xbee_send_modify_at_command("ID", s);
959
}
960

    
961
/**
962
 * Get the PAN ID for the XBee.
963
 *
964
 * @return the personal area network id, or
965
 * XBEE_PAN_DEFAULT if it has not yet been set.
966
 **/
967
unsigned int xbee_get_pan_id()
968
{
969
        return xbee_panID;
970
}
971

    
972
/**
973
 * Set the channel the XBee is using.
974
 *
975
 * @param channel the channel the XBee will not use,
976
 * between 0x0B and 0x1A
977
 *
978
 * @see xbee_get_channel
979
 **/
980
int xbee_set_channel(int channel)
981
{
982
        if (channel < 0x0B || channel > 0x1A)
983
        {
984
                WL_DEBUG_PRINT("Channel out of range.\r\n");
985
                return -1;
986
        }
987

    
988
        char s[3];
989
        s[0] = channel & 0xFF;
990
        s[1] = 0;
991
        xbee_pending_channel = channel;
992

    
993
        return xbee_send_modify_at_command("CH", s);
994
}
995

    
996
/**
997
 * Returns the channel which the XBee is currently using.
998
 *
999
 * @return the channel the XBee is using
1000
 *
1001
 * @see xbee_set_channel
1002
 **/
1003
int xbee_get_channel(void)
1004
{
1005
        return xbee_channel;
1006
}
1007

    
1008
/**
1009
 * Get the 16-bit address of the XBee.
1010
 * This is used to specify who to send messages to
1011
 * and who messages are from.
1012
 *
1013
 * @return the 16-bit address of the XBee.
1014
 **/
1015
unsigned int xbee_get_address()
1016
{
1017
        return xbee_address;
1018
}
1019

    
1020
#ifndef ROBOT
1021
void xbee_set_com_port(char* port)
1022
{
1023
        xbee_com_port = port;
1024
}
1025
#endif