diff --git a/drivers/cc110x/cc1100-interface.h b/drivers/cc110x/cc1100-interface.h index 6919ea8311..37944611d0 100644 --- a/drivers/cc110x/cc1100-interface.h +++ b/drivers/cc110x/cc1100-interface.h @@ -66,6 +66,9 @@ and the mailinglist (subscription via web site) // Define default radio mode to constant RX if no // project specific setting is available. #ifndef CC1100_RADIO_MODE +#ifdef MODULE_RPL +#warning RPL currently works with CC1100_MODE_WOR +#endif #define CC1100_RADIO_MODE CC1100_MODE_CONSTANT_RX #endif diff --git a/sys/include/vtimer.h b/sys/include/vtimer.h index 371cee9048..c0c042973d 100644 --- a/sys/include/vtimer.h +++ b/sys/include/vtimer.h @@ -96,4 +96,14 @@ int vtimer_remove(vtimer_t *t); */ void vtimer_print(vtimer_t *t); +/** + * @brief Prints the vtimer shortterm queue (use for debug purposes) + */ +void vtimer_print_short_queue(); + +/** + * @brief Prints the vtimer longterm queue (use for debug purposes) + */ +void vtimer_print_long_queue(); + #endif /* __VTIMER_H */ diff --git a/sys/net/sixlowpan/rpl/etx_beaconing.c b/sys/net/sixlowpan/rpl/etx_beaconing.c new file mode 100644 index 0000000000..f6af4653b9 --- /dev/null +++ b/sys/net/sixlowpan/rpl/etx_beaconing.c @@ -0,0 +1,506 @@ +/* + * etx_beaconing.c + * + * Created on: Feb 26, 2013 + * Author: stephan + */ +#include "etx_beaconing.h" + +#include +#include +#include + +#include +#include +#include +#include + +#include "sys/net/sixlowpan/sixlowmac.h" +#include "sys/net/sixlowpan/ieee802154_frame.h" + +//prototytpes +static uint8_t etx_count_packet_tx(etx_neighbor_t * candidate); +static void etx_set_packets_received(void); +static bool etx_equal_id(ipv6_addr_t *id1, ipv6_addr_t *id2); + +//Buffer +char etx_beacon_buf[ETX_BEACON_STACKSIZE] = { 0 }; +char etx_radio_buf[ETX_RADIO_STACKSIZE] = { 0 }; +char etx_clock_buf[ETX_CLOCK_STACKSIZE] = { 0 }; + +uint8_t etx_send_buf[ETX_BUF_SIZE] = { 0 }; +uint8_t etx_rec_buf[ETX_BUF_SIZE] = { 0 }; + +//PIDs +int etx_beacon_pid = 0; +int etx_radio_pid = 0; +int etx_clock_pid = 0; + +/* + * xxx If you get a -Wmissing-braces warning here: + * A -Wmissing-braces warning at this point is a gcc-bug! + * Please delete this information once it's fixed + * See: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53119 + */ +//Message queue for radio +msg_t msg_que[ETX_RCV_QUEUE_SIZE] = { 0 }; + +/* + * The counter for the current 'round'. An ETX beacon is sent every ETX_INTERVAL + * u-seconds and a node computes the ETX value by comparing the the received + * probes vs the expected probes from a neighbor every ETX_ROUND intervals. + */ +static uint8_t cur_round = 0; + +/* + * If we have not yet reached WINDOW intervals, won't calculate the ETX just yet + */ +static char reached_window = 0; + +/* + * This could (and should) be done differently, once the RPL implementation + * deals with candidate neighbors in another way than just defining that every + * possible neighbor we hear from is a parent. + * Right now, we need to keep track of the ETX values of other nodes without + * needing them to be in our parent array, so we have another array here in + * which we put all necessary info for up to ETX_MAX_CANDIDATE_NEIHGBORS + * candidates. + * + * xxx If you get a -Wmissing-braces warning here: + * A -Wmissing-braces warning at this point is a gcc-bug! + * Please delete this information once it's fixed + * See: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53119 + */ +//Candidate array +static etx_neighbor_t candidates[ETX_MAX_CANDIDATE_NEIGHBORS] = { 0 }; + +/* + * Each time we send a beacon packet we need to reset some values for the + * current 'round' (a round being the time between each sent beacon packet). + * + * In this time, no packet may be handled, otherwise it could assume values + * from the last round to count for this round. + */ +mutex_t etx_mutex; +//Transceiver command for sending ETX probes +transceiver_command_t tcmd; + +//Message to send probes with +msg_t mesg; + +//RPL-address +static ipv6_addr_t * own_address; + +static etx_probe_t * etx_get_send_buf(void) { + return ((etx_probe_t *) &(etx_send_buf[0])); +} +static etx_probe_t * etx_get_rec_buf(void) { + return ((etx_probe_t *) &(etx_rec_buf[0])); +} + +void show_candidates(void) { + etx_neighbor_t * candidate; + etx_neighbor_t *end; + + for (candidate = &candidates[0], end = candidates + + ETX_MAX_CANDIDATE_NEIGHBORS; candidate < end; + candidate++) { + if (candidate->used == 0) { + break; + } + printf("Candidates Addr:%d\n" + "\t cur_etx:%f\n" + "\t packets_rx:%d\n" + "\t packets_tx:%d\n" + "\t used:%d\n", candidate->addr.uint8[ETX_IPV6_LAST_BYTE], + candidate->cur_etx, candidate->packets_rx, + etx_count_packet_tx(candidate), + candidate->used); + } +} + +void etx_init_beaconing(ipv6_addr_t * address) { + mutex_init(&etx_mutex); + own_address = address; + //set code + puts("ETX BEACON INIT"); + etx_send_buf[0] = ETX_PKT_OPTVAL; + + etx_beacon_pid = thread_create(etx_beacon_buf, ETX_BEACON_STACKSIZE, + PRIORITY_MAIN - 1, CREATE_STACKTEST, + etx_beacon, "etx_beacon"); + + etx_radio_pid = thread_create(etx_radio_buf, ETX_RADIO_STACKSIZE, + PRIORITY_MAIN - 1, CREATE_STACKTEST, + etx_radio, "etx_radio"); + + etx_clock_pid = thread_create(etx_clock_buf, ETX_CLOCK_STACKSIZE, + PRIORITY_MAIN - 1, CREATE_STACKTEST, + etx_clock, "etx_clock"); + //register at transceiver + transceiver_register(TRANSCEIVER_CC1100, etx_radio_pid); + puts("...[DONE]"); +} + +void etx_beacon(void) { + /* + * Sends a message every ETX_INTERVAL +/- a jitter-value (default is 10%) . + * A correcting variable is needed to stay at a base interval of + * ETX_INTERVAL between the wakeups. It takes the old jittervalue in account + * and modifies the time to wait accordingly. + */ + etx_probe_t * packet = etx_get_send_buf(); + uint8_t p_length = 0; + + /* + * xxx If you get a -Wmissing-braces warning here: + * A -Wmissing-braces warning at this point is a gcc-bug! + * Please delete this information once it's fixed + * See: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53119 + */ + ieee_802154_long_t empty_addr = { 0 }; + + while (true) { + thread_sleep(); + mutex_lock(&etx_mutex); + //Build etx packet + p_length = 0; + for (uint8_t i = 0; i < ETX_BEST_CANDIDATES; i++) { + if (candidates[i].used != 0) { + packet->data[i * ETX_TUPLE_SIZE] = + candidates[i].addr.uint8[ETX_IPV6_LAST_BYTE]; + packet->data[i * ETX_TUPLE_SIZE + ETX_PKT_REC_OFFSET] = + etx_count_packet_tx(&candidates[i]); + p_length = p_length + ETX_PKT_HDR_LEN; + } + } + packet->length = p_length; + send_ieee802154_frame(&empty_addr, &etx_send_buf[0], + ETX_DATA_MAXLEN+ETX_PKT_HDR_LEN, 1); + DEBUG("sent beacon!\n"); + etx_set_packets_received(); + cur_round++; + if (cur_round == ETX_WINDOW) { + if (reached_window != 1) { + //first round is through + reached_window = 1; + } + cur_round = 0; + } + mutex_unlock(&etx_mutex,0); + } +} + +etx_neighbor_t * etx_find_candidate(ipv6_addr_t * address) { + /* + * find the candidate with address address and returns it, or returns NULL + * if no candidate having this address was found. + */ + for (uint8_t i = 0; i < ETX_MAX_CANDIDATE_NEIGHBORS; i++) { + if (candidates[i].used + && (etx_equal_id(&candidates[i].addr, address))) { + return &candidates[i]; + } + } + return NULL ; +} + +void etx_clock(void) { + /* + * Manages the etx_beacon thread to wake up every full second +- jitter + */ + + /* + * The jittercorrection and jitter variables keep usecond values divided + * through 1000 to fit into uint8 variables. + * + * That is why they are multiplied by 1000 when used for hwtimer_wait. + */ + uint8_t jittercorrection = ETX_DEF_JIT_CORRECT; + uint8_t jitter = (uint8_t) (rand() % ETX_JITTER_MOD); + + while (true) { + thread_wakeup(etx_beacon_pid); + + /* + * Vtimer is buggy, but I seem to have no hwtimers left, so using this + * for now. + */ + vtimer_usleep( + ((ETX_INTERVAL - ETX_MAX_JITTER)*MS)+ jittercorrection*MS + jitter*MS - ETX_CLOCK_ADJUST); + + //hwtimer_wait( + // HWTIMER_TICKS(((ETX_INTERVAL - ETX_MAX_JITTER)*MS) + jittercorrection*MS + jitter*MS - ETX_CLOCK_ADJUST)); + + jittercorrection = (ETX_MAX_JITTER) - jitter; + jitter = (uint8_t) (rand() % ETX_JITTER_MOD); + } +} + +double etx_get_metric(ipv6_addr_t * address) { + etx_neighbor_t * candidate = etx_find_candidate(address); + if (candidate != NULL ) { + if (etx_count_packet_tx(candidate) > 0) { + //this means the current etx_value is not outdated + return candidate->cur_etx; + } else { + //The last time I received a packet is too long ago to give a + //good estimate of the etx value + return 0; + } + } + return 0; +} + +etx_neighbor_t * etx_add_candidate(ipv6_addr_t * address) { + DEBUG("add candidate\n"); + /* + * Pre-Condition: etx_add_candidate should only be called when the + * candidate is not yet in the list. + * Otherwise the candidate will be added a second time, + * leading to unknown behavior. + * + * Check if there is still enough space to add this candidate + * + * a) + * Space is available: + * Add candidate + * + * b) + * Space is not available: + * ignore new candidate + * This shouldn't really happen though, since we have enough + * place in the array. + * + * Returns the pointer to the candidate if it was added, or a NULL-pointer + * otherwise. + */ + etx_neighbor_t * candidate; + etx_neighbor_t * end; + + for (candidate = &candidates[0], end = candidates + + ETX_MAX_CANDIDATE_NEIGHBORS; candidate < end; + candidate++) { + if (candidate->used) { + //skip + continue; + } else { + //We still have a free place add the new candidate + memset(candidate, 0, sizeof(*candidate)); + candidate->addr = *address; + candidate->cur_etx = 0; + candidate->packets_rx = 0; + candidate->used = 1; + return candidate; + } + } + return NULL ; +} + +void etx_handle_beacon(ipv6_addr_t * candidate_address) { + /* + * Handle the ETX probe that has been received and update all infos. + * If the candidate address is unknown, try to add it to my struct. + */ + + DEBUG( + "ETX beacon package received with following values:\n" + "\tPackage Option:%x\n" + "\t Data Length:%u\n" + "\tSource Address:%d\n\n", etx_rec_buf[ETX_PKT_OPT], etx_rec_buf[ETX_PKT_LEN], + candidate_address->uint8[ETX_IPV6_LAST_BYTE]); + + etx_neighbor_t* candidate = etx_find_candidate(candidate_address); + if (candidate == NULL ) { + //Candidate was not found in my list, I should add it + candidate = etx_add_candidate(candidate_address); + if (candidate == NULL ) { + puts("[ERROR] Candidate could not get added"); + puts("Increase the constant ETX_MAX_CANDIDATE_NEIHGBORS"); + return; + } + } + + //I have received 1 packet from this candidate in this round + //This value will be reset by etx_update to 0 + candidate->tx_cur_round = 1; + + // If i find my address in this probe, update the packet_rx value for + // this candidate. + etx_probe_t * rec_pkt = etx_get_rec_buf(); + + for (uint8_t i = 0; i < rec_pkt->length / ETX_TUPLE_SIZE; i++) { + DEBUG("\tIPv6 short Addr:%u\n" + "\tPackets f. Addr:%u\n\n", rec_pkt->data[i * ETX_TUPLE_SIZE], + rec_pkt->data[i * ETX_TUPLE_SIZE + ETX_PKT_REC_OFFSET]); + + if (rec_pkt->data[i * ETX_TUPLE_SIZE] + == own_address->uint8[ETX_IPV6_LAST_BYTE]) { + + candidate->packets_rx = rec_pkt->data[i * ETX_TUPLE_SIZE + + ETX_PKT_REC_OFFSET]; + } + } + + //Last, update the ETX value for this candidate + etx_update(candidate); +} + +void etx_radio(void) { + msg_t m; + radio_packet_t *p; + + ieee802154_frame_t frame; + + msg_init_queue(msg_que, ETX_RCV_QUEUE_SIZE); + + ipv6_addr_t ll_address; + ipv6_addr_t candidate_addr; + + ipv6_set_ll_prefix(&ll_address); + ipv6_get_saddr(&candidate_addr, &ll_address); + + while (1) { + msg_receive(&m); + if (m.type == PKT_PENDING) { + p = (radio_packet_t*) m.content.ptr; + + read_802154_frame(p->data, &frame, p->length); + + if (frame.payload[0] == ETX_PKT_OPTVAL) { + //copy to receive buffer + memcpy(etx_rec_buf, &frame.payload[0], frame.payload_len); + + //create IPv6 address from radio packet + //we can do the cast here since rpl nodes can only have addr + //up to 8 bits + candidate_addr.uint8[ETX_IPV6_LAST_BYTE] = (uint8_t) p->src; + //handle the beacon + mutex_lock(&etx_mutex); + etx_handle_beacon(&candidate_addr); + mutex_unlock(&etx_mutex,1); + } + + p->processing--; + } + else if (m.type == ENOBUFFER) { + puts("Transceiver buffer full"); + } + else { + //packet is not for me, whatever + } + } +} + +void etx_update(etx_neighbor_t * candidate) { + DEBUG("update!\n"); + /* + * Update the current ETX value of a candidate + */ + double d_f; + double d_r; + + if (reached_window != 1 || candidate == NULL ) { + //We will wait at least ETX_WINDOW beacons until we decide to + //calculate an ETX value, so that we have a good estimate + return; + } + + /* + * Calculate d_f (the forward PDR) from ME to this candidate. + */ + d_f = candidate->packets_rx / (double) ETX_WINDOW; + + /* + * Calculate d_r (the backwards PDR) from this candidate to ME + */ + d_r = etx_count_packet_tx(candidate) / (double) ETX_WINDOW; + + /* + * Calculate the current ETX value for my link to this candidate. + */ + if (d_f * d_r != 0) { + candidate->cur_etx = 1 / (d_f * d_r); + } else { + candidate->cur_etx = 0; + } + + DEBUG( + "Estimated ETX Metric is %f for candidate w/ addr %d\n" + "Estimated PDR_forward is %f\n" + "Estimated PDR_backwrd is %f\n" + "\n" + "Received Packets: %d\n" + "Sent Packets : %d\n\n", + candidate->cur_etx, candidate->addr.uint8[ETX_IPV6_LAST_BYTE], + d_f, d_r, candidate->packets_rx, etx_count_packet_tx(candidate)); +} + +static uint8_t etx_count_packet_tx(etx_neighbor_t * candidate) { + /* + * Counts the number of packets that were received for this candidate + * in the last ETX_WINDOW intervals. + */ + DEBUG("counting packets"); + uint8_t pkt_count = 0; + DEBUG("["); + for (uint8_t i = 0; i < ETX_WINDOW; i++) { + if (i != cur_round) { + pkt_count = pkt_count + candidate->packets_tx[i]; +#ifdef ENABLE_DEBUG + DEBUG("%d",candidate->packets_tx[i]); + if (i < ETX_WINDOW - 1) { + DEBUG(","); + } +#endif + } else { + //Check if I received something for the current round + if (candidate->tx_cur_round == 0) { + //Didn't receive a packet, zero the field and don't add + candidate->packets_tx[i] = 0; +#ifdef ENABLE_DEBUG + DEBUG("%d!",candidate->packets_tx[i]); + if (i < ETX_WINDOW - 1) { + DEBUG(","); + } +#endif + } else { + //Add 1 and set field + pkt_count = pkt_count + 1; + candidate->packets_tx[i] = 1; +#ifdef ENABLE_DEBUG + DEBUG("%d!",candidate->packets_tx[i]); + if (i < ETX_WINDOW - 1) { + DEBUG(","); + } +#endif + } + } + } + DEBUG("]\n"); + return pkt_count; +} + +static void etx_set_packets_received(void) { + /* + * Set for all candidates if they received a packet this round or not + */ + for (uint8_t i = 0; i < ETX_MAX_CANDIDATE_NEIGHBORS; i++) { + if (candidates[i].used) { + if (candidates[i].tx_cur_round != 0) { + candidates[i].packets_tx[cur_round] = 1; + candidates[i].tx_cur_round = 0; + } + } + } +} + +bool etx_equal_id(ipv6_addr_t *id1, ipv6_addr_t *id2){ + for(uint8_t i=0;i<4;i++){ + if(id1->uint32[i] != id2->uint32[i]){ + return false; + } + } + return true; + +} diff --git a/sys/net/sixlowpan/rpl/etx_beaconing.h b/sys/net/sixlowpan/rpl/etx_beaconing.h new file mode 100644 index 0000000000..611b45de66 --- /dev/null +++ b/sys/net/sixlowpan/rpl/etx_beaconing.h @@ -0,0 +1,119 @@ +/* + * Header for the ETX-beaconing module + * etx_beaconing.h + * + * Created on: Feb 26, 2013 + * Author: stephan + */ + +#ifndef ETX_BEACONING_H_ +#define ETX_BEACONING_H_ + +#include "sys/net/sixlowpan/sixlowip.h" + +//For debugging purposes +#define ENABLE_DEBUG +#include + +#ifdef ENABLE_DEBUG + #define ETX_BEACON_STACKSIZE 4500 + #define ETX_RADIO_STACKSIZE 4500 + #define ETX_CLOCK_STACKSIZE 500 +#else + #define ETX_BEACON_STACKSIZE 2500 //TODO optimize, maybe 2000 is enough + #define ETX_RADIO_STACKSIZE 2500 //TODO optimize, maybe 2000 is enough + #define ETX_CLOCK_STACKSIZE 500 //TODO optimize, maybe 250 is enough +#endif + +//[option|length|ipaddr.|packetcount] with up to 15 ipaddr|packetcount pairs +// 1 Byte 1 Byte 1 Byte 1 Byte +#define ETX_BUF_SIZE (32) + +#define ETX_RCV_QUEUE_SIZE (128) + +/* + * Default 40, should be enough to get all messages for neighbors. + * In my tests, the maximum count of neighbors was around 30-something + */ +#ifdef ENABLE_DEBUG + #define ETX_MAX_CANDIDATE_NEIGHBORS 15 //Stacksizes are huge in debug mode, so memory is rare +#else + #define ETX_MAX_CANDIDATE_NEIGHBORS 40 +#endif +//ETX Interval parameters +#define MS 1000 + +/* + * ETX_INTERVAL + * + * Given in ms, the default is 1 second. + * Should be divisible through 2 (For ETX_DEF_JIT_CORRECT) + * and 5 (For ETX_MAX_JITTER) unless those values are adjusted too. + */ +#define ETX_INTERVAL (1000) +#define ETX_WINDOW (10) //10 is the default value +#define ETX_BEST_CANDIDATES (15) //Sent only 15 candidates in a beaconing packet +#define ETX_TUPLE_SIZE (2) //1 Byte for Addr, 1 Byte for packets rec. +#define ETX_PKT_REC_OFFSET (ETX_TUPLE_SIZE - 1) //Offset in a tuple of (addr,pkt_rec), will always be the last byte +#define ETX_IPV6_LAST_BYTE (15) //The last byte for an ipv6 address +#define ETX_MAX_JITTER (ETX_INTERVAL / 5) //The default value is 20% of ETX_INTERVAL +#define ETX_JITTER_MOD (ETX_MAX_JITTER + 1) //The modulo value for jitter computation +#define ETX_DEF_JIT_CORRECT (ETX_MAX_JITTER / 2) //Default Jitter correction value (normally ETX_MAX_JITTER / 2) +#define ETX_CLOCK_ADJUST (52500) //Adjustment for clockthread computations to stay close/near ETX_INTERVAL + +/* + * The ETX beaconing packet consists of: + * + * 0 1 2 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- - - - - - - - + * | Option Type | Option Length | Data + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- - - - - - - - + * Option type: Set to 0x20 + * + * Option Length: The length of the Data sent with this packet + * + * Option Data: 2-Octet Pairs of 8 bit for addresses and a positive integer + * denoting the amount of packets received from that IP address + * + * We only need 1 octet for the ip address since RPL for now only allows for + * 255 different addresses. + * + * If the length of this packet says 0, it has received no other beaconing + * packets itself so far. + * + * The packet is always 32bytes long, but may contain varying amounts of + * information. + * The information processed shall not exceed the value set in Option Length. + */ +typedef struct __attribute__((packed)) etx_probe_t{ + uint8_t code; + uint8_t length; + uint8_t data[30]; +} etx_probe_t; + +typedef struct etx_neighbor_t { + ipv6_addr_t addr; //The address of this node + uint8_t tx_cur_round; //The indicator for receiving a packet from this candidate this round + uint8_t packets_tx[ETX_WINDOW]; //The packets this node has transmitted TO ME + uint8_t packets_rx; //The packets this node has received FROM ME + double cur_etx; //The currently calculated ETX-value + uint8_t used; //The indicator if this node is active or not +} etx_neighbor_t; + +//prototypes +void etx_init_beaconing(ipv6_addr_t * address); +void etx_beacon(void); +void etx_clock(void); +double etx_get_metric(ipv6_addr_t * address); +void etx_update(etx_neighbor_t * neighbor); +void etx_radio(void); + +#define ETX_PKT_OPT (0) //Position of Option-Type-Byte +#define ETX_PKT_OPTVAL (0x20) //Non-standard way of saying this is an ETX-Packet. +#define ETX_PKT_LEN (1) //Position of Length-Byte +#define ETX_DATA_MAXLEN (30) //max length of the data +#define ETX_PKT_HDR_LEN (2) //Option type + Length (1 Byte each) +#define ETX_PKT_DATA (2) //Begin of Data Bytes + +#endif /* ETX_BEACONING_H_ */ diff --git a/sys/net/sixlowpan/rpl/objective_functions.c b/sys/net/sixlowpan/rpl/objective_functions.c deleted file mode 100644 index cf22f81215..0000000000 --- a/sys/net/sixlowpan/rpl/objective_functions.c +++ /dev/null @@ -1,7 +0,0 @@ -#include "objective_functions.h" - -void of0(void) -{ - - -} diff --git a/sys/net/sixlowpan/rpl/objective_functions.h b/sys/net/sixlowpan/rpl/objective_functions.h deleted file mode 100644 index 06c7b1620a..0000000000 --- a/sys/net/sixlowpan/rpl/objective_functions.h +++ /dev/null @@ -1,3 +0,0 @@ -#include - -void of0(void); diff --git a/sys/net/sixlowpan/rpl/of0.c b/sys/net/sixlowpan/rpl/of0.c index 661ef37e3c..2890bf22c4 100644 --- a/sys/net/sixlowpan/rpl/of0.c +++ b/sys/net/sixlowpan/rpl/of0.c @@ -18,6 +18,12 @@ #include #include "of0.h" +//Function Prototypes +static uint16_t calc_rank(rpl_parent_t *, uint16_t); +static rpl_parent_t *which_parent(rpl_parent_t *, rpl_parent_t *); +static rpl_dodag_t *which_dodag(rpl_dodag_t *, rpl_dodag_t *); +static void reset(rpl_dodag_t *); + rpl_of_t rpl_of0 = { 0x0, calc_rank, @@ -73,6 +79,7 @@ rpl_parent_t *which_parent(rpl_parent_t *p1, rpl_parent_t *p2) return p2; } +/* Not used yet, as the implementation only makes use of one dodag for now. */ rpl_dodag_t *which_dodag(rpl_dodag_t *d1, rpl_dodag_t *d2) { return d1; diff --git a/sys/net/sixlowpan/rpl/of0.h b/sys/net/sixlowpan/rpl/of0.h index 72a6900e8b..998f522884 100644 --- a/sys/net/sixlowpan/rpl/of0.h +++ b/sys/net/sixlowpan/rpl/of0.h @@ -1,8 +1,3 @@ #include "rpl_structs.h" rpl_of_t *rpl_get_of0(void); -uint16_t calc_rank(rpl_parent_t *, uint16_t); -rpl_parent_t *which_parent(rpl_parent_t *, rpl_parent_t *); -rpl_dodag_t *which_dodag(rpl_dodag_t *, rpl_dodag_t *); -void reset(rpl_dodag_t *); - diff --git a/sys/net/sixlowpan/rpl/of_mrhof.c b/sys/net/sixlowpan/rpl/of_mrhof.c new file mode 100644 index 0000000000..66f04f7c6a --- /dev/null +++ b/sys/net/sixlowpan/rpl/of_mrhof.c @@ -0,0 +1,160 @@ +#include +#include +#include "of_mrhof.h" + +#include "etx_beaconing.h" + +// Function Prototypes +static uint16_t calc_rank(rpl_parent_t *, uint16_t); +static rpl_parent_t *which_parent(rpl_parent_t *, rpl_parent_t *); +static rpl_dodag_t *which_dodag(rpl_dodag_t *, rpl_dodag_t *); +static void reset(rpl_dodag_t *); +static uint16_t calc_path_cost(rpl_parent_t * parent); + +uint16_t cur_min_path_cost = MAX_PATH_COST; +rpl_parent_t * cur_preferred_parent = NULL; + +rpl_of_t rpl_of_mrhof = { + 0x1, + calc_rank, + which_parent, + which_dodag, + reset, + NULL + }; + +rpl_of_t * rpl_get_of_mrhof(void) { + return &rpl_of_mrhof; +} + +void reset(rpl_dodag_t *dodag) { +} + +static uint16_t calc_path_cost(rpl_parent_t * parent) { + puts("calc_pathcost"); + /* + * Calculates the path cost through the parent, for now, only for ETX + */ + if (parent == NULL ) { + // Shouldn't ever happen since this function is supposed to be always + // run with a parent. If it does happen, we can assume a root called it. + puts("[WARNING] calc_path_cost called without parent!"); + return DEFAULT_MIN_HOP_RANK_INCREASE; + } + + double etx_value = etx_get_metric(&(parent->addr)); + printf("Metric for parent returned: %f", etx_value); + if (etx_value != 0) { + /* + * (ETX_for_link_to_neighbor * 128) + Rank_of_that_neighbor + * + * This means I get the rank of that neighbor (which is the etx + * of the whole path from him to the root node) plus my ETX to + * that neighbor*128, which would be the 'rank' of the single link + * from me to that neighbor + * + */ + if (etx_value * ETX_RANK_MULTIPLIER > MAX_LINK_METRIC) { + // Disallow links with an estimated ETX of 4 or higher + return MAX_PATH_COST; + } + + if (etx_value * ETX_RANK_MULTIPLIER + parent->rank + < parent->rank) { + //Overflow + return MAX_PATH_COST; + } + //TODO runden + return etx_value * ETX_RANK_MULTIPLIER + + parent->rank; + } else { + // IMPLEMENT HANDLING OF OTHER METRICS HERE + // if it is 0, it hasn't been computed, thus we cannot compute a path + // cost + return MAX_PATH_COST; + } +} + +static uint16_t calc_rank(rpl_parent_t * parent, uint16_t base_rank) { + puts("calc_rank"); + /* + * Return the rank for this node. + * + * For now, there is no metric-selection or specification, so the rank com- + * putation will always be assumed to be done for the ETX metric. + * Baserank is pretty much only used to find out if a node is a root or not. + */ + if (parent == NULL ) { + if (base_rank == 0) { + //No parent, no rank, a root node would have a rank != 0 + return INFINITE_RANK; + } + + /* + * No parent, base_rank != 0 means this is a root node or a node which + * is recalculating. + * Since a recalculating node must have a parent in this implementation + * (see rpl.c, function global_repair), we can assume this node is root. + */ + return DEFAULT_MIN_HOP_RANK_INCREASE; + } else { + /* + * We have a parent and are a non-root node, calculate the path cost for + * the parent and choose the maximum of that value and the advertised + * rank of the parent + minhoprankincrease for our rank. + */ + uint16_t calculated_pcost = calc_path_cost(parent); + + if (calculated_pcost < MAX_PATH_COST) { + if ((parent->rank + parent->dodag->minhoprankincrease) + > calculated_pcost) { + return parent->rank + parent->dodag->minhoprankincrease; + } else { + return calculated_pcost; + } + } else { + //Path costs are greater than allowed + return INFINITE_RANK; + } + } +} + +static rpl_parent_t * which_parent(rpl_parent_t * p1, rpl_parent_t * p2) { + puts("which_parent"); + /* + * Return the parent with the lowest path cost. + * Before returning any of the two given parents, make sure that a switch is + * desirable. + * + */ + uint16_t path_p1 = calc_path_cost(p1); + uint16_t path_p2 = calc_path_cost(p2); + + if(cur_preferred_parent != NULL){ + //test if the parent from which we got this path is still active + if(cur_preferred_parent->used != 0){ + // Test, if the current best path is better than both parents given + if(cur_min_path_cost < path_p1 + PARENT_SWITCH_THRESHOLD + && cur_min_path_cost < path_p2 + PARENT_SWITCH_THRESHOLD){ + return cur_preferred_parent; + } + } + } + + if (path_p1 < path_p2) { + /* + * Return the current best parent, and set it as current best parent + */ + cur_min_path_cost = path_p1; + cur_preferred_parent = p1; + return p1; + } + cur_min_path_cost = path_p2; + cur_preferred_parent = p2; + return p2; +} + +//Not used yet, as the implementation only makes use of one dodag for now. +static rpl_dodag_t * which_dodag(rpl_dodag_t *d1, rpl_dodag_t *d2) { + return d1; +} diff --git a/sys/net/sixlowpan/rpl/of_mrhof.h b/sys/net/sixlowpan/rpl/of_mrhof.h new file mode 100644 index 0000000000..214353bc7b --- /dev/null +++ b/sys/net/sixlowpan/rpl/of_mrhof.h @@ -0,0 +1,40 @@ +//For debugging purposes +#define ENABLE_DEBUG +#include + + +#include "rpl_structs.h" + +/* + * Disallow links with greater than 4 expected + * transmission counts on the selected path. + */ +#define MAX_LINK_METRIC (512) + +/* + * Disallow paths with greater than 256 + * expected transmission counts. + */ +#define MAX_PATH_COST (0x8000) + +/* + * Switch to a new path only if it is + * expected to require at least 1.5 fewer transmissions than the + * current path. + */ +#define PARENT_SWITCH_THRESHOLD (192) + +/* + * Do not allow a node to become a floating root. + * (Currently unused, since the RPL-implementation does not allow for floating + * roots). + */ +#define ALLOW_FLOATING_ROOT (0) + +/* + * While assigning Rank when using ETX, use the representation of ETX described + * in [RFC6551], i.e., assign Rank equal to ETX * 128. + */ +#define ETX_RANK_MULTIPLIER (0x80) + +rpl_of_t *rpl_get_of_mrhof(); diff --git a/sys/net/sixlowpan/rpl/rpl.c b/sys/net/sixlowpan/rpl/rpl.c index e51caf9f22..337e34096d 100644 --- a/sys/net/sixlowpan/rpl/rpl.c +++ b/sys/net/sixlowpan/rpl/rpl.c @@ -21,7 +21,9 @@ #include #include "msg.h" #include "rpl.h" +#include "etx_beaconing.h" #include "of0.h" +#include "of_mrhof.h" #include "trickle.h" #include "sys/net/sixlowpan/sixlowmac.h" @@ -210,8 +212,13 @@ uint8_t rpl_init(transceiver_type_t trans, uint16_t rpl_address) ipv6_get_saddr(&my_address, &ll_address); set_rpl_process_pid(rpl_process_pid); - return SUCCESS; + /* Initialize ETX-calculation if needed */ + if(RPL_DEFAULT_OCP == 1){ + puts("INIT ETX BEACONING"); + etx_init_beaconing(&my_address); + } + return SUCCESS; } void rpl_init_root(void) @@ -246,6 +253,7 @@ void rpl_init_root(void) dodag->lifetime_unit = RPL_LIFETIME_UNIT; dodag->version = RPL_COUNTER_INIT; dodag->grounded = RPL_GROUNDED; + dodag->node_status = (uint8_t) ROOT_NODE; dodag->my_rank = RPL_ROOT_RANK; dodag->joined = 1; dodag->my_preferred_parent = NULL; @@ -453,8 +461,6 @@ void send_DAO_ACK(ipv6_addr_t *destination) uint16_t plen = ICMPV6_HDR_LEN + DIS_BASE_LEN; rpl_send(destination, (uint8_t *)icmp_send_buf, plen, PROTO_NUM_ICMPV6, NULL); mutex_unlock(&rpl_send_mutex, 0); - - } void rpl_process(void) @@ -498,7 +504,6 @@ void rpl_process(void) default: mutex_unlock(&rpl_recv_mutex, 0); - puts("default unlock"); break; } } @@ -847,7 +852,6 @@ void recv_rpl_dao(void) len += rpl_opt_transit_buf->length + 2; /* Die eigentliche Lebenszeit einer Route errechnet sich aus (Lifetime aus DAO) * (Lifetime Unit) Sekunden */ rpl_add_routing_entry(&rpl_opt_target_buf->target, &ipv6_buf->srcaddr, rpl_opt_transit_buf->path_lifetime * my_dodag->lifetime_unit); - /* puts("Updated route \n"); */ increment_seq = 1; break; } @@ -898,6 +902,7 @@ void recv_rpl_dao_ack(void) } +/* TODO: tcp_socket unused? */ void rpl_send(ipv6_addr_t *destination, uint8_t *payload, uint16_t p_len, uint8_t next_header, void *tcp_socket) { uint8_t *p_ptr; diff --git a/sys/net/sixlowpan/rpl/rpl.h b/sys/net/sixlowpan/rpl/rpl.h index 5ac849964d..7ab2f87206 100644 --- a/sys/net/sixlowpan/rpl/rpl.h +++ b/sys/net/sixlowpan/rpl/rpl.h @@ -23,6 +23,8 @@ #include "sys/net/sixlowpan/sixlowip.h" #include "rpl_dodag.h" +#define CC1100_RADIO_MODE CC1100_MODE_WOR + #define RPL_PKT_RECV_BUF_SIZE 20 #define RPL_PROCESS_STACKSIZE 4096 diff --git a/sys/net/sixlowpan/rpl/rpl_dodag.c b/sys/net/sixlowpan/rpl/rpl_dodag.c index 625a591cca..d80e9fb941 100644 --- a/sys/net/sixlowpan/rpl/rpl_dodag.c +++ b/sys/net/sixlowpan/rpl/rpl_dodag.c @@ -317,6 +317,7 @@ void rpl_join_dodag(rpl_dodag_t *dodag, ipv6_addr_t *parent, uint16_t parent_ran my_dodag->grounded = dodag->grounded; my_dodag->joined = 1; my_dodag->my_preferred_parent = preferred_parent; + my_dodag->node_status = (uint8_t) NORMAL_NODE; my_dodag->my_rank = dodag->of->calc_rank(preferred_parent, dodag->my_rank); my_dodag->dao_seq = RPL_COUNTER_INIT; my_dodag->min_rank = my_dodag->my_rank; diff --git a/sys/net/sixlowpan/rpl/rpl_structs.h b/sys/net/sixlowpan/rpl/rpl_structs.h index 32ce99492d..5056389b91 100644 --- a/sys/net/sixlowpan/rpl/rpl_structs.h +++ b/sys/net/sixlowpan/rpl/rpl_structs.h @@ -70,6 +70,14 @@ #define RPL_COUNTER_GREATER_THAN_LOCAL(A,B) (((A B) && (A-B < RPL_COUNTER_SEQ_WINDOW))) #define RPL_COUNTER_GREATER_THAN(A,B) ((A>RPL_COUNTER_LOWER_REGION) ? ((B > RPL_COUNTER_LOWER_REGION ) ? RPL_COUNTER_GREATER_THAN_LOCAL(A,B) : 0): (( B>RPL_COUNTER_LOWER_REGION ) ? 1: RPL_COUNTER_GREATER_THAN_LOCAL(A,B))) +/* Node Status */ +#define NORMAL_NODE 0 +#define ROOT_NODE 1 +#define LEAF_NODE 2 + +/* Link Metric Type */ +#define METRIC_ETX 1 + /* Default values */ #define RPL_DEFAULT_MOP STORING_MODE_NO_MC @@ -77,7 +85,6 @@ /* RPL Constants and Variables */ #define BASE_RANK 0 -#define ROOT_RANK 1 #define INFINITE_RANK 0xFFFF #define RPL_DEFAULT_INSTANCE 0 #define DEFAULT_PATH_CONTROL_SIZE 0 @@ -89,6 +96,7 @@ /* #define DEFAULT_DIO_INTERVAL_DOUBLINGS 20 */ #define DEFAULT_DIO_REDUNDANCY_CONSTANT 10 #define DEFAULT_MIN_HOP_RANK_INCREASE 256 +#define ROOT_RANK DEFAULT_MIN_HOP_RANK_INCREASE /* DAO_DELAY is in seconds */ #define DEFAULT_DAO_DELAY 3 #define REGULAR_DAO_INTERVAL 300 @@ -98,7 +106,7 @@ /* others */ -#define NUMBER_IMPLEMENTED_OFS 1 +#define NUMBER_IMPLEMENTED_OFS 2 #define RPL_MAX_DODAGS 3 #define RPL_MAX_INSTANCES 1 #define RPL_MAX_PARENTS 5 @@ -114,8 +122,9 @@ #define RPL_DIS_I_MASK 0x40 #define RPL_DIS_D_MASK 0x20 #define RPL_GROUNDED_SHIFT 7 -#define RPL_DEFAULT_OCP 0 +#define RPL_DEFAULT_OCP 1 +/* DIO Base Object (RFC 6550 Fig. 14) */ struct __attribute__((packed)) rpl_dio_t { uint8_t rpl_instanceid; uint8_t version_number; @@ -132,6 +141,7 @@ struct __attribute__((packed)) rpl_dis_t { uint8_t reserved; }; +/* DAO Base Object (RFC 6550 Fig. 16) */ struct __attribute__((packed)) rpl_dao_t { uint8_t rpl_instanceid; uint8_t k_d_flags; @@ -139,6 +149,7 @@ struct __attribute__((packed)) rpl_dao_t { uint8_t dao_sequence; }; +/* DAO ACK Base Object (RFC 6550 Fig. 17.) */ struct __attribute__((packed)) rpl_dao_ack_t { uint8_t rpl_instanceid; uint8_t d_reserved; @@ -146,16 +157,19 @@ struct __attribute__((packed)) rpl_dao_ack_t { uint8_t status; }; +/* DODAG ID Struct */ /* may be present in dao or dao_ack packets */ struct __attribute__((packed)) dodag_id_t { ipv6_addr_t dodagid; }; +/* RPL-Option Generic Format (RFC 6550 Fig. 19) */ typedef struct __attribute__((packed)) { uint8_t type; uint8_t length; } rpl_opt_t; +/* DODAG Configuration-Option (RFC 6550 Fig. 24) */ typedef struct __attribute__((packed)) { uint8_t type; uint8_t length; @@ -171,6 +185,7 @@ typedef struct __attribute__((packed)) { uint16_t lifetime_unit; } rpl_opt_dodag_conf_t; +/* RPL Solicited Information Option (RFC 6550 Fig. 28) */ typedef struct __attribute__((packed)) { uint8_t type; uint8_t length; @@ -180,7 +195,8 @@ typedef struct __attribute__((packed)) { uint8_t version; } rpl_opt_solicited_t; -/* ipv6_addr_t target may be replaced by a target prefix of variable length */ +/* RPL Target-Option (RFC 6550 Fig. 25) */ +/* TODO: ipv6_addr_t target may be replaced by a target prefix of variable length */ typedef struct __attribute__((packed)) { uint8_t type; uint8_t length; @@ -189,6 +205,7 @@ typedef struct __attribute__((packed)) { ipv6_addr_t target; } rpl_opt_target_t; +/* RPL Transit-Option (RFC 6550 Fig. 26) */ typedef struct __attribute__((packed)) { uint8_t type; uint8_t length; @@ -201,12 +218,14 @@ typedef struct __attribute__((packed)) { struct rpl_dodag_t; typedef struct { - ipv6_addr_t addr; - uint16_t rank; - uint8_t dtsn; + ipv6_addr_t addr; + uint16_t rank; + uint8_t dtsn; struct rpl_dodag_t *dodag; - uint16_t lifetime; - uint8_t used; + uint16_t lifetime; + double link_metric; + uint8_t link_metric_type; + uint8_t used; } rpl_parent_t; struct rpl_of_t; @@ -218,6 +237,7 @@ typedef struct { } rpl_instance_t; +//Node-internal representation of a DODAG, with nodespecific information typedef struct rpl_dodag_t { rpl_instance_t *instance; ipv6_addr_t dodag_id; @@ -235,6 +255,7 @@ typedef struct rpl_dodag_t { uint8_t version; uint8_t grounded; uint16_t my_rank; + uint8_t node_status; uint8_t dao_seq; uint16_t min_rank; uint8_t joined; @@ -244,11 +265,13 @@ typedef struct rpl_dodag_t { typedef struct rpl_of_t { uint16_t ocp; - uint16_t (*calc_rank)(rpl_parent_t *, uint16_t); + uint16_t (*calc_rank)(rpl_parent_t * parent, uint16_t base_rank); rpl_parent_t *(*which_parent)(rpl_parent_t *, rpl_parent_t *); rpl_dodag_t *(*which_dodag)(rpl_dodag_t *, rpl_dodag_t *); void (*reset)(rpl_dodag_t *); void (*parent_state_callback)(rpl_parent_t *, int, int); + void (*init) (void); //OF specific init function + void (*process_dio) (); //DIO processing callback (acc. to OF0 spec, chpt 5) } rpl_of_t; typedef struct { diff --git a/sys/net/sixlowpan/rpl/trickle.c b/sys/net/sixlowpan/rpl/trickle.c index 1f72fc4ed9..f74c1fec65 100644 --- a/sys/net/sixlowpan/rpl/trickle.c +++ b/sys/net/sixlowpan/rpl/trickle.c @@ -24,9 +24,10 @@ #include "trickle.h" #include "sixlowpan/rpl/rpl.h" -char timer_over_buf[TRICKLE_TIMER_STACKSIZE]; -char interval_over_buf[TRICKLE_INTERVAL_STACKSIZE]; -char dao_delay_over_buf[DAO_DELAY_STACKSIZE]; +//TODO in pointer umwandeln, speicher mit malloc holen +char * timer_over_buf; +char * interval_over_buf; +char * dao_delay_over_buf; char routing_table_buf[RT_STACKSIZE]; int timer_over_pid; int interval_over_pid; @@ -70,6 +71,22 @@ void reset_trickletimer(void) void init_trickle(void) { + timer_over_buf = calloc(TRICKLE_TIMER_STACKSIZE,sizeof(char)); + if(timer_over_buf == NULL){ + puts("[ERROR] Could not allocate enough memory for timer_over_buf!"); + return; + } + interval_over_buf = calloc(TRICKLE_INTERVAL_STACKSIZE,sizeof(char)); + if(interval_over_buf == NULL){ + puts("[ERROR] Could not allocate enough memory for interval_over_buf!"); + return; + } + dao_delay_over_buf = calloc(DAO_DELAY_STACKSIZE,sizeof(char)); + if(dao_delay_over_buf == NULL){ + puts("[ERROR] Could not allocate enough memory for interval_over_buf!"); + return; + } + /* Create threads */ ack_received = true; timer_over_pid = thread_create(timer_over_buf, TRICKLE_TIMER_STACKSIZE, @@ -85,7 +102,6 @@ void init_trickle(void) 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, diff --git a/sys/net/sixlowpan/sixlowmac.c b/sys/net/sixlowpan/sixlowmac.c index deef901235..741d7987b0 100644 --- a/sys/net/sixlowpan/sixlowmac.c +++ b/sys/net/sixlowpan/sixlowmac.c @@ -225,7 +225,6 @@ void send_ieee802154_frame(ieee_802154_long_t *addr, uint8_t *payload, p.data = buf; msg_send_receive(&mesg, &transceiver_rsp, transceiver_pid); - printf("%s, %u: %"PRIu32"\n", __FILE__, __LINE__, transceiver_rsp.content.value); hwtimer_wait(5000); } diff --git a/sys/vtimer/vtimer.c b/sys/vtimer/vtimer.c index cd22840adc..c27384a03e 100644 --- a/sys/vtimer/vtimer.c +++ b/sys/vtimer/vtimer.c @@ -129,9 +129,12 @@ void vtimer_callback(void *ptr) msg.content.value = (unsigned int) timer->arg; msg_send_int(&msg, timer->pid); } - else { + else if (timer->action == (void*) thread_wakeup){ timer->action(timer->arg); } + else { + DEBUG("Timer was poisoned."); + } in_callback = false; update_shortterm(); @@ -285,7 +288,15 @@ int vtimer_set_msg(vtimer_t *t, timex_t interval, unsigned int pid, void *ptr) return 0; } -void vtimer_print(vtimer_t *t) +void vtimer_print_short_queue(){ + queue_print(&shortterm_queue_root); +} + +void vtimer_print_long_queue(){ + queue_print(&longterm_queue_root); +} + +static void vtimer_print(vtimer_t *t) { printf("Seconds: %"PRIu32" - Microseconds: %"PRIu32"\n \ action: %p\n \