2 * Copyright (c) 2011, Olivier MATZ <zer0@droids-corp.org>
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the University of California, Berkeley nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include <aversive/pgmspace.h>
30 #include <aversive/queue.h>
31 #include <aversive/endian.h>
41 #include "xbee_neighbor.h"
42 #include "xbee_stats.h"
43 #include "xbee_rxtx.h"
46 /* Return -1 if the frame is invalid. The arguments buf and len correspond to
47 * the whole xbee frame, from delimiter to cksum. */
48 static int xbee_parse_atresp(struct xbee_dev *dev, void *buf, unsigned len)
50 struct xbee_atresp_hdr *atresp_hdr;
52 dev->stats.rx_atresp++;
54 if (len < sizeof(struct xbee_hdr) + sizeof(struct xbee_atresp_hdr)) {
55 dev->stats.rx_frame_too_small++;
59 atresp_hdr = buf + sizeof(struct xbee_hdr);
61 /* bad status, but let the frame continue */
62 if (atresp_hdr->status != 0)
63 dev->stats.rx_atresp_error++;
68 /* Return -1 if the frame is invalid. The arguments buf and len correspond to
69 * the whole xbee frame, from delimiter to cksum. */
70 static int xbee_parse_rmt_atresp(struct xbee_dev *dev, void *buf, unsigned len)
72 struct xbee_rmt_atresp_hdr *rmt_atresp_hdr;
74 dev->stats.rx_rmt_atresp++;
76 if (len < sizeof(struct xbee_hdr) + sizeof(struct xbee_rmt_atresp_hdr)) {
77 dev->stats.rx_frame_too_small++;
81 rmt_atresp_hdr = buf + sizeof(struct xbee_hdr);
83 /* bad status, but let the frame continue */
84 if (rmt_atresp_hdr->status != 0)
85 dev->stats.rx_rmt_atresp_error++;
90 /* Parse the reception of a "xmit status message". The arguments buf and len
91 * correspond to the whole xbee frame, from delimiter to cksum. Return -1 if the
93 static int xbee_parse_xmit_status(struct xbee_dev *dev, void *buf, unsigned len)
95 struct xbee_xmit_status_hdr *xmit_status_hdr;
97 dev->stats.rx_xmit_status++;
99 if (len < sizeof(struct xbee_hdr) + sizeof(struct xbee_xmit_status_hdr)) {
100 dev->stats.rx_frame_too_small++;
104 xmit_status_hdr = buf + sizeof(struct xbee_hdr);
105 dev->stats.tx_xmit_retries += xmit_status_hdr->xmit_retry_cnt;
107 /* bad status, but let the frame continue */
108 if (xmit_status_hdr->delivery_status != 0)
109 dev->stats.rx_xmit_status_error++;
114 /* parse the frame stored in the xbee_dev structure: return 0 if the frame is
115 * valid, else a negative value */
116 static void xbee_parse_frame(struct xbee_dev *dev)
118 void *buf = dev->frame;
119 uint8_t len = dev->frame_len;
121 struct xbee_hdr *hdr = buf;
124 int channel = XBEE_DEFAULT_CHANNEL;
126 dev->stats.rx_frame++;
129 case XBEE_TYPE_MODEM_STATUS:
131 case XBEE_TYPE_EXPL_RECV:
132 hdrlen = sizeof(struct xbee_hdr) - 1; /* no frame ID */
135 hdrlen = sizeof(struct xbee_hdr);
139 /* check frame len */
140 if (len < (hdrlen + 1)) {
141 dev->stats.rx_frame_too_small++;
142 fprintf_P(stderr, PSTR("Frame too small\r\n"));
146 /* validate the cksum */
147 for (i = 3; i < (len - 1); i++)
148 cksum += ((uint8_t *)buf)[i];
149 cksum = 0xff - cksum;
150 if (cksum != ((uint8_t *)buf)[len-1]) {
151 fprintf_P(stderr, PSTR("Invalid cksum\r\n"));
152 dev->stats.rx_invalid_cksum++;
158 case XBEE_TYPE_MODEM_STATUS:
159 dev->stats.rx_modem_status++;
160 channel = XBEE_DEFAULT_CHANNEL;
162 case XBEE_TYPE_ATRESP:
163 if (xbee_parse_atresp(dev, buf, len) < 0)
167 case XBEE_TYPE_RMT_ATRESP:
168 if (xbee_parse_rmt_atresp(dev, buf, len) < 0)
172 case XBEE_TYPE_XMIT_STATUS:
173 if (xbee_parse_xmit_status(dev, buf, len) < 0)
178 dev->stats.rx_data++;
179 channel = XBEE_DEFAULT_CHANNEL;
181 case XBEE_TYPE_EXPL_RECV:
182 dev->stats.rx_expl_data++;
183 channel = XBEE_DEFAULT_CHANNEL;
185 case XBEE_TYPE_NODE_ID:
186 dev->stats.rx_node_id++;
187 channel = hdr->id; //XXX
189 /* invalid commands */
190 case XBEE_TYPE_ATCMD:
191 case XBEE_TYPE_ATCMD_Q:
193 case XBEE_TYPE_EXPL_XMIT:
194 case XBEE_TYPE_RMT_ATCMD:
196 dev->stats.rx_invalid_type++;
200 /* fallback to default channel if not registered */
201 if (channel < 0 || channel >= XBEE_MAX_CHANNEL ||
202 dev->channel[channel].registered == 0)
203 channel = XBEE_DEFAULT_CHANNEL;
205 /* execute the callback if any */
206 if (dev->channel[channel].rx_cb == NULL)
208 if (dev->channel[channel].rx_cb(dev, channel, hdr->type,
211 dev->channel[channel].arg) < 0)
212 dev->stats.rx_usr_error++;
215 int xbee_tx_iovec(struct xbee_dev *dev, uint8_t channel_id, uint8_t type,
216 const struct xbee_msg *msg)
223 for (i = 0; i < msg->iovlen; i++)
224 len += msg->iov[i].len;
226 /* prepare an iovec to avoid a copy: prepend a header to the
227 * buffer and append a checksum */
228 hdr.delimiter = XBEE_DELIMITER;
229 hdr.len = htons(len + 2);
233 if (channel_id >= XBEE_MAX_CHANNEL ||
234 dev->channel[channel_id].registered == 0) {
235 dev->stats.tx_invalid_channel ++;
239 /* calculate the cksum */
242 for (i = 0; i < msg->iovlen; i++) {
243 for (j = 0; j < msg->iov[i].len; j++)
244 cksum += ((uint8_t *)msg->iov[i].buf)[j];
246 cksum = 0xff - cksum;
247 dev->stats.tx_frame ++;
249 /* some additional checks before sending */
252 case XBEE_TYPE_ATCMD:
254 dev->stats.tx_atcmd ++;
256 case XBEE_TYPE_ATCMD_Q:
257 dev->stats.tx_atcmd_q ++;
260 dev->stats.tx_data ++;
262 case XBEE_TYPE_EXPL_XMIT:
263 dev->stats.tx_expl_data ++;
265 case XBEE_TYPE_RMT_ATCMD:
266 dev->stats.tx_rmt_atcmd ++;
269 /* invalid commands */
270 case XBEE_TYPE_XMIT_STATUS:
271 case XBEE_TYPE_MODEM_STATUS:
272 case XBEE_TYPE_ATRESP:
274 case XBEE_TYPE_EXPL_RECV:
275 case XBEE_TYPE_NODE_ID:
276 case XBEE_TYPE_RMT_ATRESP:
278 dev->stats.tx_invalid_type ++;
279 fprintf_P(stderr, PSTR("unhandled xmit type=%x\r\n"),
284 /* send the frame on the wire */
285 fwrite(&hdr, 1, sizeof(hdr), dev->file);
286 for (i = 0; i < msg->iovlen; i++)
287 fwrite(msg->iov[i].buf, 1, msg->iov[i].len, dev->file);
288 fwrite(&cksum, 1, 1, dev->file);
293 int xbee_tx(struct xbee_dev *dev, uint8_t channel_id, uint8_t type,
294 char *buf, unsigned len)
298 msg.iov[0].buf = buf;
299 msg.iov[0].len = len;
300 return xbee_tx_iovec(dev, channel_id, type, &msg);
303 void xbee_rx(struct xbee_dev *dev)
306 struct xbee_hdr *hdr = (struct xbee_hdr *)dev->frame;
312 c = fgetc(dev->file);
316 /* frame too long XXX stats */
317 if (dev->frame_len >= XBEE_MAX_FRAME_LEN) {
322 if (dev->frame_len == 0 && c != XBEE_DELIMITER)
325 dev->frame[dev->frame_len++] = c;
327 /* not enough data to read len */
328 if (dev->frame_len < sizeof(*hdr))
331 framelen = ntohs(hdr->len);
332 framelen += 4; /* 1 for delimiter, 2 for len, 1 for cksum */
334 /* frame too long XXX stats */
335 if (framelen >= XBEE_MAX_FRAME_LEN) {
337 dev->stats.rx_frame++;
338 dev->stats.rx_frame_too_large++;
342 /* not enough data */
343 if (dev->frame_len < framelen)
346 xbee_parse_frame(dev);