Project

General

Profile

Statistics
| Revision:

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

History | View | Annotate | Download (47.8 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
    
648
  setStatus(LAST_PACKET_MASK,i);
649
  WL_DEBUG_PRINT_P("check last receive: LP.src=");
650
  WL_DEBUG_PRINT_INT(lastPacket[i].source);
651
  WL_DEBUG_PRINT_P("|GET.src=");
652
  WL_DEBUG_PRINT_INT(source);
653
  WL_DEBUG_PRINT_P("|LP.framenum=");
654
  WL_DEBUG_PRINT_INT(lastPacket[i].framenum);
655
  WL_DEBUG_PRINT_P("|GET.framenum=");
656
  WL_DEBUG_PRINT_INT(framenum);
657
  WL_DEBUG_PRINT_P("\r\n");
658
  return WL_SUCCESS;
659
}
660

    
661
/** status functions **/
662
inline uint8_t getStatus(uint8_t mask) { return xbee_status&mask; }
663
void setStatus(uint8_t mask,uint8_t value) { xbee_status = ((xbee_status&(~mask))|value); }
664

    
665

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

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

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

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

    
879
/**
880
 * Sends a character to the XBee.
881
 *
882
 * @param c the byte to send
883
 * @return 0 for success, nonzero for failure
884
 **/
885
int8_t xbee_putc(uint8_t c) {
886

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

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

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

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

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

    
960
#ifdef FIREFLY
961
  loop_until_bit_is_set(UCSR0A, UDRE0);  
962
  UDR0 = byte;
963
#else
964
  loop_until_bit_is_set(UCSR1A, UDRE1);
965
  UDR1 = byte;
966
#endif
967
  
968
  return WL_SUCCESS;
969
}
970

    
971

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

    
986
  return WL_SUCCESS;
987
}
988

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

    
1003
  return WL_SUCCESS;
1004
}
1005

    
1006

    
1007
/**
1008
 * Enter into command mode.
1009
 **/
1010
static int8_t xbee_enter_command_mode(void)
1011
{
1012
  if (xbee_send_string((uint8_t*)"+++") != WL_SUCCESS) {
1013
    return WL_ERROR_XBEE_COMMAND;
1014
  }
1015
  WL_DEBUG_PRINT_P("sent command +++|");
1016

    
1017
  if (xbee_wait_for_ok() != WL_SUCCESS) {
1018
    return WL_ERROR_XBEE_COMMAND;
1019
  }
1020
  WL_DEBUG_PRINT_P("got OK\r\n");
1021
  
1022
  return WL_SUCCESS;
1023
}
1024

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

    
1038
  return WL_SUCCESS;
1039
}
1040

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

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

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

    
1120
/**
1121
 * Wait until the string "OK\r" is received from the XBee.
1122
 **/
1123
static int8_t xbee_wait_for_ok()
1124
{
1125
  //delay_ms(1000);
1126
  //return WL_SUCCESS;
1127
  return xbee_wait_for_string((uint8_t*)"OK", 2);
1128
}
1129

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

    
1162
  return 0;
1163
}
1164

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

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

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

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

    
1263

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

    
1282
  return WL_SUCCESS;
1283
}
1284

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

    
1302
  // send body
1303
  if (xbee_send(buf, len) != WL_SUCCESS)
1304
    return WL_ERROR_SEND;
1305
  
1306
  // send checksum
1307
  if (xbee_sendc(checksum) != WL_SUCCESS)
1308
    return WL_ERROR_SEND;
1309
  
1310
  return WL_SUCCESS;
1311
}
1312

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

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

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

    
1350
  return xbee_send_frame(buf, 4 + len);
1351
}
1352

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

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

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

    
1412
  // send packet
1413
  if (xbee_send(packet, len) != WL_SUCCESS)
1414
    return WL_ERROR_SEND;
1415

    
1416
  // send checksum
1417
  if (xbee_sendc(sum) != WL_SUCCESS)
1418
    return WL_ERROR_SEND;
1419

    
1420
  return WL_SUCCESS;
1421
}
1422

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

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

    
1518
  return WL_SUCCESS;
1519
}
1520

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

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

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

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

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

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

    
1692
/**@} **/ // end xbee group
1693