Project

General

Profile

Statistics
| Revision:

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

History | View | Annotate | Download (38 KB)

1 1576 dsschult
/**
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 1642 dsschult
#include <lights.h>
35 1576 dsschult
36 1601 dsschult
#include <string.h>
37 1642 dsschult
#include <avr/io.h>
38 1601 dsschult
#include <avr/interrupt.h>
39 1576 dsschult
#include <time.h>
40 1642 dsschult
#include <wl_defs.h>
41
#include <wireless.h>
42 1601 dsschult
#include "xbee.h"
43 1576 dsschult
44
45 1601 dsschult
/* Internal Function Prototypes */
46 1576 dsschult
47 1601 dsschult
/* I/O Functions */
48 1611 dsschult
static int8_t xbee_send_string(uint8_t* c);
49 1576 dsschult
50 1601 dsschult
/* Command Mode Functions */
51 1611 dsschult
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 1576 dsschult
58 1601 dsschult
/* API Mode Functions */
59 1616 dsschult
//TODO: does this exist?  static int8_t xbee_handle_packet(uint8_t* packet, uint16_t len);
60 1642 dsschult
static int8_t xbee_handle_at_command_response(uint16_t command, uint8_t status, uint8_t len);
61 1609 dsschult
static void xbee_handle_status(uint8_t status);
62 1611 dsschult
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 1576 dsschult
68 1601 dsschult
/* 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 1576 dsschult
73 1616 dsschult
/* 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 1576 dsschult
78 1601 dsschult
/*Global Variables*/
79 1576 dsschult
80 1616 dsschult
// 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 1591 dsschult
// array for basic packets
88 1648 dsschult
uint8_t xbee_basic_buf[PACKET_BUFFER_SIZE];
89 1591 dsschult
90
// beginning of first packet in basic buffer
91 1648 dsschult
uint8_t basic_buf_first = 0xFF;
92 1591 dsschult
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 1648 dsschult
uint8_t basic_buf_last = 0;
96 1591 dsschult
97
// array for other packets
98 1648 dsschult
uint8_t xbee_other_buf[PACKET_BUFFER_SIZE];
99 1576 dsschult
100 1591 dsschult
// beginning of first packet in other buffer
101 1648 dsschult
uint8_t other_buf_first = 0xFF;
102 1591 dsschult
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 1648 dsschult
uint8_t other_buf_last = 0;
106 1591 dsschult
107 1600 dsschult
// xbee status
108 1616 dsschult
#define XBEE_API_OFF 0x00
109
#define XBEE_API_ON 0x10
110
#define XBEE_API_ESCAPE 0x20
111
#define XBEE_API_MASK 0x30
112 1600 dsschult
#define XBEE_COMMAND_WAIT 0x80
113
#define XBEE_COMMAND_RESPONSE 0xC0
114 1616 dsschult
#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 1600 dsschult
120
// xbee command response (for PAN, channel, address, etc)
121 1642 dsschult
static uint8_t xbee_command[8];
122 1600 dsschult
123 1591 dsschult
// external ack handler (wireless_send.c)
124 1648 dsschult
extern void ackhandle(uint8_t num,uint8_t val);
125 1591 dsschult
126 1601 dsschult
127 1642 dsschult
128 1587 dsschult
/**@addtogroup xbee
129
 * @{ **/
130
131 1576 dsschult
/*Function Implementations*/
132
133
/**
134
 * Interrupt for the robot. Adds bytes received from the xbee
135
 * to the buffer.
136
 **/
137 1624 dsschult
138 1642 dsschult
139 1576 dsschult
#ifndef FIREFLY
140 1642 dsschult
#define PORT UDR1
141
#define FLAG (UCSR1A & (1<<RXC1))
142
ISR(USART1_RX_vect) {
143 1576 dsschult
#else
144 1642 dsschult
#define PORT UDR0
145
#define FLAG (UCSR0A & (1<<RXC0))
146 1624 dsschult
SIGNAL(SIG_USART0_RECV)
147
#endif
148 1591 dsschult
  // start of frame
149 1624 dsschult
  uint8_t apitype = PORT; // get frame start byte
150 1591 dsschult
  uint16_t i=0;
151
  uint16_t len=0;
152 1654 dsschult
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 1600 dsschult
  // check that we're in API mode
167 1616 dsschult
  if (getStatus(XBEE_API_MASK) == XBEE_API_OFF || apitype != XBEE_FRAME_START) {
168 1600 dsschult
    // not in API mode
169 1654 dsschult
    WL_DEBUG_PRINT("|api off branch");
170 1642 dsschult
171 1616 dsschult
    if (getStatus(XBEE_COMMAND_MASK) == XBEE_COMMAND_WAIT) {
172 1600 dsschult
      // get rest of command and put in basic buf
173 1642 dsschult
      xbee_basic_buf[i] = apitype;
174
      if (xbee_basic_buf[i++] != '\r') {
175 1600 dsschult
        while(i < PACKET_BUFFER_SIZE) {
176
          if (FLAG) {
177
            xbee_basic_buf[i] = PORT;
178
            if (xbee_basic_buf[i] == '\r')
179
              break;
180 1642 dsschult
            i++;
181 1600 dsschult
          }
182
        }
183
      }
184 1654 dsschult
      WL_DEBUG_PRINT("got packet, len=");
185 1642 dsschult
      WL_DEBUG_PRINT_INT(i);
186
      WL_DEBUG_PRINT("str=");
187 1624 dsschult
      WL_DEBUG_PRINT(xbee_basic_buf);
188 1600 dsschult
      // signal handler that command response is done
189 1616 dsschult
      setStatus(XBEE_COMMAND_MASK,XBEE_COMMAND_RESPONSE);
190 1600 dsschult
    }
191 1624 dsschult
    WL_DEBUG_PRINT("return\r\n");
192 1600 dsschult
    return;
193 1624 dsschult
  }
194 1654 dsschult
  //WL_DEBUG_PRINT("|api on branch");
195 1600 dsschult
196 1591 dsschult
  // get length and type
197
  while(i<3) {
198
    if (FLAG) {
199 1642 dsschult
      if (i==0) {
200 1654 dsschult
        len |= PORT<<8;
201
        //WL_DEBUG_PRINT("|len_hi");
202 1642 dsschult
      } else if (i==1) {
203 1591 dsschult
        len |= PORT;
204 1654 dsschult
        //WL_DEBUG_PRINT("|len_lo");
205 1642 dsschult
      } else if (i==2) {
206 1591 dsschult
        apitype = PORT;
207 1654 dsschult
        //WL_DEBUG_PRINT("|GOT APITYPE");
208 1642 dsschult
      }
209 1591 dsschult
      i++;
210
    }
211
  }
212
213
  // do something based on the type
214
  i=1;
215
  switch(apitype) {
216 1611 dsschult
  case XBEE_FRAME_AT_COMMAND_RESPONSE: {
217 1591 dsschult
    // AT command response
218 1616 dsschult
    if (getStatus(XBEE_COMMAND_MASK) == XBEE_COMMAND_RESPONSE)
219 1642 dsschult
      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 1591 dsschult
    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 1600 dsschult
          if (xbee_basic_buf_add(&ptr,PORT) != 0)
235 1591 dsschult
            break;
236
        }
237
        i++;
238
      }
239 1642 dsschult
    }
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 1611 dsschult
    break; }
257
  case XBEE_FRAME_TX_STATUS: {
258 1591 dsschult
    // TX status
259 1609 dsschult
    uint8_t frame_id = 0;
260 1591 dsschult
    while(i<len) {
261
      if (FLAG) {
262
        if (i==1)
263 1609 dsschult
          frame_id = PORT;
264 1591 dsschult
        else {
265 1609 dsschult
          ackhandle(frame_id,PORT); // handle the status
266 1591 dsschult
          break;
267
        }
268
        i++;
269
      }
270
    }
271 1611 dsschult
    break; }
272
  case XBEE_FRAME_RX_64: {
273 1591 dsschult
    // receive a packet with 64bit address
274 1611 dsschult
    break; } // TODO: implement this (even if we don't use it)
275
  case XBEE_FRAME_RX_16: {
276 1591 dsschult
    // 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 1616 dsschult
          if (check_last_receive(source,framenum) != WL_SUCCESS) {
294 1591 dsschult
            // 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 1600 dsschult
            if (xbee_basic_buf_add(&ptr,(uint8_t)((source&0xFF00)>>8)) != 0)
305 1591 dsschult
              break;
306 1600 dsschult
            if (xbee_basic_buf_add(&ptr,(uint8_t)(source&0x00FF)) != 0)
307 1591 dsschult
              break;
308
          } else {
309
            ptr = other_buf_last+1;
310 1600 dsschult
            // add source and group to buffer
311
            if (xbee_other_buf_add(&ptr,group) != 0)
312 1591 dsschult
              break;
313 1600 dsschult
            if (xbee_other_buf_add(&ptr,(uint8_t)((source&0xFF00)>>8)) != 0)
314 1591 dsschult
              break;
315 1600 dsschult
            if (xbee_other_buf_add(&ptr,(uint8_t)(source&0x00FF)) != 0)
316 1591 dsschult
              break;
317
          }
318
        }
319 1600 dsschult
        else { // TODO: handle escaped characters supported by APIv2
320 1591 dsschult
          // put packet data on the correct buffer
321 1600 dsschult
          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 1591 dsschult
        }
326
        i++;
327
      }
328
    }
329 1600 dsschult
    if (ptr != 0xFF && i > 6) {
330 1591 dsschult
      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 1611 dsschult
    break; }
350 1642 dsschult
    default:
351 1654 dsschult
      WL_DEBUG_PRINT("|BAD APITYPE");
352 1600 dsschult
  } // end of switch statement
353
  while (1) {
354
    if (FLAG) {
355
      apitype = PORT; // get checksum, and ignore
356
      break;
357
    }
358 1591 dsschult
  }
359 1654 dsschult
  WL_DEBUG_PRINT("|interrupt - return\r\n");
360 1624 dsschult
} // end of interrupt
361 1576 dsschult
362 1642 dsschult
363 1600 dsschult
/* 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 1654