Contiki 2.5
runicast.c
Go to the documentation of this file.
1 /**
2  * \addtogroup rimerunicast
3  * @{
4  */
5 
6 
7 /*
8  * Copyright (c) 2006, Swedish Institute of Computer Science.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  * notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  * notice, this list of conditions and the following disclaimer in the
18  * documentation and/or other materials provided with the distribution.
19  * 3. Neither the name of the Institute nor the names of its contributors
20  * may be used to endorse or promote products derived from this software
21  * without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  *
35  * This file is part of the Contiki operating system.
36  *
37  * $Id: runicast.c,v 1.12 2010/03/26 12:29:29 nifi Exp $
38  */
39 
40 /**
41  * \file
42  * Reliable unicast
43  * \author
44  * Adam Dunkels <adam@sics.se>
45  */
46 
47 #include "net/rime/runicast.h"
48 #include "net/rime.h"
49 #include <string.h>
50 
51 
52 #ifdef RUNICAST_CONF_REXMIT_TIME
53 #define REXMIT_TIME RUNICAST_CONF_REXMIT_TIME
54 #else /* RUNICAST_CONF_REXMIT_TIME */
55 #define REXMIT_TIME CLOCK_SECOND
56 #endif /* RUNICAST_CONF_REXMIT_TIME */
57 
58 static const struct packetbuf_attrlist attributes[] =
59  {
60  RUNICAST_ATTRIBUTES
61  PACKETBUF_ATTR_LAST
62  };
63 
64 #define DEBUG 0
65 #if DEBUG
66 #include <stdio.h>
67 #define PRINTF(...) printf(__VA_ARGS__)
68 #else
69 #define PRINTF(...)
70 #endif
71 
72 /*---------------------------------------------------------------------------*/
73 static void
74 sent_by_stunicast(struct stunicast_conn *stunicast, int status, int num_tx)
75 {
76  struct runicast_conn *c = (struct runicast_conn *)stunicast;
77 
78  PRINTF("runicast: sent_by_stunicast c->rxmit %d num_tx %d\n",
79  c->rxmit, num_tx);
80 
81  /* Only process data packets, not ACKs. */
82  if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) == PACKETBUF_ATTR_PACKET_TYPE_DATA) {
83 
84  c->rxmit += 1;
85 
86  if(c->rxmit != 0) {
87  RIMESTATS_ADD(rexmit);
88  PRINTF("%d.%d: runicast: sent_by_stunicast packet %u (%u) resent %u\n",
90  packetbuf_attr(PACKETBUF_ATTR_PACKET_ID),
91  c->sndnxt, c->rxmit);
92  }
93  if(c->rxmit >= c->max_rxmit) {
94  RIMESTATS_ADD(timedout);
95  c->is_tx = 0;
96  stunicast_cancel(&c->c);
97  if(c->u->timedout) {
98  c->u->timedout(c, stunicast_receiver(&c->c), c->rxmit);
99  }
100  c->rxmit = 0;
101  PRINTF("%d.%d: runicast: packet %d timed out\n",
103  c->sndnxt);
104  c->sndnxt = (c->sndnxt + 1) % (1 << RUNICAST_PACKET_ID_BITS);
105  } else {
106 // int shift;
107 
108 // shift = c->rxmit > 4? 4: c->rxmit;
109 // stunicast_set_timer(&c->c, (REXMIT_TIME) << shift);
110  }
111  }
112 }
113 /*---------------------------------------------------------------------------*/
114 static void
115 recv_from_stunicast(struct stunicast_conn *stunicast, const rimeaddr_t *from)
116 {
117  struct runicast_conn *c = (struct runicast_conn *)stunicast;
118  /* struct runicast_hdr *hdr = packetbuf_dataptr();*/
119 
120  PRINTF("%d.%d: runicast: recv_from_stunicast from %d.%d type %d seqno %d\n",
122  from->u8[0], from->u8[1],
123  packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE),
124  packetbuf_attr(PACKETBUF_ATTR_PACKET_ID));
125 
126  if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) ==
127  PACKETBUF_ATTR_PACKET_TYPE_ACK) {
128  PRINTF("%d.%d: runicast: got ACK from %d.%d, seqno %d (%d)\n",
130  from->u8[0], from->u8[1],
131  packetbuf_attr(PACKETBUF_ATTR_PACKET_ID),
132  c->sndnxt);
133  if(packetbuf_attr(PACKETBUF_ATTR_PACKET_ID) == c->sndnxt) {
134  RIMESTATS_ADD(ackrx);
135  PRINTF("%d.%d: runicast: ACKed %d\n",
137  packetbuf_attr(PACKETBUF_ATTR_PACKET_ID));
138  c->sndnxt = (c->sndnxt + 1) % (1 << RUNICAST_PACKET_ID_BITS);
139  c->is_tx = 0;
140  stunicast_cancel(&c->c);
141  if(c->u->sent != NULL) {
142  c->u->sent(c, stunicast_receiver(&c->c), c->rxmit);
143  }
144  } else {
145  PRINTF("%d.%d: runicast: received bad ACK %d for %d\n",
147  packetbuf_attr(PACKETBUF_ATTR_PACKET_ID),
148  c->sndnxt);
149  RIMESTATS_ADD(badackrx);
150  }
151  } else if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) ==
152  PACKETBUF_ATTR_PACKET_TYPE_DATA) {
153  /* int send_ack = 1;*/
154  uint16_t packet_seqno;
155  struct queuebuf *q;
156 
157  RIMESTATS_ADD(reliablerx);
158 
159  PRINTF("%d.%d: runicast: got packet %d\n",
161  packetbuf_attr(PACKETBUF_ATTR_PACKET_ID));
162 
163  packet_seqno = packetbuf_attr(PACKETBUF_ATTR_PACKET_ID);
164 
165  /* packetbuf_hdrreduce(sizeof(struct runicast_hdr));*/
166 
167  q = queuebuf_new_from_packetbuf();
168  if(q != NULL) {
169  PRINTF("%d.%d: runicast: Sending ACK to %d.%d for %d\n",
171  from->u8[0], from->u8[1],
172  packet_seqno);
173  packetbuf_clear();
174  /* packetbuf_hdralloc(sizeof(struct runicast_hdr));
175  hdr = packetbuf_hdrptr();
176  hdr->type = TYPE_ACK;
177  hdr->seqno = packet_seqno;*/
178  packetbuf_set_attr(PACKETBUF_ATTR_PACKET_TYPE, PACKETBUF_ATTR_PACKET_TYPE_ACK);
179  packetbuf_set_attr(PACKETBUF_ATTR_PACKET_ID, packet_seqno);
180  stunicast_send(&c->c, from);
181  RIMESTATS_ADD(acktx);
182 
183  queuebuf_to_packetbuf(q);
184  queuebuf_free(q);
185  } else {
186  PRINTF("%d.%d: runicast: could not send ACK to %d.%d for %d: no queued buffers\n",
188  from->u8[0], from->u8[1],
189  packet_seqno);
190  }
191  if(c->u->recv != NULL) {
192  c->u->recv(c, from, packet_seqno);
193  }
194  }
195 }
196 /*---------------------------------------------------------------------------*/
197 static const struct stunicast_callbacks runicast = {recv_from_stunicast,
198  sent_by_stunicast};
199 /*---------------------------------------------------------------------------*/
200 void
201 runicast_open(struct runicast_conn *c, uint16_t channel,
202  const struct runicast_callbacks *u)
203 {
204  stunicast_open(&c->c, channel, &runicast);
205  channel_set_attributes(channel, attributes);
206  c->u = u;
207  c->is_tx = 0;
208  c->rxmit = 0;
209  c->sndnxt = 0;
210 }
211 /*---------------------------------------------------------------------------*/
212 void
213 runicast_close(struct runicast_conn *c)
214 {
215  stunicast_close(&c->c);
216 }
217 /*---------------------------------------------------------------------------*/
218 uint8_t
219 runicast_is_transmitting(struct runicast_conn *c)
220 {
221  return c->is_tx;
222 }
223 /*---------------------------------------------------------------------------*/
224 int
225 runicast_send(struct runicast_conn *c, const rimeaddr_t *receiver,
226  uint8_t max_retransmissions)
227 {
228  int ret;
229  if(runicast_is_transmitting(c)) {
230  PRINTF("%d.%d: runicast: already transmitting\n",
232  return 0;
233  }
234  packetbuf_set_attr(PACKETBUF_ATTR_RELIABLE, 1);
235  packetbuf_set_attr(PACKETBUF_ATTR_PACKET_TYPE, PACKETBUF_ATTR_PACKET_TYPE_DATA);
236  packetbuf_set_attr(PACKETBUF_ATTR_PACKET_ID, c->sndnxt);
237  packetbuf_set_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS, 3);
238  c->max_rxmit = max_retransmissions;
239  c->rxmit = 0;
240  c->is_tx = 1;
241  RIMESTATS_ADD(reliabletx);
242  PRINTF("%d.%d: runicast: sending packet %d\n",
244  c->sndnxt);
245  ret = stunicast_send_stubborn(&c->c, receiver, REXMIT_TIME);
246  if(!ret) {
247  c->is_tx = 0;
248  }
249  return ret;
250 }
251 /*---------------------------------------------------------------------------*/
252 /** @} */