nullrdc.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: nullrdc.c,v 1.4 2010/11/23 18:11:00 nifi Exp $
00032  */
00033 
00034 /**
00035  * \file
00036  *         A null RDC implementation that uses framer for headers.
00037  * \author
00038  *         Adam Dunkels <adam@sics.se>
00039  *         Niclas Finne <nfi@sics.se>
00040  */
00041 
00042 #include "net/mac/nullrdc.h"
00043 #include "net/packetbuf.h"
00044 #include "net/netstack.h"
00045 #include <string.h>
00046 
00047 #define DEBUG 0
00048 #if DEBUG
00049 #include <stdio.h>
00050 #define PRINTF(...) printf(__VA_ARGS__)
00051 #else
00052 #define PRINTF(...)
00053 #endif
00054 
00055 #ifndef NULLRDC_802154_AUTOACK
00056 #ifdef NULLRDC_CONF_802154_AUTOACK
00057 #define NULLRDC_802154_AUTOACK NULLRDC_CONF_802154_AUTOACK
00058 #else
00059 #define NULLRDC_802154_AUTOACK 0
00060 #endif /* NULLRDC_CONF_802154_AUTOACK */
00061 #endif /* NULLRDC_802154_AUTOACK */
00062 
00063 #ifndef NULLRDC_802154_AUTOACK_HW
00064 #ifdef NULLRDC_CONF_802154_AUTOACK_HW
00065 #define NULLRDC_802154_AUTOACK_HW NULLRDC_CONF_802154_AUTOACK_HW
00066 #else
00067 #define NULLRDC_802154_AUTOACK_HW 0
00068 #endif /* NULLRDC_CONF_802154_AUTOACK_HW */
00069 #endif /* NULLRDC_802154_AUTOACK_HW */
00070 
00071 #if NULLRDC_802154_AUTOACK
00072 #include "sys/rtimer.h"
00073 #include "dev/watchdog.h"
00074 
00075 #define ACK_WAIT_TIME                      RTIMER_SECOND / 2500
00076 #define AFTER_ACK_DETECTED_WAIT_TIME       RTIMER_SECOND / 1500
00077 #define ACK_LEN 3
00078 #endif /* NULLRDC_802154_AUTOACK */
00079 
00080 #if NULLRDC_802154_AUTOACK || NULLRDC_802154_AUTOACK_HW
00081 struct seqno {
00082   rimeaddr_t sender;
00083   uint8_t seqno;
00084 };
00085 
00086 #ifdef NETSTACK_CONF_MAC_SEQNO_HISTORY
00087 #define MAX_SEQNOS NETSTACK_CONF_MAC_SEQNO_HISTORY
00088 #else /* NETSTACK_CONF_MAC_SEQNO_HISTORY */
00089 #define MAX_SEQNOS 16
00090 #endif /* NETSTACK_CONF_MAC_SEQNO_HISTORY */
00091 
00092 static struct seqno received_seqnos[MAX_SEQNOS];
00093 #endif /* NULLRDC_802154_AUTOACK || NULLRDC_802154_AUTOACK_HW */
00094 
00095 /*---------------------------------------------------------------------------*/
00096 static void
00097 send_packet(mac_callback_t sent, void *ptr)
00098 {
00099   int ret;
00100   packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &rimeaddr_node_addr);
00101 #if NULLRDC_802154_AUTOACK || NULLRDC_802154_AUTOACK_HW
00102   packetbuf_set_attr(PACKETBUF_ATTR_MAC_ACK, 1);
00103 #endif /* NULLRDC_802154_AUTOACK || NULLRDC_802154_AUTOACK_HW */
00104 
00105   if(NETSTACK_FRAMER.create() == 0) {
00106     /* Failed to allocate space for headers */
00107     PRINTF("nullrdc: send failed, too large header\n");
00108     ret = MAC_TX_ERR_FATAL;
00109   } else {
00110 
00111 #if NULLRDC_802154_AUTOACK
00112     int is_broadcast;
00113     uint8_t dsn;
00114     dsn = ((uint8_t *)packetbuf_hdrptr())[2] & 0xff;
00115 
00116     NETSTACK_RADIO.prepare(packetbuf_hdrptr(), packetbuf_totlen());
00117 
00118     is_broadcast = rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
00119                                 &rimeaddr_null);
00120 
00121     if(NETSTACK_RADIO.receiving_packet() ||
00122        (!is_broadcast && NETSTACK_RADIO.pending_packet())) {
00123 
00124       /* Currently receiving a packet over air or the radio has
00125          already received a packet that needs to be read before
00126          sending with auto ack. */
00127       ret = MAC_TX_COLLISION;
00128 
00129     } else {
00130       switch(NETSTACK_RADIO.transmit(packetbuf_totlen())) {
00131       case RADIO_TX_OK:
00132         if(is_broadcast) {
00133           ret = MAC_TX_OK;
00134         } else {
00135           rtimer_clock_t wt;
00136 
00137           /* Check for ack */
00138           wt = RTIMER_NOW();
00139           watchdog_periodic();
00140           while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + ACK_WAIT_TIME));
00141 
00142           ret = MAC_TX_NOACK;
00143           if(NETSTACK_RADIO.receiving_packet() ||
00144              NETSTACK_RADIO.pending_packet() ||
00145              NETSTACK_RADIO.channel_clear() == 0) {
00146             int len;
00147             uint8_t ackbuf[ACK_LEN];
00148 
00149             wt = RTIMER_NOW();
00150             watchdog_periodic();
00151             while(RTIMER_CLOCK_LT(RTIMER_NOW(),
00152                                   wt + AFTER_ACK_DETECTED_WAIT_TIME));
00153 
00154             if(NETSTACK_RADIO.pending_packet()) {
00155               len = NETSTACK_RADIO.read(ackbuf, ACK_LEN);
00156               if(len == ACK_LEN && ackbuf[2] == dsn) {
00157                 /* Ack received */
00158                 ret = MAC_TX_OK;
00159               } else {
00160                 /* Not an ack or ack not for us: collision */
00161                 ret = MAC_TX_COLLISION;
00162               }
00163             }
00164           }
00165         }
00166         break;
00167       case RADIO_TX_COLLISION:
00168         ret = MAC_TX_COLLISION;
00169         break;
00170       default:
00171         ret = MAC_TX_ERR;
00172         break;
00173       }
00174     }
00175 
00176 #else /* ! NULLRDC_802154_AUTOACK */
00177 
00178     switch(NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen())) {
00179     case RADIO_TX_OK:
00180       ret = MAC_TX_OK;
00181       break;
00182     case RADIO_TX_COLLISION:
00183       ret = MAC_TX_COLLISION;
00184       break;
00185     case RADIO_TX_NOACK:
00186       ret = MAC_TX_NOACK;
00187       break;
00188     default:
00189       ret = MAC_TX_ERR;
00190       break;
00191     }
00192 
00193 #endif /* ! NULLRDC_802154_AUTOACK */
00194   }
00195   mac_call_sent_callback(sent, ptr, ret, 1);
00196 }
00197 /*---------------------------------------------------------------------------*/
00198 static void
00199 packet_input(void)
00200 {
00201 #if NULLRDC_802154_AUTOACK
00202   if(packetbuf_datalen() == ACK_LEN) {
00203     /* Ignore ack packets */
00204     /* PRINTF("nullrdc: ignored ack\n"); */
00205   } else
00206 #endif /* NULLRDC_802154_AUTOACK */
00207   if(NETSTACK_FRAMER.parse() == 0) {
00208     PRINTF("nullrdc: failed to parse %u\n", packetbuf_datalen());
00209   } else {
00210 #if NULLRDC_802154_AUTOACK || NULLRDC_802154_AUTOACK_HW
00211     /* Check for duplicate packet by comparing the sequence number
00212        of the incoming packet with the last few ones we saw. */
00213     int i;
00214     for(i = 0; i < MAX_SEQNOS; ++i) {
00215       if(packetbuf_attr(PACKETBUF_ATTR_PACKET_ID) == received_seqnos[i].seqno &&
00216          rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_SENDER),
00217                       &received_seqnos[i].sender)) {
00218         /* Drop the packet. */
00219         PRINTF("nullrdc: drop duplicate link layer packet %u\n",
00220                packetbuf_attr(PACKETBUF_ATTR_PACKET_ID));
00221         return;
00222       }
00223     }
00224     for(i = MAX_SEQNOS - 1; i > 0; --i) {
00225       memcpy(&received_seqnos[i], &received_seqnos[i - 1],
00226              sizeof(struct seqno));
00227     }
00228     received_seqnos[0].seqno = packetbuf_attr(PACKETBUF_ATTR_PACKET_ID);
00229     rimeaddr_copy(&received_seqnos[0].sender,
00230                   packetbuf_addr(PACKETBUF_ADDR_SENDER));
00231 #endif /* NULLRDC_802154_AUTOACK */
00232     NETSTACK_MAC.input();
00233   }
00234 }
00235 /*---------------------------------------------------------------------------*/
00236 static int
00237 on(void)
00238 {
00239   return NETSTACK_RADIO.on();
00240 }
00241 /*---------------------------------------------------------------------------*/
00242 static int
00243 off(int keep_radio_on)
00244 {
00245   if(keep_radio_on) {
00246     return NETSTACK_RADIO.on();
00247   } else {
00248     return NETSTACK_RADIO.off();
00249   }
00250 }
00251 /*---------------------------------------------------------------------------*/
00252 static unsigned short
00253 channel_check_interval(void)
00254 {
00255   return 0;
00256 }
00257 /*---------------------------------------------------------------------------*/
00258 static void
00259 init(void)
00260 {
00261   on();
00262 }
00263 /*---------------------------------------------------------------------------*/
00264 const struct rdc_driver nullrdc_driver = {
00265   "nullrdc",
00266   init,
00267   send_packet,
00268   packet_input,
00269   on,
00270   off,
00271   channel_check_interval,
00272 };
00273 /*---------------------------------------------------------------------------*/

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