Project

General

Profile

Statistics
| Revision:

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

History | View | Annotate | Download (47.6 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
      WL_DEBUG_PRINT_P("Duplicate Packet: LP.src=");
630
      WL_DEBUG_PRINT_INT(lastPacket[i].source);
631
      WL_DEBUG_PRINT_P("|GET.src=");
632
      WL_DEBUG_PRINT_INT(source);
633
      WL_DEBUG_PRINT_P("|LP.framenum=");
634
      WL_DEBUG_PRINT_INT(lastPacket[i].framenum);
635
      WL_DEBUG_PRINT_P("|GET.framenum=");
636
      WL_DEBUG_PRINT_INT(framenum);
637
      WL_DEBUG_PRINT_P("\r\n");      
638
      return -1; // duplicate packet, so return error
639
    }
640
  }
641
  // save packet source and framenum
642
  i=getStatus(LAST_PACKET_MASK);
643
  lastPacket[i].source = source;
644
  lastPacket[i].framenum = framenum;
645
  if (++i>=NUM_LAST_PACKETS)
646
    i = 0;
647
  //WL_DEBUG_PRINT_P("check last receive, status_before=");
648
  //WL_DEBUG_PRINT_HEX(xbee_status);
649
  setStatus(LAST_PACKET_MASK,i);
650
  //WL_DEBUG_PRINT_P("|after=");
651
  //WL_DEBUG_PRINT_HEX(xbee_status);
652
  //WL_DEBUG_PRINT_P("\r\n");
653
  return WL_SUCCESS;
654
}
655

    
656
/** status functions **/
657
inline uint8_t getStatus(uint8_t mask) { return xbee_status&mask; }
658
void setStatus(uint8_t mask,uint8_t value) { xbee_status = ((xbee_status&(~mask))|value); }
659

    
660

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

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

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

    
850
/**
851
 * Call when finished using the XBee library.
852
 **/
853
int8_t xbee_terminate()
854
{
855
  int ret=xbee_exit_api_mode();
856
  if (ret != WL_SUCCESS) {
857
    WL_DEBUG_PRINT_P("xbee termination failed\r\n");
858
    WL_DEBUG_PRINT_INT(ret);
859
    WL_DEBUG_PRINT_P("|\r\n");
860
    return WL_ERROR_TERMINATION_FAILED;
861
  }
862
  delay_ms(1000);
863
  // reset baud to defaults
864
  xbee_enter_command_mode();
865
  xbee_send_string((uint8_t*)"ATBD 3\r");
866
  xbee_wait_for_ok();
867
  xbee_exit_command_mode();
868
  UBRR1H = 0x00;
869
  UBRR1L = 103;
870
  setStatus(XBEE_NOT_INITD,XBEE_NOT_INITD); // clean initd status
871
  return WL_SUCCESS;
872
}
873

    
874
/**
875
 * Sends a character to the XBee.
876
 *
877
 * @param c the byte to send
878
 * @return 0 for success, nonzero for failure
879
 **/
880
int8_t xbee_putc(uint8_t c) {
881

    
882
  // Wait until buffer is clear for sending
883
  // Then load buffer with your character
884
  
885
#ifdef FIREFLY
886
  loop_until_bit_is_set(UCSR0A, UDRE0);  
887
  UDR0 = c;
888
#else
889
  loop_until_bit_is_set(UCSR1A, UDRE1);
890
  UDR1 = c;
891
#endif
892
  
893
  return WL_SUCCESS;
894
}
895

    
896
/**
897
 * Returns the first byte in the buffer received from xbee.
898
 * This function blocks execution until a character has been
899
 * received. xbee_init must be called before this function
900
 * may be used.
901
 * 
902
 * @return the first character in the xbee buffer, -1 on error
903
 * 
904
 * @see xbee_init, xbee_getc_nb
905
 **/
906
int16_t xbee_getc(void) {
907
    
908
  // Wait for the receive buffer to be filled
909
  // Then read the receive buffer
910
#ifdef FIREFLY
911
  loop_until_bit_is_set(UCSR0A, RXC0);  
912
  return UDR0;
913
#else
914
  loop_until_bit_is_set(UCSR1A, RXC1);
915
  return UDR1;
916
#endif
917
}
918

    
919
/**
920
 * Non blocking version of xbee_getc. If a byte is present in the buffer,
921
 * it is returned, otherwise -1 is returned immediately. xbee_init
922
 * must be called before this function can be used.
923
 *
924
 * @param c The received byte. This will be set if a byte has been received.
925
 * 
926
 * @return -1 If no byte is available, 0 otherwise, positive for error
927
 *
928
 * @see xbee_getc
929
 **/
930
int8_t xbee_getc_nb(uint8_t *c) {
931

    
932
  // check if the receive buffer is filled
933
#ifdef FIREFLY
934
  if (UCSR0A & (1<<RXC0)) {
935
    (*c) = UDR0;
936
#else
937
  if (UCSR1A & (1<<RXC1)) {
938
    (*c) = UDR1;
939
#endif
940
    return WL_SUCCESS;
941
  }
942
  return -1; // Return empty
943
}
944

    
945
/**
946
 * Send byte to the xbee in API mode.
947
 *
948
 * @param byte the byte to be sent
949
 **/
950
int8_t xbee_sendc(uint8_t byte) {
951
  if (getStatus(XBEE_API_MASK) == XBEE_API_ESCAPE && 
952
      (byte == ESCAPE1 || byte == ESCAPE2 || byte == ESCAPE3 || byte == ESCAPE4))
953
    byte ^= ESCAPE_XOR;
954

    
955
#ifdef FIREFLY
956
  loop_until_bit_is_set(UCSR0A, UDRE0);  
957
  UDR0 = byte;
958
#else
959
  loop_until_bit_is_set(UCSR1A, UDRE1);
960
  UDR1 = byte;
961
#endif
962
  
963
  return WL_SUCCESS;
964
}
965

    
966

    
967
/**
968
 * Send a buffer buf of size bytes to the XBee in API mode
969
 *
970
 * @param buf the buffer of data to send
971
 * @param size the number of bytes to send
972
 **/
973
int8_t xbee_send(uint8_t* buf, uint16_t size)
974
{
975
  uint16_t i=0; // check if we need this variable
976
  while(i<size) {
977
    if (xbee_sendc(buf[i++]) != WL_SUCCESS)
978
      return WL_ERROR_SEND;
979
  }
980

    
981
  return WL_SUCCESS;
982
}
983

    
984
/**
985
 * Sends a string direct to the XBee.
986
 *
987
 * @param c the string to send to the XBEE
988
 **/
989
static int8_t xbee_send_string(uint8_t* c)
990
{
991
  uint16_t size = strlen((char*)c);
992
  uint16_t i=0; // check if we need this variable
993
  while(i<size) {
994
    if (xbee_putc(c[i++]) != WL_SUCCESS)
995
      return WL_ERROR_SEND;
996
  }
997

    
998
  return WL_SUCCESS;
999
}
1000

    
1001

    
1002
/**
1003
 * Enter into command mode.
1004
 **/
1005
static int8_t xbee_enter_command_mode(void)
1006
{
1007
  if (xbee_send_string((uint8_t*)"+++") != WL_SUCCESS) {
1008
    return WL_ERROR_XBEE_COMMAND;
1009
  }
1010
  WL_DEBUG_PRINT_P("sent command +++|");
1011

    
1012
  if (xbee_wait_for_ok() != WL_SUCCESS) {
1013
    return WL_ERROR_XBEE_COMMAND;
1014
  }
1015
  WL_DEBUG_PRINT_P("got OK\r\n");
1016
  
1017
  return WL_SUCCESS;
1018
}
1019

    
1020
/**
1021
 * Exit from command mode.
1022
 **/
1023
static int8_t xbee_exit_command_mode()
1024
{
1025
  if (xbee_send_string((uint8_t*)"ATCN\r") != 0) {
1026
    return WL_ERROR_SEND;
1027
  }
1028
  if (xbee_wait_for_ok() != WL_SUCCESS) {
1029
    WL_DEBUG_PRINT_P("failed to exit command mode\r\n");
1030
    return WL_ERROR_SEND;
1031
  }
1032

    
1033
  return WL_SUCCESS;
1034
}
1035

    
1036
/**
1037
 * Enter API mode.
1038
 **/
1039
static int8_t xbee_enter_api_mode(void) {
1040
  if (xbee_send_string((uint8_t*)"ATAP 1\r") != 0) {
1041
    return WL_ERROR_SEND;
1042
  }
1043
  if (xbee_wait_for_ok() != WL_SUCCESS) {
1044
    WL_DEBUG_PRINT_P("failed to enter API mode\r\n");
1045
    return WL_ERROR_SEND;
1046
  }
1047
  if (xbee_exit_command_mode() != WL_SUCCESS) {
1048
    WL_DEBUG_PRINT_P("failed to enter API mode\r\n");
1049
    return WL_ERROR_SEND;
1050
  }    
1051
  WL_DEBUG_PRINT_P("got OK after entering API mode\r\n");
1052
  
1053
  setStatus(XBEE_API_MASK,XBEE_API_ON); // set status
1054
  
1055
  return WL_SUCCESS;
1056
}
1057

    
1058
/**
1059
 * Enter API mode 2.
1060
 **/
1061
static int8_t xbee_enter_api_mode2(void) {
1062
  if (xbee_send_string((uint8_t*)"ATAP 2\r") != 0) {
1063
    return WL_ERROR_SEND;
1064
  }
1065
  if (xbee_wait_for_ok() != WL_SUCCESS) {
1066
    WL_DEBUG_PRINT_P("failed to enter API mode2\r\n");
1067
    return WL_ERROR_SEND;
1068
  }
1069
  if (xbee_exit_command_mode() != WL_SUCCESS) {
1070
    WL_DEBUG_PRINT_P("failed to enter API mode2\r\n");
1071
    return WL_ERROR_SEND;
1072
  }    
1073
  WL_DEBUG_PRINT_P("got OK after entering API mode2\r\n");
1074
  
1075
  setStatus(XBEE_API_MASK,XBEE_API_ESCAPE); // set status
1076
  
1077
  return WL_SUCCESS;
1078
}
1079

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

    
1115
/**
1116
 * Wait until the string "OK\r" is received from the XBee.
1117
 **/
1118
static int8_t xbee_wait_for_ok()
1119
{
1120
  //delay_ms(1000);
1121
  //return WL_SUCCESS;
1122
  return xbee_wait_for_string((uint8_t*)"OK", 2);
1123
}
1124

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

    
1157
  return 0;
1158
}
1159

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

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

    
1220
/**
1221
 * Returns the checksum of the given packet.
1222
 *
1223
 * @param buf the data for the packet to send
1224
 * @param len the length of the packet in bytes
1225
 *
1226
 * @return the checksum of the packet, which will
1227
 * become the last byte sent in the packet
1228
 **/
1229
uint8_t xbee_compute_checksum(uint8_t* buf, uint16_t len)
1230
{
1231
  uint8_t sum = 0;
1232
  while(--len > 0) {
1233
    sum += buf[len];
1234
  }
1235
  sum += buf[0];
1236
  return 0xFF - sum;
1237
}
1238

    
1239
/**
1240
 * Adds buf to the previous checksum total
1241
 *
1242
 * @param buf a byte buffer to add to the checksum
1243
 * @param len the length of the buffer
1244
 * @param sum the previous sum
1245
 *
1246
 * @return error code
1247
 **/
1248
int8_t xbee_checksum_add(uint8_t *buf, uint8_t len, uint8_t* sum) {
1249
  if (buf == NULL || sum == NULL)
1250
    return WL_ERROR_ARGUMENT;
1251
  while(--len > 0) {
1252
    *sum += buf[len];
1253
  }
1254
  *sum += buf[0];
1255
  return WL_SUCCESS;
1256
}
1257

    
1258

    
1259
/**
1260
 * Sends header information. Header information includes
1261
 * XBEE_FRAME_START and the packet length, as two bytes.
1262
 *
1263
 * @param type the packet type
1264
 * @param len the size in bytes of the packet data
1265
 *
1266
 **/
1267
int8_t xbee_send_header(uint16_t len)
1268
{  
1269
  //packet prefix
1270
  if (xbee_putc(XBEE_FRAME_START) != WL_SUCCESS)
1271
    return WL_ERROR_SEND;
1272
  if (xbee_sendc((uint8_t)((len&0xFF00)>>8)) != WL_SUCCESS)
1273
    return WL_ERROR_SEND;
1274
  if (xbee_sendc((uint8_t)(len&0x00FF)) != WL_SUCCESS)
1275
    return WL_ERROR_SEND;
1276

    
1277
  return WL_SUCCESS;
1278
}
1279

    
1280
/**
1281
 * Adds header information and checksum to the given
1282
 * packet and sends it. Header information includes
1283
 * XBEE_FRAME_START and the packet length, as two bytes.
1284
 *
1285
 * @param buf the packet data
1286
 * @param len the size in bytes of the packet data
1287
 *
1288
 **/
1289
static int8_t xbee_send_frame(uint8_t* buf, uint16_t len)
1290
{
1291
  uint8_t checksum = xbee_compute_checksum(buf, len);
1292
  
1293
  // send header
1294
  if (xbee_send_header(len) != WL_SUCCESS)
1295
    return WL_ERROR_SEND;
1296

    
1297
  // send body
1298
  if (xbee_send(buf, len) != WL_SUCCESS)
1299
    return WL_ERROR_SEND;
1300
  
1301
  // send checksum
1302
  if (xbee_sendc(checksum) != WL_SUCCESS)
1303
    return WL_ERROR_SEND;
1304
  
1305
  return WL_SUCCESS;
1306
}
1307

    
1308
/**
1309
 * Sends an AT command to read a parameter.
1310
 *
1311
 * @param command the AT command to send. For exmaple,
1312
 * use ID to read the PAN ID and MY to return the XBee ID.
1313
 * See the XBee reference guide for a complete listing.
1314
 **/
1315
int8_t xbee_send_read_at_command(uint8_t* command)
1316
{
1317
  return xbee_send_modify_at_command(command, NULL, 0);
1318
}
1319

    
1320
/**
1321
 * Sends the given AT command.
1322
 *
1323
 * @param command the AT command to send (e.g., MY, ID)
1324
 * @param value the value to pass as a parameter
1325
 * (or NULL if there is no parameter)
1326
 **/
1327
static int8_t xbee_send_modify_at_command(uint8_t* command, uint8_t* value, uint8_t len)
1328
{
1329
  uint8_t buf[12];
1330

    
1331
  buf[0] = XBEE_FRAME_AT_COMMAND;
1332
  buf[1] = 1;
1333
  buf[2] = command[0];
1334
  buf[3] = command[1];
1335
  if (value != NULL)
1336
  {
1337
    if (len > 8)
1338
    {
1339
      WL_DEBUG_PRINT_P("AT Command too large.\r\n");
1340
      return WL_ERROR_ARGUMENT;
1341
    }
1342
    memcpy(buf+4,value,len);
1343
  }
1344

    
1345
  return xbee_send_frame(buf, 4 + len);
1346
}
1347

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

    
1372
  if (len > 100)
1373
  {
1374
    WL_DEBUG_PRINT_P("Packet is too large.\r\n");
1375
    return WL_ERROR_ARGUMENT;
1376
  }
1377
  
1378
  // calculate checksum
1379
  for(;i<len;i++)
1380
    sum += packet[len];
1381
  sum += frame;
1382
  sum += (dest&0xFF00) >> 8;
1383
  sum += dest&0x00FF;
1384
  sum += options;
1385
  sum = 0xFF - sum;
1386

    
1387
  //packet prefix
1388
  if (xbee_putc(XBEE_FRAME_START) != WL_SUCCESS)
1389
    return WL_ERROR_SEND;
1390
  if (xbee_sendc(0x00) != WL_SUCCESS)
1391
    return WL_ERROR_SEND;
1392
  if (xbee_sendc(len+5) != WL_SUCCESS)
1393
    return WL_ERROR_SEND;
1394
    
1395
  //send header for TX request
1396
  if (xbee_sendc(XBEE_FRAME_TX_REQUEST_16) != WL_SUCCESS)
1397
    return WL_ERROR_SEND;
1398
  if (xbee_sendc(frame) != WL_SUCCESS)
1399
    return WL_ERROR_SEND;
1400
  if (xbee_sendc((uint8_t)((dest&0xFF00) >> 8)) != WL_SUCCESS)
1401
    return WL_ERROR_SEND;
1402
  if (xbee_sendc((uint8_t)(dest&0x00FF)) != WL_SUCCESS)
1403
    return WL_ERROR_SEND;
1404
  if (xbee_sendc(options) != WL_SUCCESS)
1405
    return WL_ERROR_SEND;
1406

    
1407
  // send packet
1408
  if (xbee_send(packet, len) != WL_SUCCESS)
1409
    return WL_ERROR_SEND;
1410

    
1411
  // send checksum
1412
  if (xbee_sendc(sum) != WL_SUCCESS)
1413
    return WL_ERROR_SEND;
1414

    
1415
  return WL_SUCCESS;
1416
}
1417

    
1418
/**
1419
 * Handles modem status packets.
1420
 *
1421
 * @param status the type of status packet received.
1422
 **/
1423
void xbee_handle_status(uint8_t status)
1424
{
1425
  switch (status)
1426
  {
1427
    case 0:
1428
      WL_DEBUG_PRINT_P("XBee hardware reset.\r\n");
1429
      break;
1430
    case 1:
1431
      WL_DEBUG_PRINT_P("Watchdog timer reset.\r\n");
1432
      break;
1433
    case 2:
1434
      WL_DEBUG_PRINT_P("Associated.\r\n");
1435
      break;
1436
    case 3:
1437
      WL_DEBUG_PRINT_P("Disassociated.\r\n");
1438
      break;
1439
    case 4:
1440
      WL_DEBUG_PRINT_P("Synchronization lost.\r\n");
1441
      break;
1442
    case 5:
1443
      WL_DEBUG_PRINT_P("Coordinator realignment.\r\n");
1444
      break;
1445
    case 6:
1446
      WL_DEBUG_PRINT_P("Coordinator started.\r\n");
1447
      break;
1448
  }
1449
}
1450

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

    
1513
  return WL_SUCCESS;
1514
}
1515

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

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

    
1582
/**
1583
 * Set the channel the XBee is using.
1584
 *
1585
 * @param channel the channel the XBee will not use,
1586
 * between 0x0B and 0x1A
1587
 *
1588
 * @see xbee_get_channel
1589
 **/
1590
int8_t xbee_set_channel(uint8_t channel)
1591
{
1592
  if (channel < 0x0B || channel > 0x1A)
1593
  {
1594
    WL_DEBUG_PRINT_P("Channel out of range.\r\n");
1595
    return WL_ERROR_ARGUMENT;
1596
  }
1597

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

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

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

    
1687
/**@} **/ // end xbee group
1688