Contiki 2.6

runicast.c

Go to the documentation of this file.
00001 /**
00002  * \addtogroup rimerunicast
00003  * @{
00004  */
00005 
00006 
00007 /*
00008  * Copyright (c) 2006, Swedish Institute of Computer Science.
00009  * All rights reserved.
00010  *
00011  * Redistribution and use in source and binary forms, with or without
00012  * modification, are permitted provided that the following conditions
00013  * are met:
00014  * 1. Redistributions of source code must retain the above copyright
00015  *    notice, this list of conditions and the following disclaimer.
00016  * 2. Redistributions in binary form must reproduce the above copyright
00017  *    notice, this list of conditions and the following disclaimer in the
00018  *    documentation and/or other materials provided with the distribution.
00019  * 3. Neither the name of the Institute nor the names of its contributors
00020  *    may be used to endorse or promote products derived from this software
00021  *    without specific prior written permission.
00022  *
00023  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
00024  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00025  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00026  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
00027  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00028  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00029  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00030  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00032  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00033  * SUCH DAMAGE.
00034  *
00035  * This file is part of the Contiki operating system.
00036  *
00037  * $Id: runicast.c,v 1.12 2010/03/26 12:29:29 nifi Exp $
00038  */
00039 
00040 /**
00041  * \file
00042  *         Reliable unicast
00043  * \author
00044  *         Adam Dunkels <adam@sics.se>
00045  */
00046 
00047 #include "net/rime/runicast.h"
00048 #include "net/rime.h"
00049 #include <string.h>
00050 
00051 
00052 #ifdef RUNICAST_CONF_REXMIT_TIME
00053 #define REXMIT_TIME RUNICAST_CONF_REXMIT_TIME
00054 #else /* RUNICAST_CONF_REXMIT_TIME */
00055 #define REXMIT_TIME CLOCK_SECOND
00056 #endif /* RUNICAST_CONF_REXMIT_TIME */
00057 
00058 static const struct packetbuf_attrlist attributes[] =
00059   {
00060     RUNICAST_ATTRIBUTES
00061     PACKETBUF_ATTR_LAST
00062   };
00063 
00064 #define DEBUG 0
00065 #if DEBUG
00066 #include <stdio.h>
00067 #define PRINTF(...) printf(__VA_ARGS__)
00068 #else
00069 #define PRINTF(...)
00070 #endif
00071 
00072 /*---------------------------------------------------------------------------*/
00073 static void
00074 sent_by_stunicast(struct stunicast_conn *stunicast, int status, int num_tx)
00075 {
00076   struct runicast_conn *c = (struct runicast_conn *)stunicast;
00077 
00078   PRINTF("runicast: sent_by_stunicast c->rxmit %d num_tx %d\n",
00079          c->rxmit, num_tx);
00080 
00081   /* Only process data packets, not ACKs. */
00082   if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) == PACKETBUF_ATTR_PACKET_TYPE_DATA) {
00083     
00084     c->rxmit += 1;
00085     
00086     if(c->rxmit != 0) {
00087       RIMESTATS_ADD(rexmit);
00088       PRINTF("%d.%d: runicast: sent_by_stunicast packet %u (%u) resent %u\n",
00089              rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
00090              packetbuf_attr(PACKETBUF_ATTR_PACKET_ID),
00091              c->sndnxt, c->rxmit);
00092     }
00093     if(c->rxmit >= c->max_rxmit) {
00094       RIMESTATS_ADD(timedout);
00095       c->is_tx = 0;
00096       stunicast_cancel(&c->c);
00097       if(c->u->timedout) {
00098         c->u->timedout(c, stunicast_receiver(&c->c), c->rxmit);
00099       }
00100       c->rxmit = 0;
00101       PRINTF("%d.%d: runicast: packet %d timed out\n",
00102              rimeaddr_node_addr.u8[0],rimeaddr_node_addr.u8[1],
00103              c->sndnxt);
00104       c->sndnxt = (c->sndnxt + 1) % (1 << RUNICAST_PACKET_ID_BITS);
00105     } else {
00106 //      int shift;
00107       
00108 //      shift = c->rxmit > 4? 4: c->rxmit;
00109 //      stunicast_set_timer(&c->c, (REXMIT_TIME) << shift);
00110     }
00111   }
00112 }
00113 /*---------------------------------------------------------------------------*/
00114 static void
00115 recv_from_stunicast(struct stunicast_conn *stunicast, const rimeaddr_t *from)
00116 {
00117   struct runicast_conn *c = (struct runicast_conn *)stunicast;
00118   /*  struct runicast_hdr *hdr = packetbuf_dataptr();*/
00119 
00120   PRINTF("%d.%d: runicast: recv_from_stunicast from %d.%d type %d seqno %d\n",
00121          rimeaddr_node_addr.u8[0],rimeaddr_node_addr.u8[1],
00122          from->u8[0], from->u8[1],
00123          packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE),
00124          packetbuf_attr(PACKETBUF_ATTR_PACKET_ID));
00125 
00126   if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) ==
00127      PACKETBUF_ATTR_PACKET_TYPE_ACK) {
00128       PRINTF("%d.%d: runicast: got ACK from %d.%d, seqno %d (%d)\n",
00129              rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
00130              from->u8[0], from->u8[1],
00131              packetbuf_attr(PACKETBUF_ATTR_PACKET_ID),
00132              c->sndnxt);
00133     if(packetbuf_attr(PACKETBUF_ATTR_PACKET_ID) == c->sndnxt) {
00134       RIMESTATS_ADD(ackrx);
00135       PRINTF("%d.%d: runicast: ACKed %d\n",
00136              rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
00137              packetbuf_attr(PACKETBUF_ATTR_PACKET_ID));
00138       c->sndnxt = (c->sndnxt + 1) % (1 << RUNICAST_PACKET_ID_BITS);
00139       c->is_tx = 0;
00140       stunicast_cancel(&c->c);
00141       if(c->u->sent != NULL) {
00142         c->u->sent(c, stunicast_receiver(&c->c), c->rxmit);
00143       }
00144     } else {
00145       PRINTF("%d.%d: runicast: received bad ACK %d for %d\n",
00146              rimeaddr_node_addr.u8[0],rimeaddr_node_addr.u8[1],
00147              packetbuf_attr(PACKETBUF_ATTR_PACKET_ID),
00148              c->sndnxt);
00149       RIMESTATS_ADD(badackrx);
00150     }
00151   } else if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) ==
00152             PACKETBUF_ATTR_PACKET_TYPE_DATA) {
00153     /*    int send_ack = 1;*/
00154     uint16_t packet_seqno;
00155     struct queuebuf *q;
00156 
00157     RIMESTATS_ADD(reliablerx);
00158 
00159     PRINTF("%d.%d: runicast: got packet %d\n",
00160            rimeaddr_node_addr.u8[0],rimeaddr_node_addr.u8[1],
00161            packetbuf_attr(PACKETBUF_ATTR_PACKET_ID));
00162 
00163     packet_seqno = packetbuf_attr(PACKETBUF_ATTR_PACKET_ID);
00164 
00165     /*    packetbuf_hdrreduce(sizeof(struct runicast_hdr));*/
00166 
00167     q = queuebuf_new_from_packetbuf();
00168     if(q != NULL) {
00169       PRINTF("%d.%d: runicast: Sending ACK to %d.%d for %d\n",
00170              rimeaddr_node_addr.u8[0],rimeaddr_node_addr.u8[1],
00171              from->u8[0], from->u8[1],
00172              packet_seqno);
00173       packetbuf_clear();
00174       /*    packetbuf_hdralloc(sizeof(struct runicast_hdr));
00175             hdr = packetbuf_hdrptr();
00176             hdr->type = TYPE_ACK;
00177             hdr->seqno = packet_seqno;*/
00178       packetbuf_set_attr(PACKETBUF_ATTR_PACKET_TYPE, PACKETBUF_ATTR_PACKET_TYPE_ACK);
00179       packetbuf_set_attr(PACKETBUF_ATTR_PACKET_ID, packet_seqno);
00180       stunicast_send(&c->c, from);
00181       RIMESTATS_ADD(acktx);
00182 
00183       queuebuf_to_packetbuf(q);
00184       queuebuf_free(q);
00185     } else {
00186       PRINTF("%d.%d: runicast: could not send ACK to %d.%d for %d: no queued buffers\n",
00187              rimeaddr_node_addr.u8[0],rimeaddr_node_addr.u8[1],
00188              from->u8[0], from->u8[1],
00189              packet_seqno);
00190     }
00191     if(c->u->recv != NULL) {
00192       c->u->recv(c, from, packet_seqno);
00193     }
00194   }
00195 }
00196 /*---------------------------------------------------------------------------*/
00197 static const struct stunicast_callbacks runicast = {recv_from_stunicast,
00198                                                     sent_by_stunicast};
00199 /*---------------------------------------------------------------------------*/
00200 void
00201 runicast_open(struct runicast_conn *c, uint16_t channel,
00202           const struct runicast_callbacks *u)
00203 {
00204   stunicast_open(&c->c, channel, &runicast);
00205   channel_set_attributes(channel, attributes);
00206   c->u = u;
00207   c->is_tx = 0;
00208   c->rxmit = 0;
00209   c->sndnxt = 0;
00210 }
00211 /*---------------------------------------------------------------------------*/
00212 void
00213 runicast_close(struct runicast_conn *c)
00214 {
00215   stunicast_close(&c->c);
00216 }
00217 /*---------------------------------------------------------------------------*/
00218 uint8_t
00219 runicast_is_transmitting(struct runicast_conn *c)
00220 {
00221   return c->is_tx;
00222 }
00223 /*---------------------------------------------------------------------------*/
00224 int
00225 runicast_send(struct runicast_conn *c, const rimeaddr_t *receiver,
00226               uint8_t max_retransmissions)
00227 {
00228   int ret;
00229   if(runicast_is_transmitting(c)) {
00230     PRINTF("%d.%d: runicast: already transmitting\n",
00231         rimeaddr_node_addr.u8[0],rimeaddr_node_addr.u8[1]);
00232     return 0;
00233   }
00234   packetbuf_set_attr(PACKETBUF_ATTR_RELIABLE, 1);
00235   packetbuf_set_attr(PACKETBUF_ATTR_PACKET_TYPE, PACKETBUF_ATTR_PACKET_TYPE_DATA);
00236   packetbuf_set_attr(PACKETBUF_ATTR_PACKET_ID, c->sndnxt);
00237   packetbuf_set_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS, 3);
00238   c->max_rxmit = max_retransmissions;
00239   c->rxmit = 0;
00240   c->is_tx = 1;
00241   RIMESTATS_ADD(reliabletx);
00242   PRINTF("%d.%d: runicast: sending packet %d\n",
00243          rimeaddr_node_addr.u8[0],rimeaddr_node_addr.u8[1],
00244          c->sndnxt);
00245   ret = stunicast_send_stubborn(&c->c, receiver, REXMIT_TIME);
00246   if(!ret) {
00247     c->is_tx = 0;
00248   }
00249   return ret;
00250 }
00251 /*---------------------------------------------------------------------------*/
00252 /** @} */