Contiki 2.5
csma.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2010, Swedish Institute of Computer Science.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * This file is part of the Contiki operating system.
30  *
31  * $Id: csma.c,v 1.27 2011/01/25 14:24:38 adamdunkels Exp $
32  */
33 
34 /**
35  * \file
36  * A Carrier Sense Multiple Access (CSMA) MAC layer
37  * \author
38  * Adam Dunkels <adam@sics.se>
39  */
40 
41 #include "net/mac/csma.h"
42 #include "net/packetbuf.h"
43 #include "net/queuebuf.h"
44 
45 #include "sys/ctimer.h"
46 
47 #include "lib/random.h"
48 
49 #include "net/netstack.h"
50 
51 #include "lib/list.h"
52 #include "lib/memb.h"
53 
54 #include <string.h>
55 
56 #include <stdio.h>
57 #include <stdlib.h>
58 
59 #define DEBUG 0
60 #if DEBUG
61 #include <stdio.h>
62 #define PRINTF(...) printf(__VA_ARGS__)
63 #else /* DEBUG */
64 #define PRINTF(...)
65 #endif /* DEBUG */
66 
67 #ifndef CSMA_MAX_MAC_TRANSMISSIONS
68 #ifdef CSMA_CONF_MAX_MAC_TRANSMISSIONS
69 #define CSMA_MAX_MAC_TRANSMISSIONS CSMA_CONF_MAX_MAC_TRANSMISSIONS
70 #else
71 #define CSMA_MAX_MAC_TRANSMISSIONS 3
72 #endif /* CSMA_CONF_MAX_MAC_TRANSMISSIONS */
73 #endif /* CSMA_MAX_MAC_TRANSMISSIONS */
74 
75 #if CSMA_MAX_MAC_TRANSMISSIONS < 1
76 #error CSMA_CONF_MAX_MAC_TRANSMISSIONS must be at least 1.
77 #error Change CSMA_CONF_MAX_MAC_TRANSMISSIONS in contiki-conf.h or in your Makefile.
78 #endif /* CSMA_CONF_MAX_MAC_TRANSMISSIONS < 1 */
79 
80 struct queued_packet {
81  struct queued_packet *next;
82  struct queuebuf *buf;
83  /* struct ctimer retransmit_timer;*/
84  mac_callback_t sent;
85  void *cptr;
86  uint8_t transmissions, max_transmissions;
87  uint8_t collisions, deferrals;
88 };
89 
90 #define MAX_QUEUED_PACKETS 6
91 MEMB(packet_memb, struct queued_packet, MAX_QUEUED_PACKETS);
92 LIST(queued_packet_list);
93 
94 static struct ctimer transmit_timer;
95 
96 static uint8_t rdc_is_transmitting;
97 
98 static void packet_sent(void *ptr, int status, int num_transmissions);
99 
100 /*---------------------------------------------------------------------------*/
101 static clock_time_t
102 default_timebase(void)
103 {
104  clock_time_t time;
105  /* The retransmission time must be proportional to the channel
106  check interval of the underlying radio duty cycling layer. */
107  time = NETSTACK_RDC.channel_check_interval();
108 
109  /* If the radio duty cycle has no channel check interval (i.e., it
110  does not turn the radio off), we make the retransmission time
111  proportional to the configured MAC channel check rate. */
112  if(time == 0) {
113  time = CLOCK_SECOND / NETSTACK_RDC_CHANNEL_CHECK_RATE;
114  }
115  return time;
116 }
117 /*---------------------------------------------------------------------------*/
118 static void
119 transmit_queued_packet(void *ptr)
120 {
121  /* struct queued_packet *q = ptr;*/
122  struct queued_packet *q;
123 
124  /* Don't transmit a packet if the RDC is still transmitting the
125  previous one. */
126  if(rdc_is_transmitting) {
127  return;
128  }
129 
130  // printf("q %d\n", list_length(queued_packet_list));
131 
132  q = list_head(queued_packet_list);
133 
134  if(q != NULL) {
135  queuebuf_to_packetbuf(q->buf);
136  PRINTF("csma: sending number %d %p, queue len %d\n", q->transmissions, q,
137  list_length(queued_packet_list));
138  // printf("s %d\n", packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[0]);
139  rdc_is_transmitting = 1;
140  NETSTACK_RDC.send(packet_sent, q);
141  }
142 }
143 /*---------------------------------------------------------------------------*/
144 static void
145 start_transmission_timer(void)
146 {
147  PRINTF("csma: start_transmission_timer, queue len %d\n",
148  list_length(queued_packet_list));
149  if(list_length(queued_packet_list) > 0) {
150  if(ctimer_expired(&transmit_timer)) {
151  ctimer_set(&transmit_timer, 0,
152  transmit_queued_packet, NULL);
153  }
154  }
155 }
156 /*---------------------------------------------------------------------------*/
157 static void
158 free_queued_packet(void)
159 {
160  struct queued_packet *q;
161 
162  // printf("q %d\n", list_length(queued_packet_list));
163 
164  q = list_head(queued_packet_list);
165 
166  if(q != NULL) {
167  queuebuf_free(q->buf);
168  list_remove(queued_packet_list, q);
169  memb_free(&packet_memb, q);
170  PRINTF("csma: free_queued_packet, queue length %d\n",
171  list_length(queued_packet_list));
172  if(list_length(queued_packet_list) > 0) {
173  ctimer_set(&transmit_timer, default_timebase(), transmit_queued_packet, NULL);
174  }
175  }
176 }
177 /*---------------------------------------------------------------------------*/
178 static void
179 packet_sent(void *ptr, int status, int num_transmissions)
180 {
181  struct queued_packet *q = ptr;
182  clock_time_t time = 0;
183  mac_callback_t sent;
184  void *cptr;
185  int num_tx;
186  int backoff_transmissions;
187 
188  rdc_is_transmitting = 0;
189 
190  switch(status) {
191  case MAC_TX_OK:
192  case MAC_TX_NOACK:
193  q->transmissions++;
194  break;
195  case MAC_TX_COLLISION:
196  q->collisions++;
197  break;
198  case MAC_TX_DEFERRED:
199  q->deferrals++;
200  break;
201  }
202 
203  sent = q->sent;
204  cptr = q->cptr;
205  num_tx = q->transmissions;
206 
207  if(status == MAC_TX_COLLISION ||
208  status == MAC_TX_NOACK) {
209 
210  /* If the transmission was not performed because of a collision or
211  noack, we must retransmit the packet. */
212 
213  switch(status) {
214  case MAC_TX_COLLISION:
215  PRINTF("csma: rexmit collision %d\n", q->transmissions);
216  break;
217  case MAC_TX_NOACK:
218  PRINTF("csma: rexmit noack %d\n", q->transmissions);
219  break;
220  default:
221  PRINTF("csma: rexmit err %d, %d\n", status, q->transmissions);
222  }
223 
224  /* The retransmission time must be proportional to the channel
225  check interval of the underlying radio duty cycling layer. */
226  time = default_timebase();
227 
228  /* The retransmission time uses a linear backoff so that the
229  interval between the transmissions increase with each
230  retransmit. */
231  backoff_transmissions = q->transmissions + 1;
232 
233  /* Clamp the number of backoffs so that we don't get a too long
234  timeout here, since that will delay all packets in the
235  queue. */
236  if(backoff_transmissions > 3) {
237  backoff_transmissions = 3;
238  }
239  time = time + (random_rand() % (backoff_transmissions * time));
240 
241  if(q->transmissions < q->max_transmissions) {
242  PRINTF("csma: retransmitting with time %lu %p\n", time, q);
243  ctimer_set(&transmit_timer, time,
244  transmit_queued_packet, NULL);
245 
246  /* This is needed to correctly attribute energy that we spent
247  transmitting this packet. */
248  queuebuf_update_attr_from_packetbuf(q->buf);
249 
250  } else {
251  PRINTF("csma: drop with status %d after %d transmissions, %d collisions\n",
252  status, q->transmissions, q->collisions);
253  /* queuebuf_to_packetbuf(q->buf);*/
254  free_queued_packet();
255  mac_call_sent_callback(sent, cptr, status, num_tx);
256  }
257  } else {
258  if(status == MAC_TX_OK) {
259  PRINTF("csma: rexmit ok %d\n", q->transmissions);
260  } else {
261  PRINTF("csma: rexmit failed %d: %d\n", q->transmissions, status);
262  }
263  /* queuebuf_to_packetbuf(q->buf);*/
264  free_queued_packet();
265  mac_call_sent_callback(sent, cptr, status, num_tx);
266  }
267 }
268 /*---------------------------------------------------------------------------*/
269 static void
270 send_packet(mac_callback_t sent, void *ptr)
271 {
272  struct queued_packet *q;
273  static uint16_t seqno;
274 
275  packetbuf_set_attr(PACKETBUF_ATTR_MAC_SEQNO, seqno++);
276 
277  /* If the packet is a broadcast, do not allocate a queue
278  entry. Instead, just send it out. */
279  if(!rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
280  &rimeaddr_null)) {
281 
282  /* Remember packet for later. */
283  q = memb_alloc(&packet_memb);
284  if(q != NULL) {
285  q->buf = queuebuf_new_from_packetbuf();
286  if(q->buf != NULL) {
287  if(packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS) == 0) {
288  /* Use default configuration for max transmissions */
289  q->max_transmissions = CSMA_MAX_MAC_TRANSMISSIONS;
290  } else {
291  q->max_transmissions =
292  packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS);
293  }
294  q->transmissions = 0;
295  q->collisions = 0;
296  q->deferrals = 0;
297  q->sent = sent;
298  q->cptr = ptr;
299  if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) ==
300  PACKETBUF_ATTR_PACKET_TYPE_ACK) {
301  list_push(queued_packet_list, q);
302  } else {
303  list_add(queued_packet_list, q);
304  }
305  start_transmission_timer();
306  return;
307  }
308  memb_free(&packet_memb, q);
309  PRINTF("csma: could not allocate queuebuf, will drop if collision or noack\n");
310  }
311  PRINTF("csma: could not allocate memb, will drop if collision or noack\n");
312  } else {
313  PRINTF("csma: send broadcast (%d) or without retransmissions (%d)\n",
314  !rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
315  &rimeaddr_null),
316  packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS));
317  }
318  NETSTACK_RDC.send(sent, ptr);
319 }
320 /*---------------------------------------------------------------------------*/
321 static void
322 input_packet(void)
323 {
324  PRINTF("csma: got packet\n");
325  NETSTACK_NETWORK.input();
326 }
327 /*---------------------------------------------------------------------------*/
328 static int
329 on(void)
330 {
331  return NETSTACK_RDC.on();
332 }
333 /*---------------------------------------------------------------------------*/
334 static int
335 off(int keep_radio_on)
336 {
337  return NETSTACK_RDC.off(keep_radio_on);
338 }
339 /*---------------------------------------------------------------------------*/
340 static unsigned short
341 channel_check_interval(void)
342 {
343  if(NETSTACK_RDC.channel_check_interval) {
344  return NETSTACK_RDC.channel_check_interval();
345  }
346  return 0;
347 }
348 /*---------------------------------------------------------------------------*/
349 static void
350 init(void)
351 {
352  memb_init(&packet_memb);
353  rdc_is_transmitting = 0;
354 }
355 /*---------------------------------------------------------------------------*/
356 const struct mac_driver csma_driver = {
357  "CSMA",
358  init,
359  send_packet,
360  input_packet,
361  on,
362  off,
364 };
365 /*---------------------------------------------------------------------------*/