Project

General

Profile

Statistics
| Revision:

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

History | View | Annotate | Download (38 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 "xbee.h"
43

    
44

    
45
/* Internal Function Prototypes */
46

    
47
/* I/O Functions */
48
static int8_t xbee_send_string(uint8_t* c);
49

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

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

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

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

    
78
/*Global Variables*/
79

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

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

    
90
// beginning of first packet in basic buffer
91
uint8_t basic_buf_first = 0xFF;
92

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

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

    
100
// beginning of first packet in other buffer
101
uint8_t other_buf_first = 0xFF;
102

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

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

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

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

    
126

    
127

    
128
/**@addtogroup xbee
129
 * @{ **/
130

    
131
/*Function Implementations*/
132

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

    
362

    
363
/* adds a byte to the basic buffer */
364
int8_t xbee_basic_buf_add(uint8_t *ptr, uint8_t byte) {
365
  if (*ptr == basic_buf_first) {
366
    // buffer full
367
    WL_DEBUG_PRINT("basic buffer full\r\n");
368
    return -1;
369
  }
370
  xbee_basic_buf[(*ptr)++] = byte;
371
  if (*ptr == PACKET_BUFFER_SIZE)
372
    *ptr = 0;
373
  return 0;
374
}
375
/* gets a byte from the basic buffer */
376
uint8_t xbee_basic_buf_get(uint8_t *ptr) {
377
  uint8_t byte = xbee_basic_buf[(*ptr)++];
378
  if (*ptr == PACKET_BUFFER_SIZE)
379
    *ptr = 0;
380
  return byte;
381
}
382
/* adds a byte to the other buffer */
383
int8_t xbee_other_buf_add(uint8_t *ptr, uint8_t byte) {
384
  if (*ptr == other_buf_first) {
385
    // buffer full
386
    WL_DEBUG_PRINT("other buffer full\r\n");
387
    return -1;
388
  }
389
  xbee_other_buf[(*ptr)++] = byte;
390
  if (*ptr == PACKET_BUFFER_SIZE)
391
    *ptr = 0;
392
  return 0;
393
}
394

    
395
/**
396
 * Checks if packet is a duplicate
397
 **/
398
int8_t check_last_receive(uint16_t source,uint8_t framenum) {
399
  uint8_t i=0;
400
  for(;i<NUM_LAST_PACKETS;i++) {
401
    if (lastPacket[i].source == source && lastPacket[i].framenum == framenum)
402
      return -1; // duplicate packet, so return error
403
  }
404
  // save packet source and framenum
405
  i=getStatus(LAST_PACKET_MASK);
406
  lastPacket[i].source = source;
407
  lastPacket[i].framenum = framenum;
408
  if (++i>=NUM_LAST_PACKETS)
409
    i = 0;
410
  setStatus(LAST_PACKET_MASK,i);
411
  return WL_SUCCESS;
412
}
413

    
414
/** status functions **/
415
inline uint8_t getStatus(uint8_t mask) { return xbee_status&mask; }
416
void setStatus(uint8_t mask,uint8_t value) { xbee_status = ((xbee_status&(~mask))|value); }
417

    
418

    
419
// test interrupt
420
/*ISR(USART1_RX_vect) {
421
  WL_DEBUG_PRINT("in interrupt|");
422
  char c = UDR1;
423
  WL_DEBUG_PRINT_HEX(c);
424
  WL_DEBUG_PRINT("|in interrupt");
425
}*/
426

    
427

    
428

    
429
/**
430
 * Initializes the XBee library so that other functions may be used.
431
 **/
432
int8_t xbee_init()
433
{
434
  WL_DEBUG_PRINT("in xbee_init\r\n");
435
  
436
  if(getStatus(XBEE_NOT_INITD) != XBEE_NOT_INITD) {
437
    return WL_ERROR_INIT_ALREADY_INITD;
438
  }
439
  
440
  // set status
441
  setStatus(XBEE_NOT_INITD,XBEE_COMMAND_NONE);
442
  
443
  // clear last packet buffer
444
  for(int i=0;i<NUM_LAST_PACKETS;i++)
445
    lastPacket[i].source = lastPacket[i].framenum = 0;
446
  
447
  // Set startup baud rate of 9600
448
  // Set frame format: 8data, 1stop bit, asynchronous normal mode
449
  // Enable receiver and transmitter and the receiving interrupt
450
#ifdef FIREFLY
451
  UBRR0H = 0x00;
452
  UBRR0L = 103;
453
  UCSR0A |= (1<<U2X0);
454
  UCSR0C |= (1<<UCSZ00) | (1<<UCSZ01);
455
  UCSR0B |= (1<<RXEN0) | (1<<TXEN0) | (1<<RXCIE); 
456
#else
457
  // Bayboard or robot  
458
  UBRR1H = 0x00; // baud rate
459
  UBRR1L = 103;  // baud rate
460
  UCSR1A |= (1<<U2X1); // double transmit speed 
461
  //Enable receiver and transmitter on USART1
462
  UCSR1B |= (1<<RXEN1)|(1<<TXEN1);
463
        
464
  // Set frame format: 8data, 1stop bit, asynchronous normal mode
465
  UCSR1C |= (1<<UCSZ10) | (1<<UCSZ11);
466
  
467
  UCSR1B |= (1<<RXCIE1);  // enable receive, transmit (1<<RXCIE)
468
#endif
469
  sei();
470
 
471
  // enter command mode
472
  WL_DEBUG_PRINT("entering command mode\r\n");
473
  xbee_send_string((uint8_t*)"+++");
474
  xbee_wait_for_ok();
475
  WL_DEBUG_PRINT("entered command mode\r\n");
476

    
477
  
478
  // set baud on xbee
479
#if (XBEE_BAUD == 115200)
480
  xbee_send_string((uint8_t*)"ATBD7\r");
481
#elif (XBEE_BAUD == 57600)
482
  xbee_send_string((uint8_t*)"ATBD6\r");
483
#elif (XBEE_BAUD == 38400)
484
  xbee_send_string((uint8_t*)"ATBD5\r");
485
#elif (XBEE_BAUD == 19200)
486
  xbee_send_string((uint8_t*)"ATBD4\r");
487
#elif (XBEE_BAUD == 9600)
488
  // already at this baud rate
489
  xbee_send_string("ATBD3\r\n");
490
#else
491
  WL_DEBUG_PRINT("undefined baud rate\r\n");
492
  return WL_ERROR_BAUD;
493
#endif  
494
  // exit command mode
495
  xbee_wait_for_ok();
496
  WL_DEBUG_PRINT("got ok from baud reset\r\n");
497
  xbee_send_string((uint8_t*)"ATCN\r");
498
  xbee_wait_for_ok();
499
  WL_DEBUG_PRINT("got ok from exiting command mode\r\n");
500
  
501
  // set UART baud
502
#ifdef FIREFLY
503
#if (XBEE_BAUD == 115200)
504
  UBRR0H = 0x00;
505
  UBRR0L = 8;
506
#elif (XBEE_BAUD == 57600)
507
  UBRR0H = 0x00;
508
  UBRR0L = 16;
509
#elif (XBEE_BAUD == 38400)
510
  UBRR0H = 0x00;
511
  UBRR0L = 25;
512
#elif (XBEE_BAUD == 19200)
513
  UBRR0H = 0x00;
514
  UBRR0L = 51;
515
#elif (XBEE_BAUD == 9600)
516
  /* this is the default baud rate, so do nothing
517
  UBRR0H = 0x00;
518
  UBRR0L = 103;*/
519
#else
520
  WL_DEBUG_PRINT("undefined baud rate\r\n");
521
  return WL_ERROR_BUAD;
522
#endif
523
#else // Bayboard or robot
524
#if (XBEE_BAUD == 115200)
525
  UBRR1H = 0x00;
526
  UBRR1L = 8;
527
#elif (XBEE_BAUD == 57600)
528
  UBRR1H = 0x00;
529
  UBRR1L = 16;
530
#elif (XBEE_BAUD == 38400)
531
  UBRR1H = 0x00;
532
  UBRR1L = 25;
533
#elif (XBEE_BAUD == 19200)
534
  UBRR1H = 0x00;
535
  UBRR1L = 51;
536
#elif (XBEE_BAUD == 9600)
537
  /* this is the default baud rate, so do nothing
538
  UBRR1H = 0x00;
539
  UBRR1L = 103;*/
540
#else
541
  WL_DEBUG_PRINT("undefined baud rate\r\n");
542
  return WL_ERROR_BUAD;
543
#endif
544
#endif
545
  // wait half second for the baud change to stabalize
546
  delay_ms(500);
547

    
548
  // enter command mode
549
  WL_DEBUG_PRINT("entering command mode 2\r\n");
550
  xbee_send_string((uint8_t*)"+++");
551
  xbee_wait_for_ok();
552
  WL_DEBUG_PRINT("entered command mode 2\r\n");
553
  
554
  if (xbee_enter_api_mode() != 0) {
555
    WL_DEBUG_PRINT("can't enter api mode\r\n");
556
    return -1;
557
  }
558
  /*xbee_send_string((uint8_t*)"ATAP 1\r");
559
  xbee_wait_for_ok();*/
560
  
561
  /*WL_DEBUG_PRINT("Entered api mode.\r\n");
562

563
  if (xbee_exit_command_mode() != 0) {
564
    WL_DEBUG_PRINT("can't exit command mode\r\n");
565
    return -1;
566
  }
567
  setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_NONE); // clear status
568
  
569
  WL_DEBUG_PRINT("Left command mode.\r\n");
570
  
571
  WL_DEBUG_PRINT("before status=");
572
  WL_DEBUG_PRINT_HEX(getStatus(0xFF));
573
  WL_DEBUG_PRINT("\r\n");
574
  
575
  setStatus(XBEE_API_MASK,XBEE_API_O