Contiki 2.6

rudolph0.c

Go to the documentation of this file.
00001 /**
00002  * \addtogroup rudolph0
00003  * @{
00004  */
00005 
00006 /*
00007  * Copyright (c) 2007, Swedish Institute of Computer Science.
00008  * All rights reserved.
00009  *
00010  * Redistribution and use in source and binary forms, with or without
00011  * modification, are permitted provided that the following conditions
00012  * are met:
00013  * 1. Redistributions of source code must retain the above copyright
00014  *    notice, this list of conditions and the following disclaimer.
00015  * 2. Redistributions in binary form must reproduce the above copyright
00016  *    notice, this list of conditions and the following disclaimer in the
00017  *    documentation and/or other materials provided with the distribution.
00018  * 3. Neither the name of the Institute nor the names of its contributors
00019  *    may be used to endorse or promote products derived from this software
00020  *    without specific prior written permission.
00021  *
00022  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
00023  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00024  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00025  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
00026  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00027  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00028  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00029  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00031  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00032  * SUCH DAMAGE.
00033  *
00034  * This file is part of the Contiki operating system.
00035  *
00036  * $Id: rudolph0.c,v 1.11 2009/03/12 21:58:21 adamdunkels Exp $
00037  */
00038 
00039 /**
00040  * \file
00041  *         Rudolph0: a simple block data flooding protocol
00042  * \author
00043  *         Adam Dunkels <adam@sics.se>
00044  */
00045 
00046 #include <stddef.h> /* for offsetof */
00047 
00048 #include "net/rime.h"
00049 #include "net/rime/rudolph0.h"
00050 
00051 #define STEADY_TIME CLOCK_SECOND * 2
00052 
00053 #define DEFAULT_SEND_INTERVAL CLOCK_SECOND / 2
00054 enum {
00055   TYPE_DATA,
00056   TYPE_NACK,
00057 };
00058 
00059 enum {
00060   STATE_RECEIVER,
00061   STATE_SENDER,
00062 };
00063 
00064 #define VERSION_LT(a, b) ((signed char)((a) - (b)) < 0)
00065 
00066 #define DEBUG 0
00067 #if DEBUG
00068 #include <stdio.h>
00069 #define PRINTF(...) printf(__VA_ARGS__)
00070 #else
00071 #define PRINTF(...)
00072 #endif
00073 
00074 /*---------------------------------------------------------------------------*/
00075 static void
00076 read_new_datapacket(struct rudolph0_conn *c)
00077 {
00078   int len = 0;
00079 
00080   if(c->cb->read_chunk) {
00081     len = c->cb->read_chunk(c, c->current.h.chunk * RUDOLPH0_DATASIZE,
00082                             c->current.data, RUDOLPH0_DATASIZE);
00083   }
00084   c->current.datalen = len;
00085 
00086   PRINTF("read_new_datapacket len %d\n", len);
00087 }
00088 /*---------------------------------------------------------------------------*/
00089 static void
00090 send_nack(struct rudolph0_conn *c)
00091 {
00092   struct rudolph0_hdr *hdr;
00093   packetbuf_clear();
00094   packetbuf_hdralloc(sizeof(struct rudolph0_hdr));
00095   hdr = packetbuf_hdrptr();
00096 
00097   hdr->type = TYPE_NACK;
00098   hdr->version = c->current.h.version;
00099   hdr->chunk = c->current.h.chunk;
00100 
00101   PRINTF("Sending nack for %d:%d\n", hdr->version, hdr->chunk);
00102   polite_send(&c->nackc, c->send_interval / 2, sizeof(struct rudolph0_hdr));
00103 }
00104 /*---------------------------------------------------------------------------*/
00105 static void
00106 sent(struct stbroadcast_conn *stbroadcast)
00107 {
00108   struct rudolph0_conn *c = (struct rudolph0_conn *)stbroadcast;
00109 
00110   if(c->current.datalen == RUDOLPH0_DATASIZE) {
00111     c->current.h.chunk++;
00112     PRINTF("Sending data chunk %d next time\n", c->current.h.chunk);
00113     read_new_datapacket(c);
00114   } else {
00115     stbroadcast_set_timer(&c->c, STEADY_TIME);
00116     PRINTF("Steady: Sending the same data chunk next time datalen %d, %d\n",
00117            c->current.datalen, RUDOLPH0_DATASIZE);
00118   }
00119 }
00120 /*---------------------------------------------------------------------------*/
00121 static void
00122 recv(struct stbroadcast_conn *stbroadcast)
00123 {
00124   struct rudolph0_conn *c = (struct rudolph0_conn *)stbroadcast;
00125   struct rudolph0_datapacket *p = packetbuf_dataptr();
00126 
00127   if(p->h.type == TYPE_DATA) {
00128     if(c->current.h.version != p->h.version) {
00129       PRINTF("rudolph0 new version %d\n", p->h.version);
00130       c->current.h.version = p->h.version;
00131       c->current.h.chunk = 0;
00132       c->cb->write_chunk(c, 0, RUDOLPH0_FLAG_NEWFILE, p->data, 0);
00133       if(p->h.chunk != 0) {
00134         send_nack(c);
00135       } else {
00136         c->cb->write_chunk(c, 0, RUDOLPH0_FLAG_NONE, p->data, p->datalen);
00137         c->current.h.chunk++;
00138       }
00139     } else if(p->h.version == c->current.h.version) {
00140       if(p->h.chunk == c->current.h.chunk) {
00141         PRINTF("received chunk %d\n", p->h.chunk);
00142         if(p->datalen < RUDOLPH0_DATASIZE) {
00143           c->cb->write_chunk(c, c->current.h.chunk * RUDOLPH0_DATASIZE,
00144                              RUDOLPH0_FLAG_LASTCHUNK, p->data, p->datalen);
00145         } else {
00146           c->cb->write_chunk(c, c->current.h.chunk * RUDOLPH0_DATASIZE,
00147                              RUDOLPH0_FLAG_NONE, p->data, p->datalen);
00148         }
00149         c->current.h.chunk++;
00150         
00151       } else if(p->h.chunk > c->current.h.chunk) {
00152         PRINTF("received chunk %d > %d, sending NACK\n", p->h.chunk, c->current.h.chunk);
00153         send_nack(c);
00154       }
00155     } else { /* p->h.version < c->current.h.version */
00156       /* Ignore packets with old version */
00157     }
00158   }
00159 }
00160 /*---------------------------------------------------------------------------*/
00161 static void
00162 recv_nack(struct polite_conn *polite)
00163 {
00164   struct rudolph0_conn *c = (struct rudolph0_conn *)
00165     ((char *)polite - offsetof(struct rudolph0_conn,
00166                              nackc));
00167   struct rudolph0_datapacket *p = packetbuf_dataptr();
00168 
00169   if(p->h.type == TYPE_NACK && c->state == STATE_SENDER) {
00170     if(p->h.version == c->current.h.version) {
00171       PRINTF("Reseting chunk to %d\n", p->h.chunk);
00172       c->current.h.chunk = p->h.chunk;
00173     } else {
00174       PRINTF("Wrong version, reseting chunk to 0\n");
00175       c->current.h.chunk = 0;
00176     }
00177     read_new_datapacket(c);
00178     stbroadcast_set_timer(&c->c, c->send_interval);
00179   }
00180 }
00181 /*---------------------------------------------------------------------------*/
00182 static const struct polite_callbacks polite = { recv_nack, 0, 0 };
00183 static const struct stbroadcast_callbacks stbroadcast = { recv, sent };
00184 /*---------------------------------------------------------------------------*/
00185 void
00186 rudolph0_open(struct rudolph0_conn *c, uint16_t channel,
00187               const struct rudolph0_callbacks *cb)
00188 {
00189   stbroadcast_open(&c->c, channel, &stbroadcast);
00190   polite_open(&c->nackc, channel + 1, &polite);
00191   c->cb = cb;
00192   c->current.h.version = 0;
00193   c->state = STATE_RECEIVER;
00194   c->send_interval = DEFAULT_SEND_INTERVAL;
00195 }
00196 /*---------------------------------------------------------------------------*/
00197 void
00198 rudolph0_close(struct rudolph0_conn *c)
00199 {
00200   stbroadcast_close(&c->c);
00201   polite_close(&c->nackc);
00202 }
00203 /*---------------------------------------------------------------------------*/
00204 void
00205 rudolph0_send(struct rudolph0_conn *c, clock_time_t send_interval)
00206 {
00207   c->state = STATE_SENDER;
00208   c->current.h.version++;
00209   c->current.h.version++;
00210   c->current.h.chunk = 0;
00211   c->current.h.type = TYPE_DATA;
00212   read_new_datapacket(c);
00213   packetbuf_reference(&c->current, sizeof(struct rudolph0_datapacket));
00214   c->send_interval = send_interval;
00215   stbroadcast_send_stubborn(&c->c, c->send_interval);
00216 }
00217 /*---------------------------------------------------------------------------*/
00218 void
00219 rudolph0_force_restart(struct rudolph0_conn *c)
00220 {
00221   c->current.h.chunk = 0;
00222   send_nack(c);
00223 }
00224 /*---------------------------------------------------------------------------*/
00225 void
00226 rudolph0_stop(struct rudolph0_conn *c)
00227 {
00228   stbroadcast_cancel(&c->c);
00229 }
00230 /*---------------------------------------------------------------------------*/
00231 int
00232 rudolph0_version(struct rudolph0_conn *c)
00233 {
00234   return c->current.h.version;
00235 }
00236 /*---------------------------------------------------------------------------*/
00237 void
00238 rudolph0_set_version(struct rudolph0_conn *c, int version)
00239 {
00240   c->current.h.version = version;
00241 }
00242 /*---------------------------------------------------------------------------*/
00243 /** @} */