Project

General

Profile

Statistics
| Revision:

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

History | View | Annotate | Download (32.3 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
/* I/O Functions */
46
static int8_t xbee_send_string(uint8_t* c);
47

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

    
56
/* API Mode Functions */
57
//TODO: does this exist?  static int8_t xbee_handle_packet(uint8_t* packet, uint16_t len);
58
static int8_t xbee_handle_at_command_response(uint16_t command, uint8_t result, uint8_t len);
59
static int8_t xbee_handle_at_command_response(uint16_t command, uint8_t result, uint8_t len);
60
static void xbee_handle_status(uint8_t status);
61
static int8_t xbee_verify_checksum(uint8_t* packet, uint16_t len);
62
static uint8_t xbee_compute_checksum(uint8_t* packet, uint16_t len);
63
static int8_t xbee_send_frame(uint8_t* buf, uint16_t len);
64
int8_t xbee_send_read_at_command(uint8_t* command);
65
static int8_t xbee_send_modify_at_command(uint8_t* command, uint8_t* value, uint8_t len);
66

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

    
72
/* private functions */
73
int8_t check_last_receive(uint16_t source,uint8_t framenum);
74
inline uint8_t getStatus(uint8_t mask);
75
inline void setStatus(uint8_t mask,uint8_t value);
76

    
77
/*Global Variables*/
78

    
79
// last few packet sources and frame nums
80
#define NUM_LAST_PACKETS 10
81
struct {
82
  uint16_t source;
83
  uint8_t framenum;
84
} lastPacket[NUM_LAST_PACKETS];
85

    
86
// array for basic packets
87
static uint8_t xbee_basic_buf[PACKET_BUFFER_SIZE];
88

    
89
// beginning of first packet in basic buffer
90
static uint8_t basic_buf_first = 0;
91

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

    
96
// array for other packets
97
static uint8_t xbee_other_buf[PACKET_BUFFER_SIZE];
98

    
99
// beginning of first packet in other buffer
100
static uint8_t other_buf_first = 0;
101

    
102
// byte after end of last packet in other buffer (only access < other_buf_last)
103
// aka, the first free byte in other buffer
104
static uint8_t other_buf_last = 0;
105

    
106
// xbee status
107
#define XBEE_API_OFF 0x00
108
#define XBEE_API_ON 0x10
109
#define XBEE_API_ESCAPE 0x20
110
#define XBEE_API_MASK 0x30
111
#define XBEE_COMMAND_WAIT 0x80
112
#define XBEE_COMMAND_RESPONSE 0xC0
113
#define XBEE_COMMAND_NONE 0x00
114
#define XBEE_COMMAND_MASK 0xC0
115
#define XBEE_NOT_INITD 0xF0
116
#define LAST_PACKET_MASK 0x0F
117
uint8_t xbee_status = XBEE_NOT_INITD;
118

    
119
// xbee command response (for PAN, channel, address, etc)
120
static uint8_t xbee_command[4];
121

    
122
// external ack handler (wireless_send.c)
123
extern void ackhandle(uint8_t num,uint8_t val);
124

    
125

    
126
/**@addtogroup xbee
127
 * @{ **/
128

    
129
/*Function Implementations*/
130

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

    
316

    
317
/* adds a byte to the basic buffer */
318
int8_t xbee_basic_buf_add(uint8_t *ptr, uint8_t byte) {
319
  if (*ptr == basic_buf_first) {
320
    // buffer full
321
    WL_DEBUG_PRINT("basic buffer full\r\n");
322
    return -1;
323
  }
324
  xbee_basic_buf[(*ptr)++] = byte;
325
  if (*ptr == PACKET_BUFFER_SIZE)
326
    *ptr = 0;
327
  return 0;
328
}
329
/* gets a byte from the basic buffer */
330
uint8_t xbee_basic_buf_get(uint8_t *ptr) {
331
  uint8_t byte = xbee_basic_buf[(*ptr)++];
332
  if (*ptr == PACKET_BUFFER_SIZE)
333
    *ptr = 0;
334
  return byte;
335
}
336
/* adds a byte to the other buffer */
337
int8_t xbee_other_buf_add(uint8_t *ptr, uint8_t byte) {
338
  if (*ptr == other_buf_first) {
339
    // buffer full
340
    WL_DEBUG_PRINT("other buffer full\r\n");
341
    return -1;
342
  }
343
  xbee_other_buf[(*ptr)++] = byte;
344
  if (*ptr == PACKET_BUFFER_SIZE)
345
    *ptr = 0;
346
  return 0;
347
}
348

    
349
/**
350
 * Checks if packet is a duplicate
351
 **/
352
int8_t check_last_receive(uint16_t source,uint8_t framenum) {
353
  uint8_t i=0;
354
  for(;i<NUM_LAST_PACKETS;i++) {
355
    if (lastPacket[i].source == source && lastPacket[i].framenum == framenum)
356
      return -1; // duplicate packet, so return error
357
  }
358
  // save packet source and framenum
359
  i=getStatus(LAST_PACKET_MASK);
360
  lastPacket[i].source = source;
361
  lastPacket[i].framenum = framenum;
362
  if (++i>=NUM_LAST_PACKETS)
363
    i = 0;
364
  setStatus(LAST_PACKET_MASK,i);
365
  return WL_SUCCESS;
366
}
367

    
368
/** status functions **/
369
inline uint8_t getStatus(uint8_t mask) { return xbee_status&mask; }
370
inline void setStatus(uint8_t mask,uint8_t value) { xbee_status = (xbee_status&(!mask))|value; }
371

    
372

    
373
/**
374
 * Initializes the XBee library so that other functions may be used.
375
 **/
376
int8_t xbee_init()
377
{
378
        WL_DEBUG_PRINT("in xbee_init\n");
379
  
380
  if(getStatus(XBEE_NOT_INITD) != XBEE_NOT_INITD) {
381
    return WL_ERROR_INIT_ALREADY_INITD;
382
  }
383
  
384
  // clear last packet buffer
385
  for(int i=0;i<NUM_LAST_PACKETS;i++)
386
    lastPacket[i].source = lastPacket[i].framenum = 0;
387
  
388
  // Set startup baud rate of 9600
389
        // Set frame format: 8data, 1stop bit, asynchronous normal mode
390
  // Enable receiver and transmitter and the receiving interrupt
391
#ifdef FIREFLY
392
  UCSR0A |= (1<<U2X0);
393
  UBRR0H = 0x00;
394
  UBRR0L = 103;
395
  UCSR0C |= (1<<UCSZ00) | (1<<UCSZ01);
396
        UCSR0B |= (1<<RXEN0) | (1<<TXEN0) | (1<<RXCIE0); 
397
#else
398
  // Bayboard or robot
399
  UCSR1A |= (1<<U2X1);
400
  UBRR1H = 0x00;
401
  UBRR1L = 103;
402
  UCSR1C |= (1<<UCSZ10) | (1<<UCSZ11);
403
        UCSR1B |= (1<<RXEN1) | (1<<TXEN1) | (1<<RXCIE1);
404
#endif
405
        sei();
406

    
407
        WL_DEBUG_PRINT("Entering command mode.\r\n");
408
        if (xbee_enter_command_mode() != 0) {
409
    WL_DEBUG_PRINT("error entering command mode\r\n");
410
                return -1;
411
        }
412
        WL_DEBUG_PRINT("Entered command mode.\r\n");
413

    
414
  // reset baud rate
415
  WL_DEBUG_PRINT("Resetting Baud to ");
416
  WL_DEBUG_PRINT(XBEE_BAUD_STR);
417
  WL_DEBUG_PRINT("\r\n");
418
  
419
  // set baud on xbee
420
#if (XBEE_BAUD == 115200)
421
  xbee_send_string((uint8_t*)"ATBD7\r");
422
  xbee_send_string((uint8_t*)"ATBD7\r");
423
#elif (XBEE_BAUD == 57600)
424
  xbee_send_string((uint8_t*)"ATBD6\r");
425
#elif (XBEE_BAUD == 38400)
426
  xbee_send_string((uint8_t*)"ATBD5\r");
427
#elif (XBEE_BAUD == 19200)
428
  xbee_send_string((uint8_t*)"ATBD4\r");
429
#elif (XBEE_BAUD == 9600)
430
  // already at this baud rate
431
  //xbee_send_string("ATBD3\r\n");
432
#else
433
  WL_DEBUG_PRINT("undefined baud rate\r\n");
434
  return WL_ERROR_BAUD;
435
#endif  
436
  // exit command mode
437
  xbee_wait_for_ok();
438
  WL_DEBUG_PRINT("got ok from baud reset\r\n");
439
  xbee_send_string((uint8_t*)"ATCN\r");
440
  xbee_wait_for_ok();
441
  WL_DEBUG_PRINT("got ok from exiting command mode\r\n");
442
  
443
  // set UART baud
444
#ifdef FIREFLY
445
#if (XBEE_BAUD == 115200)
446
  UBRR0H = 0x00;
447
  UBRR0L = 8;
448
#elif (XBEE_BAUD == 57600)
449
  UBRR0H = 0x00;
450
  UBRR0L = 16;
451
#elif (XBEE_BAUD == 38400)
452
  UBRR0H = 0x00;
453
  UBRR0L = 25;
454
#elif (XBEE_BAUD == 19200)
455
  UBRR0H = 0x00;
456
  UBRR0L = 51;
457
#elif (XBEE_BAUD == 9600)
458
  /* this is the default baud rate, so do nothing
459
  UBRR0H = 0x00;
460
  UBRR0L = 103;*/
461
#else
462
  WL_DEBUG_PRINT("undefined baud rate\r\n");
463
  return WL_ERROR_BUAD;
464
#endif
465
#else // Bayboard or robot
466
#if (XBEE_BAUD == 115200)
467
  UBRR1H = 0x00;
468
  UBRR1L = 8;
469
#elif (XBEE_BAUD == 57600)
470
  UBRR1H = 0x00;
471
  UBRR1L = 16;
472
#elif (XBEE_BAUD == 38400)
473
  UBRR1H = 0x00;
474
  UBRR1L = 25;
475
#elif (XBEE_BAUD == 19200)
476
  UBRR1H = 0x00;
477
  UBRR1L = 51;
478
#elif (XBEE_BAUD == 9600)
479
  /* this is the default baud rate, so do nothing
480
  UBRR1H = 0x00;
481
  UBRR1L = 103;*/
482
#else
483
  WL_DEBUG_PRINT("undefined baud rate\r\n");
484
  return WL_ERROR_BUAD;
485
#endif
486
#endif
487
  delay_ms(50);
488

    
489
  // enter command mode
490
  WL_DEBUG_PRINT("entering command mode 2\r\n");
491
  xbee_send_string((uint8_t*)"+++");
492
  xbee_wait_for_ok();
493
  WL_DEBUG_PRINT("entered command mode 2\r\n");
494
  
495
  if (xbee_enter_api_mode() != 0) {
496
    WL_DEBUG_PRINT("can't enter api mode\r\n");
497
                return -1;
498
        }
499

    
500
        WL_DEBUG_PRINT("Entered api mode.\r\n");
501

    
502
        if (xbee_exit_command_mode() != 0) {
503
    WL_DEBUG_PRINT("can't exit command mode\r\n");
504
          return -1;
505
        }
506
        
507
        WL_DEBUG_PRINT("Left command mode.\r\n");
508
  
509
  // TODO: we should set the MY address to the robot address from eeprom
510
  
511
  
512
  // set status
513
  setStatus(XBEE_NOT_INITD,XBEE_COMMAND_NONE);
514
  
515
        return WL_SUCCESS;
516
}
517

    
518
/**
519
 * Call when finished using the XBee library.
520
 **/
521
int8_t xbee_terminate()
522
{
523
  if (xbee_exit_api_mode() != WL_SUCCESS) {
524
    WL_DEBUG_PRINT("xbee termination failed\r\n");
525
    return WL_ERROR_TERMINATION_FAILED;
526
  }
527
  setStatus(XBEE_NOT_INITD,XBEE_NOT_INITD); // clean initd status
528
  return WL_SUCCESS;
529
}
530

    
531
/**
532
 * Sends a character to the XBee.
533
 *
534
 * @param c the byte to send
535
 * @return 0 for success, nonzero for failure
536
 **/
537
int8_t xbee_putc(uint8_t c) {
538

    
539
  // Wait until buffer is clear for sending
540
  // Then load buffer with your character
541
#ifdef FIREFLY
542
  loop_until_bit_is_set(UCSR0A, UDRE0);  
543
  UDR0 = c;
544
#else
545
  loop_until_bit_is_set(UCSR1A, UDRE1);
546
  UDR1 = c;
547
#endif
548
        
549
  return WL_SUCCESS;
550
}
551

    
552
/**
553
 * Returns the first byte in the buffer received from xbee.
554
 * This function blocks execution until a character has been
555
 * received. xbee_init must be called before this function
556
 * may be used.
557
 * 
558
 * @return the first character in the xbee buffer, -1 on error
559
 * 
560
 * @see xbee_init, xbee_getc_nb
561
 **/
562
int16_t xbee_getc(void) {
563
    
564
  // Wait for the receive buffer to be filled
565
  // Then read the receive buffer
566
#ifdef FIREFLY
567
  loop_until_bit_is_set(UCSR0A, RXC0);  
568
  return UDR0;
569
#else
570
  loop_until_bit_is_set(UCSR1A, RXC1);
571
  return UDR1;
572
#endif
573
}
574

    
575
/**
576
 * Non blocking version of xbee_getc. If a byte is present in the buffer,
577
 * it is returned, otherwise -1 is returned immediately. xbee_init
578
 * must be called before this function can be used.
579
 *
580
 * @param c The received byte. This will be set if a byte has been received.
581
 * 
582
 * @return -1 If no byte is available, 0 otherwise, positive for error
583
 *
584
 * @see xbee_getc
585
 **/
586
int8_t xbee_getc_nb(uint8_t *c) {
587

    
588
  // check if the receive buffer is filled
589
#ifdef FIREFLY
590
  if (UCSR0A & (1<<RXC0)) {
591
    (*c) = UDR0;
592
#else
593
  if (UCSR1A & (1<<RXC1)) {
594
    (*c) = UDR1;
595
#endif
596
    return WL_SUCCESS;
597
  }
598
  return -1; // Return empty
599
}
600

    
601
/**
602
 * Send a buffer buf of size bytes to the XBee.
603
 *
604
 * @param buf the buffer of data to send
605
 * @param size the number of bytes to send
606
 **/
607
int8_t xbee_send(uint8_t* buf, uint16_t size)
608
{
609
  uint16_t i=0; // check if we need this variable
610
        while(i<size) {
611
                if (xbee_putc(buf[i++]) != WL_SUCCESS)
612
      return WL_ERROR_SEND;
613
        }  
614
  if (xbee_putc(buf[0]) != WL_SUCCESS)
615
    return WL_ERROR_SEND;
616

    
617
        return WL_SUCCESS;
618
}
619

    
620
/**
621
 * Sends a string to the XBee.
622
 *
623
 * @param c the string to send to the XBEE
624
 **/
625
static int8_t xbee_send_string(uint8_t* c)
626
{
627
        return xbee_send(c, strlen((char*)c));
628
}
629

    
630

    
631
/**
632
 * Enter into command mode.
633
 **/
634
static int8_t xbee_enter_command_mode(void)
635
{
636
        if (xbee_send_string((uint8_t*)"+++") != WL_SUCCESS) {
637
                return WL_ERROR_XBEE_COMMAND;
638
        }
639

    
640
        if (xbee_wait_for_ok() != WL_SUCCESS) {
641
          return WL_ERROR_XBEE_COMMAND;
642
        }
643
  
644
        return WL_SUCCESS;
645
}
646

    
647
/**
648
 * Exit from command mode.
649
 **/
650
static int8_t xbee_exit_command_mode()
651
{
652
        if (xbee_send_string((uint8_t*)"ATCN\r") != 0) {
653
                return WL_ERROR_SEND;
654
        }
655
        xbee_wait_for_ok();
656

    
657
        return WL_SUCCESS;
658
}
659

    
660
/**
661
 * Enter API mode.
662
 **/
663
static int8_t xbee_enter_api_mode(void) {
664
        if (xbee_send_string((uint8_t*)"ATAP 1\r") != 0) {
665
                return WL_ERROR_SEND;
666
        }
667
        xbee_wait_for_ok();
668
  
669
  setStatus(XBEE_API_MASK,XBEE_API_ON); // set status
670

    
671
        return WL_SUCCESS;
672
}
673

    
674
/**
675
 * Enter API mode 2.
676
 **/
677
static int8_t xbee_enter_api_mode2(void) {
678
        if (xbee_send_string((uint8_t*)"ATAP 2\r") != 0) {
679
                return WL_ERROR_SEND;
680
        }
681
        xbee_wait_for_ok();
682
  
683
  setStatus(XBEE_API_MASK,XBEE_API_ESCAPE); // set status
684
  
685
        return WL_SUCCESS;
686
}
687

    
688
/**
689
 * Exit API mode.
690
 **/
691
static int8_t xbee_exit_api_mode()
692
{
693
        if (getStatus(XBEE_COMMAND_MASK) == XBEE_COMMAND_WAIT
694
    || getStatus(XBEE_COMMAND_MASK) == XBEE_COMMAND_RESPONSE)
695
    return WL_ERROR_XBEE_COMMAND; // can't do command right now
696
  
697
  int16_t i=0;
698
  // change status to command wait
699
  setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_WAIT);
700
  xbee_send_modify_at_command((uint8_t*)"AP",(uint8_t*)"0",1); // send command
701
  // wait for up to 30 ms
702
  while(getStatus(XBEE_COMMAND_MASK) != XBEE_COMMAND_RESPONSE && i++ < 10000) {
703
    delay_us(1); // wait 3us
704
  }
705
  if (i < 1000 && xbee_command[0] == 'A' && xbee_command[1] == 'P')
706
    i = WL_SUCCESS;
707
  else
708
    i = WL_ERROR_XBEE_COMMAND; // set error code
709
  setStatus(XBEE_API_MASK,XBEE_API_OFF); // reset status
710
        return (int8_t)i; // return
711
}
712

    
713
/**
714
 * Wait until the string "OK\r" is received from the XBee.
715
 **/
716
static int8_t xbee_wait_for_ok()
717
{
718
        return xbee_wait_for_string((uint8_t*)"OK\r", 3);
719
}
720

    
721
/**
722
 * Delay until the specified string is received from
723
 * the XBee.
724
 *
725
 * Only works when not in API mode
726
 *
727
 * @param s the string to receive
728
 * @param len the length of the string
729
 **/
730
static int8_t xbee_wait_for_string(uint8_t* s, uint16_t len)
731
{
732
  uint8_t i=0;
733
  if (getStatus(XBEE_API_MASK) == XBEE_API_OFF) {
734
    // wait until the response is received (only wait 1 second)
735
    while(getStatus(XBEE_COMMAND_MASK) != XBEE_COMMAND_RESPONSE && i++ < 1000) {
736
      delay_us(1);
737
    }
738
    // check response
739
    if (i >= 1000 || memcmp(s,xbee_basic_buf,len) != 0) {
740
      // bad response
741
      WL_DEBUG_PRINT("Bad response when waiting for string ");
742
      WL_DEBUG_PRINT(s);
743
      WL_DEBUG_PRINT("\r\n");
744
      return -1;
745
    }
746
    
747
    setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_NONE); // clear status
748
  }
749

    
750
        return 0;
751
}
752

    
753
/**
754
 * Delay until we receive a command response.
755
 * (either OK\r or some actual value)
756
 *
757
 * Only works when not in API mode
758
 *
759
 * @param s the string to store the response in
760
 * @param len the length of the string
761
 */
762
static int8_t xbee_wait_for_response(uint8_t* s, int16_t len) {
763
  uint8_t i=0;
764
  if (getStatus(XBEE_API_MASK) == XBEE_API_OFF) {
765
    // wait until the response is received (only wait 1 second)
766
    while(getStatus(XBEE_COMMAND_MASK) != XBEE_COMMAND_RESPONSE && i++ < 1000) {
767
      delay_us(1);
768
    }
769
    // check response
770
    if (i >= 1000) {
771
      return -1;
772
    } else {
773
      i=strcspn((char*)xbee_basic_buf,"\r");
774
      if (i<PACKET_BUFFER_SIZE) {
775
        memcpy(s,xbee_basic_buf,i);
776
        setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_NONE); // clear response
777
        return 0;
778
      }
779
      else
780
        return -1;      
781
    }
782
  }
783
  // TODO: do something for API mode
784
  
785
  return 0;
786
}
787

    
788
/**  TODO: since we don't use this, do we need it?
789
 *
790
 * Verifies that the packets checksum is correct.
791
 * (If the checksum is correct, the sum of the bytes
792
 * is 0xFF.)
793
 *
794
 * @param packet the packet received. This includes the first
795
 * three bytes, which are header information from the XBee.
796
 *
797
 * @param len The length of the packet received from the XBee
798
 *
799
 * @return 0 if the checksum is incorrect, nonzero
800
 * otherwise
801
 **/
802
int8_t xbee_verify_checksum(uint8_t* packet, uint16_t len)
803
{
804
        uint8_t sum = 0;
805
        while(--len > 0) {
806
                sum += packet[len];
807
  }
808
  sum += packet[0];
809
        return (sum == 0xFF);
810
}
811

    
812
/**
813
 * Returns the checksum of the given packet.
814
 *
815
 * @param buf the data for the packet to send
816
 * @param len the length of the packet in bytes
817
 *
818
 * @return the checksum of the packet, which will
819
 * become the last byte sent in the packet
820
 **/
821
uint8_t xbee_compute_checksum(uint8_t* buf, uint16_t len)
822
{
823
        uint8_t sum = 0;
824
        while(--len > 0) {
825
                sum += buf[len];
826
  }
827
  sum += buf[0];
828
        return 0xFF - sum;
829
}
830

    
831
/**
832
 * Adds buf to the previous checksum total
833
 *
834
 * @param buf a byte buffer to add to the checksum
835
 * @param len the length of the buffer
836
 * @param sum the previous sum
837
 *
838
 * @return error code
839
 **/
840
int8_t xbee_checksum_add(uint8_t *buf, uint8_t len, uint8_t* sum) {
841
  if (buf == NULL || sum == NULL)
842
    return WL_ERROR_ARGUMENT;
843
  while(--len > 0) {
844
                *sum += buf[len];
845
  }
846
  *sum += buf[0];
847
  return WL_SUCCESS;
848
}
849

    
850

    
851
/**
852
 * Sends header information. Header information includes
853
 * XBEE_FRAME_START and the packet length, as two bytes.
854
 *
855
 * @param type the packet type
856
 * @param len the size in bytes of the packet data
857
 *
858
 **/
859
int8_t xbee_send_header(uint8_t type, uint16_t len)
860
{  
861
  //packet prefix
862
  if (xbee_putc(XBEE_FRAME_START) != WL_SUCCESS)
863
    return WL_ERROR_SEND;
864
  if (xbee_putc((uint8_t)((len & 0xFF00) >> 8)) != WL_SUCCESS)
865
    return WL_ERROR_SEND;
866
  if (xbee_putc((uint8_t)(len & 0x00FF)) != WL_SUCCESS)
867
    return WL_ERROR_SEND;
868

    
869
        return WL_SUCCESS;
870
}
871

    
872
/**
873
 * Adds header information and checksum to the given
874
 * packet and sends it. Header information includes
875
 * XBEE_FRAME_START and the packet length, as two bytes.
876
 *
877
 * @param buf the packet data
878
 * @param len the size in bytes of the packet data
879
 *
880
 **/
881
static int8_t xbee_send_frame(uint8_t* buf, uint16_t len)
882
{
883
        uint8_t checksum = xbee_compute_checksum(buf, len);
884
  
885
  //packet prefix
886
  if (xbee_putc(XBEE_FRAME_START) != WL_SUCCESS)
887
    return WL_ERROR_SEND;
888
  if (xbee_putc((uint8_t)((len & 0xFF00) >> 8)) != WL_SUCCESS)
889
    return WL_ERROR_SEND;
890
  if (xbee_putc((uint8_t)(len & 0x00FF)) != WL_SUCCESS)
891
    return WL_ERROR_SEND;
892

    
893
        if (xbee_send(buf, len) != WL_SUCCESS)
894
                return WL_ERROR_SEND;
895
        
896
        if (xbee_putc(checksum) != WL_SUCCESS)
897
                return WL_ERROR_SEND;
898
        
899
        return WL_SUCCESS;
900
}
901

    
902
/**
903
 * Sends an AT command to read a parameter.
904
 *
905
 * @param command the AT command to send. For exmaple,
906
 * use ID to read the PAN ID and MY to return the XBee ID.
907
 * See the XBee reference guide for a complete listing.
908
 **/
909
int8_t xbee_send_read_at_command(uint8_t* command)
910
{
911
        return xbee_send_modify_at_command(command, NULL, 0);
912
}
913

    
914
/**
915
 * Sends the given AT command.
916
 *
917
 * @param command the AT command to send (e.g., MY, ID)
918
 * @param value the value to pass as a parameter
919
 * (or NULL if there is no parameter)
920
 **/
921
static int8_t xbee_send_modify_at_command(uint8_t* command, uint8_t* value, uint8_t len)
922
{
923
        uint8_t buf[12];
924

    
925
        buf[0] = XBEE_FRAME_AT_COMMAND;
926
        buf[1] = 1;
927
        buf[2] = command[0];
928
        buf[3] = command[1];
929
        if (value != NULL)
930
        {
931
                if (len > 8)
932
                {
933
                        WL_DEBUG_PRINT("AT Command too large.\r\n");
934
                        return WL_ERROR_ARGUMENT;
935
                }
936
    memcpy(buf+4,value,len);
937
        }
938

    
939
        return xbee_send_frame(buf, 4 + len);
940
}
941

    
942
/**
943
 * Send the specified packet.
944
 *
945
 * @param packet the packet data to send
946
 * @param len the number of bytes in the packet
947
 *
948
 * @param dest the ID of the XBee to send the packet to,
949
 * or XBEE_BROADCAST to send the message to all robots
950
 * in the PAN.
951
 *
952
 * @param options a combination of the flags
953
 * XBEE_OPTIONS_NONE, XBEE_OPTIONS_DISABLE_RESPONSE and
954
 * XBEE_OPTIONS_BROADCAST_ALL_PANS
955
 *
956
 * @param frame the frame number to associate this packet
957
 * with. This will be used to identify the response when
958
 * the XBee alerts us as to whether or not our message
959
 * was received.
960
 **/
961
int8_t xbee_send_packet(uint8_t* packet, uint8_t len, uint16_t dest, uint8_t options, uint8_t frame)
962
{
963
        uint8_t sum = XBEE_FRAME_TX_REQUEST_16;
964
  uint8_t i = 0;
965

    
966
        if (len > 100)
967
        {
968
                WL_DEBUG_PRINT("Packet is too large.\r\n");
969
                return WL_ERROR_ARGUMENT;
970
        }
971
  
972
  // calculate checksum
973
        for(;i<len;i++)
974
                sum += packet[len];
975
  sum += frame;
976
  sum += (dest&0xFF00) >> 8;
977
  sum += dest&0x00FF;
978
  sum += options;
979
        sum = 0xFF - sum;
980

    
981
        //packet prefix
982
  if (xbee_putc(XBEE_FRAME_START) != WL_SUCCESS)
983
    return WL_ERROR_SEND;
984
  if (xbee_putc(0x00) != WL_SUCCESS)
985
    return WL_ERROR_SEND;
986
  if (xbee_putc(len+5) != WL_SUCCESS)
987
    return WL_ERROR_SEND;
988
    
989
        //send header for TX request
990
  if (xbee_putc(XBEE_FRAME_TX_REQUEST_16) != WL_SUCCESS)
991
    return WL_ERROR_SEND;
992
  if (xbee_putc(frame) != WL_SUCCESS)
993
    return WL_ERROR_SEND;
994
  if (xbee_putc((uint8_t)((dest&0xFF00) >> 8)) != WL_SUCCESS)
995
    return WL_ERROR_SEND;
996
  if (xbee_putc((uint8_t)(dest&0x00FF)) != WL_SUCCESS)
997
    return WL_ERROR_SEND;
998
  if (xbee_putc(options) != WL_SUCCESS)
999
    return WL_ERROR_SEND;
1000

    
1001
  // send packet
1002
        if (xbee_send(packet, len) != WL_SUCCESS)
1003
                return WL_ERROR_SEND;
1004

    
1005
  // send checksum
1006
        if (xbee_putc(sum) != WL_SUCCESS)
1007
                return WL_ERROR_SEND;
1008

    
1009
        return WL_SUCCESS;
1010
}
1011

    
1012
/**
1013
 * Handles modem status packets.
1014
 *
1015
 * @param status the type of status packet received.
1016
 **/
1017
void xbee_handle_status(uint8_t status)
1018
{
1019
        switch (status)
1020
        {
1021
                case 0:
1022
                        WL_DEBUG_PRINT("XBee hardware reset.\r\n");
1023
                        break;
1024
                case 1:
1025
                        WL_DEBUG_PRINT("Watchdog timer reset.\r\n");
1026
                        break;
1027
                case 2:
1028
                        WL_DEBUG_PRINT("Associated.\r\n");
1029
                        break;
1030
                case 3:
1031
                        WL_DEBUG_PRINT("Disassociated.\r\n");
1032
                        break;
1033
                case 4:
1034
                        WL_DEBUG_PRINT("Synchronization lost.\r\n");
1035
                        break;
1036
                case 5:
1037
                        WL_DEBUG_PRINT("Coordinator realignment.\r\n");
1038
                        break;
1039
                case 6:
1040
                        WL_DEBUG_PRINT("Coordinator started.\r\n");
1041
                        break;
1042
        }
1043
}
1044

    
1045
/**
1046
 * Handles AT command response packets.
1047
 * @param command the two character AT command, e.g. MY or ID
1048
 * @param result 0 for success, 1 for an error
1049
 * @param len the length in bytes of extra
1050
 **/
1051
static int8_t xbee_handle_at_command_response(uint16_t command, uint8_t result, uint8_t len)
1052
{
1053
        if (result == 1)
1054
        {
1055
                WL_DEBUG_PRINT("Error with AT");
1056
                WL_DEBUG_PRINT(command);
1057
                WL_DEBUG_PRINT(" packet. Result = ");
1058
    switch(result) {
1059
    case 1:
1060
      WL_DEBUG_PRINT("ERROR\r\n");
1061
      break;
1062
    case 2:
1063
      WL_DEBUG_PRINT("Invalid Command\r\n");
1064
      break;
1065
    case 3:
1066
      WL_DEBUG_PRINT("Invalid Parameter\r\n");
1067
      break;
1068
    }
1069
    return WL_SUCCESS;
1070
        }
1071
        WL_DEBUG_PRINT("AT");
1072
        WL_DEBUG_PRINT(command);
1073
        WL_DEBUG_PRINT(" command was successful.\r\n");
1074
  
1075
  // TODO: program more command responses here (ND, etc)
1076
  switch(command) {
1077
  case ('I'<<8)+'D': // PAN
1078
  case ('C'<<8)+'H': // channel
1079
  case ('M'<<8)+'Y': // address
1080
    // copy command to handler
1081
    xbee_command[0] = (command&0xFF00)>>8;
1082
    xbee_command[1] = command&0x00FF;
1083
    result = basic_buf_last;
1084
    for(command=2;command<len+2;command++)
1085
      xbee_command[command] = xbee_basic_buf_get(&result);
1086
    break;
1087
  default:
1088
    WL_DEBUG_PRINT("unknown AT command");
1089
  }
1090
  
1091
  // signal handler that command response is done
1092
  setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_NONE);
1093

    
1094
  return WL_SUCCESS;
1095
}
1096

    
1097
/**
1098
 * Sets the personal area network id.
1099
 *
1100
 * @param id the new personal area network (PAN) id
1101
 **/
1102
int8_t xbee_set_pan_id(uint16_t id)
1103
{
1104
        if (getStatus(XBEE_COMMAND_MASK) == XBEE_COMMAND_WAIT
1105
    || getStatus(XBEE_COMMAND_MASK) == XBEE_COMMAND_RESPONSE)
1106
    return WL_ERROR_XBEE_COMMAND; // can't do command right now
1107
  
1108
  int16_t i=0;
1109
  // change status to command wait
1110
  setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_WAIT);
1111
  xbee_send_modify_at_command((uint8_t*)"ID",(uint8_t*)(&id),2); // send command to set the channel
1112
  // wait for up to 30 ms
1113
  while(getStatus(XBEE_COMMAND_MASK) != XBEE_COMMAND_RESPONSE && i++ < 10000) {
1114
    delay_us(1); // wait 3us
1115
  }
1116
  if (i < 1000 && xbee_command[0] == 'O' && xbee_command[1] == 'K')
1117
    i = WL_SUCCESS;
1118
  else
1119
    i = WL_ERROR_XBEE_COMMAND; // set error code
1120
  setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_NONE); // reset status
1121
        return (int8_t)i; // return
1122
}
1123

    
1124
/**
1125
 * Get the PAN ID for the XBee.
1126
 *
1127
 * @return the personal area network id, or
1128
 * XBEE_PAN_DEFAULT if it has not yet been set.
1129
 **/
1130
uint16_t xbee_get_pan_id()
1131
{
1132
        if (getStatus(XBEE_COMMAND_MASK) == XBEE_COMMAND_WAIT
1133
    || getStatus(XBEE_COMMAND_MASK) == XBEE_COMMAND_RESPONSE)
1134
    return WL_ERROR_XBEE_COMMAND_16BIT; // can't do command right now
1135
  
1136
  uint16_t i=0;
1137
  // change status to command wait
1138
  setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_WAIT);
1139
  xbee_send_read_at_command((uint8_t*)"ID"); // send command to get the PAN
1140
  // wait for up to 30 ms
1141
  while(getStatus(XBEE_COMMAND_MASK) != XBEE_COMMAND_RESPONSE && i++ < 10000) {
1142
    delay_us(1); // wait 3us
1143
  }
1144
  if (i < 1000 && xbee_command[0] == 'I' && xbee_command[1] == 'D')
1145
    i = (xbee_command[2]<<8)|xbee_command[3]; // get PAN
1146
  else
1147
    i = WL_ERROR_XBEE_COMMAND_16BIT; // set error code
1148
  setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_NONE); // reset status
1149
        return i; // return
1150
}
1151

    
1152
/**
1153
 * Set the channel the XBee is using.
1154
 *
1155
 * @param channel the channel the XBee will not use,
1156
 * between 0x0B and 0x1A
1157
 *
1158
 * @see xbee_get_channel
1159
 **/
1160
int8_t xbee_set_channel(uint8_t channel)
1161
{
1162
        if (channel < 0x0B || channel > 0x1A)
1163
        {
1164
                WL_DEBUG_PRINT("Channel out of range.\r\n");
1165
                return -1;
1166
        }
1167

    
1168
        if (getStatus(XBEE_COMMAND_MASK) == XBEE_COMMAND_WAIT
1169
    || getStatus(XBEE_COMMAND_MASK) == XBEE_COMMAND_RESPONSE)
1170
    return WL_ERROR_XBEE_COMMAND; // can't do command right now
1171
  
1172
  int16_t i=0;
1173
  // change status to command wait
1174
  setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_WAIT);
1175
  xbee_send_modify_at_command((uint8_t*)"CH",&channel,1); // send command to set the channel
1176
  // wait for up to 30 ms
1177
  while(getStatus(XBEE_COMMAND_MASK) != XBEE_COMMAND_RESPONSE && i++ < 10000) {
1178
    delay_us(1); // wait 3us
1179
  }
1180
  if (i < 1000 && xbee_command[0] == 'O' && xbee_command[1] == 'K')
1181
    i = WL_SUCCESS;
1182
  else
1183
    i = WL_ERROR_XBEE_COMMAND; // set error code
1184
  setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_NONE); // reset status
1185
        return (int8_t)i; // return
1186
}
1187

    
1188
/**
1189
 * Returns the channel which the XBee is currently using.
1190
 *
1191
 * @return the channel the XBee is using
1192
 *
1193
 * @see xbee_set_channel
1194
 **/
1195
int8_t xbee_get_channel(void)
1196
{
1197
        if (getStatus(XBEE_COMMAND_MASK) == XBEE_COMMAND_WAIT
1198
    || getStatus(XBEE_COMMAND_MASK) == XBEE_COMMAND_RESPONSE)
1199
    return WL_ERROR_XBEE_COMMAND; // can't do command right now
1200
  
1201
  int16_t i=0;
1202
  // change status to command wait
1203
  setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_WAIT);
1204
  xbee_send_read_at_command((uint8_t*)"ID"); // send command to get the channel
1205
  // wait for up to 30 ms
1206
  while(getStatus(XBEE_COMMAND_MASK) != XBEE_COMMAND_RESPONSE && i++ < 10000) {
1207
    delay_us(1); // wait 3us
1208
  }
1209
  if (i < 1000 && xbee_command[0] == 'C' && xbee_command[1] == 'H')
1210
    i = xbee_command[2]; // get channel
1211
  else
1212
    i = WL_ERROR_XBEE_COMMAND; // set error code
1213
  setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_NONE); // reset status
1214
        return i; // return
1215
}
1216

    
1217
/**
1218
 * Get the 16-bit address of the XBee.
1219
 * This is used to specify who to send messages to
1220
 * and who messages are from.
1221
 *
1222
 * @return the 16-bit address of the XBee.
1223
 **/
1224
uint16_t xbee_get_address(void)
1225
{
1226
        if (getStatus(XBEE_COMMAND_MASK) == XBEE_COMMAND_WAIT
1227
    || getStatus(XBEE_COMMAND_MASK) == XBEE_COMMAND_RESPONSE)
1228
    return WL_ERROR_XBEE_COMMAND_16BIT; // can't do command right now
1229
  
1230
  uint16_t i=0;
1231
  // change status to command wait
1232
  setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_WAIT);
1233
  xbee_send_read_at_command((uint8_t*)"MY"); // send command to get the address
1234
  // wait for up to 30 ms
1235
  while(getStatus(XBEE_COMMAND_MASK) != XBEE_COMMAND_RESPONSE && i++ < 10000) {
1236
    delay_us(1); // wait 3us
1237
  }
1238
  if (i < 1000 && xbee_command[0] == 'M' && xbee_command[1] == 'Y')
1239
    i = (xbee_command[2]<<8)+xbee_command[3]; // get address
1240
  else
1241
    i = WL_ERROR_XBEE_COMMAND_16BIT; // set error code
1242
  setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_NONE); // reset status
1243
        return i; // return
1244
}
1245

    
1246
/**@} **/ // end xbee group
1247