csma.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2010, Swedish Institute of Computer Science.
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the Institute nor the names of its contributors
00014  *    may be used to endorse or promote products derived from this software
00015  *    without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00027  * SUCH DAMAGE.
00028  *
00029  * This file is part of the Contiki operating system.
00030  *
00031  * $Id: csma.c,v 1.27 2011/01/25 14:24:38 adamdunkels Exp $
00032  */
00033 
00034 /**
00035  * \file
00036  *         A Carrier Sense Multiple Access (CSMA) MAC layer
00037  * \author
00038  *         Adam Dunkels <adam@sics.se>
00039  */
00040 
00041 #include "net/mac/csma.h"
00042 #include "net/packetbuf.h"
00043 #include "net/queuebuf.h"
00044 
00045 #include "sys/ctimer.h"
00046 
00047 #include "lib/random.h"
00048 
00049 #include "net/netstack.h"
00050 
00051 #include "lib/list.h"
00052 #include "lib/memb.h"
00053 
00054 #include <string.h>
00055 
00056 #include <stdio.h>
00057 
00058 #define DEBUG 0
00059 #if DEBUG
00060 #include <stdio.h>
00061 #define PRINTF(...) printf(__VA_ARGS__)
00062 #else /* DEBUG */
00063 #define PRINTF(...)
00064 #endif /* DEBUG */
00065 
00066 #ifndef CSMA_MAX_MAC_TRANSMISSIONS
00067 #ifdef CSMA_CONF_MAX_MAC_TRANSMISSIONS
00068 #define CSMA_MAX_MAC_TRANSMISSIONS CSMA_CONF_MAX_MAC_TRANSMISSIONS
00069 #else
00070 #define CSMA_MAX_MAC_TRANSMISSIONS 3
00071 #endif /* CSMA_CONF_MAX_MAC_TRANSMISSIONS */
00072 #endif /* CSMA_MAX_MAC_TRANSMISSIONS */
00073 
00074 #if CSMA_MAX_MAC_TRANSMISSIONS < 1
00075 #error CSMA_CONF_MAX_MAC_TRANSMISSIONS must be at least 1.
00076 #error Change CSMA_CONF_MAX_MAC_TRANSMISSIONS in contiki-conf.h or in your Makefile.
00077 #endif /* CSMA_CONF_MAX_MAC_TRANSMISSIONS < 1 */
00078 
00079 struct queued_packet {
00080   struct queued_packet *next;
00081   struct queuebuf *buf;
00082   /*  struct ctimer retransmit_timer;*/
00083   mac_callback_t sent;
00084   void *cptr;
00085   uint8_t transmissions, max_transmissions;
00086   uint8_t collisions, deferrals;
00087 };
00088 
00089 #define MAX_QUEUED_PACKETS 6
00090 MEMB(packet_memb, struct queued_packet, MAX_QUEUED_PACKETS);
00091 LIST(queued_packet_list);
00092 
00093 static struct ctimer transmit_timer;
00094 
00095 static uint8_t rdc_is_transmitting;
00096 
00097 static void packet_sent(void *ptr, int status, int num_transmissions);
00098 
00099 /*---------------------------------------------------------------------------*/
00100 static clock_time_t
00101 default_timebase(void)
00102 {
00103   clock_time_t time;
00104   /* The retransmission time must be proportional to the channel
00105      check interval of the underlying radio duty cycling layer. */
00106   time = NETSTACK_RDC.channel_check_interval();
00107 
00108   /* If the radio duty cycle has no channel check interval (i.e., it
00109      does not turn the radio off), we make the retransmission time
00110      proportional to the configured MAC channel check rate. */
00111   if(time == 0) {
00112     time = CLOCK_SECOND / NETSTACK_RDC_CHANNEL_CHECK_RATE;
00113   }
00114   return time;
00115 }
00116 /*---------------------------------------------------------------------------*/
00117 static void
00118 transmit_queued_packet(void *ptr)
00119 {
00120   /*  struct queued_packet *q = ptr;*/
00121   struct queued_packet *q;
00122 
00123   /* Don't transmit a packet if the RDC is still transmitting the
00124      previous one. */
00125   if(rdc_is_transmitting) {
00126     return;
00127   }
00128   
00129   //  printf("q %d\n", list_length(queued_packet_list));
00130 
00131   q = list_head(queued_packet_list);
00132 
00133   if(q != NULL) {
00134     queuebuf_to_packetbuf(q->buf);
00135     PRINTF("csma: sending number %d %p, queue len %d\n", q->transmissions, q,
00136            list_length(queued_packet_list));
00137     //    printf("s %d\n", packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[0]);
00138     rdc_is_transmitting = 1;
00139     NETSTACK_RDC.send(packet_sent, q);
00140   }
00141 }
00142 /*---------------------------------------------------------------------------*/
00143 static void
00144 start_transmission_timer(void)
00145 {
00146   PRINTF("csma: start_transmission_timer, queue len %d\n",
00147          list_length(queued_packet_list));
00148   if(list_length(queued_packet_list) > 0) {
00149     if(ctimer_expired(&transmit_timer)) {
00150       ctimer_set(&transmit_timer, 0,
00151                  transmit_queued_packet, NULL);
00152     }
00153   }
00154 }
00155 /*---------------------------------------------------------------------------*/
00156 static void
00157 free_queued_packet(void)
00158 {
00159   struct queued_packet *q;
00160 
00161   //  printf("q %d\n", list_length(queued_packet_list));
00162 
00163   q = list_head(queued_packet_list);
00164 
00165   if(q != NULL) {
00166     queuebuf_free(q->buf);
00167     list_remove(queued_packet_list, q);
00168     memb_free(&packet_memb, q);
00169     PRINTF("csma: free_queued_packet, queue length %d\n",
00170            list_length(queued_packet_list));
00171     if(list_length(queued_packet_list) > 0) {
00172       ctimer_set(&transmit_timer, default_timebase(), transmit_queued_packet, NULL);
00173     }
00174   }
00175 }
00176 /*---------------------------------------------------------------------------*/
00177 static void
00178 packet_sent(void *ptr, int status, int num_transmissions)
00179 {
00180   struct queued_packet *q = ptr;
00181   clock_time_t time = 0;
00182   mac_callback_t sent;
00183   void *cptr;
00184   int num_tx;
00185   int backoff_transmissions;
00186 
00187   rdc_is_transmitting = 0;
00188   
00189   switch(status) {
00190   case MAC_TX_OK:
00191   case MAC_TX_NOACK:
00192     q->transmissions++;
00193     break;
00194   case MAC_TX_COLLISION:
00195     q->collisions++;
00196     break;
00197   case MAC_TX_DEFERRED:
00198     q->deferrals++;
00199     break;
00200   }
00201 
00202   sent = q->sent;
00203   cptr = q->cptr;
00204   num_tx = q->transmissions;
00205   
00206   if(status == MAC_TX_COLLISION ||
00207      status == MAC_TX_NOACK) {
00208 
00209     /* If the transmission was not performed because of a collision or
00210        noack, we must retransmit the packet. */
00211     
00212     switch(status) {
00213     case MAC_TX_COLLISION:
00214       PRINTF("csma: rexmit collision %d\n", q->transmissions);
00215       break;
00216     case MAC_TX_NOACK:
00217       PRINTF("csma: rexmit noack %d\n", q->transmissions);
00218       break;
00219     default:
00220       PRINTF("csma: rexmit err %d, %d\n", status, q->transmissions);
00221     }
00222 
00223     /* The retransmission time must be proportional to the channel
00224        check interval of the underlying radio duty cycling layer. */
00225     time = default_timebase();
00226 
00227     /* The retransmission time uses a linear backoff so that the
00228        interval between the transmissions increase with each
00229        retransmit. */
00230     backoff_transmissions = q->transmissions + 1;
00231 
00232     /* Clamp the number of backoffs so that we don't get a too long
00233        timeout here, since that will delay all packets in the
00234        queue. */
00235     if(backoff_transmissions > 3) {
00236       backoff_transmissions = 3;
00237     }
00238     time = time + (random_rand() % (backoff_transmissions * time));
00239 
00240     if(q->transmissions < q->max_transmissions) {
00241       PRINTF("csma: retransmitting with time %lu %p\n", time, q);
00242       ctimer_set(&transmit_timer, time,
00243                  transmit_queued_packet, NULL);
00244     } else {
00245       PRINTF("csma: drop with status %d after %d transmissions, %d collisions\n",
00246              status, q->transmissions, q->collisions);
00247       /*      queuebuf_to_packetbuf(q->buf);*/
00248       free_queued_packet();
00249       mac_call_sent_callback(sent, cptr, status, num_tx);
00250     }
00251   } else {
00252     if(status == MAC_TX_OK) {
00253       PRINTF("csma: rexmit ok %d\n", q->transmissions);
00254     } else {
00255       PRINTF("csma: rexmit failed %d: %d\n", q->transmissions, status);
00256     }
00257     /*    queuebuf_to_packetbuf(q->buf);*/
00258     free_queued_packet();
00259     mac_call_sent_callback(sent, cptr, status, num_tx);
00260   }
00261 }
00262 /*---------------------------------------------------------------------------*/
00263 static void
00264 send_packet(mac_callback_t sent, void *ptr)
00265 {
00266   struct queued_packet *q;
00267   static uint16_t seqno;
00268   
00269   packetbuf_set_attr(PACKETBUF_ATTR_MAC_SEQNO, seqno++);
00270   
00271   /* If the packet is a broadcast, do not allocate a queue
00272      entry. Instead, just send it out.  */
00273   if(!rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
00274                    &rimeaddr_null)) {
00275 
00276     /* Remember packet for later. */
00277     q = memb_alloc(&packet_memb);
00278     if(q != NULL) {
00279       q->buf = queuebuf_new_from_packetbuf();
00280       if(q->buf != NULL) {
00281         if(packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS) == 0) {
00282           /* Use default configuration for max transmissions */
00283           q->max_transmissions = CSMA_MAX_MAC_TRANSMISSIONS;
00284         } else {
00285           q->max_transmissions =
00286             packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS);
00287         }
00288         q->transmissions = 0;
00289         q->collisions = 0;
00290         q->deferrals = 0;
00291         q->sent = sent;
00292         q->cptr = ptr;
00293         if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) ==
00294            PACKETBUF_ATTR_PACKET_TYPE_ACK) {
00295           list_push(queued_packet_list, q);
00296         } else {
00297           list_add(queued_packet_list, q);
00298         }
00299         start_transmission_timer();
00300         return;
00301       }
00302       memb_free(&packet_memb, q);
00303       PRINTF("csma: could not allocate queuebuf, will drop if collision or noack\n");
00304     }
00305     PRINTF("csma: could not allocate memb, will drop if collision or noack\n");
00306   } else {
00307     PRINTF("csma: send broadcast (%d) or without retransmissions (%d)\n",
00308            !rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
00309                          &rimeaddr_null),
00310            packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS));
00311   }
00312   NETSTACK_RDC.send(sent, ptr);
00313 }
00314 /*---------------------------------------------------------------------------*/
00315 static void
00316 input_packet(void)
00317 {
00318   NETSTACK_NETWORK.input();
00319 }
00320 /*---------------------------------------------------------------------------*/
00321 static int
00322 on(void)
00323 {
00324   return NETSTACK_RDC.on();
00325 }
00326 /*---------------------------------------------------------------------------*/
00327 static int
00328 off(int keep_radio_on)
00329 {
00330   return NETSTACK_RDC.off(keep_radio_on);
00331 }
00332 /*---------------------------------------------------------------------------*/
00333 static unsigned short
00334 channel_check_interval(void)
00335 {
00336   if(NETSTACK_RDC.channel_check_interval) {
00337     return NETSTACK_RDC.channel_check_interval();
00338   }
00339   return 0;
00340 }
00341 /*---------------------------------------------------------------------------*/
00342 static void
00343 init(void)
00344 {
00345   memb_init(&packet_memb);
00346   rdc_is_transmitting = 0;
00347 }
00348 /*---------------------------------------------------------------------------*/
00349 const struct mac_driver csma_driver = {
00350   "CSMA",
00351   init,
00352   send_packet,
00353   input_packet,
00354   on,
00355   off,
00356   channel_check_interval,
00357 };
00358 /*---------------------------------------------------------------------------*/

Generated on Mon Apr 11 14:23:29 2011 for Contiki 2.5 by  doxygen 1.6.1