Project

General

Profile

Statistics
| Revision:

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

History | View | Annotate | Download (30.9 KB)

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

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

    
35
#include <string.h>
36
#include <avr/interrupt.h>
37
#include <time.h>
38
#include <serial.h> // TODO: integrate serial xbee functions into this file
39
#include "wl_defs.h"
40
#include "xbee.h"
41

    
42

    
43
/* Internal Function Prototypes */
44

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

    
47
/* I/O Functions */
48
static int8_t xbee_send_string(unsigned char* c);
49

    
50
/* Command Mode Functions */
51
static int xbee_enter_command_mode(void);
52
static int xbee_exit_command_mode(void);
53
static int xbee_enter_api_mode(void);
54
static int xbee_exit_api_mode(void);
55
static int xbee_wait_for_string(char* s, uint16_t len);
56
static int xbee_wait_for_ok(void);
57

    
58
/* API Mode Functions */
59
static int xbee_handle_packet(uint8_t* packet, uint16_t len);
60
static int xbee_handle_at_command_response(uint16_t command, uint8_t result, uint8_t len);
61
static int xbee_handle_at_command_response(uint16_t command, uint8_t result, uint8_t len);
62
static void xbee_handle_status(uint8_t status);
63
static int xbee_verify_checksum(uint8_t* packet, uint16_t len);
64
static char xbee_compute_checksum(uint8_t* packet, uint16_t len);
65
static int xbee_send_frame(uint8_t* buf, int len);
66
int xbee_send_read_at_command(uint8_t* command);
67
static int xbee_send_modify_at_command(uint8_t* command, uint8_t* value, uint8_t len);
68

    
69
/* Buffer Manipulation Functions */
70
int8_t xbee_basic_buf_add(uint8_t *ptr, uint8_t byte);
71
uint8_t xbee_basic_buf_get(uint8_t *ptr);
72
int8_t xbee_other_buf_add(uint8_t *ptr, uint8_t byte);
73

    
74

    
75
/*Global Variables*/
76

    
77
// array for basic packets
78
static uint8_t xbee_basic_buf[PACKET_BUFFER_SIZE];
79

    
80
// beginning of first packet in basic buffer
81
static uint8_t basic_buf_first = 0;
82

    
83
// byte after end of last packet in basic buffer (only access < basic_buf_last)
84
// aka, the first free byte in basic buffer
85
static uint8_t basic_buf_last = 0;
86

    
87
// array for other packets
88
static uint8_t xbee_other_buf[PACKET_BUFFER_SIZE];
89

    
90
// beginning of first packet in other buffer
91
static uint8_t other_buf_first = 0;
92

    
93
// byte after end of last packet in other buffer (only access < other_buf_last)
94
// aka, the first free byte in other buffer
95
static uint8_t other_buf_last = 0;
96

    
97
// xbee status
98
#define XBEE_API_OFF 0x0
99
#define XBEE_API_ON 0x1
100
#define XBEE_API_ESCAPE 0x2
101
#define XBEE_NORMAL 0x00
102
#define XBEE_COMMAND_WAIT 0x80
103
#define XBEE_COMMAND_RESPONSE 0xC0
104
#define XBEE_INITD 0x08
105
static uint8_t xbee_status = XBEE_API_OFF|XBEE_NORMAL;
106

    
107
// xbee command response (for PAN, channel, address, etc)
108
static uint8_t xbee_command[4];
109

    
110
// external ack handler (wireless_send.c)
111
extern void ackhandle(uint8_t num,uint8_t val);
112

    
113

    
114
/**@addtogroup xbee
115
 * @{ **/
116

    
117
/*Function Implementations*/
118

    
119
/**
120
 * Interrupt for the robot. Adds bytes received from the xbee
121
 * to the buffer.
122
 **/
123
#ifndef FIREFLY
124
#define PORT UDR1
125
#define FLAG RXC1
126
ISR(USART1_RX_vect)
127
#else
128
#define PORT UDR0
129
#define FLAG RXC0
130
SIGNAL(SIG_USART0_RECV)
131
#endif
132
{
133
  // start of frame
134
        uint8_t apitype = PORT; // get frame start byte
135
  uint16_t i=0;
136
  uint16_t len=0;
137
  
138
  // check that we're in API mode
139
  if ((xbee_status&0x03) == XBEE_API_OFF || apitype != XBEE_FRAME_START) {
140
    // not in API mode
141
    if ((xbee_status&0xC0) == XBEE_COMMAND_WAIT) {
142
      // get rest of command and put in basic buf
143
      xbee_basic_buf[0] = apitype;
144
      if (xbee_basic_buf[i] != '\r') {
145
        while(i < PACKET_BUFFER_SIZE) {
146
          if (FLAG) {
147
            xbee_basic_buf[i] = PORT;
148
            if (xbee_basic_buf[i] == '\r')
149
              break;
150
          }
151
        }
152
      }
153
      // signal handler that command response is done
154
      xbee_status = (xbee_status&0x3F)|XBEE_COMMAND_RESPONSE;
155
    }
156
    return;
157
  }
158
    
159
  // get length and type
160
  while(i<3) {
161
    if (FLAG) {
162
      if (i==0)
163
        len |= PORT<<8;
164
      else if (i==1)
165
        len |= PORT;
166
      else if (i==2)
167
        apitype = PORT;
168
      i++;
169
    }
170
  }
171
  
172
  // do something based on the type
173
  i=1;
174
  switch(apitype) {
175
  case XBEE_FRAME_AT_COMMAND_RESPONSE:
176
    // AT command response
177
    if ((xbee_status&0xC0) == XBEE_COMMAND_RESPONSE)
178
      return; // we're currently processing a command, so drop the incoming one
179
    uint16_t atcommand=0;
180
    uint8_t ptr=basic_buf_last;
181
    while(i<len) {
182
      if (FLAG) {
183
        if (i==1)
184
          apitype = PORT; // get frame id, but ignore it
185
        else if (i==2)
186
          atcommand |= PORT<<8; // get command char1
187
        else if (i==3)
188
          atcommand |= PORT; // get command char2
189
        else if (i==4)
190
          apitype = PORT; // get status
191
        else {
192
          // put the command response on the basic buf temporarily
193
          if (xbee_basic_buf_add(&ptr,PORT) != 0)
194
            break;
195
        }
196
        i++;
197
      }
198
    }  
199
    // handle AT command  
200
    xbee_handle_at_command_response(atcommand,apitype,i-5); // TODO: rewrite function
201
    break;
202
  case XBEE_FRAME_TX_STATUS:
203
    // TX status
204
    if (0) { WL_DEBUG_PRINT("test"); } // why do I need this statement?
205
    uint8_t frame_id = 0;
206
    while(i<len) {
207
      if (FLAG) {
208
        if (i==1)
209
          frame_id = PORT;
210
        else {
211
          ackhandle(frame_id,PORT); // handle the status
212
          break;
213
        }
214
        i++;
215
      }
216
    }
217
    break;
218
  case XBEE_FRAME_RX_64:
219
    // receive a packet with 64bit address
220
    break; // TODO: implement this (even if we don't use it)
221
  case XBEE_FRAME_RX_16:
222
    // receive a packet with 16bit address
223
    uint16_t source = 0;
224
    uint8_t framenum = 0;
225
    uint8_t group = 0;
226
    uint8_t ptr=basic_buf_last;
227
    while(i<len) {
228
      if (FLAG) {
229
        if (i==1)
230
          source |= PORT<<8; // get source hi byte
231
        else if (i==2)
232
          source |= PORT; // get source lo byte
233
        else if (i==3)
234
          apitype = PORT; // get RSSI, and ignore
235
        else if (i==4)
236
          apitype = PORT; // get options, and ignore
237
        else if (i==5) {
238
          framenum = PORT; // get the frame number
239
          if (check_last_receive(source,framenum) != 0) {  // TODO: write function
240
            // we've already received this frame
241
            ptr = 0xFF; // signal to skip processing
242
            break;
243
          }
244
        }
245
        else if (i==6) {
246
          group = PORT; // get group number
247
          if (group == 0) {
248
            ptr = basic_buf_last+1;
249
            // add source to buffer
250
            if (xbee_basic_buf_add(&ptr,(uint8_t)((source&0xFF00)>>8)) != 0)
251
              break;
252
            if (xbee_basic_buf_add(&ptr,(uint8_t)(source&0x00FF)) != 0)
253
              break;
254
          } else {
255
            ptr = other_buf_last+1;
256
            // add source and group to buffer
257
            if (xbee_other_buf_add(&ptr,group) != 0)
258
              break;
259
            if (xbee_other_buf_add(&ptr,(uint8_t)((source&0xFF00)>>8)) != 0)
260
              break;
261
            if (xbee_other_buf_add(&ptr,(uint8_t)(source&0x00FF)) != 0)
262
              break;
263
          }
264
        }
265
        else { // TODO: handle escaped characters supported by APIv2
266
          // put packet data on the correct buffer
267
          if (group == 0 && xbee_basic_buf_add(&ptr,PORT) != 0)
268
            break;
269
          else if (xbee_other_buf_add(&ptr,PORT) != 0)
270
            break;
271
        }
272
        i++;
273
      }
274
    }
275
    if (ptr != 0xFF && i > 6) {
276
      if (group == 0) {
277
        xbee_basic_buf[basic_buf_last] = i-6; // set length
278
        basic_buf_last = ptr;
279
      }
280
      else {        
281
        xbee_other_buf[other_buf_last] = i-6; // set length
282
        // check if we have a high priority group
283
        for(;;)
284
          if (HIGH_PRIORITY) {
285
            // handle receive now
286
            ptr = 0xFF;
287
            break;
288
          }        
289
        if (ptr != 0xFF) {
290
          // handle receive later
291
          other_buf_last = ptr;
292
        }
293
      }
294
    }
295
    break;
296
  } // end of switch statement
297
  while (1) {
298
    if (FLAG) {
299
      apitype = PORT; // get checksum, and ignore
300
      break;
301
    }
302
  }
303
} // end of interrupt
304

    
305

    
306
/* adds a byte to the basic buffer */
307
int8_t xbee_basic_buf_add(uint8_t *ptr, uint8_t byte) {
308
  if (*ptr == basic_buf_first) {
309
    // buffer full
310
    WL_DEBUG_PRINT("basic buffer full\r\n");
311
    return -1;
312
  }
313
  xbee_basic_buf[(*ptr)++] = byte);
314
  if (*ptr == PACKET_BUFFER_SIZE)
315
    *ptr = 0;
316
  return 0;
317
}
318
/* gets a byte from the basic buffer */
319
uint8_t xbee_basic_buf_get(uint8_t *ptr) {
320
  uint8_t byte = xbee_basic_buf[(*ptr)++];
321
  if (*ptr == PACKET_BUFFER_SIZE)
322
    *ptr = 0;
323
  return byte;
324
}
325
/* adds a byte to the other buffer */
326
int8_t xbee_other_buf_add(uint8_t *ptr, uint8_t byte) {
327
  if (*ptr == other_buf_first) {
328
    // buffer full
329
    WL_DEBUG_PRINT("other buffer full\r\n");
330
    return -1;
331
  }
332
  xbee_other_buf[(*ptr)++] = byte;
333
  if (ptr == PACKET_BUFFER_SIZE)
334
    *ptr = 0;
335
  return 0;
336
}
337

    
338

    
339
/**
340
 * Initializes the XBee library so that other functions may be used.
341
 **/
342
int8_t xbee_init()
343
{
344
        WL_DEBUG_PRINT("in xbee_init\n");
345
  
346
  if(xbee_status&0x08 == XBEE_INITD) {
347
    return WL_ERROR_INIT_ALREADY_INITD;
348
  }
349
  
350
  // Set startup baud rate of 9600
351
        // Set frame format: 8data, 1stop bit, asynchronous normal mode
352
  // Enable receiver and transmitter and the receiving interrupt
353
#ifdef FIREFLY
354
  UCSR0A |= (1<<U2X0);
355
  UBRR0H = 0x00;
356
  UBRR0L = 103;
357
  UCSR0C |= (1<<UCSZ00) | (1<<UCSZ01);
358
        UCSR0B |= (1<<RXEN0) | (1<<TXEN0) | (1<<RXCIE0); 
359
#else
360
  // Bayboard or robot
361
  UCSR1A |= (1<<U2X1);
362
  UBRR1H = 0x00;
363
  UBRR1L = 103;
364
  UCSR1C |= (1<<UCSZ10) | (1<<UCSZ11);
365
        UCSR1B |= (1<<RXEN1) | (1<<TXEN1) | (1<<RXCIE1);
366
#endif
367
        sei();
368

    
369
        WL_DEBUG_PRINT("Entering command mode.\r\n");
370
        if (xbee_enter_command_mode() != 0) {
371
    usb_puts("error entering command mode\r\n");
372
                return -1;
373
        }
374
        WL_DEBUG_PRINT("Entered command mode.\r\n");
375

    
376
  // reset baud rate
377
  WL_DEBUG_PRINT("Resetting Baud to ");
378
  WL_DEBUG_PRINT(XBEE_BAUD_STR);
379
  WL_DEBUG_PRINT("\r\n");
380
  
381
  // set baud on xbee
382
#if (XBEE_BAUD == 115200)
383
  xbee_send_string("ATBD7\r");
384
#elif (XBEE_BAUD == 57600)
385
  xbee_send_string("ATBD6\r");
386
#elif (XBEE_BAUD == 38400)
387
  xbee_send_string("ATBD5\r");
388
#elif (XBEE_BAUD == 19200)
389
  xbee_send_string("ATBD4\r");
390
#elif (XBEE_BAUD == 9600)
391
  // already at this baud rate
392
  //xbee_send_string("ATBD3\r\n");
393
#else
394
  WL_DEBUG_PRINT("undefined baud rate\r\n");
395
  return WL_ERROR_BAUD;
396
#endif  
397
  // exit command mode
398
  xbee_wait_for_ok();
399
  WL_DEBUG_PRINT("got ok from baud reset\r\n");
400
  xbee_send_string("ATCN\r");
401
  xbee_wait_for_ok();
402
  WL_DEBUG_PRINT("got ok from exiting command mode\r\n");
403
  
404
  // set UART baud
405
#ifdef FIREFLY
406
#if (XBEE_BAUD == 115200)
407
  UBRR0H = 0x00;
408
  UBRR0L = 8;
409
#elif (XBEE_BAUD == 57600)
410
  UBRR0H = 0x00;
411
  UBRR0L = 16;
412
#elif (XBEE_BAUD == 38400)
413
  UBRR0H = 0x00;
414
  UBRR0L = 25;
415
#elif (XBEE_BAUD == 19200)
416
  UBRR0H = 0x00;
417
  UBRR0L = 51;
418
#elif (XBEE_BAUD == 9600)
419
  /* this is the default baud rate, so do nothing
420
  UBRR0H = 0x00;
421
  UBRR0L = 103;*/
422
#else
423
  WL_DEBUG_PRINT("undefined baud rate\r\n");
424
  return WL_ERROR_BUAD;
425
#endif
426
#else // Bayboard or robot
427
#if (XBEE_BAUD == 115200)
428
  UBRR1H = 0x00;
429
  UBRR1L = 8;
430
#elif (XBEE_BAUD == 57600)
431
  UBRR1H = 0x00;
432
  UBRR1L = 16;
433
#elif (XBEE_BAUD == 38400)
434
  UBRR1H = 0x00;
435
  UBRR1L = 25;
436
#elif (XBEE_BAUD == 19200)
437
  UBRR1H = 0x00;
438
  UBRR1L = 51;
439
#elif (XBEE_BAUD == 9600)
440
  /* this is the default baud rate, so do nothing
441
  UBRR1H = 0x00;
442
  UBRR1L = 103;*/
443
#else
444
  WL_DEBUG_PRINT("undefined baud rate\r\n");
445
  return WL_ERROR_BUAD;
446
#endif
447
#endif
448
  delay_ms(50);
449

    
450
  // enter command mode
451
  WL_DEBUG_PRINT("entering command mode 2\r\n");
452
  xbee_send_string("+++");
453
  xbee_wait_for_ok();
454
  WL_DEBUG_PRINT("entered command mode 2\r\n");
455
  
456
  if (xbee_enter_api_mode() != 0) {
457
    WL_DEBUG_PRINT("can't enter api mode\r\n");
458
                return -1;
459
        }
460

    
461
        WL_DEBUG_PRINT("Entered api mode.\r\n");
462

    
463
        if (xbee_exit_command_mode() != 0) {
464
    WL_DEBUG_PRINT("can't exit command mode\r\n");
465
          return -1;
466
        }
467
        
468
        WL_DEBUG_PRINT("Left command mode.\r\n");
469
  
470
  // TODO: we should set the MY address to the robot address from eeprom
471
  
472
  
473
  // set status
474
  xbee_status |= XBEE_INITD;
475
  
476
        return WL_SUCCESS;
477
}
478

    
479
/**
480
 * Call when finished using the XBee library.
481
 **/
482
int8_t xbee_terminate()
483
{
484
  if (xbee_exit_api_mode() != WL_SUCCESS) {
485
    WL_DEBUG_PRINT("xbee termination failed\r\n");
486
    return WL_ERROR_TERMINATION_FAILED;
487
  }
488
  xbee_status = xbee_status&0xF7; // clean initd status
489
  return WL_SUCCESS;
490
}
491

    
492
/**
493
 * Sends a character to the XBee.
494
 *
495
 * @param c the byte to send
496
 * @return 0 for success, nonzero for failure
497
 **/
498
int xbee_putc(char c) {
499
  if(!(xbee_status&XBEE_INITD))
500
    return WL_ERROR_LIBRARY_NOT_INITD;
501

    
502
  // Wait until buffer is clear for sending
503
  // Then load buffer with your character
504
#ifdef FIREFLY
505
  loop_until_bit_is_set(UCSR0A, UDRE0);  
506
  UDR0 = c;
507
#else
508
  loop_until_bit_is_set(UCSR1A, UDRE1);
509
  UDR1 = c;
510
#endif
511
        
512
  return WL_SUCCESS;
513
}
514

    
515
/**
516
 * Returns the first byte in the buffer received from xbee.
517
 * This function blocks execution until a character has been
518
 * received. xbee_init must be called before this function
519
 * may be used.
520
 * 
521
 * @return the first character in the xbee buffer, -1 on error
522
 * 
523
 * @see xbee_init, xbee_getc_nb
524
 **/
525
int16_t xbee_getc(void) {
526
  if(!(xbee_status&XBEE_INITD))
527
    return WL_ERROR_LIBRARY_NOT_INITD;
528

    
529
  // Wait for the receive buffer to be filled
530
  // Then read the receive buffer
531
#ifdef FIREFLY
532
  loop_until_bit_is_set(UCSR0A, RXC0);  
533
  return UDR0;
534
#else
535
  loop_until_bit_is_set(UCSR1A, RXC1);
536
  return UDR1;
537
#endif
538
}
539

    
540
/**
541
 * Non blocking version of xbee_getc. If a byte is present in the buffer,
542
 * it is returned, otherwise -1 is returned immediately. xbee_init
543
 * must be called before this function can be used.
544
 *
545
 * @param c The received byte. This will be set if a byte has been received.
546
 * 
547
 * @return -1 If no byte is available, 0 otherwise, positive for error
548
 *
549
 * @see xbee_getc
550
 **/
551
int8_t xbee_getc_nb(uint8_t *c) {
552
  if(!(xbee_status&XBEE_INITD))
553
    return WL_ERROR_LIBRARY_NOT_INITD;
554

    
555
  // check if the receive buffer is filled
556
#ifdef FIREFLY
557
  if (UCSR0A & (1<<RXC0)) {
558
    (*c) = UDR0;
559
#else
560
  if (UCSR1A & (1<<RXC1)) {
561
    (*c) = UDR1;
562
#endif
563
    return WL_SUCCESS;
564
  }
565
  return -1; // Return empty
566
}
567

    
568
/**
569
 * Send a buffer buf of size bytes to the XBee.
570
 *
571
 * @param buf the buffer of data to send
572
 * @param size the number of bytes to send
573
 **/
574
static int8_t xbee_send(uint8_t* buf, uint16_t size)
575
{
576
        while(--size > 0)
577
                if (xbee_putc(buf[i]) != WL_SUCCESS)
578
      return WL_ERROR_SEND;
579
        }  
580
  if (xbee_putc(buf[0]) != WL_SUCCESS)
581
    return WL_ERROR_SEND;
582

    
583
        return WL_SUCCESS;
584
}
585

    
586
/**
587
 * Sends a string to the XBee.
588
 *
589
 * @param c the string to send to the XBEE
590
 **/
591
static int8_t xbee_send_string(unsigned char* c)
592
{
593
        return xbee_send(c, strlen(c));
594
}
595

    
596

    
597
/**
598
 * Enter into command mode.
599
 **/
600
static int8_t xbee_enter_command_mode()
601
{
602
        if (xbee_send_string("+++") != WL_SUCCESS) {
603
                return WL_ERROR_XBEE_COMMAND;
604
        }
605

    
606
        if (xbee_wait_for_ok() != WL_SUCCESS) {
607
          return WL_ERROR_XBEE_COMMAND;
608
        }
609
  
610
        return WL_SUCCESS;
611
}
612

    
613
/**
614
 * Exit from command mode.
615
 **/
616
static int8_t xbee_exit_command_mode()
617
{
618
        if (xbee_send_string("ATCN\r") != 0) {
619
                return WL_ERROR_SEND;
620
        }
621
        xbee_wait_for_ok();
622

    
623
        return WL_SUCCESS;
624
}
625

    
626
/**
627
 * Enter API mode.
628
 **/
629
static int8_t xbee_enter_api_mode()
630
{
631
        if (xbee_send_string("ATAP 1\r") != 0) {
632
                return WL_ERROR_SEND;
633
        }
634
        xbee_wait_for_ok();
635
  
636
  xbee_status = (xbee_status&0xFC)|XBEE_API_ON;
637

    
638
        return WL_SUCCESS;
639
}
640

    
641
/**
642
 * Enter API mode 2.
643
 **/
644
static int8_t xbee_enter_api_mode2()
645
{
646
        if (xbee_send_string("ATAP 2\r") != 0) {
647
                return WL_ERROR_SEND;
648
        }
649
        xbee_wait_for_ok();
650
  
651
  xbee_status = (xbee_status&0xFC)|XBEE_API_ESCAPE;
652
  
653
        return WL_SUCCESS;
654
}
655

    
656
/**
657
 * Exit API mode.
658
 **/
659
static int8_t xbee_exit_api_mode()
660
{
661
        if (xbee_status&0xC0 == XBEE_COMMAND_WAIT
662
    || xbee_status&0xC0 == XBEE_COMMAND_RESPONSE)
663
    return WL_ERROR_XBEE_COMMAND; // can't do command right now
664
  
665
  int16_t i=0;
666
  // change status to command wait
667
  xbee_status = (xbee_status&0x3F)|XBEE_COMMAND_WAIT;
668
  xbee_send_modify_at_command("AP","0",1); // send command
669
  // wait for up to 30 ms
670
  while(xbee_status&0xC0 != XBEE_COMMAND_RESPONSE && i++ < 10000) {
671
    delay_us(1); // wait 3us
672
  }
673
  if (i < 1000 && xbee_command[0] == 'A' && xbee_command[1] == 'P') {
674
    i = WL_SUCCESS;
675
  else
676
    i = WL_ERROR_XBEE_COMMAND; // set error code
677
  xbee_status = (xbee_status&0x3C)|XBEE_API_OFF; // reset status
678
        return (int8_t)i; // return
679
}
680

    
681
/**
682
 * Wait until the string "OK\r" is received from the XBee.
683
 **/
684
static int xbee_wait_for_ok()
685
{
686
        return xbee_wait_for_string("OK\r", 3);
687
}
688

    
689
/**
690
 * Delay until the specified string is received from
691
 * the XBee.
692
 *
693
 * Only works when not in API mode
694
 *
695
 * @param s the string to receive
696
 * @param len the length of the string
697
 **/
698
static int8_t xbee_wait_for_string(char* s, int len)
699
{
700
  uint8_t i=0;
701
  if (xbee_status&0x03 == XBEE_API_OFF) {
702
    // wait until the response is received (only wait 1 second)
703
    while(xbee_status&0xC0 != XBEE_COMMAND_RESPONSE && i++ < 1000) {
704
      delay_us(1);
705
    }
706
    // check response
707
    if (i >= 1000 || memcmp(s,xbee_basic_buf,len) != 0) {
708
      // bad response
709
      WL_DEBUG_PRINT("Bad response when waiting for string ");
710
      WL_DEBUG_PRINT(s);
711
      WL_DEBUG_PRINT("\r\n");
712
      return -1;
713
    }
714
    
715
    // clear response
716
    xbee_status = xbee_status&0x3F;
717
  }
718

    
719
        return 0;
720
}
721

    
722
/**
723
 * Delay until we receive a command response.
724
 * (either OK\r or some actual value)
725
 *
726
 * Only works when not in API mode
727
 *
728
 * @param s the string to store the response in
729
 * @param len the length of the string
730
 */
731
static int8_t xbee_wait_for_response(char* s, int len) {
732
  uint8_t i=0;
733
  if (xbee_status&0x03 == XBEE_API_OFF) {
734
    // wait until the response is received (only wait 1 second)
735
    while(xbee_status&0xC0 != XBEE_COMMAND_RESPONSE && i++ < 1000) {
736
      delay_us(1);
737
    }
738
    // check response
739
    if (i >= 1000)
740
      return -1;
741
    } else {
742
      i=strcspn(xbee_basic_buf,"\r");
743
      if (i<PACKET_BUFFER_SIZE) {
744
        memcpy(s,xbee_basic_buf,i);
745
        xbee_status = xbee_status&0x3F; // clear response
746
        return 0;
747
      }
748
      else
749
        return -1;      
750
    }
751
  }
752
  // TODO: do something for API mode
753
  
754
  return 0;
755
}
756

    
757
/**  TODO: since we don't use this, do we need it?
758
 *
759
 * Verifies that the packets checksum is correct.
760
 * (If the checksum is correct, the sum of the bytes
761
 * is 0xFF.)
762
 *
763
 * @param packet the packet received. This includes the first
764
 * three bytes, which are header information from the XBee.
765
 *
766
 * @param len The length of the packet received from the XBee
767
 *
768
 * @return 0 if the checksum is incorrect, nonzero
769
 * otherwise
770
 **/
771
uint8_t xbee_verify_checksum(uint8_t* packet, uint16_t len)
772
{
773
        uint8_t sum = 0;
774
        while(--len > 0) {
775
                sum += packet[len];
776
  }
777
  sum += packet[0];
778
        return (sum == 0xFF);
779
}
780

    
781
/**
782
 * Returns the checksum of the given packet.
783
 *
784
 * @param buf the data for the packet to send
785
 * @param len the length of the packet in bytes
786
 *
787
 * @return the checksum of the packet, which will
788
 * become the last byte sent in the packet
789
 **/
790
uint8_t xbee_compute_checksum(uint8_t* buf, uint16_t len)
791
{
792
        uint8_t sum = 0;
793
        while(--len > 0) {
794
                sum += buf[len];
795
  }
796
  sum += buf[0];
797
        return 0xFF - sum;
798
}
799

    
800
/**
801
 * Adds buf to the previous checksum total
802
 *
803
 * @param buf a byte buffer to add to the checksum
804
 * @param len the length of the buffer
805
 * @param sum the previous sum
806
 *
807
 * @return error code
808
 **/
809
static int8_t xbee_checksum_add(uint8_t *buf, uint8_t len, uint8_t* sum) {
810
  if (buf == NULL || sum == NULL)
811
    return WL_ERROR_ARGUMENT;
812
  while(--len > 0) {
813
                *sum += buf[len];
814
  }
815
  *sum += buf[0];
816
}
817

    
818

    
819
/**
820
 * Sends header information. Header information includes
821
 * XBEE_FRAME_START and the packet length, as two bytes.
822
 *
823
 * @param type the packet type
824
 * @param len the size in bytes of the packet data
825
 *
826
 **/
827
static int8_t xbee_send_header(uint8_t type, uint16_t len)
828
{  
829
  //packet prefix
830
  if (xbee_putc(XBEE_FRAME_START) != WL_SUCCESS)
831
    return WL_ERROR_SEND;
832
  if (xbee_putc((uint8_t)((len & 0xFF00) >> 8)) != WL_SUCCESS)
833
    return WL_ERROR_SEND;
834
  if (xbee_putc((uint8_t)(len & 0x00FF)) != WL_SUCCESS)
835
    return WL_ERROR_SEND;
836

    
837
        if (xbee_send(buf, len) != WL_SUCCESS)
838
                return WL_ERROR_SEND;
839
        
840
        if (xbee_putc(checksum) != WL_SUCCESS)
841
                return WL_ERROR_SEND;
842
        
843
        return WL_SUCCESS;
844
}
845

    
846
/**
847
 * Adds header information and checksum to the given
848
 * packet and sends it. Header information includes
849
 * XBEE_FRAME_START and the packet length, as two bytes.
850
 *
851
 * @param buf the packet data
852
 * @param len the size in bytes of the packet data
853
 *
854
 **/
855
static int8_t xbee_send_frame(uint8_t* buf, uint16_t len)
856
{
857
        uint8_t checksum = xbee_compute_checksum(buf, len);
858
  
859
  //packet prefix
860
  if (xbee_putc(XBEE_FRAME_START) != WL_SUCCESS)
861
    return WL_ERROR_SEND;
862
  if (xbee_putc((uint8_t)((len & 0xFF00) >> 8)) != WL_SUCCESS)
863
    return WL_ERROR_SEND;
864
  if (xbee_putc((uint8_t)(len & 0x00FF)) != WL_SUCCESS)
865
    return WL_ERROR_SEND;
866

    
867
        if (xbee_send(buf, len) != WL_SUCCESS)
868
                return WL_ERROR_SEND;
869
        
870
        if (xbee_putc(checksum) != WL_SUCCESS)
871
                return WL_ERROR_SEND;
872
        
873
        return WL_SUCCESS;
874
}
875

    
876
/**
877
 * Sends an AT command to read a parameter.
878
 *
879
 * @param command the AT command to send. For exmaple,
880
 * use ID to read the PAN ID and MY to return the XBee ID.
881
 * See the XBee reference guide for a complete listing.
882
 **/
883
int8_t xbee_send_read_at_command(uint8_t* command)
884
{
885
        return xbee_send_modify_at_command(command, NULL, 0);
886
}
887

    
888
/**
889
 * Sends the given AT command.
890
 *
891
 * @param command the AT command to send (e.g., MY, ID)
892
 * @param value the value to pass as a parameter
893
 * (or NULL if there is no parameter)
894
 **/
895
static int8_t xbee_send_modify_at_command(uint8_t* command, uint8_t* value, uint8_t len)
896
{
897
        uint8_t buf[12];
898

    
899
        buf[0] = XBEE_FRAME_AT_COMMAND;
900
        buf[1] = 1;
901
        buf[2] = command[0];
902
        buf[3] = command[1];
903
        if (value != NULL)
904
        {
905
                if (len > 8)
906
                {
907
                        WL_DEBUG_PRINT("AT Command too large.\r\n");
908
                        return WL_ERROR_ARGUMENT;
909
                }
910
    memcpy(buf+4,value,len);
911
        }
912

    
913
        return xbee_send_frame(buf, 4 + len);
914
}
915

    
916
/**
917
 * Send the specified packet.
918
 *
919
 * @param packet the packet data to send
920
 * @param len the number of bytes in the packet
921
 *
922
 * @param dest the ID of the XBee to send the packet to,
923
 * or XBEE_BROADCAST to send the message to all robots
924
 * in the PAN.
925
 *
926
 * @param options a combination of the flags
927
 * XBEE_OPTIONS_NONE, XBEE_OPTIONS_DISABLE_RESPONSE and
928
 * XBEE_OPTIONS_BROADCAST_ALL_PANS
929
 *
930
 * @param frame the frame number to associate this packet
931
 * with. This will be used to identify the response when
932
 * the XBee alerts us as to whether or not our message
933
 * was received.
934
 **/
935
int8_t xbee_send_packet(uint8_t* packet, uint8_t len, uint16_t dest, uint8_t options, uint8_t frame)
936
{
937
        uint8_t sum = XBEE_FRAME_TX_REQUEST_16;
938
  uint8_t i = 0;
939

    
940
        if (len > 100)
941
        {
942
                WL_DEBUG_PRINT("Packet is too large.\r\n");
943
                return WL_ERROR_ARGUMENT;
944
        }
945
  
946
  // calculate checksum
947
        for(;i<len;i++)
948
                sum += packet[len];
949
  sum += frame;
950
  sum += (dest&0xFF00) >> 8;
951
  sum += dest&0x00FF;
952
  sum += options;
953
        sum = 0xFF - sum;
954

    
955
        //packet prefix
956
  if (xbee_putc(XBEE_FRAME_START) != WL_SUCCESS)
957
    return WL_ERROR_SEND;
958
  if (xbee_putc(0x00) != WL_SUCCESS)
959
    return WL_ERROR_SEND;
960
  if (xbee_putc(len+5) != WL_SUCCESS)
961
    return WL_ERROR_SEND;
962
    
963
        //send header for TX request
964
  if (xbee_putc(XBEE_FRAME_TX_REQUEST_16) != WL_SUCCESS)
965
    return WL_ERROR_SEND;
966
  if (xbee_putc(frame) != WL_SUCCESS)
967
    return WL_ERROR_SEND;
968
  if (xbee_putc((uint8_t)((dest&0xFF00) >> 8)) != WL_SUCCESS)
969
    return WL_ERROR_SEND;
970
  if (xbee_putc((uint8_t)(dest&0x00FF)) != WL_SUCCESS)
971
    return WL_ERROR_SEND;
972
  if (xbee_putc(options) != WL_SUCCESS)
973
    return WL_ERROR_SEND;
974

    
975
  // send packet
976
        if (xbee_send(packet, len) != WL_SUCCESS)
977
                return WL_ERROR_SEND;
978

    
979
  // send checksum
980
        if (xbee_putc(sum) != WL_SUCCESS)
981
                return WL_ERROR_SEND;
982

    
983
        return WL_SUCCESS;
984
}
985

    
986
/**
987
 * Handles modem status packets.
988
 *
989
 * @param status the type of status packet received.
990
 **/
991
void xbee_handle_status(char status)
992
{
993
        switch (status)
994
        {
995
                case 0:
996
                        WL_DEBUG_PRINT("XBee hardware reset.\r\n");
997
                        break;
998
                case 1:
999
                        WL_DEBUG_PRINT("Watchdog timer reset.\r\n");
1000
                        break;
1001
                case 2:
1002
                        WL_DEBUG_PRINT("Associated.\r\n");
1003
                        break;
1004
                case 3:
1005
                        WL_DEBUG_PRINT("Disassociated.\r\n");
1006
                        break;
1007
                case 4:
1008
                        WL_DEBUG_PRINT("Synchronization lost.\r\n");
1009
                        break;
1010
                case 5:
1011
                        WL_DEBUG_PRINT("Coordinator realignment.\r\n");
1012
                        break;
1013
                case 6:
1014
                        WL_DEBUG_PRINT("Coordinator started.\r\n");
1015
                        break;
1016
        }
1017
}
1018

    
1019
/**
1020
 * Handles AT command response packets.
1021
 * @param command the two character AT command, e.g. MY or ID
1022
 * @param result 0 for success, 1 for an error
1023
 * @param len the length in bytes of extra
1024
 **/
1025
static int8_t xbee_handle_at_command_response(uint16_t command, uint8_t result, uint8_t len)
1026
{
1027
        if (result == 1)
1028
        {
1029
                WL_DEBUG_PRINT("Error with AT");
1030
                WL_DEBUG_PRINT(command);
1031
                WL_DEBUG_PRINT(" packet. Result = ");
1032
    switch(result) {
1033
    case 1:
1034
      WL_DEBUG_PRINT("ERROR\r\n");
1035
      break;
1036
    case 2:
1037
      WL_DEBUG_PRINT("Invalid Command\r\n");
1038
      break;
1039
    case 3:
1040
      WL_DEBUG_PRINT("Invalid Parameter\r\n");
1041
      break;
1042
    }
1043
    return WL_SUCCESS;
1044
        }
1045
        WL_DEBUG_PRINT("AT");
1046
        WL_DEBUG_PRINT(command);
1047
        WL_DEBUG_PRINT(" command was successful.\r\n");
1048
  
1049
  // TODO: program more command responses here (ND, etc)
1050
  switch(command) {
1051
  case ('I'<<8)+'D': // PAN
1052
  case ('C'<<8)+'H': // channel
1053
  case ('M'<<8)+'Y': // address
1054
    // copy command to handler
1055
    xbee_command[0] = (command&0xFF00)>>8;
1056
    xbee_command[1] = command&0x00FF;
1057
    result = basic_buf_last;
1058
    for(command=2;command<len+2;command++)
1059
      xbee_command[command] = xbee_basic_buf_get(&result);
1060
    break;
1061
  default:
1062
    WL_DEBUG_PRINT("unknown AT command");
1063
  }
1064
  
1065
  // signal handler that command response is done
1066
  xbee_status = (xbee_status&0x3F)|XBEE_COMMAND_RESPONSE;
1067

    
1068
  return WL_SUCCESS;
1069
}
1070

    
1071
/**
1072
 * Sets the personal area network id.
1073
 *
1074
 * @param id the new personal area network (PAN) id
1075
 **/
1076
int8_t xbee_set_pan_id(uint16_t id)
1077
{
1078
        if (xbee_status&0xC0 == XBEE_COMMAND_WAIT
1079
    || xbee_status&0xC0 == XBEE_COMMAND_RESPONSE)
1080
    return WL_ERROR_XBEE_COMMAND; // can't do command right now
1081
  
1082
  int16_t i=0;
1083
  // change status to command wait
1084
  xbee_status = (xbee_status&0x3F)|XBEE_COMMAND_WAIT;
1085
  xbee_send_modify_at_command("ID",id,2); // send command to set the channel
1086
  // wait for up to 30 ms
1087
  while(xbee_status&0xC0 != XBEE_COMMAND_RESPONSE && i++ < 10000) {
1088
    delay_us(1); // wait 3us
1089
  }
1090
  if (i < 1000 && xbee_command[0] == 'O' && xbee_command[1] == 'K') {
1091
    i = WL_SUCCESS;
1092
  else
1093
    i = WL_ERROR_XBEE_COMMAND; // set error code
1094
  xbee_status = xbee_status&0x3F; // reset status
1095
        return (int8_t)i; // return
1096
}
1097

    
1098
/**
1099
 * Get the PAN ID for the XBee.
1100
 *
1101
 * @return the personal area network id, or
1102
 * XBEE_PAN_DEFAULT if it has not yet been set.
1103
 **/
1104
uint16_t xbee_get_pan_id()
1105
{
1106
  if (xbee_status&0xC0 == XBEE_COMMAND_WAIT
1107
    || xbee_status&0xC0 == XBEE_COMMAND_RESPONSE)
1108
    return WL_ERROR_XBEE_COMMAND_16BIT; // can't do command right now
1109
  
1110
  uint16_t i=0;
1111
  // change status to command wait
1112
  xbee_status = (xbee_status&0x3F)|XBEE_COMMAND_WAIT;
1113
  xbee_send_read_at_command("ID"); // send command to get the PAN
1114
  // wait for up to 30 ms
1115
  while(xbee_status&0xC0 != XBEE_COMMAND_RESPONSE && i++ < 10000) {
1116
    delay_us(1); // wait 3us
1117
  }
1118
  if (i < 1000 && xbee_command[0] == 'I' && xbee_command[1] == 'D') {
1119
    i = (xbee_command[2]<<8)|xbee_command[3]; // get PAN
1120
  else
1121
    i = WL_ERROR_XBEE_COMMAND_16BIT; // set error code
1122
  xbee_status = xbee_status&0x3F; // reset status
1123
        return i; // return
1124
}
1125

    
1126
/**
1127
 * Set the channel the XBee is using.
1128
 *
1129
 * @param channel the channel the XBee will not use,
1130
 * between 0x0B and 0x1A
1131
 *
1132
 * @see xbee_get_channel
1133
 **/
1134
int8_t xbee_set_channel(uint8_t channel)
1135
{
1136
        if (channel < 0x0B || channel > 0x1A)
1137
        {
1138
                WL_DEBUG_PRINT("Channel out of range.\r\n");
1139
                return -1;
1140
        }
1141

    
1142
        if (xbee_status&0xC0 == XBEE_COMMAND_WAIT
1143
    || xbee_status&0xC0 == XBEE_COMMAND_RESPONSE)
1144
    return WL_ERROR_XBEE_COMMAND; // can't do command right now
1145
  
1146
  int16_t i=0;
1147
  // change status to command wait
1148
  xbee_status = (xbee_status&0x3F)|XBEE_COMMAND_WAIT;
1149
  xbee_send_modify_at_command("CH",channel,1); // send command to set the channel
1150
  // wait for up to 30 ms
1151
  while((xbee_status&0xC0) != XBEE_COMMAND_RESPONSE && i++ < 10000) {
1152
    delay_us(1); // wait 3us
1153
  }
1154
  if (i < 1000 && xbee_command[0] == 'O' && xbee_command[1] == 'K')
1155
    i = WL_SUCCESS;
1156
  else
1157
    i = WL_ERROR_XBEE_COMMAND; // set error code
1158
  xbee_status = xbee_status&0x3F; // reset status
1159
        return (int8_t)i; // return
1160
}
1161

    
1162
/**
1163
 * Returns the channel which the XBee is currently using.
1164
 *
1165
 * @return the channel the XBee is using
1166
 *
1167
 * @see xbee_set_channel
1168
 **/
1169
int8_t xbee_get_channel(void)
1170
{
1171
  if ((xbee_status&0xC0) == XBEE_COMMAND_WAIT
1172
    || (xbee_status&0xC0) == XBEE_COMMAND_RESPONSE)
1173
    return WL_ERROR_XBEE_COMMAND; // can't do command right now
1174
  
1175
  int16_t i=0;
1176
  // change status to command wait
1177
  xbee_status = (xbee_status&0x3F)|XBEE_COMMAND_WAIT;
1178
  xbee_send_read_at_command("ID"); // send command to get the channel
1179
  // wait for up to 30 ms
1180
  while((xbee_status&0xC0) != XBEE_COMMAND_RESPONSE && i++ < 10000) {
1181
    delay_us(1); // wait 3us
1182
  }
1183
  if (i < 1000 && xbee_command[0] == 'C' && xbee_command[1] == 'H')
1184
    i = xbee_command[2]; // get channel
1185
  else
1186
    i = WL_ERROR_XBEE_COMMAND; // set error code
1187
  xbee_status = xbee_status&0x3F; // reset status
1188
        return i; // return
1189
}
1190

    
1191
/**
1192
 * Get the 16-bit address of the XBee.
1193
 * This is used to specify who to send messages to
1194
 * and who messages are from.
1195
 *
1196
 * @return the 16-bit address of the XBee.
1197
 **/
1198
uint16_t xbee_get_address(void)
1199
{
1200
  if ((xbee_status&0xC0) == XBEE_COMMAND_WAIT
1201
    || (xbee_status&0xC0) == XBEE_COMMAND_RESPONSE)
1202
    return WL_ERROR_XBEE_COMMAND_16BIT; // can't do command right now
1203
  
1204
  uint16_t i=0;
1205
  // change status to command wait
1206
  xbee_status = (xbee_status&0x3F)|XBEE_COMMAND_WAIT;
1207
  xbee_send_read_at_command("MY"); // send command to get the address
1208
  // wait for up to 30 ms
1209
  while((xbee_status&0xC0) != XBEE_COMMAND_RESPONSE && i++ < 10000) {
1210
    delay_us(1); // wait 3us
1211
  }
1212
  if (i < 1000 && xbee_command[0] == 'M' && xbee_command[1] == 'Y')
1213
    i = (xbee_command[2]<<8)+xbee_command[3]; // get address
1214
  else
1215
    i = WL_ERROR_XBEE_COMMAND_16BIT; // set error code
1216
  xbee_status = xbee_status&0x3F; // reset status
1217
        return i; // return
1218
}
1219

    
1220
/**@} **/ // end xbee group
1221