1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/sys/net/routing/rpl/trickle.c
2014-03-01 14:44:21 +01:00

263 lines
6.9 KiB
C

/**
* Trickle implementation
*
* Copyright (C) 2013 INRIA.
*
* This file is subject to the terms and conditions of the GNU Lesser General
* Public License. See the file LICENSE in the top level directory for more
* details.
*
* @ingroup rpl
* @{
* @file trickle.c
* @brief Trickle implementation
* @author Eric Engel <eric.engel@fu-berlin.de>
* @}
*/
#include <string.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "inttypes.h"
#include "trickle.h"
#include "rpl.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
/* thread stacks */
char timer_over_buf[TRICKLE_TIMER_STACKSIZE];
char interval_over_buf[TRICKLE_INTERVAL_STACKSIZE];
char dao_delay_over_buf[DAO_DELAY_STACKSIZE];
char routing_table_buf[RT_STACKSIZE];
int timer_over_pid;
int interval_over_pid;
int dao_delay_over_pid;
int rt_timer_over_pid;
bool ack_received;
uint8_t dao_counter;
uint8_t k;
uint32_t Imin;
uint8_t Imax;
uint32_t I;
uint32_t t;
uint16_t c;
vtimer_t trickle_t_timer;
vtimer_t trickle_I_timer;
vtimer_t dao_timer;
vtimer_t rt_timer;
timex_t t_time;
timex_t I_time;
timex_t dao_time;
timex_t rt_time;
void reset_trickletimer(void)
{
I = Imin;
c = 0;
/* start timer */
t = (I / 2) + (rand() % (I - (I / 2) + 1));
t_time = timex_set(0, t * 1000);
I_time = timex_set(0, I * 1000);
timex_normalize(&t_time);
timex_normalize(&I_time);
vtimer_remove(&trickle_t_timer);
vtimer_remove(&trickle_I_timer);
vtimer_set_wakeup(&trickle_t_timer, t_time, timer_over_pid);
vtimer_set_wakeup(&trickle_I_timer, I_time, interval_over_pid);
}
void init_trickle(void)
{
/* Create threads */
ack_received = true;
dao_counter = 0;
timer_over_pid = thread_create(timer_over_buf, TRICKLE_TIMER_STACKSIZE,
PRIORITY_MAIN - 1, CREATE_STACKTEST,
trickle_timer_over, "trickle_timer_over");
interval_over_pid = thread_create(interval_over_buf, TRICKLE_INTERVAL_STACKSIZE,
PRIORITY_MAIN - 1, CREATE_STACKTEST,
trickle_interval_over, "trickle_interval_over");
dao_delay_over_pid = thread_create(dao_delay_over_buf, DAO_DELAY_STACKSIZE,
PRIORITY_MAIN - 1, CREATE_STACKTEST,
dao_delay_over, "dao_delay_over");
rt_timer_over_pid = thread_create(routing_table_buf, RT_STACKSIZE,
PRIORITY_MAIN - 1, CREATE_STACKTEST,
rt_timer_over, "rt_timer_over");
}
void start_trickle(uint8_t DIOIntMin, uint8_t DIOIntDoubl,
uint8_t DIORedundancyConstant)
{
c = 0;
k = DIORedundancyConstant;
Imin = (1 << DIOIntMin);
Imax = DIOIntDoubl;
/* Eigentlich laut Spezifikation erste Bestimmung von I wie auskommentiert: */
/* I = Imin + ( rand() % ( (Imin << Imax) - Imin + 1 ) ); */
I = Imin + (rand() % (4 * Imin)) ;
t = (I / 2) + (rand() % (I - (I / 2) + 1));
t_time = timex_set(0, t * 1000);
timex_normalize(&t_time);
I_time = timex_set(0, I * 1000);
timex_normalize(&I_time);
vtimer_remove(&trickle_t_timer);
vtimer_remove(&trickle_I_timer);
vtimer_set_wakeup(&trickle_t_timer, t_time, timer_over_pid);
vtimer_set_wakeup(&trickle_I_timer, I_time, interval_over_pid);
}
void trickle_increment_counter(void)
{
/* call this function, when received DIO message */
c++;
}
void trickle_timer_over(void)
{
ipv6_addr_t mcast;
ipv6_addr_set_all_nodes_addr(&mcast);
while (1) {
thread_sleep();
/* Handle k=0 like k=infinity (according to RFC6206, section 6.5) */
if ((c < k) || (k == 0)) {
send_DIO(&mcast);
}
}
}
void trickle_interval_over(void)
{
while (1) {
thread_sleep();
I = I * 2;
DEBUG("TRICKLE new Interval %" PRIu32 "\n", I);
if (I == 0) {
puts("[WARNING] Interval was 0");
if (Imax == 0) {
puts("[WARNING] Imax == 0");
}
I = (Imin << Imax);
}
if (I > (Imin << Imax)) {
I = (Imin << Imax);
}
c = 0;
t = (I / 2) + (rand() % (I - (I / 2) + 1));
/* start timer */
t_time = timex_set(0, t * 1000);
timex_normalize(&t_time);
I_time = timex_set(0, I * 1000);
timex_normalize(&I_time);
vtimer_remove(&trickle_t_timer);
if (vtimer_set_wakeup(&trickle_t_timer, t_time, timer_over_pid) != 0) {
puts("[ERROR] setting Wakeup");
}
vtimer_remove(&trickle_I_timer);
if (vtimer_set_wakeup(&trickle_I_timer, I_time, interval_over_pid) != 0) {
puts("[ERROR] setting Wakeup");
}
}
}
void delay_dao(void)
{
dao_time = timex_set(DEFAULT_DAO_DELAY, 0);
dao_counter = 0;
ack_received = false;
vtimer_remove(&dao_timer);
vtimer_set_wakeup(&dao_timer, dao_time, dao_delay_over_pid);
}
/* This function is used for regular update of the routes. The Timer can be overwritten, as the normal delay_dao function gets called */
void long_delay_dao(void)
{
dao_time = timex_set(REGULAR_DAO_INTERVAL, 0);
dao_counter = 0;
ack_received = false;
vtimer_remove(&dao_timer);
vtimer_set_wakeup(&dao_timer, dao_time, dao_delay_over_pid);
}
void dao_delay_over(void)
{
while (1) {
thread_sleep();
if ((ack_received == false) && (dao_counter < DAO_SEND_RETRIES)) {
dao_counter++;
send_DAO(NULL, 0, true, 0);
dao_time = timex_set(DEFAULT_WAIT_FOR_DAO_ACK, 0);
vtimer_remove(&dao_timer);
vtimer_set_wakeup(&dao_timer, dao_time, dao_delay_over_pid);
}
else if (ack_received == false) {
long_delay_dao();
}
}
}
void dao_ack_received()
{
ack_received = true;
long_delay_dao();
}
void rt_timer_over(void)
{
rpl_routing_entry_t *rt;
while (1) {
rpl_dodag_t *my_dodag = rpl_get_my_dodag();
if (my_dodag != NULL) {
rt = rpl_get_routing_table();
for (uint8_t i = 0; i < RPL_MAX_ROUTING_ENTRIES; i++) {
if (rt[i].used) {
if (rt[i].lifetime <= 1) {
memset(&rt[i], 0, sizeof(rt[i]));
}
else {
rt[i].lifetime--;
}
}
}
/* Parent is NULL for root too */
if (my_dodag->my_preferred_parent != NULL) {
if (my_dodag->my_preferred_parent->lifetime <= 1) {
puts("parent lifetime timeout");
rpl_parent_update(NULL);
}
else {
my_dodag->my_preferred_parent->lifetime--;
}
}
}
/* Wake up every second */
vtimer_usleep(1000000);
}
}