Project

General

Profile

Statistics
| Revision:

root / trunk / code / projects / test / xbee.c @ 1432

History | View | Annotate | Download (21.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

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

    
43
#ifndef ROBOT
44

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

    
51
#else
52

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

    
56
#endif
57

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

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

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

    
75
/*Internal Function Prototypes*/
76

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

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

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

    
94
/*API Mode Functions*/
95

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

    
105
/*Global Variables*/
106

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

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

    
123

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

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

    
135
/*Function Implementations*/
136

    
137
#ifdef ROBOT
138

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

    
173
#else
174

    
175
// Computer code
176

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

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

    
200
                usleep(1000);
201
        }
202

    
203
        return NULL;
204
}
205

    
206
#endif
207

    
208
/**
209
 * Initializes the XBee library so that other functions may be used.
210
 **/
211
int xbee_lib_init()
212
{
213
        WL_DEBUG_PRINT("in xbee_init\n");
214
#ifdef ROBOT
215

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

    
241
        // set baud rate, etc. correctly
242
        struct termios options;
243

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

    
258
        if (tcsetattr(xbee_stream, TCSANOW, &options))
259
        {
260
                WL_DEBUG_PRINT("Error setting attributes.\n");
261
                return -1;
262
        }
263

    
264
        xbee_listen_thread = (pthread_t*)malloc(sizeof(pthread_t));
265
        if (xbee_listen_thread == NULL)
266
        {
267
                WL_DEBUG_PRINT("Malloc failed.\n");
268
                return -1;
269
        }
270

    
271
        int ret = pthread_create(xbee_listen_thread, NULL, listen_to_xbee, NULL);
272
        if (ret)
273
        {
274
                WL_DEBUG_PRINT("Failed to create listener thread.\n");
275
                return -1;
276
        }
277
#endif
278

    
279
        WL_DEBUG_PRINT("Entering command mode.\n");
280

    
281
        if (xbee_enter_command_mode() != 0) {
282
                return -1;
283
        }
284

    
285
        WL_DEBUG_PRINT("Entered command mode.\n");
286

    
287
        if (xbee_enter_api_mode() != 0) {
288
                return -1;
289
        }
290

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

    
293
        if (xbee_exit_command_mode() != 0) {
294
             return -1;
295
        }
296
        
297
        WL_DEBUG_PRINT("Left command mode.\n");
298

    
299
        if (xbee_send_read_at_command("MY")) {
300
                return -1;
301
        }
302
        WL_DEBUG_PRINT("Getting ATMY address.\n");
303

    
304
#ifndef ROBOT
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
/*             WL_DEBUG_PRINT("xbee_get_packet(NULL) failed.\n"); */
313
/*             return -1; */
314
/*           } */
315
        }
316
#else
317
        //wait to return until the address is set
318
  //TODO: this shouldn't wait indefinitely.  There should be some sort of reasonable timeout
319
  // so if the address is never set right, an error can be returned instead of having the
320
  // robot hang forever
321
        while (xbee_address == 0) {
322
          xbee_get_packet(NULL);
323
        }
324
#endif
325
        WL_DEBUG_PRINT("Got ATMY address.\n");
326

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

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

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

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

    
369
        return 0;
370

    
371
#else
372

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

    
389
        //write was interrupted after writing ret bytes
390
        return xbee_send(buf + ret, size - ret);
391
#endif
392
}
393

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

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

    
412
        return 0;
413
}
414
#endif
415

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

    
425
        if (xbee_wait_for_ok() != 0) {
426
          return -1;
427
        }
428
          return 0;
429
}
430

    
431
/**
432
 * Exit from command mode.
433
 **/
434
static int xbee_exit_command_mode()
435
{
436
        if (xbee_send_string("ATCN\r") != 0) {
437
                return -1;
438
        }
439

    
440
        xbee_wait_for_ok();
441

    
442
        return 0;
443
}
444

    
445
/**
446
 * Enter API mode.
447
 **/
448
static int xbee_enter_api_mode()
449
{
450
        if (xbee_send_string("ATAP 1\r") != 0) {
451
                return -1;
452
        }
453
        xbee_wait_for_ok();
454

    
455
        return 0;
456
}
457

    
458
/**
459
 * Wait until the string "OK\r" is received from the XBee.
460
 **/
461
static int xbee_wait_for_ok()
462
{
463
        return xbee_wait_for_string("OK\r", 3);
464
}
465

    
466
/**
467
 * Delay until the specified string is received from
468
 * the XBee. Discards all other XBee data.
469
 *
470
 * ********* Robot often hangs here ****************
471
 *
472
 * @param s the string to receive
473
 * @param len the length of the string
474
 **/
475
static int xbee_wait_for_string(char* s, int len)
476
{
477
        char* curr = s;
478
        while (curr - s < len) {
479
    WL_DEBUG_PRINT("waiting for string\r\n");
480
                // check if buffer is empty
481
                if (buffer_last != buffer_first) {
482
                        char c = arrival_buf[buffer_first++];
483
                        if (buffer_first == XBEE_BUFFER_SIZE) {
484
                                buffer_first = 0;
485
                        }
486

    
487
                        if (c == *curr) {
488
                                curr++;
489
                        } else {
490
#ifndef ROBOT
491
                          //return -1; // Computer is less forgiving.
492
                          curr = s;
493
#else
494
                          curr = s;
495
#endif
496
                        }
497
                } // else buffer is empty.
498

    
499
#ifndef ROBOT
500
                usleep(100);
501
#endif
502
        }
503

    
504
        return 0;
505
}
506

    
507
/**
508
 * Verifies that the packets checksum is correct.
509
 * (If the checksum is correct, the sum of the bytes
510
 * is 0xFF.)
511
 *
512
 * @param packet the packet received. This includes the first
513
 * three bytes, which are header information from the XBee.
514
 *
515
 * @param len The length of the packet received from the XBee
516
 *
517
 * @return 0 if the checksum is incorrect, nonzero
518
 * otherwise
519
 **/
520
int xbee_verify_checksum(char* packet, int len)
521
{
522
        unsigned char sum = 0;
523
        int i;
524
        for (i = 3; i < len; i++)
525
                sum += (unsigned char)packet[i];
526
        return sum == 0xFF;
527
}
528

    
529
/**
530
 * Returns the checksum of the given packet.
531
 *
532
 * @param buf the data for the packet to send
533
 * @param len the length of the packet in bytes
534
 *
535
 * @return the checksum of the packet, which will
536
 * become the last byte sent in the packet
537
 **/
538
char xbee_compute_checksum(char* buf, int len)
539
{
540
        int i;
541
        unsigned char sum = 0;
542
        for (i = 0; i < len; i++)
543
                sum += (unsigned char)buf[i];
544
        return 0xFF - sum;
545
}
546

    
547
/**
548
 * Adds header information and checksum to the given
549
 * packet and sends it. Header information includes
550
 * XBEE_FRAME_START and the packet length, as two bytes.
551
 *
552
 * @param buf the packet data
553
 * @param len the size in bytes of the packet data
554
 *
555
 **/
556
static int xbee_send_frame(char* buf, int len)
557
{
558
        char prefix[3];
559
        prefix[0] = XBEE_FRAME_START;
560
        prefix[1] = (len & 0xFF00) >> 8;
561
        prefix[2] = len & 0xFF;
562
        char checksum = xbee_compute_checksum(buf, len);
563

    
564
        if (xbee_send(prefix, 3) != 0) {
565
                return -1;
566
        }
567

    
568
        if (xbee_send(buf, len) != 0) {
569
                return -1;
570
        }
571

    
572
        if (xbee_send(&checksum, 1) != 0) {
573
                return -1;
574
        }
575

    
576
        return 0;
577
}
578

    
579
/**
580
 * Sends an AT command to read a parameter.
581
 *
582
 * @param command the AT command to send. For exmaple,
583
 * use ID to read the PAN ID and MY to return the XBee ID.
584
 * See the XBee reference guide for a complete listing.
585
 **/
586
int xbee_send_read_at_command(char* command)
587
{
588
        return xbee_send_modify_at_command(command, NULL);
589
}
590

    
591
/**
592
 * Sends the given AT command.
593
 *
594
 * @param command the AT command to send (e.g., MY, ID)
595
 * @param value the value to pass as a parameter
596
 * (or NULL if there is no parameter)
597
 **/
598
static int xbee_send_modify_at_command(char* command, char* value)
599
{
600
        char buf[16];
601
        int i;
602

    
603
        buf[0] = XBEE_FRAME_AT_COMMAND;
604
        buf[1] = 1;
605
        buf[2] = command[0];
606
        buf[3] = command[1];
607
        int valueLen = 0;
608
        if (value != NULL)
609
        {
610
                valueLen = strlen(value);
611
                if (valueLen > 8)
612
                {
613
                        WL_DEBUG_PRINT("AT Command too large.\r\n");
614
                        return -1;
615
                }
616

    
617
                for (i = 0; i < valueLen; i++) {
618
                        buf[4 + i] = value[i];
619
                }
620
        }
621

    
622
        return xbee_send_frame(buf, 4 + valueLen);
623
}
624

    
625
/**
626
 * Send the specified packet.
627
 *
628
 * @param packet the packet data to send
629
 * @param len the number of bytes in the packet
630
 *
631
 * @param dest the ID of the XBee to send the packet to,
632
 * or XBEE_BROADCAST to send the message to all robots
633
 * in the PAN.
634
 *
635
 * @param options a combination of the flags
636
 * XBEE_OPTIONS_NONE, XBEE_OPTIONS_DISABLE_RESPONSE and
637
 * XBEE_OPTIONS_BROADCAST_ALL_PANS
638
 *
639
 * @param frame the frame number to associate this packet
640
 * with. This will be used to identify the response when
641
 * the XBee alerts us as to whether or not our message
642
 * was received.
643
 **/
644
int xbee_send_packet(char* packet, int len, int dest, char options, char frame)
645
{
646
        char buf[5];
647
        char prefix[3];
648
        int i;
649
        unsigned char checksum = 0;
650

    
651
        if (len > 100)
652
        {
653
                WL_DEBUG_PRINT("Packet is too large.\r\n");
654
                return -1;
655
        }
656

    
657
        //data for sending request
658
        buf[0] = XBEE_FRAME_TX_REQUEST_16;
659
        buf[1] = frame;
660
        buf[2] = (dest >> 8) & 0xFF;
661
        buf[3] = dest & 0xFF;
662
        buf[4] = options;
663

    
664
        //packet prefix, do this here so we don't need an extra buffer
665
        prefix[0] = XBEE_FRAME_START;
666
        prefix[1] = ((5 + len) & 0xFF00) >> 8;
667
        prefix[2] = (5 + len) & 0xFF;
668

    
669
        for (i = 0; i < 5; i++)
670
                checksum += (unsigned char)buf[i];
671
        for (i = 0; i < len; i++)
672
                checksum += (unsigned char)packet[i];
673
        checksum = 0xFF - checksum;
674

    
675
        if (xbee_send(prefix, 3) != 0) {
676
                return -1;
677
        }
678

    
679
        if (xbee_send(buf, 5) != 0) {
680
                return -1;
681
        }
682

    
683
        if (xbee_send(packet, len) != 0) {
684
                return -1;
685
        }
686

    
687
        if (xbee_send((char*)&checksum, 1) != 0) {
688
                return -1;
689
        }
690

    
691
        return 0;
692
}
693

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

    
744
                if (buffer_first == XBEE_BUFFER_SIZE) {
745
                        buffer_first = 0;
746
                }
747
                xbee_buf[0] = XBEE_FRAME_START;
748
                currentBufPos++;
749
        }
750

    
751
        int len = -1;
752
        if (currentBufPos >= 3) {
753
                len = (int)xbee_buf[2] + ((int)xbee_buf[1] << 8);
754
        }
755

    
756
        while (len == -1 //packet length has not been read yet
757
                || currentBufPos < len + 4)
758
        {
759
                if (currentBufPos == 3)
760
                {
761
                        len = (int)xbee_buf[2] + ((int)xbee_buf[1] << 8);
762
                        if (len > 120)
763
                        {
764
                                WL_DEBUG_PRINT("Packet too large. Probably error in XBee transmission.\n");
765
                                currentBufPos = 0;
766
                                return -1;
767
                        }
768
                }
769

    
770
                // check if buffer is empty
771
                if (buffer_first == buffer_last) {
772
                        return -1;
773
                }
774
                xbee_buf[currentBufPos++] = arrival_buf[buffer_first++];
775
                if (buffer_first == XBEE_BUFFER_SIZE) {
776
                        buffer_first = 0;
777
                }
778
        }
779

    
780
        currentBufPos = 0;
781

    
782
        if (!xbee_verify_checksum(xbee_buf, len + 4))
783
        {
784
                WL_DEBUG_PRINT("XBee checksum failed.\r\n");
785
                return -1;
786
        }
787

    
788
        //we will take care of the packet
789
        
790
        ret = xbee_handle_packet(xbee_buf+3, len);
791
        if (ret == 1) {
792
                return 3;
793
        }
794
        
795
        if (dest == NULL) {
796
                return -1;
797
        }
798

    
799
        int i;
800
        for (i = 3; i < len + 3; i++) {
801
                dest[i - 3] = xbee_buf[i];
802
        }
803
        return len;
804
}
805

    
806
/**
807
 * Handles modem status packets.
808
 *
809
 * @param status the type of status packet received.
810
 **/
811
void xbee_handle_status(char status)
812
{
813
        switch (status)
814
        {
815
                case 0:
816
                        WL_DEBUG_PRINT("XBee hardware reset.\r\n");
817
                        break;
818
                case 1:
819
                        WL_DEBUG_PRINT("Watchdog timer reset.\r\n");
820
                        break;
821
                case 2:
822
                        WL_DEBUG_PRINT("Associated.\r\n");
823
                        break;
824
                case 3:
825
                        WL_DEBUG_PRINT("Disassociated.\r\n");
826
                        break;
827
                case 4:
828
                        WL_DEBUG_PRINT("Synchronization lost.\r\n");
829
                        break;
830
                case 5:
831
                        WL_DEBUG_PRINT("Coordinator realignment.\r\n");
832
                        break;
833
                case 6:
834
                        WL_DEBUG_PRINT("Coordinator started.\r\n");
835
                        break;
836
        }
837
}
838

    
839
/**
840
 * Handles AT command response packets.
841
 * @param command the two character AT command, e.g. MY or ID
842
 * @param result 0 for success, 1 for an error
843
 * @param extra the hex value of the requested register
844
 * @param extraLen the length in bytes of extra
845
 **/
846
static void xbee_handle_at_command_response(char* command, char result, char* extra, int extraLen)
847
{
848
        if (result == 1)
849
        {
850
                WL_DEBUG_PRINT("Error with AT");
851
                WL_DEBUG_PRINT(command);
852
                WL_DEBUG_PRINT(" packet.\r\n");
853
        }
854
        WL_DEBUG_PRINT("AT");
855
        WL_DEBUG_PRINT(command);
856
        WL_DEBUG_PRINT(" command was successful.\r\n");
857

    
858
        if (command[0] == 'I' && command[1] == 'D')
859
        {
860
                xbee_panID = xbee_pending_panID;
861
                WL_DEBUG_PRINT("PAN ID set to ");
862
                WL_DEBUG_PRINT_INT(xbee_panID);
863
                WL_DEBUG_PRINT(".\r\n");
864
                return;
865
        }
866

    
867
        if (command[0] == 'C' && command[1] == 'H')
868
        {
869
                xbee_channel = xbee_pending_channel;
870
                WL_DEBUG_PRINT("Channel set to ");
871
                WL_DEBUG_PRINT_INT(xbee_channel);
872
                WL_DEBUG_PRINT(".\r\n");
873
                return;
874
        }
875

    
876
        if (command[0] == 'M' && command[1] == 'Y' && extraLen != 0)
877
        {
878
                xbee_address = 0;
879
                int i;
880
                for (i = 0; i < extraLen; i++) {
881
                        xbee_address = (xbee_address << 8) + extra[i];
882
                }
883

    
884
                WL_DEBUG_PRINT("XBee address is ");
885
                WL_DEBUG_PRINT_INT(xbee_address);
886
                WL_DEBUG_PRINT(".\r\n");
887

    
888
                if (xbee_address == 0)
889
                {
890
                        WL_DEBUG_PRINT("XBee 16-bit address must be set using ATMY.\r\n");
891
                        #ifndef ROBOT
892
                        exit(0);
893
                        #endif
894
                }
895
        }
896
}
897

    
898
/**
899
 * Attempts to handle the packet if it is dealt with
900
 * by the library.
901
 * We will handle the following packet types:
902
 *    Modem Status
903
 *    AT Command Response
904
 *
905
 * @param packet the packet to handle
906
 * @param len the length of the packet
907
 *
908
 * @return 1 if we have handled the packet, 0 otherwise
909
 */
910
static int xbee_handle_packet(char* packet, int len)
911
{
912

    
913
        char command[3] = {1, 2, 3};
914
        if (len <= 0) //this should not happend
915
        {
916
                WL_DEBUG_PRINT("Non-positive packet length.\r\n");
917
                return 0;
918
        }
919

    
920
        switch ((unsigned char)packet[0]) //packet type
921
        {
922
                case XBEE_FRAME_STATUS:
923
                        xbee_handle_status(packet[1]);
924
                        return 1;
925
                case XBEE_FRAME_AT_COMMAND_RESPONSE:
926
                        command[0] = packet[2];
927
                        command[1] = packet[3];
928
                        command[2] = 0;
929
                        xbee_handle_at_command_response(command, packet[4], packet + 5, len - 5);
930
                        return 1;
931
        }
932
        return 0;
933
}
934

    
935
/**
936
 * Sets the personal area network id.
937
 *
938
 * @param id the new personal area network (PAN) id
939
 **/
940
int xbee_set_pan_id(int id)
941
{
942
        char s[3];
943
        s[0] = (id >> 8) & 0xFF;
944
        s[1] = id & 0xFF;
945
        s[2] = 0;
946
        xbee_pending_panID = id;
947
        return xbee_send_modify_at_command("ID", s);
948
}
949

    
950
/**
951
 * Get the PAN ID for the XBee.
952
 *
953
 * @return the personal area network id, or
954
 * XBEE_PAN_DEFAULT if it has not yet been set.
955
 **/
956
unsigned int xbee_get_pan_id()
957
{
958
        return xbee_panID;
959
}
960

    
961
/**
962
 * Set the channel the XBee is using.
963
 *
964
 * @param channel the channel the XBee will not use,
965
 * between 0x0B and 0x1A
966
 *
967
 * @see xbee_get_channel
968
 **/
969
int xbee_set_channel(int channel)
970
{
971
        if (channel < 0x0B || channel > 0x1A)
972
        {
973
                WL_DEBUG_PRINT("Channel out of range.\r\n");
974
                return -1;
975
        }
976

    
977
        char s[3];
978
        s[0] = channel & 0xFF;
979
        s[1] = 0;
980
        xbee_pending_channel = channel;
981

    
982
        return xbee_send_modify_at_command("CH", s);
983
}
984

    
985
/**
986
 * Returns the channel which the XBee is currently using.
987
 *
988
 * @return the channel the XBee is using
989
 *
990
 * @see xbee_set_channel
991
 **/
992
int xbee_get_channel(void)
993
{
994
        return xbee_channel;
995
}
996

    
997
/**
998
 * Get the 16-bit address of the XBee.
999
 * This is used to specify who to send messages to
1000
 * and who messages are from.
1001
 *
1002
 * @return the 16-bit address of the XBee.
1003
 **/
1004
unsigned int xbee_get_address()
1005
{
1006
        return xbee_address;
1007
}
1008

    
1009
#ifndef ROBOT
1010
void xbee_set_com_port(char* port)
1011
{
1012
        xbee_com_port = port;
1013
}
1014
#endif