Contiki-Inga 3.x
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  */
38 
39 /**
40  * \file
41  * Reliable unicast
42  * \author
43  * Adam Dunkels <adam@sics.se>
44  */
45 
46 #include "net/rime/runicast.h"
47 #include "net/rime/rime.h"
48 #include <string.h>
49 
50 
51 #ifdef RUNICAST_CONF_REXMIT_TIME
52 #define REXMIT_TIME RUNICAST_CONF_REXMIT_TIME
53 #else /* RUNICAST_CONF_REXMIT_TIME */
54 #define REXMIT_TIME CLOCK_SECOND
55 #endif /* RUNICAST_CONF_REXMIT_TIME */
56 
57 static const struct packetbuf_attrlist attributes[] =
58  {
59  RUNICAST_ATTRIBUTES
60  PACKETBUF_ATTR_LAST
61  };
62 
63 #define DEBUG 0
64 #if DEBUG
65 #include <stdio.h>
66 #define PRINTF(...) printf(__VA_ARGS__)
67 #else
68 #define PRINTF(...)
69 #endif
70 
71 /*---------------------------------------------------------------------------*/
72 static void
73 sent_by_stunicast(struct stunicast_conn *stunicast, int status, int num_tx)
74 {
75  struct runicast_conn *c = (struct runicast_conn *)stunicast;
76 
77  PRINTF("runicast: sent_by_stunicast c->rxmit %d num_tx %d\n",
78  c->rxmit, num_tx);
79 
80  /* Only process data packets, not ACKs. */
81  if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) == PACKETBUF_ATTR_PACKET_TYPE_DATA) {
82 
83  c->rxmit += 1;
84 
85  if(c->rxmit != 0) {
86  RIMESTATS_ADD(rexmit);
87  PRINTF("%d.%d: runicast: sent_by_stunicast packet %u (%u) resent %u\n",
89  packetbuf_attr(PACKETBUF_ATTR_PACKET_ID),
90  c->sndnxt, c->rxmit);
91  }
92  if(c->rxmit >= c->max_rxmit) {
93  RIMESTATS_ADD(timedout);
94  c->is_tx = 0;
95  stunicast_cancel(&c->c);
96  if(c->u->timedout) {
97  c->u->timedout(c, stunicast_receiver(&c->c), c->rxmit);
98  }
99  c->rxmit = 0;
100  PRINTF("%d.%d: runicast: packet %d timed out\n",
102  c->sndnxt);
103  c->sndnxt = (c->sndnxt + 1) % (1 << RUNICAST_PACKET_ID_BITS);
104  } else {
105 // int shift;
106 
107 // shift = c->rxmit > 4? 4: c->rxmit;
108 // stunicast_set_timer(&c->c, (REXMIT_TIME) << shift);
109  }
110  }
111 }
112 /*---------------------------------------------------------------------------*/
113 static void
114 recv_from_stunicast(struct stunicast_conn *stunicast, const linkaddr_t *from)
115 {
116  struct runicast_conn *c = (struct runicast_conn *)stunicast;
117  /* struct runicast_hdr *hdr = packetbuf_dataptr();*/
118 
119  PRINTF("%d.%d: runicast: recv_from_stunicast from %d.%d type %d seqno %d\n",
121  from->u8[0], from->u8[1],
122  packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE),
123  packetbuf_attr(PACKETBUF_ATTR_PACKET_ID));
124 
125  if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) ==
126  PACKETBUF_ATTR_PACKET_TYPE_ACK) {
127  PRINTF("%d.%d: runicast: got ACK from %d.%d, seqno %d (%d)\n",
129  from->u8[0], from->u8[1],
130  packetbuf_attr(PACKETBUF_ATTR_PACKET_ID),
131  c->sndnxt);
132  if(packetbuf_attr(PACKETBUF_ATTR_PACKET_ID) == c->sndnxt) {
133  RIMESTATS_ADD(ackrx);
134  PRINTF("%d.%d: runicast: ACKed %d\n",
136  packetbuf_attr(PACKETBUF_ATTR_PACKET_ID));
137  c->sndnxt = (c->sndnxt + 1) % (1 << RUNICAST_PACKET_ID_BITS);
138  c->is_tx = 0;
139  stunicast_cancel(&c->c);
140  if(c->u->sent != NULL) {
141  c->u->sent(c, stunicast_receiver(&c->c), c->rxmit);
142  }
143  } else {
144  PRINTF("%d.%d: runicast: received bad ACK %d for %d\n",
146  packetbuf_attr(PACKETBUF_ATTR_PACKET_ID),
147  c->sndnxt);
148  RIMESTATS_ADD(badackrx);
149  }
150  } else if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) ==
151  PACKETBUF_ATTR_PACKET_TYPE_DATA) {
152  /* int send_ack = 1;*/
153  uint16_t packet_seqno;
154  struct queuebuf *q;
155 
156  RIMESTATS_ADD(reliablerx);
157 
158  PRINTF("%d.%d: runicast: got packet %d\n",
160  packetbuf_attr(PACKETBUF_ATTR_PACKET_ID));
161 
162  packet_seqno = packetbuf_attr(PACKETBUF_ATTR_PACKET_ID);
163 
164  /* packetbuf_hdrreduce(sizeof(struct runicast_hdr));*/
165 
166  q = queuebuf_new_from_packetbuf();
167  if(q != NULL) {
168  PRINTF("%d.%d: runicast: Sending ACK to %d.%d for %d\n",
170  from->u8[0], from->u8[1],
171  packet_seqno);
172  packetbuf_clear();
173  /* packetbuf_hdralloc(sizeof(struct runicast_hdr));
174  hdr = packetbuf_hdrptr();
175  hdr->type = TYPE_ACK;
176  hdr->seqno = packet_seqno;*/
177  packetbuf_set_attr(PACKETBUF_ATTR_PACKET_TYPE, PACKETBUF_ATTR_PACKET_TYPE_ACK);
178  packetbuf_set_attr(PACKETBUF_ATTR_PACKET_ID, packet_seqno);
179  stunicast_send(&c->c, from);
180  RIMESTATS_ADD(acktx);
181 
182  queuebuf_to_packetbuf(q);
183  queuebuf_free(q);
184  } else {
185  PRINTF("%d.%d: runicast: could not send ACK to %d.%d for %d: no queued buffers\n",
187  from->u8[0], from->u8[1],
188  packet_seqno);
189  }
190  if(c->u->recv != NULL) {
191  c->u->recv(c, from, packet_seqno);
192  }
193  }
194 }
195 /*---------------------------------------------------------------------------*/
196 static const struct stunicast_callbacks runicast = {recv_from_stunicast,
197  sent_by_stunicast};
198 /*---------------------------------------------------------------------------*/
199 void
200 runicast_open(struct runicast_conn *c, uint16_t channel,
201  const struct runicast_callbacks *u)
202 {
203  stunicast_open(&c->c, channel, &runicast);
204  channel_set_attributes(channel, attributes);
205  c->u = u;
206  c->is_tx = 0;
207  c->rxmit = 0;
208  c->sndnxt = 0;
209 }
210 /*---------------------------------------------------------------------------*/
211 void
212 runicast_close(struct runicast_conn *c)
213 {
214  stunicast_close(&c->c);
215 }
216 /*---------------------------------------------------------------------------*/
217 uint8_t
218 runicast_is_transmitting(struct runicast_conn *c)
219 {
220  return c->is_tx;
221 }
222 /*---------------------------------------------------------------------------*/
223 int
224 runicast_send(struct runicast_conn *c, const linkaddr_t *receiver,
225  uint8_t max_retransmissions)
226 {
227  int ret;
228  if(runicast_is_transmitting(c)) {
229  PRINTF("%d.%d: runicast: already transmitting\n",
231  return 0;
232  }
233  packetbuf_set_attr(PACKETBUF_ATTR_RELIABLE, 1);
234  packetbuf_set_attr(PACKETBUF_ATTR_PACKET_TYPE, PACKETBUF_ATTR_PACKET_TYPE_DATA);
235  packetbuf_set_attr(PACKETBUF_ATTR_PACKET_ID, c->sndnxt);
236  packetbuf_set_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS, 3);
237  c->max_rxmit = max_retransmissions;
238  c->rxmit = 0;
239  c->is_tx = 1;
240  RIMESTATS_ADD(reliabletx);
241  PRINTF("%d.%d: runicast: sending packet %d\n",
243  c->sndnxt);
244  ret = stunicast_send_stubborn(&c->c, receiver, REXMIT_TIME);
245  if(!ret) {
246  c->is_tx = 0;
247  }
248  return ret;
249 }
250 /*---------------------------------------------------------------------------*/
251 /** @} */