Project

General

Profile

Statistics
| Revision:

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

History | View | Annotate | Download (47.2 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
#include <lights.h>
35

    
36
#include <string.h>
37
#include <avr/io.h>
38
#include <avr/interrupt.h>
39
#include <time.h>
40
#include <wl_defs.h>
41
#include <wireless.h>
42
#include <eeprom.h>
43
#include "xbee.h"
44

    
45

    
46
/* Internal Function Prototypes */
47

    
48
/* I/O Functions */
49
static int8_t xbee_send_string(uint8_t* c);
50
int8_t xbee_putc(uint8_t c);
51
int16_t xbee_getc(void);
52
int8_t xbee_getc_nb(uint8_t *c);
53

    
54
/* Command Mode Functions */
55
static int8_t xbee_enter_command_mode(void);
56
static int8_t xbee_exit_command_mode(void);
57
static int8_t xbee_enter_api_mode(void);
58
static int8_t xbee_exit_api_mode(void);
59
static int8_t xbee_wait_for_string(uint8_t* s, uint16_t len);
60
static int8_t xbee_wait_for_ok(void);
61

    
62
/* API Mode Functions */
63
//TODO: does this exist?  static int8_t xbee_handle_packet(uint8_t* packet, uint16_t len);
64
static int8_t xbee_handle_at_command_response(uint16_t command, uint8_t status, uint8_t len);
65
static void xbee_handle_status(uint8_t status);
66
static int8_t xbee_verify_checksum(uint8_t* packet, uint16_t len);
67
static uint8_t xbee_compute_checksum(uint8_t* packet, uint16_t len);
68
static int8_t xbee_send_frame(uint8_t* buf, uint16_t len);
69
int8_t xbee_send_read_at_command(uint8_t* command);
70
static int8_t xbee_send_modify_at_command(uint8_t* command, uint8_t* value, uint8_t len);
71

    
72
/* Buffer Manipulation Functions */
73
int8_t xbee_basic_buf_add(uint8_t *ptr, uint8_t byte);
74
uint8_t xbee_basic_buf_get(uint8_t *ptr);
75
int8_t xbee_other_buf_add(uint8_t *ptr, uint8_t byte);
76
//uint8_t xbee_other_buf_get(uint8_t *ptr);
77

    
78
/* private functions */
79
int8_t check_last_receive(uint16_t source,uint8_t framenum);
80
inline uint8_t getStatus(uint8_t mask);
81
inline void setStatus(uint8_t mask,uint8_t value);
82

    
83
/*Global Variables*/
84

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

    
88
// beginning of first packet in basic buffer
89
uint8_t basic_buf_first = (PACKET_BUFFER_SIZE-1);
90

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

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

    
98
// beginning of first packet in other buffer
99
uint8_t other_buf_first = (PACKET_BUFFER_SIZE-1);
100

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

    
105

    
106
// last few packet sources and frame nums
107
#define NUM_LAST_PACKETS 10
108
struct {
109
  uint16_t source;
110
  uint8_t framenum;
111
} lastPacket[NUM_LAST_PACKETS];
112

    
113

    
114
// xbee status
115
#define XBEE_API_OFF 0x00
116
#define XBEE_API_ON 0x10
117
#define XBEE_API_ESCAPE 0x20
118
#define XBEE_API_MASK 0x30
119
#define XBEE_COMMAND_WAIT 0x80
120
#define XBEE_COMMAND_RESPONSE 0xC0
121
#define XBEE_COMMAND_NONE 0x00
122
#define XBEE_COMMAND_MASK 0xC0
123
#define XBEE_NOT_INITD 0xF0
124
#define LAST_PACKET_MASK 0x0F
125
uint8_t xbee_status = XBEE_NOT_INITD;
126

    
127
// xbee command response (for PAN, channel, address, etc)
128
static uint8_t xbee_command[8];
129

    
130
// external ack handler (wireless_send.c)
131
extern void ackhandle(uint8_t num,uint8_t val);
132

    
133

    
134
// define escaped bytes in API mode 2
135
#define ESCAPE_MARKER 0x7D
136
#define ESCAPE_XOR 0x20
137
#define ESCAPE1 0x7E
138
#define ESCAPE2 0x7D
139
#define ESCAPE3 0x11
140
#define ESCAPE4 0x13
141

    
142

    
143
/**@addtogroup xbee
144
 * @{ **/
145

    
146
/*Function Implementations*/
147

    
148
/**
149
 * Interrupt for the robot. Adds bytes received from the xbee
150
 * to the buffer.
151
 **/
152
 
153
 
154
#ifndef FIREFLY
155
#define PORT UDR1
156
#define FLAG (UCSR1A & (1<<RXC1))
157
ISR(USART1_RX_vect) {
158
#else
159
#define PORT UDR0
160
#define FLAG (UCSR0A & (1<<RXC0))
161
SIGNAL(SIG_USART0_RECV) {
162
#endif
163
  // start of frame
164
  uint8_t apitype = PORT; // get frame start byte
165
  uint16_t i=0;
166
  uint16_t len=0;
167
  
168
  // check that we're in API mode
169
  if (getStatus(XBEE_API_MASK) == XBEE_API_OFF || apitype != XBEE_FRAME_START) {
170
    // not in API mode
171
    WL_DEBUG_PRINT_P("|api off branch");
172
    
173
    if (getStatus(XBEE_COMMAND_MASK) == XBEE_COMMAND_WAIT) {
174
      // get rest of command and put in basic buf
175
      xbee_basic_buf[i] = apitype;
176
      if (xbee_basic_buf[i++] != '\r') {
177
        while(i < PACKET_BUFFER_SIZE) {
178
          if (FLAG) {
179
            xbee_basic_buf[i] = PORT;
180
            if (xbee_basic_buf[i] == '\r')
181
              break;
182
            i++;
183
          }
184
        }
185
      }
186
      WL_DEBUG_PRINT_P("got packet, len=");
187
      WL_DEBUG_PRINT_INT(i);
188
      WL_DEBUG_PRINT_P("str=");
189
      WL_DEBUG_PRINT((char*)xbee_basic_buf);
190
      // signal handler that command response is done
191
      setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_RESPONSE);
192
    }
193
    WL_DEBUG_PRINT_P("return\r\n");
194
    return;
195
  }  
196
  //WL_DEBUG_PRINT_P("|api on branch");
197
    
198
  // get length and type
199
  while(i<3) {
200
    if (FLAG) {
201
      if (i==0) {
202
        if (getStatus(XBEE_API_MASK) == XBEE_API_ESCAPE
203
            && apitype == ESCAPE_MARKER)
204
          apitype = PORT ^ ESCAPE_XOR;
205
        else {
206
          apitype = PORT;
207
          if (getStatus(XBEE_API_MASK) == XBEE_API_ESCAPE
208
              && apitype == ESCAPE_MARKER)
209
            continue; // get escaped character
210
        }
211
        len |= apitype<<8; // get len hi byte
212
      } else if (i==1) {
213
        if (getStatus(XBEE_API_MASK) == XBEE_API_ESCAPE
214
            && apitype == ESCAPE_MARKER)
215
          apitype = PORT ^ ESCAPE_XOR;
216
        else {
217
          apitype = PORT;
218
          if (getStatus(XBEE_API_MASK) == XBEE_API_ESCAPE
219
              && apitype == ESCAPE_MARKER)
220
            continue; // get escaped character
221
        }
222
        len |= apitype; // get len lo byte
223
      } else if (i==2) {
224
        if (getStatus(XBEE_API_MASK) == XBEE_API_ESCAPE
225
            && apitype == ESCAPE_MARKER)
226
          apitype = PORT ^ ESCAPE_XOR;
227
        else {
228
          apitype = PORT;
229
          if (getStatus(XBEE_API_MASK) == XBEE_API_ESCAPE
230
              && apitype == ESCAPE_MARKER)
231
            continue; // get escaped character
232
        }
233
        // get api type
234
        break;
235
      }
236
      i++;
237
    }
238
  }
239
  
240
  // do something based on the type
241
  i=1;
242
  switch(apitype) {
243
  case XBEE_FRAME_AT_COMMAND_RESPONSE: {
244
    // AT command response
245
    if (getStatus(XBEE_COMMAND_MASK) == XBEE_COMMAND_RESPONSE)
246
    {        WL_DEBUG_PRINT_P("ERROR: SOMETHING STRANGE HAS OCCURRED. THE ROBOT WILL SELF DESTRUCT IN 5 MINUTES!\r\n");//We better get rid of this sometime...
247
      return;} // we're currently processing a command, so drop the incoming one  ***** TODO: we need to read the whole length of the frame to do this right ****
248
    uint16_t atcommand=0;
249
    uint8_t ptr=basic_buf_last;
250
    uint8_t status=0;
251
    while(i<len) {
252
      if (FLAG) {
253
        if (i==1) {
254
          if (getStatus(XBEE_API_MASK) == XBEE_API_ESCAPE
255
              && apitype == ESCAPE_MARKER)
256
            apitype = PORT ^ ESCAPE_XOR; // get frame id, and ignore
257
          else {
258
            apitype = PORT;
259
            if (getStatus(XBEE_API_MASK) == XBEE_API_ESCAPE
260
                && apitype == ESCAPE_MARKER)
261
              continue; // get escaped character
262
          }
263
          apitype = PORT; // get frame id, but ignore it
264
        } else if (i==2) {
265
          if (getStatus(XBEE_API_MASK) == XBEE_API_ESCAPE
266
              && apitype == ESCAPE_MARKER)
267
            apitype = PORT ^ ESCAPE_XOR;
268
          else {
269
            apitype = PORT;
270
            if (getStatus(XBEE_API_MASK) == XBEE_API_ESCAPE
271
                && apitype == ESCAPE_MARKER)
272
              continue; // get escaped character
273
          }
274
          atcommand |= apitype<<8; // get command char1
275
        } else if (i==3) {
276
          if (getStatus(XBEE_API_MASK) == XBEE_API_ESCAPE
277
              && apitype == ESCAPE_MARKER)
278
            apitype = PORT ^ ESCAPE_XOR;
279
          else {
280
            apitype = PORT;
281
            if (getStatus(XBEE_API_MASK) == XBEE_API_ESCAPE
282
                && apitype == ESCAPE_MARKER)
283
              continue; // get escaped character
284
          }
285
          atcommand |= apitype; // get command char2
286
        } else if (i==4) {
287
          if (getStatus(XBEE_API_MASK) == XBEE_API_ESCAPE
288
              && apitype == ESCAPE_MARKER)
289
            apitype = PORT ^ ESCAPE_XOR;
290
          else {
291
            apitype = PORT;
292
            if (getStatus(XBEE_API_MASK) == XBEE_API_ESCAPE
293
                && apitype == ESCAPE_MARKER)
294
              continue; // get escaped character
295
          }
296
          status = apitype; // get status
297
        } else {
298
          if (getStatus(XBEE_API_MASK) == XBEE_API_ESCAPE
299
              && apitype == ESCAPE_MARKER)
300
            apitype = PORT ^ ESCAPE_XOR;
301
          else {
302
            apitype = PORT;
303
            if (getStatus(XBEE_API_MASK) == XBEE_API_ESCAPE
304
                && apitype == ESCAPE_MARKER)
305
              continue; // get escaped character
306
          }
307
          // put the command response on the basic buf temporarily
308
          if (xbee_basic_buf_add(&ptr,apitype) != 0)
309
            break;
310
        }
311
        i++;
312
      }
313
    }
314
    // handle AT command    
315
    WL_DEBUG_PRINT_P("|XBEE_FRAME_AT_COMMAND_RESPONSE");
316
    WL_DEBUG_PRINT_P("|i=");
317
    WL_DEBUG_PRINT_INT(i);
318
    WL_DEBUG_PRINT_P("|len=");
319
    WL_DEBUG_PRINT_INT(len);
320
    WL_DEBUG_PRINT_P("|status:");
321
    WL_DEBUG_PRINT_INT(status);
322
    WL_DEBUG_PRINT_P("|atcommand:");
323
    WL_DEBUG_PRINT_CHAR((uint8_t)(atcommand>>8));
324
    WL_DEBUG_PRINT_CHAR((uint8_t)(atcommand&0xFF));
325
    WL_DEBUG_PRINT_P("|first=");
326
    WL_DEBUG_PRINT_INT(basic_buf_first);
327
    WL_DEBUG_PRINT_P("|last=");
328
    WL_DEBUG_PRINT_INT(basic_buf_last);
329
    WL_DEBUG_PRINT_P("|buf=");
330
    uint8_t ptr2 = basic_buf_last;
331
    for(uint8_t j=0;j<(len-5);j++)
332
      WL_DEBUG_PRINT_HEX(xbee_basic_buf_get(&ptr2));
333
    WL_DEBUG_PRINT_P("|\r\n");
334
    xbee_handle_at_command_response(atcommand,status,len-5);
335
    break; }
336
  case XBEE_FRAME_STATUS: {
337
    // modem status
338
    while(1) {
339
      if (FLAG) {
340
        if (getStatus(XBEE_API_MASK) == XBEE_API_ESCAPE
341
            && apitype == ESCAPE_MARKER) {
342
          apitype = PORT ^ ESCAPE_XOR;
343
          break;
344
        } else {
345
          apitype = PORT;
346
          if (getStatus(XBEE_API_MASK) == XBEE_API_ESCAPE
347
              && apitype == ESCAPE_MARKER)
348
            continue; // get escaped character
349
          break;
350
        }
351
      }
352
    }
353
    xbee_handle_status(apitype); // handle the modem status
354
    break; }
355
  case XBEE_FRAME_TX_STATUS: {
356
    // TX status
357
    uint8_t frame_id = 0;
358
    while(i<3) {
359
      if (FLAG) {
360
        if (i==1) {
361
          if (getStatus(XBEE_API_MASK) == XBEE_API_ESCAPE
362
              && apitype == ESCAPE_MARKER)
363
            apitype = PORT ^ ESCAPE_XOR;
364
          else {
365
            apitype = PORT;
366
            if (getStatus(XBEE_API_MASK) == XBEE_API_ESCAPE
367
                && apitype == ESCAPE_MARKER)
368
              continue; // get escaped character
369
          }
370
          frame_id = apitype;
371
        } else {
372
          if (getStatus(XBEE_API_MASK) == XBEE_API_ESCAPE
373
              && apitype == ESCAPE_MARKER)
374
            apitype = PORT ^ ESCAPE_XOR;
375
          else {
376
            apitype = PORT;
377
            if (getStatus(XBEE_API_MASK) == XBEE_API_ESCAPE
378
                && apitype == ESCAPE_MARKER)
379
              continue; // get escaped character
380
          }
381
          ackhandle(frame_id,apitype); // handle the status
382
          break;
383
        }
384
        i++;
385
      }
386
    }
387
    WL_DEBUG_PRINT_P("|XBEE_FRAME_TX_STATUS");
388
    break; }
389
  case XBEE_FRAME_RX_64: {
390
    // receive a packet with 64bit address
391
    WL_DEBUG_PRINT_P("|XBEE_FRAME_RX_64");
392
    break; } // TODO: implement this (even if we don't use it)
393
  case XBEE_FRAME_RX_16: {
394
    // receive a packet with 16bit address
395
    uint16_t source = 0;
396
    uint8_t framenum = 0;
397
    uint8_t group = 0;
398
    uint8_t ptr=basic_buf_last;
399
    while(i<len) {
400
      if (FLAG) {
401
        if (i==1) {
402
          if (getStatus(XBEE_API_MASK) == XBEE_API_ESCAPE
403
              && apitype == ESCAPE_MARKER)
404
            apitype = PORT ^ ESCAPE_XOR; // get options, and ignore
405
          else {
406
            apitype = PORT;
407
            if (getStatus(XBEE_API_MASK) == XBEE_API_ESCAPE
408
                && apitype == ESCAPE_MARKER)
409
              continue; // get escaped character
410
          }
411
          source |= apitype<<8; // get source hi byte
412
        } else if (i==2) {
413
          if (getStatus(XBEE_API_MASK) == XBEE_API_ESCAPE
414
              && apitype == ESCAPE_MARKER)
415
            apitype = PORT ^ ESCAPE_XOR; // get options, and ignore
416
          else {
417
            apitype = PORT;
418
            if (getStatus(XBEE_API_MASK) == XBEE_API_ESCAPE
419
                && apitype == ESCAPE_MARKER)
420
              continue; // get escaped character
421
          }
422
          source |= apitype; // get source lo byte
423
        } else if (i==3) {
424
          if (getStatus(XBEE_API_MASK) == XBEE_API_ESCAPE
425
              && apitype == ESCAPE_MARKER)
426
            apitype = PORT ^ ESCAPE_XOR; // get RSSI, and ignore
427
          else {
428
            apitype = PORT;
429
            if (getStatus(XBEE_API_MASK) == XBEE_API_ESCAPE
430
                && apitype == ESCAPE_MARKER)
431
              continue; // get escaped character
432
          }
433
        } else if (i==4) {
434
          if (getStatus(XBEE_API_MASK) == XBEE_API_ESCAPE
435
              && apitype == ESCAPE_MARKER)
436
            apitype = PORT ^ ESCAPE_XOR; // get options, and ignore
437
          else {
438
            apitype = PORT;
439
            if (getStatus(XBEE_API_MASK) == XBEE_API_ESCAPE
440
                && apitype == ESCAPE_MARKER)
441
              continue; // get escaped character
442
          }
443
        } else if (i==5) {
444
          if (getStatus(XBEE_API_MASK) == XBEE_API_ESCAPE
445
              && apitype == ESCAPE_MARKER)
446
            apitype = PORT ^ ESCAPE_XOR;
447
          else {
448
            apitype = PORT;
449
            if (getStatus(XBEE_API_MASK) == XBEE_API_ESCAPE
450
                && apitype == ESCAPE_MARKER)
451
              continue; // get escaped character
452
          }
453
          framenum = apitype; // get the frame number
454
          if (check_last_receive(source,framenum) != WL_SUCCESS) {
455
            // we've already received this frame
456
            ptr = 0xFF; // signal to skip processing
457
            break;
458
          }
459
        }
460
        else if (i==6) {
461
          if (getStatus(XBEE_API_MASK) == XBEE_API_ESCAPE
462
              && apitype == ESCAPE_MARKER)
463
            apitype = PORT ^ ESCAPE_XOR;
464
          else {
465
            apitype = PORT;
466
            if (getStatus(XBEE_API_MASK) == XBEE_API_ESCAPE
467
                && apitype == ESCAPE_MARKER)
468
              continue; // get escaped character
469
          }
470
          group = apitype; // get group number
471
          
472
          if (group == 0) {
473
            ptr = basic_buf_last;
474
            if (xbee_basic_buf_add(&ptr,0x00) != 0)
475
              break;
476
            // add source to basic buffer
477
            if (xbee_basic_buf_add(&ptr,(uint8_t)((source&0xFF00)>>8)) != 0)
478
              break;
479
            if (xbee_basic_buf_add(&ptr,(uint8_t)(source&0x00FF)) != 0)
480
              break;
481
          } else {
482
            ptr = other_buf_last;
483
            // add source and group to other buffer
484
            if (xbee_other_buf_add(&ptr,group) != 0)
485
              break;
486
            if (xbee_other_buf_add(&ptr,(uint8_t)((source&0xFF00)>>8)) != 0)
487
              break;
488
            if (xbee_other_buf_add(&ptr,(uint8_t)(source&0x00FF)) != 0)
489
              break;
490
          }
491
        }
492
        else {
493
          // put packet data on the correct buffer
494
          if (getStatus(XBEE_API_MASK) == XBEE_API_ESCAPE
495
              && apitype == ESCAPE_MARKER)
496
            apitype = PORT ^ ESCAPE_XOR;
497
          else {
498
            apitype = PORT;
499
            if (getStatus(XBEE_API_MASK) == XBEE_API_ESCAPE
500
                && apitype == ESCAPE_MARKER)
501
              continue; // get escaped character
502
          }
503
          if (group == 0) {
504
            if (xbee_basic_buf_add(&ptr,apitype) != 0)
505
              break;
506
          } else {
507
            if (xbee_other_buf_add(&ptr,apitype) != 0)
508
              break;
509
          }
510
        }
511
        i++;
512
      }
513
    }
514
    if (ptr != 0xFF && i > 6) {
515
      if (group == 0) {
516
        xbee_basic_buf[basic_buf_last] = i-5; // set length
517
        basic_buf_last = ptr;
518
      }
519
      else {
520
        xbee_other_buf[other_buf_last] = i-5; // set length  ** TODO: check this number
521
        // check if we have a high priority group
522
        /*for(;;)
523
          if (HIGH_PRIORITY) {
524
            // handle receive now
525
            ptr = 0xFF;
526
            break;
527
          }*/        
528
        //if (ptr != 0xFF) {
529
          // handle receive later
530
          other_buf_last = ptr;
531
        //}
532
      }
533
    }
534
    WL_DEBUG_PRINT_P("|XBEE_FRAME_RX_16|len=");
535
    WL_DEBUG_PRINT_INT(len);
536
    WL_DEBUG_PRINT_P("|i=");
537
    WL_DEBUG_PRINT_INT(i);
538
    WL_DEBUG_PRINT_P("|source=");
539
    WL_DEBUG_PRINT_INT(source);
540
    WL_DEBUG_PRINT_P("|framenum=");
541
    WL_DEBUG_PRINT_INT(framenum);
542
    WL_DEBUG_PRINT_P("group=");
543
    WL_DEBUG_PRINT_INT(group);
544
    WL_DEBUG_PRINT_P("|ptr=");
545
    WL_DEBUG_PRINT_HEX(ptr);
546
    WL_DEBUG_PRINT_P("|first=");
547
    if (group == 0)
548
      WL_DEBUG_PRINT_INT(basic_buf_first);
549
    else
550
      WL_DEBUG_PRINT_INT(other_buf_first);
551
    WL_DEBUG_PRINT_P("|last=");
552
    if (group == 0)
553
      WL_DEBUG_PRINT_INT(basic_buf_last);
554
    else
555
      WL_DEBUG_PRINT_INT(other_buf_last);    
556
    WL_DEBUG_PRINT_P("|buffer=");
557
    for(uint8_t i=0;i<ptr;i++)
558
      WL_DEBUG_PRINT_HEX(xbee_basic_buf[i]);
559
    WL_DEBUG_PRINT_P("|\r\n");
560
    break; }
561
    default:
562
      WL_DEBUG_PRINT_P("|BAD APITYPE:");
563
      WL_DEBUG_PRINT_HEX(apitype);
564
      WL_DEBUG_PRINT_P("\r\n");
565
  } // end of switch statement
566
  while (1) {
567
    if (FLAG) {
568
      apitype = PORT; // get checksum, and ignore
569
      break;
570
    }
571
  }
572
  WL_DEBUG_PRINT_P("|interrupt - return\r\n");
573
} // end of interrupt 
574

    
575

    
576
/* adds a byte to the basic buffer */
577
int8_t xbee_basic_buf_add(uint8_t *ptr, uint8_t byte) {
578
  if (*ptr == basic_buf_first) {
579
    // buffer full
580
    WL_DEBUG_PRINT_P("basic buffer full\r\n");
581
    WL_DEBUG_PRINT_P("ptr=");
582
    WL_DEBUG_PRINT_INT(*ptr);
583
    WL_DEBUG_PRINT_P("|basic_buf_first=");
584
    WL_DEBUG_PRINT_INT(basic_buf_first);
585
    WL_DEBUG_PRINT_P("|basic_buf_last=");
586
    WL_DEBUG_PRINT_INT(basic_buf_last);
587
    WL_DEBUG_PRINT_P("\r\n");
588
    return -1;
589
  }
590
  xbee_basic_buf[(*ptr)++] = byte;
591
  if (*ptr == PACKET_BUFFER_SIZE)
592
    *ptr = 0;
593
  return 0;
594
}
595
/* gets a byte from the basic buffer */
596
uint8_t xbee_basic_buf_get(uint8_t *ptr) {
597
  uint8_t byte = xbee_basic_buf[(*ptr)++];
598
  if (*ptr == PACKET_BUFFER_SIZE)
599
    *ptr = 0;
600
  return byte;
601
}
602
/* adds a byte to the other buffer */
603
int8_t xbee_other_buf_add(uint8_t *ptr, uint8_t byte) {
604
  if (*ptr == other_buf_first) {
605
    // buffer full
606
    WL_DEBUG_PRINT_P("other buffer full\r\n");
607
    return -1;
608
  }
609
  xbee_other_buf[(*ptr)++] = byte;
610
  if (*ptr == PACKET_BUFFER_SIZE)
611
    *ptr = 0;
612
  return 0;
613
}
614
/* gets a byte from the other buffer */
615
uint8_t xbee_other_buf_get(uint8_t *ptr) {
616
  uint8_t byte = xbee_other_buf[(*ptr)++];
617
  if (*ptr == PACKET_BUFFER_SIZE)
618
    *ptr = 0;
619
  return byte;
620
}
621

    
622
/**
623
 * Checks if packet is a duplicate
624
 **/
625
int8_t check_last_receive(uint16_t source,uint8_t framenum) {
626
  uint8_t i=0;
627
  for(;i<NUM_LAST_PACKETS;i++) {
628
    if (lastPacket[i].source == source && lastPacket[i].framenum == framenum)
629
      return -1; // duplicate packet, so return error
630
  }
631
  // save packet source and framenum
632
  i=getStatus(LAST_PACKET_MASK);
633
  lastPacket[i].source = source;
634
  lastPacket[i].framenum = framenum;
635
  if (++i>=NUM_LAST_PACKETS)
636
    i = 0;
637
  //WL_DEBUG_PRINT_P("check last receive, status_before=");
638
  //WL_DEBUG_PRINT_HEX(xbee_status);
639
  setStatus(LAST_PACKET_MASK,i);
640
  //WL_DEBUG_PRINT_P("|after=");
641
  //WL_DEBUG_PRINT_HEX(xbee_status);
642
  //WL_DEBUG_PRINT_P("\r\n");
643
  return WL_SUCCESS;
644
}
645

    
646
/** status functions **/
647
inline uint8_t getStatus(uint8_t mask) { return xbee_status&mask; }
648
void setStatus(uint8_t mask,uint8_t value) { xbee_status = ((xbee_status&(~mask))|value); }
649

    
650

    
651
/**
652
 * Initializes the XBee library so that other functions may be used.
653
 **/
654
int8_t xbee_init() {
655
  WL_DEBUG_PRINT_P("in xbee_init\r\n");
656
  
657
  if(getStatus(XBEE_NOT_INITD) != XBEE_NOT_INITD) {
658
    return WL_ERROR_INIT_ALREADY_INITD;
659
  }
660
  
661
  // set status
662
  setStatus(XBEE_NOT_INITD,XBEE_COMMAND_NONE);
663
  
664
  // clear last packet buffer
665
  int i=0;
666
  for(;i<NUM_LAST_PACKETS;i++)
667
    lastPacket[i].source = lastPacket[i].framenum = 0;
668
    
669
  // clear basic and other buffers
670
  //uint8_t j=0;
671
  i=0;
672
  while(i<PACKET_BUFFER_SIZE) { xbee_basic_buf[i++] = 0xFF; } //_add(&j,0xFF); }
673
  i=0;
674
  while(i<PACKET_BUFFER_SIZE) { xbee_other_buf[i++] = 0xFF; } //_add(&j,0xFF); }
675
    
676
  // Set startup baud rate of 9600
677
  // Set frame format: 8data, 1stop bit, asynchronous normal mode
678
  // Enable receiver and transmitter and the receiving interrupt
679
#ifdef FIREFLY
680
  UBRR0H = 0x00;
681
  UBRR0L = 103;
682
  UCSR0A |= (1<<U2X0);
683
  UCSR0C |= (1<<UCSZ00) | (1<<UCSZ01);
684
  UCSR0B |= (1<<RXEN0) | (1<<TXEN0) | (1<<RXCIE); 
685
#else
686
  // Bayboard or robot  
687
  UBRR1H = 0x00; // baud rate
688
  UBRR1L = 103;  // baud rate
689
  UCSR1A |= (1<<U2X1); // double transmit speed 
690
  //Enable receiver and transmitter on USART1
691
  UCSR1B |= (1<<RXEN1)|(1<<TXEN1);
692
        
693
  // Set frame format: 8data, 1stop bit, asynchronous normal mode
694
  UCSR1C |= (1<<UCSZ10) | (1<<UCSZ11);
695
  
696
  UCSR1B |= (1<<RXCIE1);  // enable receive, transmit (1<<RXCIE)
697
#endif
698
  sei();
699
 
700
  // enter command mode
701
  WL_DEBUG_PRINT_P("entering command mode\r\n");
702
  xbee_send_string((uint8_t*)"+++");
703
  xbee_wait_for_ok();
704
  WL_DEBUG_PRINT_P("entered command mode\r\n");
705

    
706
  
707
  // set baud on xbee
708
#if (XBEE_BAUD == 115200)
709
  xbee_send_string((uint8_t*)"ATBD7\r");
710
#elif (XBEE_BAUD == 57600)
711
  xbee_send_string((uint8_t*)"ATBD6\r");
712
#elif (XBEE_BAUD == 38400)
713
  xbee_send_string((uint8_t*)"ATBD5\r");
714
#elif (XBEE_BAUD == 19200)
715
  xbee_send_string((uint8_t*)"ATBD4\r");
716
#elif (XBEE_BAUD == 9600)
717
  // already at this baud rate
718
  xbee_send_string((uint8_t*)"ATBD3\r\n");
719
#else
720
  WL_DEBUG_PRINT_P("undefined baud rate\r\n");
721
  return WL_ERROR_BAUD;
722
#endif  
723
  // exit command mode
724
  xbee_wait_for_ok();
725
  WL_DEBUG_PRINT_P("got ok from baud reset\r\n");
726
  xbee_send_string((uint8_t*)"ATCN\r");
727
  xbee_wait_for_ok();
728
  WL_DEBUG_PRINT_P("got ok from exiting command mode\r\n");
729
  
730
  // set UART baud
731
#ifdef FIREFLY
732
#if (XBEE_BAUD == 115200)
733
  UBRR0H = 0x00;
734
  UBRR0L = 8;
735
#elif (XBEE_BAUD == 57600)
736
  UBRR0H = 0x00;
737
  UBRR0L = 16;
738
#elif (XBEE_BAUD == 38400)
739
  UBRR0H = 0x00;
740
  UBRR0L = 25;
741
#elif (XBEE_BAUD == 19200)
742
  UBRR0H = 0x00;
743
  UBRR0L = 51;
744
#elif (XBEE_BAUD == 9600)
745
  /* this is the default baud rate, so do nothing
746
  UBRR0H = 0x00;
747
  UBRR0L = 103;*/
748
#else
749
  WL_DEBUG_PRINT_P("undefined baud rate\r\n");
750
  return WL_ERROR_BUAD;
751
#endif
752
#else // Bayboard or robot
753
#if (XBEE_BAUD == 115200)
754
  UBRR1H = 0x00;
755
  UBRR1L = 8;
756
#elif (XBEE_BAUD == 57600)
757
  UBRR1H = 0x00;
758
  UBRR1L = 16;
759
#elif (XBEE_BAUD == 38400)
760
  UBRR1H = 0x00;
761
  UBRR1L = 25;
762
#elif (XBEE_BAUD == 19200)
763
  UBRR1H = 0x00;
764
  UBRR1L = 51;
765
#elif (XBEE_BAUD == 9600)
766
  /* this is the default baud rate, so do nothing
767
  UBRR1H = 0x00;
768
  UBRR1L = 103;*/
769
#else
770
  WL_DEBUG_PRINT_P("undefined baud rate\r\n");
771
  return WL_ERROR_BUAD;
772
#endif
773
#endif
774
  // wait half second for the baud change to stabalize
775
  delay_ms(500);
776

    
777
  // enter command mode
778
  WL_DEBUG_PRINT_P("entering command mode 2\r\n");
779
  xbee_send_string((uint8_t*)"+++");
780
  xbee_wait_for_ok();
781
  WL_DEBUG_PRINT_P("entered command mode 2\r\n");
782
  
783
  if (xbee_enter_api_mode() != 0) {
784
    WL_DEBUG_PRINT_P("can't enter api mode\r\n");
785
    return -1;
786
  }
787
  
788
#ifdef WL_DEBUG
789
  if (getStatus(XBEE_API_MASK) == XBEE_API_OFF) {
790
    WL_DEBUG_PRINT_P("|API OFF|");
791
  } else if (getStatus(XBEE_API_MASK) == XBEE_API_ON) {
792
    WL_DEBUG_PRINT_P("|API ON|");
793
  } else {
794
    WL_DEBUG_PRINT_P("|API ERROR|");
795
  }
796
#endif
797
  
798
  // set MY address
799
  uint8_t newmy = get_robotid();
800
  uint8_t newmyarr[2] = {0x00,newmy};
801
  if (newmy == 0xFF) {
802
    WL_DEBUG_PRINT_P("can't get MY address from EEPROM\r\n");
803
  } else {
804
    WL_DEBUG_PRINT_P("MY address from eeprom:");
805
    WL_DEBUG_PRINT_HEX(newmyarr[0]);
806
    WL_DEBUG_PRINT_HEX(newmyarr[1]);
807
    WL_DEBUG_PRINT_P("\r\n");
808
    setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_WAIT); 
809
    if (xbee_send_modify_at_command((uint8_t*)"MY",newmyarr,2) != WL_SUCCESS) {
810
      WL_DEBUG_PRINT_P("setting MY address failed\r\n");
811
    }
812
    // wait for up to 30 ms
813
    newmy = 0;
814
    while(getStatus(XBEE_COMMAND_MASK) != XBEE_COMMAND_RESPONSE && newmy++ < 10000) {
815
      delay_us(1); // wait 3us
816
    }  
817
    if (newmy < 1000 && xbee_command[0] == 'M' && xbee_command[1] == 'Y') {
818
      WL_DEBUG_PRINT_P("setting MY address successful\r\n");
819
    } else
820
      WL_DEBUG_PRINT_P("setting MY address failed\r\n");
821
    setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_NONE); // reset status
822
  }
823
    
824
  // get MY address
825
  uint16_t address = xbee_get_address();
826
  if (address == WL_ERROR_XBEE_COMMAND_16BIT) {
827
    WL_DEBUG_PRINT_P("getting MY address failed\r\n");
828
  }
829
  WL_DEBUG_PRINT_P("MY address:");
830
  WL_DEBUG_PRINT_HEX((uint8_t)((address&0xFF00)>>8));
831
  WL_DEBUG_PRINT_HEX((uint8_t)(address&0x00FF));
832
  WL_DEBUG_PRINT_P("\r\n");
833
  
834
  // set PAN
835
  xbee_set_pan(0);
836
  
837
  return WL_SUCCESS;
838
}
839

    
840
/**
841
 * Call when finished using the XBee library.
842
 **/
843
int8_t xbee_terminate()
844
{
845
  int ret=xbee_exit_api_mode();
846
  if (ret != WL_SUCCESS) {
847
    WL_DEBUG_PRINT_P("xbee termination failed\r\n");
848
    WL_DEBUG_PRINT_INT(ret);
849
    WL_DEBUG_PRINT_P("|\r\n");
850
    return WL_ERROR_TERMINATION_FAILED;
851
  }
852
  delay_ms(1000);
853
  // reset baud to defaults
854
  xbee_enter_command_mode();
855
  xbee_send_string((uint8_t*)"ATBD 3\r");
856
  xbee_wait_for_ok();
857
  xbee_exit_command_mode();
858
  UBRR1H = 0x00;
859
  UBRR1L = 103;
860
  setStatus(XBEE_NOT_INITD,XBEE_NOT_INITD); // clean initd status
861
  return WL_SUCCESS;
862
}
863

    
864
/**
865
 * Sends a character to the XBee.
866
 *
867
 * @param c the byte to send
868
 * @return 0 for success, nonzero for failure
869
 **/
870
int8_t xbee_putc(uint8_t c) {
871

    
872
  // Wait until buffer is clear for sending
873
  // Then load buffer with your character
874
  
875
#ifdef FIREFLY
876
  loop_until_bit_is_set(UCSR0A, UDRE0);  
877
  UDR0 = c;
878
#else
879
  loop_until_bit_is_set(UCSR1A, UDRE1);
880
  UDR1 = c;
881
#endif
882
  
883
  return WL_SUCCESS;
884
}
885

    
886
/**
887
 * Returns the first byte in the buffer received from xbee.
888
 * This function blocks execution until a character has been
889
 * received. xbee_init must be called before this function
890
 * may be used.
891
 * 
892
 * @return the first character in the xbee buffer, -1 on error
893
 * 
894
 * @see xbee_init, xbee_getc_nb
895
 **/
896
int16_t xbee_getc(void) {
897
    
898
  // Wait for the receive buffer to be filled
899
  // Then read the receive buffer
900
#ifdef FIREFLY
901
  loop_until_bit_is_set(UCSR0A, RXC0);  
902
  return UDR0;
903
#else
904
  loop_until_bit_is_set(UCSR1A, RXC1);
905
  return UDR1;
906
#endif
907
}
908

    
909
/**
910
 * Non blocking version of xbee_getc. If a byte is present in the buffer,
911
 * it is returned, otherwise -1 is returned immediately. xbee_init
912
 * must be called before this function can be used.
913
 *
914
 * @param c The received byte. This will be set if a byte has been received.
915
 * 
916
 * @return -1 If no byte is available, 0 otherwise, positive for error
917
 *
918
 * @see xbee_getc
919
 **/
920
int8_t xbee_getc_nb(uint8_t *c) {
921

    
922
  // check if the receive buffer is filled
923
#ifdef FIREFLY
924
  if (UCSR0A & (1<<RXC0)) {
925
    (*c) = UDR0;
926
#else
927
  if (UCSR1A & (1<<RXC1)) {
928
    (*c) = UDR1;
929
#endif
930
    return WL_SUCCESS;
931
  }
932
  return -1; // Return empty
933
}
934

    
935
/**
936
 * Send byte to the xbee in API mode.
937
 *
938
 * @param byte the byte to be sent
939
 **/
940
int8_t xbee_sendc(uint8_t byte) {
941
  if (getStatus(XBEE_API_MASK) == XBEE_API_ESCAPE && 
942
      (byte == ESCAPE1 || byte == ESCAPE2 || byte == ESCAPE3 || byte == ESCAPE4))
943
    byte ^= ESCAPE_XOR;
944

    
945
#ifdef FIREFLY
946
  loop_until_bit_is_set(UCSR0A, UDRE0);  
947
  UDR0 = byte;
948
#else
949
  loop_until_bit_is_set(UCSR1A, UDRE1);
950
  UDR1 = byte;
951
#endif
952
  
953
  return WL_SUCCESS;
954
}
955

    
956

    
957
/**
958
 * Send a buffer buf of size bytes to the XBee in API mode
959
 *
960
 * @param buf the buffer of data to send
961
 * @param size the number of bytes to send
962
 **/
963
int8_t xbee_send(uint8_t* buf, uint16_t size)
964
{
965
  uint16_t i=0; // check if we need this variable
966
  while(i<size) {
967
    if (xbee_sendc(buf[i++]) != WL_SUCCESS)
968
      return WL_ERROR_SEND;
969
  }
970

    
971
  return WL_SUCCESS;
972
}
973

    
974
/**
975
 * Sends a string direct to the XBee.
976
 *
977
 * @param c the string to send to the XBEE
978
 **/
979
static int8_t xbee_send_string(uint8_t* c)
980
{
981
  uint16_t size = strlen((char*)c);
982
  uint16_t i=0; // check if we need this variable
983
  while(i<size) {
984
    if (xbee_putc(c[i++]) != WL_SUCCESS)
985
      return WL_ERROR_SEND;
986
  }
987

    
988
  return WL_SUCCESS;
989
}
990

    
991

    
992
/**
993
 * Enter into command mode.
994
 **/
995
static int8_t xbee_enter_command_mode(void)
996
{
997
  if (xbee_send_string((uint8_t*)"+++") != WL_SUCCESS) {
998
    return WL_ERROR_XBEE_COMMAND;
999
  }
1000
  WL_DEBUG_PRINT_P("sent command +++|");
1001

    
1002
  if (xbee_wait_for_ok() != WL_SUCCESS) {
1003
    return WL_ERROR_XBEE_COMMAND;
1004
  }
1005
  WL_DEBUG_PRINT_P("got OK\r\n");
1006
  
1007
  return WL_SUCCESS;
1008
}
1009

    
1010
/**
1011
 * Exit from command mode.
1012
 **/
1013
static int8_t xbee_exit_command_mode()
1014
{
1015
  if (xbee_send_string((uint8_t*)"ATCN\r") != 0) {
1016
    return WL_ERROR_SEND;
1017
  }
1018
  if (xbee_wait_for_ok() != WL_SUCCESS) {
1019
    WL_DEBUG_PRINT_P("failed to exit command mode\r\n");
1020
    return WL_ERROR_SEND;
1021
  }
1022

    
1023
  return WL_SUCCESS;
1024
}
1025

    
1026
/**
1027
 * Enter API mode.
1028
 **/
1029
static int8_t xbee_enter_api_mode(void) {
1030
  if (xbee_send_string((uint8_t*)"ATAP 1\r") != 0) {
1031
    return WL_ERROR_SEND;
1032
  }
1033
  if (xbee_wait_for_ok() != WL_SUCCESS) {
1034
    WL_DEBUG_PRINT_P("failed to enter API mode\r\n");
1035
    return WL_ERROR_SEND;
1036
  }
1037
  if (xbee_exit_command_mode() != WL_SUCCESS) {
1038
    WL_DEBUG_PRINT_P("failed to enter API mode\r\n");
1039
    return WL_ERROR_SEND;
1040
  }    
1041
  WL_DEBUG_PRINT_P("got OK after entering API mode\r\n");
1042
  
1043
  setStatus(XBEE_API_MASK,XBEE_API_ON); // set status
1044
  
1045
  return WL_SUCCESS;
1046
}
1047

    
1048
/**
1049
 * Enter API mode 2.
1050
 **/
1051
static int8_t xbee_enter_api_mode2(void) {
1052
  if (xbee_send_string((uint8_t*)"ATAP 2\r") != 0) {
1053
    return WL_ERROR_SEND;
1054
  }
1055
  if (xbee_wait_for_ok() != WL_SUCCESS) {
1056
    WL_DEBUG_PRINT_P("failed to enter API mode2\r\n");
1057
    return WL_ERROR_SEND;
1058
  }
1059
  if (xbee_exit_command_mode() != WL_SUCCESS) {
1060
    WL_DEBUG_PRINT_P("failed to enter API mode2\r\n");
1061
    return WL_ERROR_SEND;
1062
  }    
1063
  WL_DEBUG_PRINT_P("got OK after entering API mode2\r\n");
1064
  
1065
  setStatus(XBEE_API_MASK,XBEE_API_ESCAPE); // set status
1066
  
1067
  return WL_SUCCESS;
1068
}
1069

    
1070
/**
1071
 * Exit API mode.
1072
 **/
1073
static int8_t xbee_exit_api_mode()
1074
{
1075
  if (getStatus(XBEE_COMMAND_MASK) == XBEE_COMMAND_WAIT
1076
    || getStatus(XBEE_COMMAND_MASK) == XBEE_COMMAND_RESPONSE)
1077
    return WL_ERROR_XBEE_COMMAND; // can't do command right now
1078
  WL_DEBUG_PRINT_P("now exiting API mode\r\n");
1079
  
1080
  int16_t i=0;
1081
  // change status to command wait
1082
  setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_WAIT);
1083
  if (xbee_send_modify_at_command((uint8_t*)"AP",(uint8_t*)(&i),1) != WL_SUCCESS) { // send command
1084
    WL_DEBUG_PRINT_P("error sending AP 0 command\r\n");
1085
    setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_NONE); // reset status
1086
    return WL_ERROR_XBEE_COMMAND;
1087
  }
1088
  // wait for up to 30 ms
1089
  while(getStatus(XBEE_COMMAND_MASK) != XBEE_COMMAND_RESPONSE && i++ < 10000) {
1090
    delay_us(1); // wait 3us
1091
  }
1092
  if (i < 1000 && xbee_command[0] == 'A' && xbee_command[1] == 'P') {
1093
    WL_DEBUG_PRINT_P("done exiting API mode\r\n");
1094
    i = WL_SUCCESS;
1095
  } else {
1096
    WL_DEBUG_PRINT_P("failed to exit API mode\r\n");
1097
    i = WL_ERROR_XBEE_COMMAND; // set error code
1098
  }
1099
  setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_NONE); // reset status
1100
  setStatus(XBEE_API_MASK,XBEE_API_OFF);
1101
  
1102
  return (int8_t)i; // return
1103
}
1104

    
1105
/**
1106
 * Wait until the string "OK\r" is received from the XBee.
1107
 **/
1108
static int8_t xbee_wait_for_ok()
1109
{
1110
  //delay_ms(1000);
1111
  //return WL_SUCCESS;
1112
  return xbee_wait_for_string((uint8_t*)"OK", 2);
1113
}
1114

    
1115
/**
1116
 * Delay until the specified string is received from
1117
 * the XBee.
1118
 *
1119
 * Only works when not in API mode
1120
 *
1121
 * @param s the string to receive
1122
 * @param len the length of the string
1123
 **/
1124
static int8_t xbee_wait_for_string(uint8_t* s, uint16_t len)
1125
{
1126
  uint8_t i=0;  
1127
  setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_WAIT); // set status flag
1128
  if (getStatus(XBEE_API_MASK) == XBEE_API_OFF) {
1129
    // wait until the response is received (only wait 1 second)
1130
    while(getStatus(XBEE_COMMAND_MASK) != XBEE_COMMAND_RESPONSE && i++ < 1000) {
1131
      delay_us(1);
1132
    }
1133
    // check response
1134
    if (i >= 1000 || memcmp(s,xbee_basic_buf,len) != 0) {
1135
      // bad response
1136
      WL_DEBUG_PRINT_P("Bad response when waiting for string ");
1137
      WL_DEBUG_PRINT((char*)s);
1138
      WL_DEBUG_PRINT_P("\r\n");
1139
      return -1;
1140
    }
1141
    
1142
    setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_NONE); // clear status
1143
  }
1144
  
1145
  WL_DEBUG_PRINT_P("done waiting for string.\r\n");
1146

    
1147
  return 0;
1148
}
1149

    
1150
/**
1151
 * Delay until we receive a command response.
1152
 * Then copy the response to S and set the len
1153
 *
1154
 * Only works when not in API mode
1155
 *
1156
 * @param s the string to store the response in
1157
 * @param len the length of the string
1158
 */
1159
static int8_t xbee_wait_for_response(uint8_t* s, int16_t len) {
1160
  uint8_t i=0;
1161
  if (getStatus(XBEE_API_MASK) == XBEE_API_OFF) {
1162
    // wait until the response is received (only wait 1 second)
1163
    while(getStatus(XBEE_COMMAND_MASK) != XBEE_COMMAND_RESPONSE && i++ < 1000) {
1164
      delay_us(1);
1165
    }
1166
    // check response
1167
    if (i >= 1000) {
1168
      return -1;
1169
    } else {
1170
      i=strcspn((char*)xbee_basic_buf,"\r");
1171
      if (i<PACKET_BUFFER_SIZE) {
1172
        memcpy(s,xbee_basic_buf,i);
1173
        len = i;
1174
        setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_NONE); // clear response
1175
        return 0;
1176
      }
1177
      else
1178
        return -1;      
1179
    }
1180
  }
1181
  // TODO: do something for API mode
1182
  
1183
  return 0;
1184
}
1185

    
1186
/**  TODO: since we don't use this, do we need it?
1187
 *
1188
 * Verifies that the packets checksum is correct.
1189
 * (If the checksum is correct, the sum of the bytes
1190
 * is 0xFF.)
1191
 *
1192
 * @param packet the packet received. This includes the first
1193
 * three bytes, which are header information from the XBee.
1194
 *
1195
 * @param len The length of the packet received from the XBee
1196
 *
1197
 * @return 0 if the checksum is incorrect, nonzero
1198
 * otherwise
1199
 **/
1200
int8_t xbee_verify_checksum(uint8_t* packet, uint16_t len)
1201
{
1202
  uint8_t sum = 0;
1203
  while(--len > 0) {
1204
    sum += packet[len];
1205
  }
1206
  sum += packet[0];
1207
  return (sum == 0xFF);
1208
}
1209

    
1210
/**
1211
 * Returns the checksum of the given packet.
1212
 *
1213
 * @param buf the data for the packet to send
1214
 * @param len the length of the packet in bytes
1215
 *
1216
 * @return the checksum of the packet, which will
1217
 * become the last byte sent in the packet
1218
 **/
1219
uint8_t xbee_compute_checksum(uint8_t* buf, uint16_t len)
1220
{
1221
  uint8_t sum = 0;
1222
  while(--len > 0) {
1223
    sum += buf[len];
1224
  }
1225
  sum += buf[0];
1226
  return 0xFF - sum;
1227
}
1228

    
1229
/**
1230
 * Adds buf to the previous checksum total
1231
 *
1232
 * @param buf a byte buffer to add to the checksum
1233
 * @param len the length of the buffer
1234
 * @param sum the previous sum
1235
 *
1236
 * @return error code
1237
 **/
1238
int8_t xbee_checksum_add(uint8_t *buf, uint8_t len, uint8_t* sum) {
1239
  if (buf == NULL || sum == NULL)
1240
    return WL_ERROR_ARGUMENT;
1241
  while(--len > 0) {
1242
    *sum += buf[len];
1243
  }
1244
  *sum += buf[0];
1245
  return WL_SUCCESS;
1246
}
1247

    
1248

    
1249
/**
1250
 * Sends header information. Header information includes
1251
 * XBEE_FRAME_START and the packet length, as two bytes.
1252
 *
1253
 * @param type the packet type
1254
 * @param len the size in bytes of the packet data
1255
 *
1256
 **/
1257
int8_t xbee_send_header(uint16_t len)
1258
{  
1259
  //packet prefix
1260
  if (xbee_putc(XBEE_FRAME_START) != WL_SUCCESS)
1261
    return WL_ERROR_SEND;
1262
  if (xbee_sendc((uint8_t)((len&0xFF00)>>8)) != WL_SUCCESS)
1263
    return WL_ERROR_SEND;
1264
  if (xbee_sendc((uint8_t)(len&0x00FF)) != WL_SUCCESS)
1265
    return WL_ERROR_SEND;
1266

    
1267
  return WL_SUCCESS;
1268
}
1269

    
1270
/**
1271
 * Adds header information and checksum to the given
1272
 * packet and sends it. Header information includes
1273
 * XBEE_FRAME_START and the packet length, as two bytes.
1274
 *
1275
 * @param buf the packet data
1276
 * @param len the size in bytes of the packet data
1277
 *
1278
 **/
1279
static int8_t xbee_send_frame(uint8_t* buf, uint16_t len)
1280
{
1281
  uint8_t checksum = xbee_compute_checksum(buf, len);
1282
  
1283
  // send header
1284
  if (xbee_send_header(len) != WL_SUCCESS)
1285
    return WL_ERROR_SEND;
1286

    
1287
  // send body
1288
  if (xbee_send(buf, len) != WL_SUCCESS)
1289
    return WL_ERROR_SEND;
1290
  
1291
  // send checksum
1292
  if (xbee_sendc(checksum) != WL_SUCCESS)
1293
    return WL_ERROR_SEND;
1294
  
1295
  return WL_SUCCESS;
1296
}
1297

    
1298
/**
1299
 * Sends an AT command to read a parameter.
1300
 *
1301
 * @param command the AT command to send. For exmaple,
1302
 * use ID to read the PAN ID and MY to return the XBee ID.
1303
 * See the XBee reference guide for a complete listing.
1304
 **/
1305
int8_t xbee_send_read_at_command(uint8_t* command)
1306
{
1307
  return xbee_send_modify_at_command(command, NULL, 0);
1308
}
1309

    
1310
/**
1311
 * Sends the given AT command.
1312
 *
1313
 * @param command the AT command to send (e.g., MY, ID)
1314
 * @param value the value to pass as a parameter
1315
 * (or NULL if there is no parameter)
1316
 **/
1317
static int8_t xbee_send_modify_at_command(uint8_t* command, uint8_t* value, uint8_t len)
1318
{
1319
  uint8_t buf[12];
1320

    
1321
  buf[0] = XBEE_FRAME_AT_COMMAND;
1322
  buf[1] = 1;
1323
  buf[2] = command[0];
1324
  buf[3] = command[1];
1325
  if (value != NULL)
1326
  {
1327
    if (len > 8)
1328
    {
1329
      WL_DEBUG_PRINT_P("AT Command too large.\r\n");
1330
      return WL_ERROR_ARGUMENT;
1331
    }
1332
    memcpy(buf+4,value,len);
1333
  }
1334

    
1335
  return xbee_send_frame(buf, 4 + len);
1336
}
1337

    
1338
/**
1339
 * Send the specified packet.
1340
 *
1341
 * @param packet the packet data to send
1342
 * @param len the number of bytes in the packet
1343
 *
1344
 * @param dest the ID of the XBee to send the packet to,
1345
 * or XBEE_BROADCAST to send the message to all robots
1346
 * in the PAN.
1347
 *
1348
 * @param options a combination of the flags
1349
 * XBEE_OPTIONS_NONE, XBEE_OPTIONS_DISABLE_RESPONSE and
1350
 * XBEE_OPTIONS_BROADCAST_ALL_PANS
1351
 *
1352
 * @param frame the frame number to associate this packet
1353
 * with. This will be used to identify the response when
1354
 * the XBee alerts us as to whether or not our message
1355
 * was received.
1356
 **/
1357
int8_t xbee_send_packet(uint8_t* packet, uint8_t len, uint16_t dest, uint8_t options, uint8_t frame)
1358
{
1359
  uint8_t sum = XBEE_FRAME_TX_REQUEST_16;
1360
  uint8_t i = 0;
1361

    
1362
  if (len > 100)
1363
  {
1364
    WL_DEBUG_PRINT_P("Packet is too large.\r\n");
1365
    return WL_ERROR_ARGUMENT;
1366
  }
1367
  
1368
  // calculate checksum
1369
  for(;i<len;i++)
1370
    sum += packet[len];
1371
  sum += frame;
1372
  sum += (dest&0xFF00) >> 8;
1373
  sum += dest&0x00FF;
1374
  sum += options;
1375
  sum = 0xFF - sum;
1376

    
1377
  //packet prefix
1378
  if (xbee_putc(XBEE_FRAME_START) != WL_SUCCESS)
1379
    return WL_ERROR_SEND;
1380
  if (xbee_sendc(0x00) != WL_SUCCESS)
1381
    return WL_ERROR_SEND;
1382
  if (xbee_sendc(len+5) != WL_SUCCESS)
1383
    return WL_ERROR_SEND;
1384
    
1385
  //send header for TX request
1386
  if (xbee_sendc(XBEE_FRAME_TX_REQUEST_16) != WL_SUCCESS)
1387
    return WL_ERROR_SEND;
1388
  if (xbee_sendc(frame) != WL_SUCCESS)
1389
    return WL_ERROR_SEND;
1390
  if (xbee_sendc((uint8_t)((dest&0xFF00) >> 8)) != WL_SUCCESS)
1391
    return WL_ERROR_SEND;
1392
  if (xbee_sendc((uint8_t)(dest&0x00FF)) != WL_SUCCESS)
1393
    return WL_ERROR_SEND;
1394
  if (xbee_sendc(options) != WL_SUCCESS)
1395
    return WL_ERROR_SEND;
1396

    
1397
  // send packet
1398
  if (xbee_send(packet, len) != WL_SUCCESS)
1399
    return WL_ERROR_SEND;
1400

    
1401
  // send checksum
1402
  if (xbee_sendc(sum) != WL_SUCCESS)
1403
    return WL_ERROR_SEND;
1404

    
1405
  return WL_SUCCESS;
1406
}
1407

    
1408
/**
1409
 * Handles modem status packets.
1410
 *
1411
 * @param status the type of status packet received.
1412
 **/
1413
void xbee_handle_status(uint8_t status)
1414
{
1415
  switch (status)
1416
  {
1417
    case 0:
1418
      WL_DEBUG_PRINT_P("XBee hardware reset.\r\n");
1419
      break;
1420
    case 1:
1421
      WL_DEBUG_PRINT_P("Watchdog timer reset.\r\n");
1422
      break;
1423
    case 2:
1424
      WL_DEBUG_PRINT_P("Associated.\r\n");
1425
      break;
1426
    case 3:
1427
      WL_DEBUG_PRINT_P("Disassociated.\r\n");
1428
      break;
1429
    case 4:
1430
      WL_DEBUG_PRINT_P("Synchronization lost.\r\n");
1431
      break;
1432
    case 5:
1433
      WL_DEBUG_PRINT_P("Coordinator realignment.\r\n");
1434
      break;
1435
    case 6:
1436
      WL_DEBUG_PRINT_P("Coordinator started.\r\n");
1437
      break;
1438
  }
1439
}
1440

    
1441
/**
1442
 * Handles AT command response packets.
1443
 * @param command the two character AT command, e.g. MY or ID
1444
 * @param result 0 for success, 1 for an error
1445
 * @param len the length in bytes of extra
1446
 **/
1447
static int8_t xbee_handle_at_command_response(uint16_t command, uint8_t status, uint8_t len)
1448
{
1449
  WL_DEBUG_PRINT_P("HANDLE AT COMMAND\r\n");
1450
  if (status != 0)
1451
  {
1452
    WL_DEBUG_PRINT_P("Error with AT");
1453
    WL_DEBUG_PRINT((char*)command);
1454
    WL_DEBUG_PRINT_P(" packet. Result = ");
1455
    switch(status) {
1456
    case 1:
1457
      WL_DEBUG_PRINT_P("ERROR\r\n");
1458
      break;
1459
    case 2:
1460
      WL_DEBUG_PRINT_P("Invalid Command\r\n");
1461
      break;
1462
    case 3:
1463
      WL_DEBUG_PRINT_P("Invalid Parameter\r\n");
1464
      break;
1465
    }
1466
    return WL_SUCCESS;
1467
  }
1468
  WL_DEBUG_PRINT_P("AT");
1469
  WL_DEBUG_PRINT_CHAR((uint8_t)(command>>8));
1470
  WL_DEBUG_PRINT_CHAR((uint8_t)(command));
1471
  WL_DEBUG_PRINT_P(" command is being handled\r\n");
1472
  
1473
  // TODO: program more command responses here (ND, etc)
1474
  switch(command) {
1475
  case ('I'<<8)+'D': // PAN
1476
  case ('C'<<8)+'H': // channel
1477
  case ('M'<<8)+'Y': // address
1478
  case ('A'<<8)+'P': // api mode
1479
    // copy command to handler
1480
    xbee_command[0] = (command&0xFF00)>>8;
1481
    xbee_command[1] = command&0x00FF;
1482
    uint8_t ptr = basic_buf_last;
1483
    for(command=2;command<len+2;command++) {
1484
      xbee_command[command] = xbee_basic_buf_get(&ptr);
1485
      if (xbee_command[command] == '\r')
1486
        break; // done with command
1487
      WL_DEBUG_PRINT_HEX(xbee_command[command]);
1488
    }
1489
    xbee_command[command] = '\0';
1490
    WL_DEBUG_PRINT_P("len=");
1491
    WL_DEBUG_PRINT_INT(len);
1492
    WL_DEBUG_PRINT_P("ID,CH,or MY command result:");
1493
    WL_DEBUG_PRINT((char*)xbee_command);
1494
    WL_DEBUG_PRINT_P("\r\n");
1495
    break;
1496
  default:
1497
    WL_DEBUG_PRINT_P("unknown AT command");
1498
  }
1499
  
1500
  // signal handler that command response is done
1501
  setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_RESPONSE);
1502

    
1503
  return WL_SUCCESS;
1504
}
1505

    
1506
/**
1507
 * Sets the personal area network id.
1508
 *
1509
 * @param id the new personal area network (PAN) id
1510
 **/
1511
int8_t xbee_set_pan(uint16_t id)
1512
{
1513
  if (getStatus(XBEE_COMMAND_MASK) == XBEE_COMMAND_WAIT
1514
    || getStatus(XBEE_COMMAND_MASK) == XBEE_COMMAND_RESPONSE)
1515
    return WL_ERROR_XBEE_COMMAND; // can't do command right now
1516
  
1517
  
1518
  uint8_t arr[2] = {(id&0xFF00)>>8,(id&0x00FF)};
1519
  WL_DEBUG_PRINT_P("setting PAN address:");
1520
  WL_DEBUG_PRINT_HEX(arr[0]);
1521
  WL_DEBUG_PRINT_HEX(arr[1]);
1522
  WL_DEBUG_PRINT_P("\r\n");
1523
  
1524
  // change status to command wait
1525
  setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_WAIT);
1526
  xbee_send_modify_at_command((uint8_t*)"ID",arr,2); // send command to set the channel
1527
  // wait for up to 30 ms
1528
  uint16_t i=0;
1529
  while(getStatus(XBEE_COMMAND_MASK) != XBEE_COMMAND_RESPONSE && i++ < 10000) {
1530
    delay_us(1); // wait 3us
1531
  }
1532
  if (i < 1000 && xbee_command[0] == 'I' && xbee_command[1] == 'D')
1533
    i = WL_SUCCESS;
1534
  else
1535
    i = WL_ERROR_XBEE_COMMAND; // set error code
1536
  setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_NONE); // reset status
1537
  return (int8_t)i; // return
1538
}
1539

    
1540
/**
1541
 * Get the PAN ID for the XBee.
1542
 *
1543
 * @return the personal area network id, or
1544
 * XBEE_PAN_DEFAULT if it has not yet been set.
1545
 **/
1546
uint16_t xbee_get_pan()
1547
{
1548
  if (getStatus(XBEE_COMMAND_MASK) == XBEE_COMMAND_WAIT
1549
    || getStatus(XBEE_COMMAND_MASK) == XBEE_COMMAND_RESPONSE)
1550
    return WL_ERROR_XBEE_COMMAND_16BIT; // can't do command right now
1551
  
1552
  uint16_t i=0;
1553
  // change status to command wait
1554
  setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_WAIT);
1555
  xbee_send_read_at_command((uint8_t*)"ID"); // send command to get the PAN
1556
  // wait for up to 30 ms
1557
  while(getStatus(XBEE_COMMAND_MASK) != XBEE_COMMAND_RESPONSE && i++ < 10000) {
1558
    delay_us(1); // wait 3us
1559
  }
1560
  if (i < 1000 && xbee_command[0] == 'I' && xbee_command[1] == 'D')
1561
    i = (xbee_command[2]<<8)|xbee_command[3]; // do ntoh16 coversion
1562
  else
1563
    i = WL_ERROR_XBEE_COMMAND_16BIT; // set error code
1564
  setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_NONE); // reset status
1565
  WL_DEBUG_PRINT_P("got PAN address:");
1566
  WL_DEBUG_PRINT_HEX((i&0xFF00)>>8);
1567
  WL_DEBUG_PRINT_HEX((i&0x00FF));
1568
  WL_DEBUG_PRINT_P("\r\n");
1569
  return i; // return
1570
}
1571

    
1572
/**
1573
 * Set the channel the XBee is using.
1574
 *
1575
 * @param channel the channel the XBee will not use,
1576
 * between 0x0B and 0x1A
1577
 *
1578
 * @see xbee_get_channel
1579
 **/
1580
int8_t xbee_set_channel(uint8_t channel)
1581
{
1582
  if (channel < 0x0B || channel > 0x1A)
1583
  {
1584
    WL_DEBUG_PRINT_P("Channel out of range.\r\n");
1585
    return WL_ERROR_ARGUMENT;
1586
  }
1587

    
1588
  if (getStatus(XBEE_COMMAND_MASK) == XBEE_COMMAND_WAIT
1589
    || getStatus(XBEE_COMMAND_MASK) == XBEE_COMMAND_RESPONSE)
1590
    return WL_ERROR_XBEE_COMMAND; // can't do command right now
1591
  
1592
  WL_DEBUG_PRINT_P("setting channel:");
1593
  WL_DEBUG_PRINT_HEX(channel);
1594
  WL_DEBUG_PRINT_P("\r\n");
1595
  int16_t i=0;
1596
  // change status to command wait
1597
  setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_WAIT);
1598
  xbee_send_modify_at_command((uint8_t*)"CH",&channel,1); // send command to set the channel
1599
  // wait for up to 30 ms
1600
  while(getStatus(XBEE_COMMAND_MASK) != XBEE_COMMAND_RESPONSE && i++ < 10000) {
1601
    delay_us(1); // wait 3us
1602
  }
1603
  if (i < 1000 && xbee_command[0] == 'C' && xbee_command[1] == 'H')
1604
    i = WL_SUCCESS;
1605
  else
1606
    i = WL_ERROR_XBEE_COMMAND; // set error code
1607
  setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_NONE); // reset status
1608
  return (int8_t)i; // return
1609
}
1610

    
1611
/**
1612
 * Returns the channel which the XBee is currently using.
1613
 *
1614
 * @return the channel the XBee is using
1615
 *
1616
 * @see xbee_set_channel
1617
 **/
1618
int8_t xbee_get_channel(void)
1619
{
1620
  if (getStatus(XBEE_COMMAND_MASK) == XBEE_COMMAND_WAIT
1621
    || getStatus(XBEE_COMMAND_MASK) == XBEE_COMMAND_RESPONSE)
1622
    return WL_ERROR_XBEE_COMMAND; // can't do command right now
1623
  
1624
  int16_t i=0;
1625
  // change status to command wait
1626
  setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_WAIT);
1627
  xbee_send_read_at_command((uint8_t*)"CH"); // send command to get the channel
1628
  // wait for up to 30 ms
1629
  while(getStatus(XBEE_COMMAND_MASK) != XBEE_COMMAND_RESPONSE && i++ < 10000) {
1630
    delay_us(1); // wait 3us
1631
  }
1632
  if (i < 1000 && xbee_command[0] == 'C' && xbee_command[1] == 'H')
1633
    i = (int8_t)xbee_command[2]; // get channel
1634
  else
1635
    i = WL_ERROR_XBEE_COMMAND; // set error code
1636
  setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_NONE); // reset status
1637
  WL_DEBUG_PRINT_P("got channel:");
1638
  WL_DEBUG_PRINT_HEX((uint8_t)i);
1639
  WL_DEBUG_PRINT_P("\r\n");
1640
  return i; // return
1641
}
1642

    
1643
/**
1644
 * Get the 16-bit address of the XBee.
1645
 * This is used to specify who to send messages to
1646
 * and who messages are from.
1647
 *
1648
 * @return the 16-bit address of the XBee.
1649
 **/
1650
uint16_t xbee_get_address(void)
1651
{
1652
  if (getStatus(XBEE_COMMAND_MASK) == XBEE_COMMAND_WAIT
1653
    || getStatus(XBEE_COMMAND_MASK) == XBEE_COMMAND_RESPONSE)
1654
    return WL_ERROR_XBEE_COMMAND_16BIT; // can't do command right now
1655
  
1656
  uint16_t i=0;
1657
  // change status to command wait 
1658
  setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_WAIT);
1659
  xbee_send_read_at_command((uint8_t*)"MY"); // send command to get the address
1660
  // wait for up to 30 ms
1661
  while(getStatus(XBEE_COMMAND_MASK) != XBEE_COMMAND_RESPONSE && i++ < 10000) {
1662
    delay_us(1); // wait 3us
1663
  }
1664
  
1665
  if (i < 1000 && xbee_command[0] == 'M' && xbee_command[1] == 'Y') {
1666
    i = (xbee_command[2]<<8)|xbee_command[3]; // do ntoh16 coversion
1667
  } else
1668
    i = WL_ERROR_XBEE_COMMAND_16BIT; // set error code
1669
  setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_NONE); // reset status
1670
  WL_DEBUG_PRINT_P("got MY address:");
1671
  WL_DEBUG_PRINT_HEX((i&0xFF00)>>8);
1672
  WL_DEBUG_PRINT_HEX((i&0x00FF));
1673
  WL_DEBUG_PRINT_P("\r\n");
1674
  return i; // return
1675
}
1676

    
1677
/**@} **/ // end xbee group
1678