Project

General

Profile

Statistics
| Revision:

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

History | View | Annotate | Download (26.1 KB)

1
/**
2
 * Copyright (c) 2009 Colony Project
3
 *
4
 * Permission is hereby granted, free of charge, to any person
5
 * obtaining a copy of this software and associated documentation
6
 * files (the "Software"), to deal in the Software without
7
 * restriction, including without limitation the rights to use,
8
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
9
 * copies of the Software, and to permit persons to whom the
10
 * Software is furnished to do so, subject to the following
11
 * conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be
14
 * included in all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23
 * OTHER DEALINGS IN THE SOFTWARE.
24
 **/
25

    
26
/**
27
 * @file xbee.c
28
 * @brief XBee Interface
29
 *
30
 * Implementation of low level communication with the XBee in API mode.
31
 *
32
 * @author Colony Project, CMU Robotics Club
33
 **/
34

    
35
#include <string.h>
36
#include <avr/interrupt.h>
37
#include <time.h>
38
#include <serial.h> // TODO: integrate serial xbee functions into this file
39
#include "wl_defs.h"
40
#include "xbee.h"
41

    
42

    
43
/* Internal Function Prototypes */
44

    
45
// TODO: convert all int references to int16_t syntax (see stdint.h)
46

    
47
/* I/O Functions */
48
static int8_t xbee_send(uint8_t* buf, uint16_t size);
49
static int8_t xbee_send_string(unsigned char* c);
50

    
51
/* Command Mode Functions */
52
static int xbee_enter_command_mode(void);
53
static int xbee_exit_command_mode(void);
54
static int xbee_enter_api_mode(void);
55
static int xbee_exit_api_mode(void);
56
static int xbee_wait_for_string(char* s, int len);
57
static int xbee_wait_for_ok(void);
58

    
59
/* API Mode Functions */
60
static int xbee_handle_packet(uint8_t* packet, uint16_t len);
61
static int xbee_handle_at_command_response(uint16_t command, uint8_t result, uint8_t len);
62
static int xbee_handle_at_command_response(uint16_t command, uint8_t result, uint8_t len);
63
static void xbee_handle_status(char status);
64
static int xbee_verify_checksum(char* packet, int len);
65
static char xbee_compute_checksum(char* packet, int len);
66
static int xbee_send_frame(char* buf, int len);
67
int xbee_send_read_at_command(char* command);
68
static int xbee_send_modify_at_command(char* command, char* value);
69

    
70
/* Buffer Manipulation Functions */
71
int8_t xbee_basic_buf_add(uint8_t *ptr, uint8_t byte);
72
uint8_t xbee_basic_buf_get(uint8_t *ptr);
73
int8_t xbee_other_buf_add(uint8_t *ptr, uint8_t byte);
74

    
75

    
76
/*Global Variables*/
77

    
78
// array for basic packets
79
static uint8_t xbee_basic_buf[PACKET_BUFFER_SIZE];
80

    
81
// beginning of first packet in basic buffer
82
static uint8_t basic_buf_first = 0;
83

    
84
// byte after end of last packet in basic buffer (only access < basic_buf_last)
85
// aka, the first free byte in basic buffer
86
static uint8_t basic_buf_last = 0;
87

    
88
// array for other packets
89
static uint8_t xbee_other_buf[PACKET_BUFFER_SIZE];
90

    
91
// beginning of first packet in other buffer
92
static uint8_t other_buf_first = 0;
93

    
94
// byte after end of last packet in other buffer (only access < other_buf_last)
95
// aka, the first free byte in other buffer
96
static uint8_t other_buf_last = 0;
97

    
98

    
99
// xbee status
100
#define XBEE_API_OFF 0x0
101
#define XBEE_API_ON 0x1
102
#define XBEE_API_ESCAPE 0x2
103
#define XBEE_NORMAL 0x00
104
#define XBEE_COMMAND_WAIT 0x80
105
#define XBEE_COMMAND_RESPONSE 0xC0
106
static uint8_t xbee_status = XBEE_API_OFF|XBEE_NORMAL;
107

    
108
// xbee command response (for PAN, channel, address, etc)
109
static uint8_t xbee_command[4];
110

    
111
// external ack handler (wireless_send.c)
112
extern void ackhandle(uint8_t num,uint8_t val);
113

    
114

    
115
/**@addtogroup xbee
116
 * @{ **/
117

    
118
/*Function Implementations*/
119

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

    
305

    
306

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

    
339

    
340
/**
341
 * Initializes the XBee library so that other functions may be used.
342
 **/
343
int8_t xbee_lib_init()
344
{
345
  // do serial.c xbee init     TODO: merge this into xbee.c
346
  if (xbee_init() != 0) {
347
    usb_puts("xbee_init error");
348
    return WL_ERROR_INIT_FAILED;
349
  }
350

    
351
        WL_DEBUG_PRINT("in xbee_init\n");
352

    
353
        //enable the receiving interrupt
354
#ifdef FIREFLY
355
        UCSR0B |= _BV(RXCIE) | _BV(RXEN);
356
#else
357
#ifdef BAYBOARD
358
        UCSR1B |= _BV(RXCIE1);
359
#else
360
        UCSR1B |= _BV(RXCIE);
361
#endif
362
#endif
363
        sei();
364

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

    
372
  // reset baud rate
373
  WL_DEBUG_PRINT("Resetting Baud to ");
374
  WL_DEBUG_PRINT(XBEE_BAUD_STR);
375
  WL_DEBUG_PRINT("\r\n");
376
  
377
  // set baud on xbee
378
#if (XBEE_BAUD == 115200)
379
  xbee_send_string("ATBD7\r");
380
#elif (XBEE_BAUD == 57600)
381
  xbee_send_string("ATBD6\r");
382
#elif (XBEE_BAUD == 38400)
383
  xbee_send_string("ATBD5\r");
384
#elif (XBEE_BAUD == 19200)
385
  xbee_send_string("ATBD4\r");
386
#elif (XBEE_BAUD == 9600)
387
  // already at this baud rate
388
  //xbee_send_string("ATBD3\r\n");
389
#else
390
  WL_DEBUG_PRINT("undefined baud rate\r\n");
391
  return WL_ERROR_BAUD;
392
#endif  
393
  // exit command mode
394
  xbee_wait_for_ok();
395
  WL_DEBUG_PRINT("got ok from baud reset\r\n");
396
  xbee_send_string("ATCN\r");
397
  xbee_wait_for_ok();
398
  WL_DEBUG_PRINT("got ok from exiting command mode\r\n");
399
  
400
  // set UART baud
401
#if (XBEE_BAUD == 115200)
402
  UBRR1H = 0x00;
403
  UBRR1L = 8;
404
  UCSR1A |= _BV(U2X1);
405
#elif (XBEE_BAUD == 57600)
406
  UBRR1H = 0x00;
407
  UBRR1L = 16;
408
  UCSR1A |= _BV(U2X1);
409
#elif (XBEE_BAUD == 38400)
410
  UBRR1H = 0x00;
411
  UBRR1L = 25;
412
  UCSR1A |= _BV(U2X1);
413
#elif (XBEE_BAUD == 19200)
414
  UBRR1H = 0x00;
415
  UBRR1L = 51;
416
  UCSR1A |= _BV(U2X1);
417
#elif (XBEE_BAUD == 9600)
418
  /* this is the default baud rate, so do nothing
419
  UBRR1H = 0x00;
420
  UBRR1L = 103;
421
  UCSR1A |= _BV(U2X1);*/
422
#else
423
  WL_DEBUG_PRINT("undefined baud rate\r\n");
424
  return WL_ERROR_BUAD;
425
#endif
426
  delay_ms(50);
427

    
428
  // enter command mode
429
  WL_DEBUG_PRINT("entering command mode 2\r\n");
430
  xbee_send_string("+++");
431
  xbee_wait_for_ok();
432
  WL_DEBUG_PRINT("entered command mode 2\r\n");
433
  
434
  if (xbee_enter_api_mode() != 0) {
435
    WL_DEBUG_PRINT("can't enter api mode\r\n");
436
                return -1;
437
        }
438

    
439
        WL_DEBUG_PRINT("Entered api mode.\r\n");
440

    
441
        if (xbee_exit_command_mode() != 0) {
442
    WL_DEBUG_PRINT("can't exit command mode\r\n");
443
          return -1;
444
        }
445
        
446
        WL_DEBUG_PRINT("Left command mode.\r\n");
447
  
448
  // TODO: we should set the MY address to the robot address from eeprom
449
  
450
        return WL_SUCCESS;
451
}
452

    
453
/**
454
 * Call when finished using the XBee library.
455
 **/
456
void xbee_terminate()
457
{
458
  xbee_exit_api_mode();
459
}
460

    
461
/**
462
 * Send a buffer buf of size bytes to the XBee.
463
 *
464
 * @param buf the buffer of data to send
465
 * @param size the number of bytes to send
466
 **/
467
static int8_t xbee_send(uint8_t* buf, uint16_t size)
468
{
469
        while(--size > 0)
470
                if (xbee_putc(buf[i]) != WL_SUCCESS)
471
      return WL_ERROR_SEND;
472
        }  
473
  if (xbee_putc(buf[0]) != WL_SUCCESS)
474
    return WL_ERROR_SEND;
475

    
476
        return WL_SUCCESS;
477
}
478

    
479
/**
480
 * Sends a string to the XBee.
481
 *
482
 * @param c the string to send to the XBEE
483
 **/
484
static int8_t xbee_send_string(unsigned char* c)
485
{
486
        return xbee_send(c, strlen(c));
487
}
488

    
489

    
490
/**
491
 * Enter into command mode.
492
 **/
493
static int8_t xbee_enter_command_mode()
494
{
495
        if (xbee_send_string("+++") != WL_SUCCESS) {
496
                return WL_ERROR_XBEE_COMMAND;
497
        }
498

    
499
        if (xbee_wait_for_ok() != WL_SUCCESS) {
500
          return WL_ERROR_XBEE_COMMAND;
501
        }
502
  
503
        return WL_SUCCESS;
504
}
505

    
506
/**
507
 * Exit from command mode.
508
 **/
509
static int8_t xbee_exit_command_mode()
510
{
511
        if (xbee_send_string("ATCN\r") != 0) {
512
                return -1;
513
        }
514

    
515
        xbee_wait_for_ok();
516

    
517
        return 0;
518
}
519

    
520
/**
521
 * Enter API mode.
522
 **/
523
static int xbee_enter_api_mode()
524
{
525
        if (xbee_send_string("ATAP 1\r") != 0) {
526
                return -1;
527
        }
528
        xbee_wait_for_ok();
529
  
530
  xbee_status = (xbee_status&0xFC)|XBEE_API_ON;
531

    
532
        return 0;
533
}
534

    
535
/**
536
 * Enter API mode 2.
537
 **/
538
static int xbee_enter_api_mode2()
539
{
540
        if (xbee_send_string("ATAP 2\r") != 0) {
541
                return -1;
542
        }
543
        xbee_wait_for_ok();
544
  
545
  xbee_status = (xbee_status&0xFC)|XBEE_API_ESCAPE;
546
  
547
        return 0;
548
}
549

    
550
/**
551
 * Exit API mode.
552
 **/
553
static int xbee_exit_api_mode()
554
{
555
        if (xbee_send_modify_at_command("AP","0") != 0) {
556
                return -1;
557
        }
558
  
559
  xbee_status = (xbee_status&0xFC)|XBEE_API_OFF;
560

    
561
        return 0;
562
}
563

    
564
/**
565
 * Wait until the string "OK\r" is received from the XBee.
566
 **/
567
static int xbee_wait_for_ok()
568
{
569
        return xbee_wait_for_string("OK\r", 3);
570
}
571

    
572
/**
573
 * Delay until the specified string is received from
574
 * the XBee. Discards all other XBee data.
575
 *
576
 * ********* Robot often hangs here ****************
577
 *
578
 * @param s the string to receive
579
 * @param len the length of the string
580
 **/
581
static int8_t xbee_wait_for_string(char* s, int len)
582
{
583
  uint8_t i=0;
584
  if (xbee_status&0x03 == XBEE_API_OFF) {
585
    // wait until the response is received (only wait 1 second)
586
    while(xbee_status&0xC0 != XBEE_COMMAND_RESPONSE && i++ < 1000) {
587
      delay_us(1);
588
    }
589
    // check response
590
    if (i >= 1000 || memcmp(s,xbee_basic_buf,len) != 0) {
591
      // bad response
592
      WL_DEBUG_PRINT("Bad response when waiting for string ");
593
      WL_DEBUG_PRINT(s);
594
      WL_DEBUG_PRINT("\r\n");
595
      return -1;
596
    }
597
    
598
    // clear response
599
    xbee_status = xbee_status&0x3F;
600
  }
601

    
602
        return 0;
603
}
604

    
605
/**
606
 * Delay until we receive a command response.
607
 * (either OK\r or some actual value)
608
 *
609
 * Only works when not in API mode
610
 *
611
 * @param s the string to store the response in
612
 * @param len the length of the string
613
 */
614
static int8_t xbee_wait_for_response(char* s, int len) {
615
  uint8_t i=0;
616
  if (xbee_status&0x03 == XBEE_API_OFF) {
617
    // wait until the response is received (only wait 1 second)
618
    while(xbee_status&0xC0 != XBEE_COMMAND_RESPONSE && i++ < 1000) {
619
      delay_us(1);
620
    }
621
    // check response
622
    if (i >= 1000)
623
      return -1;
624
    } else {
625
      i=strcspn(xbee_basic_buf,"\r");
626
      if (i<PACKET_BUFFER_SIZE) {
627
        memcpy(s,xbee_basic_buf,i);
628
        xbee_status = xbee_status&0x3F; // clear response
629
        return 0;
630
      }
631
      else
632
        return -1;      
633
    }
634
  }
635
  // TODO: do something for API mode
636
  
637
  return 0;
638
}
639

    
640
/**  TODO: since we don't use this, do we need it?
641
 *
642
 * Verifies that the packets checksum is correct.
643
 * (If the checksum is correct, the sum of the bytes
644
 * is 0xFF.)
645
 *
646
 * @param packet the packet received. This includes the first
647
 * three bytes, which are header information from the XBee.
648
 *
649
 * @param len The length of the packet received from the XBee
650
 *
651
 * @return 0 if the checksum is incorrect, nonzero
652
 * otherwise
653
 **/
654
uint8_t xbee_verify_checksum(uint8_t* packet, uint16_t len)
655
{
656
        uint8_t sum = 0;
657
        while(--len > 0) {
658
                sum += packet[len];
659
  }
660
  sum += packet[0];
661
        return (sum == 0xFF);
662
}
663

    
664
/**
665
 * Returns the checksum of the given packet.
666
 *
667
 * @param buf the data for the packet to send
668
 * @param len the length of the packet in bytes
669
 *
670
 * @return the checksum of the packet, which will
671
 * become the last byte sent in the packet
672
 **/
673
char xbee_compute_checksum(uint8_t* buf, uint16_t len)
674
{
675
        uint8_t sum = 0;
676
        while(--len > 0) {
677
                sum += buf[len];
678
  }
679
  sum += buf[0];
680
        return 0xFF - sum;
681
}
682

    
683
/**
684
 * Adds header information and checksum to the given
685
 * packet and sends it. Header information includes
686
 * XBEE_FRAME_START and the packet length, as two bytes.
687
 *
688
 * @param buf the packet data
689
 * @param len the size in bytes of the packet data
690
 *
691
 **/
692
static int8_t xbee_send_frame(uint8_t* buf, uint16_t len)
693
{
694
        uint8_t prefix[3];
695
        prefix[0] = XBEE_FRAME_START;
696
        prefix[1] = (len & 0xFF00) >> 8;
697
        prefix[2] = len & 0x00FF;
698
        uint8_t checksum = xbee_compute_checksum(buf, len);
699

    
700
        if (xbee_send(prefix, 3) != 0) {
701
                return WL_ERROR_SEND;
702
        }
703

    
704
        if (xbee_send(buf, len) != 0) {
705
                return WL_ERROR_SEND;
706
        }
707

    
708
        if (xbee_send(&checksum, 1) != 0) {
709
                return WL_ERROR_SEND;
710
        }
711

    
712
        return WL_SUCCESS;
713
}
714

    
715
/**
716
 * Sends an AT command to read a parameter.
717
 *
718
 * @param command the AT command to send. For exmaple,
719
 * use ID to read the PAN ID and MY to return the XBee ID.
720
 * See the XBee reference guide for a complete listing.
721
 **/
722
int8_t xbee_send_read_at_command(uint8_t* command)
723
{
724
        return xbee_send_modify_at_command(command, NULL, 0);
725
}
726

    
727
/**
728
 * Sends the given AT command.
729
 *
730
 * @param command the AT command to send (e.g., MY, ID)
731
 * @param value the value to pass as a parameter
732
 * (or NULL if there is no parameter)
733
 **/
734
static int8_t xbee_send_modify_at_command(uint8_t* command, uint8_t* value, uint8_t len)
735
{
736
        uint8_t buf[12];
737

    
738
        buf[0] = XBEE_FRAME_AT_COMMAND;
739
        buf[1] = 1;
740
        buf[2] = command[0];
741
        buf[3] = command[1];
742
        if (value != NULL)
743
        {
744
                if (len > 8)
745
                {
746
                        WL_DEBUG_PRINT("AT Command too large.\r\n");
747
                        return WL_ERROR_ARGUMENT;
748
                }
749
    memcpy(buf+4,value,len);
750
        }
751

    
752
        return xbee_send_frame(buf, 4 + len);
753
}
754

    
755
/**
756
 * Send the specified packet.
757
 *
758
 * @param packet the packet data to send
759
 * @param len the number of bytes in the packet
760
 *
761
 * @param dest the ID of the XBee to send the packet to,
762
 * or XBEE_BROADCAST to send the message to all robots
763
 * in the PAN.
764
 *
765
 * @param options a combination of the flags
766
 * XBEE_OPTIONS_NONE, XBEE_OPTIONS_DISABLE_RESPONSE and
767
 * XBEE_OPTIONS_BROADCAST_ALL_PANS
768
 *
769
 * @param frame the frame number to associate this packet
770
 * with. This will be used to identify the response when
771
 * the XBee alerts us as to whether or not our message
772
 * was received.
773
 **/
774
int xbee_send_packet(char* packet, int len, int dest, char options, char frame)
775
{
776
        char buf[5];
777
        char prefix[3];
778
        int i;
779
        unsigned char checksum = 0;
780

    
781
        if (len > 100)
782
        {
783
                WL_DEBUG_PRINT("Packet is too large.\r\n");
784
                return -1;
785
        }
786

    
787
        //data for sending request
788
        buf[0] = XBEE_FRAME_TX_REQUEST_16;
789
        buf[1] = frame;
790
        buf[2] = (dest >> 8) & 0xFF;
791
        buf[3] = dest & 0xFF;
792
        buf[4] = options;
793

    
794
        //packet prefix, do this here so we don't need an extra buffer
795
        prefix[0] = XBEE_FRAME_START;
796
        prefix[1] = ((5 + len) & 0xFF00) >> 8;
797
        prefix[2] = (5 + len) & 0xFF;
798

    
799
        for (i = 0; i < 5; i++)
800
                checksum += (unsigned char)buf[i];
801
        for (i = 0; i < len; i++)
802
                checksum += (unsigned char)packet[i];
803
        checksum = 0xFF - checksum;
804

    
805
        if (xbee_send(prefix, 3) != 0) {
806
                return -1;
807
        }
808

    
809
        if (xbee_send(buf, 5) != 0) {
810
                return -1;
811
        }
812

    
813
        if (xbee_send(packet, len) != 0) {
814
                return -1;
815
        }
816

    
817
        if (xbee_send((char*)&checksum, 1) != 0) {
818
                return -1;
819
        }
820

    
821
        return 0;
822
}
823

    
824
/**
825
 * Handles modem status packets.
826
 *
827
 * @param status the type of status packet received.
828
 **/
829
void xbee_handle_status(char status)
830
{
831
        switch (status)
832
        {
833
                case 0:
834
                        WL_DEBUG_PRINT("XBee hardware reset.\r\n");
835
                        break;
836
                case 1:
837
                        WL_DEBUG_PRINT("Watchdog timer reset.\r\n");
838
                        break;
839
                case 2:
840
                        WL_DEBUG_PRINT("Associated.\r\n");
841
                        break;
842
                case 3:
843
                        WL_DEBUG_PRINT("Disassociated.\r\n");
844
                        break;
845
                case 4:
846
                        WL_DEBUG_PRINT("Synchronization lost.\r\n");
847
                        break;
848
                case 5:
849
                        WL_DEBUG_PRINT("Coordinator realignment.\r\n");
850
                        break;
851
                case 6:
852
                        WL_DEBUG_PRINT("Coordinator started.\r\n");
853
                        break;
854
        }
855
}
856

    
857
/**
858
 * Handles AT command response packets.
859
 * @param command the two character AT command, e.g. MY or ID
860
 * @param result 0 for success, 1 for an error
861
 * @param len the length in bytes of extra
862
 **/
863
static int8_t xbee_handle_at_command_response(uint16_t command, uint8_t result, uint8_t len)
864
{
865
        if (result == 1)
866
        {
867
                WL_DEBUG_PRINT("Error with AT");
868
                WL_DEBUG_PRINT(command);
869
                WL_DEBUG_PRINT(" packet. Result = ");
870
    switch(result) {
871
    case 1:
872
      WL_DEBUG_PRINT("ERROR\r\n");
873
      break;
874
    case 2:
875
      WL_DEBUG_PRINT("Invalid Command\r\n");
876
      break;
877
    case 3:
878
      WL_DEBUG_PRINT("Invalid Parameter\r\n");
879
      break;
880
    }
881
    return WL_SUCCESS;
882
        }
883
        WL_DEBUG_PRINT("AT");
884
        WL_DEBUG_PRINT(command);
885
        WL_DEBUG_PRINT(" command was successful.\r\n");
886
  
887
  // TODO: program more command responses here (ND, etc)
888
  switch(command) {
889
  case ('I'<<8)+'D': // PAN
890
  case ('C'<<8)+'H': // channel
891
  case ('M'<<8)+'Y': // address
892
    // copy command to handler
893
    xbee_command[0] = (command&0xFF00)>>8;
894
    xbee_command[1] = command&0x00FF;
895
    result = basic_buf_last;
896
    for(command=2;command<len+2;command++)
897
      xbee_command[command] = xbee_basic_buf_get(&result);
898
    break;
899
  default:
900
    WL_DEBUG_PRINT("unknown AT command");
901
  }
902
  
903
  // signal handler that command response is done
904
  xbee_status = (xbee_status&0x3F)|XBEE_COMMAND_RESPONSE;
905

    
906
  return WL_SUCCESS;
907
}
908

    
909
/**
910
 * Sets the personal area network id.
911
 *
912
 * @param id the new personal area network (PAN) id
913
 **/
914
int8_t xbee_set_pan_id(uint16_t id)
915
{
916
        if (xbee_status&0xC0 == XBEE_COMMAND_WAIT
917
    || xbee_status&0xC0 == XBEE_COMMAND_RESPONSE)
918
    return WL_ERROR_XBEE_COMMAND; // can't do command right now
919
  
920
  int16_t i=0;
921
  // change status to command wait
922
  xbee_status = (xbee_status&0x3F)|XBEE_COMMAND_WAIT;
923
  xbee_send_modify_at_command("ID",id); // send command to set the channel
924
  // wait for up to 30 ms
925
  while(xbee_status&0xC0 != XBEE_COMMAND_RESPONSE && i++ < 10000) {
926
    delay_us(1); // wait 3us
927
  }
928
  if (i < 1000 && xbee_command[0] == 'O' && xbee_command[1] == 'K') {
929
    i = WL_SUCCESS;
930
  else
931
    i = WL_ERROR_XBEE_COMMAND; // set error code
932
  xbee_status = xbee_status&0x3F; // reset status
933
        return (int8_t)i; // return
934
}
935

    
936
/**
937
 * Get the PAN ID for the XBee.
938
 *
939
 * @return the personal area network id, or
940
 * XBEE_PAN_DEFAULT if it has not yet been set.
941
 **/
942
uint16_t xbee_get_pan_id()
943
{
944
  if (xbee_status&0xC0 == XBEE_COMMAND_WAIT
945
    || xbee_status&0xC0 == XBEE_COMMAND_RESPONSE)
946
    return WL_ERROR_XBEE_COMMAND_16BIT; // can't do command right now
947
  
948
  uint16_t i=0;
949
  // change status to command wait
950
  xbee_status = (xbee_status&0x3F)|XBEE_COMMAND_WAIT;
951
  xbee_send_read_at_command("ID"); // send command to get the PAN
952
  // wait for up to 30 ms
953
  while(xbee_status&0xC0 != XBEE_COMMAND_RESPONSE && i++ < 10000) {
954
    delay_us(1); // wait 3us
955
  }
956
  if (i < 1000 && xbee_command[0] == 'I' && xbee_command[1] == 'D') {
957
    i = (xbee_command[2]<<8)|xbee_command[3]; // get PAN
958
  else
959
    i = WL_ERROR_XBEE_COMMAND_16BIT; // set error code
960
  xbee_status = xbee_status&0x3F; // reset status
961
        return i; // return
962
}
963

    
964
/**
965
 * Set the channel the XBee is using.
966
 *
967
 * @param channel the channel the XBee will not use,
968
 * between 0x0B and 0x1A
969
 *
970
 * @see xbee_get_channel
971
 **/
972
int8_t xbee_set_channel(uint8_t channel)
973
{
974
        if (channel < 0x0B || channel > 0x1A)
975
        {
976
                WL_DEBUG_PRINT("Channel out of range.\r\n");
977
                return -1;
978
        }
979

    
980
        if (xbee_status&0xC0 == XBEE_COMMAND_WAIT
981
    || xbee_status&0xC0 == XBEE_COMMAND_RESPONSE)
982
    return WL_ERROR_XBEE_COMMAND; // can't do command right now
983
  
984
  int16_t i=0;
985
  // change status to command wait
986
  xbee_status = (xbee_status&0x3F)|XBEE_COMMAND_WAIT;
987
  xbee_send_modify_at_command("CH",channel); // send command to set the channel
988
  // wait for up to 30 ms
989
  while(xbee_status&0xC0 != XBEE_COMMAND_RESPONSE && i++ < 10000) {
990
    delay_us(1); // wait 3us
991
  }
992
  if (i < 1000 && xbee_command[0] == 'O' && xbee_command[1] == 'K') {
993
    i = WL_SUCCESS;
994
  else
995
    i = WL_ERROR_XBEE_COMMAND; // set error code
996
  xbee_status = xbee_status&0x3F; // reset status
997
        return (int8_t)i; // return
998
}
999

    
1000
/**
1001
 * Returns the channel which the XBee is currently using.
1002
 *
1003
 * @return the channel the XBee is using
1004
 *
1005
 * @see xbee_set_channel
1006
 **/
1007
int8_t xbee_get_channel(void)
1008
{
1009
  if (xbee_status&0xC0 == XBEE_COMMAND_WAIT
1010
    || xbee_status&0xC0 == XBEE_COMMAND_RESPONSE)
1011
    return WL_ERROR_XBEE_COMMAND; // can't do command right now
1012
  
1013
  int16_t i=0;
1014
  // change status to command wait
1015
  xbee_status = (xbee_status&0x3F)|XBEE_COMMAND_WAIT;
1016
  xbee_send_read_at_command("ID"); // send command to get the channel
1017
  // wait for up to 30 ms
1018
  while(xbee_status&0xC0 != XBEE_COMMAND_RESPONSE && i++ < 10000) {
1019
    delay_us(1); // wait 3us
1020
  }
1021
  if (i < 1000 && xbee_command[0] == 'C' && xbee_command[1] == 'H') {
1022
    i = xbee_command[2]; // get channel
1023
  else
1024
    i = WL_ERROR_XBEE_COMMAND; // set error code
1025
  xbee_status = xbee_status&0x3F; // reset status
1026
        return i; // return
1027
}
1028

    
1029
/**
1030
 * Get the 16-bit address of the XBee.
1031
 * This is used to specify who to send messages to
1032
 * and who messages are from.
1033
 *
1034
 * @return the 16-bit address of the XBee.
1035
 **/
1036
uint16_t xbee_get_address(void)
1037
{
1038
  if (xbee_status&0xC0 == XBEE_COMMAND_WAIT
1039
    || xbee_status&0xC0 == XBEE_COMMAND_RESPONSE)
1040
    return WL_ERROR_XBEE_COMMAND_16BIT; // can't do command right now
1041
  
1042
  uint16_t i=0;
1043
  // change status to command wait
1044
  xbee_status = (xbee_status&0x3F)|XBEE_COMMAND_WAIT;
1045
  xbee_send_read_at_command("MY"); // send command to get the address
1046
  // wait for up to 30 ms
1047
  while(xbee_status&0xC0 != XBEE_COMMAND_RESPONSE && i++ < 10000) {
1048
    delay_us(1); // wait 3us
1049
  }
1050
  if (i < 1000 && xbee_command[0] == 'M' && xbee_command[1] == 'Y') {
1051
    i = (xbee_command[2]<<8)+xbee_command[3]; // get address
1052
  else
1053
    i = WL_ERROR_XBEE_COMMAND_16BIT; // set error code
1054
  xbee_status = xbee_status&0x3F; // reset status
1055
        return i; // return
1056
}
1057

    
1058
/**@} **/ // end xbee group
1059