Project

General

Profile

Statistics
| Revision:

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

History | View | Annotate | Download (31 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 "wl_defs.h"
39
#include "wireless.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(uint8_t* c);
49

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

    
58
/* API Mode Functions */
59
static int8_t xbee_handle_packet(uint8_t* packet, uint16_t len);
60
static int8_t xbee_handle_at_command_response(uint16_t command, uint8_t result, uint8_t len);
61
static int8_t 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 int8_t xbee_verify_checksum(uint8_t* packet, uint16_t len);
64
static uint8_t xbee_compute_checksum(uint8_t* packet, uint16_t len);
65
static int8_t xbee_send_frame(uint8_t* buf, uint16_t len);
66
int8_t xbee_send_read_at_command(uint8_t* command);
67
static int8_t 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
    uint8_t frame_id = 0;
205
    while(i<len) {
206
      if (FLAG) {
207
        if (i==1)
208
          frame_id = PORT;
209
        else {
210
          ackhandle(frame_id,PORT); // handle the status
211
          break;
212
        }
213
        i++;
214
      }
215
    }
216
    break; }
217
  case XBEE_FRAME_RX_64: {
218
    // receive a packet with 64bit address
219
    break; } // TODO: implement this (even if we don't use it)
220
  case XBEE_FRAME_RX_16: {
221
    // receive a packet with 16bit address
222
    uint16_t source = 0;
223
    uint8_t framenum = 0;
224
    uint8_t group = 0;
225
    uint8_t ptr=basic_buf_last;
226
    while(i<len) {
227
      if (FLAG) {
228
        if (i==1)
229
          source |= PORT<<8; // get source hi byte
230
        else if (i==2)
231
          source |= PORT; // get source lo byte
232
        else if (i==3)
233
          apitype = PORT; // get RSSI, and ignore
234
        else if (i==4)
235
          apitype = PORT; // get options, and ignore
236
        else if (i==5) {
237
          framenum = PORT; // get the frame number
238
          if (check_last_receive(source,framenum) != 0) {  // TODO: write function
239
            // we've already received this frame
240
            ptr = 0xFF; // signal to skip processing
241
            break;
242
          }
243
        }
244
        else if (i==6) {
245
          group = PORT; // get group number
246
          if (group == 0) {
247
            ptr = basic_buf_last+1;
248
            // add source to buffer
249
            if (xbee_basic_buf_add(&ptr,(uint8_t)((source&0xFF00)>>8)) != 0)
250
              break;
251
            if (xbee_basic_buf_add(&ptr,(uint8_t)(source&0x00FF)) != 0)
252
              break;
253
          } else {
254
            ptr = other_buf_last+1;
255
            // add source and group to buffer
256
            if (xbee_other_buf_add(&ptr,group) != 0)
257
              break;
258
            if (xbee_other_buf_add(&ptr,(uint8_t)((source&0xFF00)>>8)) != 0)
259
              break;
260
            if (xbee_other_buf_add(&ptr,(uint8_t)(source&0x00FF)) != 0)
261
              break;
262
          }
263
        }
264
        else { // TODO: handle escaped characters supported by APIv2
265
          // put packet data on the correct buffer
266
          if (group == 0 && xbee_basic_buf_add(&ptr,PORT) != 0)
267
            break;
268
          else if (xbee_other_buf_add(&ptr,PORT) != 0)
269
            break;
270
        }
271
        i++;
272
      }
273
    }
274
    if (ptr != 0xFF && i > 6) {
275
      if (group == 0) {
276
        xbee_basic_buf[basic_buf_last] = i-6; // set length
277
        basic_buf_last = ptr;
278
      }
279
      else {        
280
        xbee_other_buf[other_buf_last] = i-6; // set length
281
        // check if we have a high priority group
282
        for(;;)
283
          if (HIGH_PRIORITY) {
284
            // handle receive now
285
            ptr = 0xFF;
286
            break;
287
          }        
288
        if (ptr != 0xFF) {
289
          // handle receive later
290
          other_buf_last = ptr;
291
        }
292
      }
293
    }
294
    break; }
295
  } // end of switch statement
296
  while (1) {
297
    if (FLAG) {
298
      apitype = PORT; // get checksum, and ignore
299
      break;
300
    }
301
  }
302
} // end of interrupt
303

    
304

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

    
337

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

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

    
375
  // reset baud rate
376
  WL_DEBUG_PRINT("Resetting Baud to ");
377
  WL_DEBUG_PRINT(XBEE_BAUD_STR);
378
  WL_DEBUG_PRINT("\r\n");
379
  
380
  // set baud on xbee
381
#if (XBEE_BAUD == 115200)
382
  xbee_send_string((uint8_t*)"ATBD7\r");
383
  xbee_send_string((uint8_t*)"ATBD7\r");
384
#elif (XBEE_BAUD == 57600)
385
  xbee_send_string((uint8_t*)"ATBD6\r");
386
#elif (XBEE_BAUD == 38400)
387
  xbee_send_string((uint8_t*)"ATBD5\r");
388
#elif (XBEE_BAUD == 19200)
389
  xbee_send_string((uint8_t*)"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((uint8_t*)"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((uint8_t*)"+++");
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
int8_t xbee_putc(uint8_t 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
  uint16_t i=0; // check if we need this variable
577
        while(i<size) {
578
                if (xbee_putc(buf[i++]) != WL_SUCCESS)
579
      return WL_ERROR_SEND;
580
        }  
581
  if (xbee_putc(buf[0]) != WL_SUCCESS)
582
    return WL_ERROR_SEND;
583

    
584
        return WL_SUCCESS;
585
}
586

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

    
597

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

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

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

    
624
        return WL_SUCCESS;
625
}
626

    
627
/**
628
 * Enter API mode.
629
 **/
630
static int8_t xbee_enter_api_mode(void) {
631
        if (xbee_send_string((uint8_t*)"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(void) {
645
        if (xbee_send_string((uint8_t*)"ATAP 2\r") != 0) {
646
                return WL_ERROR_SEND;
647
        }
648
        xbee_wait_for_ok();
649
  
650
  xbee_status = (xbee_status&0xFC)|XBEE_API_ESCAPE;
651
  
652
        return WL_SUCCESS;
653
}
654

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

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

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

    
718
        return 0;
719
}
720

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

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

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

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

    
817

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

    
836
        return WL_SUCCESS;
837
}
838

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

    
860
        if (xbee_send(buf, len) != WL_SUCCESS)
861
                return WL_ERROR_SEND;
862
        
863
        if (xbee_putc(checksum) != WL_SUCCESS)
864
                return WL_ERROR_SEND;
865
        
866
        return WL_SUCCESS;
867
}
868

    
869
/**
870
 * Sends an AT command to read a parameter.
871
 *
872
 * @param command the AT command to send. For exmaple,
873
 * use ID to read the PAN ID and MY to return the XBee ID.
874
 * See the XBee reference guide for a complete listing.
875
 **/
876
int8_t xbee_send_read_at_command(uint8_t* command)
877
{
878
        return xbee_send_modify_at_command(command, NULL, 0);
879
}
880

    
881
/**
882
 * Sends the given AT command.
883
 *
884
 * @param command the AT command to send (e.g., MY, ID)
885
 * @param value the value to pass as a parameter
886
 * (or NULL if there is no parameter)
887
 **/
888
static int8_t xbee_send_modify_at_command(uint8_t* command, uint8_t* value, uint8_t len)
889
{
890
        uint8_t buf[12];
891

    
892
        buf[0] = XBEE_FRAME_AT_COMMAND;
893
        buf[1] = 1;
894
        buf[2] = command[0];
895
        buf[3] = command[1];
896
        if (value != NULL)
897
        {
898
                if (len > 8)
899
                {
900
                        WL_DEBUG_PRINT("AT Command too large.\r\n");
901
                        return WL_ERROR_ARGUMENT;
902
                }
903
    memcpy(buf+4,value,len);
904
        }
905

    
906
        return xbee_send_frame(buf, 4 + len);
907
}
908

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

    
933
        if (len > 100)
934
        {
935
                WL_DEBUG_PRINT("Packet is too large.\r\n");
936
                return WL_ERROR_ARGUMENT;
937
        }
938
  
939
  // calculate checksum
940
        for(;i<len;i++)
941
                sum += packet[len];
942
  sum += frame;
943
  sum += (dest&0xFF00) >> 8;
944
  sum += dest&0x00FF;
945
  sum += options;
946
        sum = 0xFF - sum;
947

    
948
        //packet prefix
949
  if (xbee_putc(XBEE_FRAME_START) != WL_SUCCESS)
950
    return WL_ERROR_SEND;
951
  if (xbee_putc(0x00) != WL_SUCCESS)
952
    return WL_ERROR_SEND;
953
  if (xbee_putc(len+5) != WL_SUCCESS)
954
    return WL_ERROR_SEND;
955
    
956
        //send header for TX request
957
  if (xbee_putc(XBEE_FRAME_TX_REQUEST_16) != WL_SUCCESS)
958
    return WL_ERROR_SEND;
959
  if (xbee_putc(frame) != WL_SUCCESS)
960
    return WL_ERROR_SEND;
961
  if (xbee_putc((uint8_t)((dest&0xFF00) >> 8)) != WL_SUCCESS)
962
    return WL_ERROR_SEND;
963
  if (xbee_putc((uint8_t)(dest&0x00FF)) != WL_SUCCESS)
964
    return WL_ERROR_SEND;
965
  if (xbee_putc(options) != WL_SUCCESS)
966
    return WL_ERROR_SEND;
967

    
968
  // send packet
969
        if (xbee_send(packet, len) != WL_SUCCESS)
970
                return WL_ERROR_SEND;
971

    
972
  // send checksum
973
        if (xbee_putc(sum) != WL_SUCCESS)
974
                return WL_ERROR_SEND;
975

    
976
        return WL_SUCCESS;
977
}
978

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

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

    
1061
  return WL_SUCCESS;
1062
}
1063

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

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

    
1119
/**
1120
 * Set the channel the XBee is using.
1121
 *
1122
 * @param channel the channel the XBee will not use,
1123
 * between 0x0B and 0x1A
1124
 *
1125
 * @see xbee_get_channel
1126
 **/
1127
int8_t xbee_set_channel(uint8_t channel)
1128
{
1129
        if (channel < 0x0B || channel > 0x1A)
1130
        {
1131
                WL_DEBUG_PRINT("Channel out of range.\r\n");
1132
                return -1;
1133
        }
1134

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

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

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

    
1213
/**@} **/ // end xbee group
1214