Contiki 2.6

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