From 7eabf8d391f9004ac46cfa682898e87d879348e3 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sat, 21 Nov 2015 00:08:00 +0100 Subject: [PATCH] TSCH: latest update from https://github.com/EIT-ICT-RICH/contiki --- apps/orchestra/orchestra-conf.h | 14 +++---- .../orchestra-rule-unicast-per-neighbor.c | 2 +- core/net/mac/tsch/README.md | 2 +- core/net/mac/tsch/tsch-queue.c | 41 ++++++++----------- core/net/mac/tsch/tsch-queue.h | 22 ++++++++-- core/net/mac/tsch/tsch-slot-operation.c | 39 ++++++++---------- core/net/mac/tsch/tsch-slot-operation.h | 16 ++++++++ core/net/mac/tsch/tsch.c | 16 ++++---- examples/ipv6/rpl-tsch/project-conf.h | 6 +-- 9 files changed, 85 insertions(+), 73 deletions(-) diff --git a/apps/orchestra/orchestra-conf.h b/apps/orchestra/orchestra-conf.h index cef850b1d..2d3379e7e 100644 --- a/apps/orchestra/orchestra-conf.h +++ b/apps/orchestra/orchestra-conf.h @@ -66,11 +66,11 @@ #define ORCHESTRA_COMMON_SHARED_PERIOD 31 #endif /* ORCHESTRA_CONF_COMMON_SHARED_PERIOD */ -#ifdef ORCHESTRA_CONF_EBSF_PERIOD -#define ORCHESTRA_UNICAST_PERIOD ORCHESTRA_CONF_EBSF_PERIOD -#else /* ORCHESTRA_CONF_COMMON_SHARED_PERIOD */ +#ifdef ORCHESTRA_CONF_UNICAST_PERIOD +#define ORCHESTRA_UNICAST_PERIOD ORCHESTRA_CONF_UNICAST_PERIOD +#else /* ORCHESTRA_CONF_UNICAST_PERIOD */ #define ORCHESTRA_UNICAST_PERIOD 17 -#endif /* ORCHESTRA_CONF_COMMON_SHARED_PERIOD */ +#endif /* ORCHESTRA_CONF_UNICAST_PERIOD */ /* Is the per-neighbor unicast slotframe sender-based (if not, it is receiver-based). * Note: sender-based works only with RPL storing mode as it relies on DAO and @@ -81,12 +81,12 @@ #define ORCHESTRA_UNICAST_SENDER_BASED 0 #endif /* ORCHESTRA_CONF_UNICAST_SENDER_BASED */ -/* The hash function used to assign timeslot to a diven node (based on its link-layer address) */ +/* The hash function used to assign timeslot to a given node (based on its link-layer address) */ #ifdef ORCHESTRA_CONF_LINKADDR_HASH #define ORCHESTRA_LINKADDR_HASH ORCHESTRA_CONF_LINKADDR_HASH -#else /* ORCHESTRA_CONF_UNICAST_SENDER_BASED */ +#else /* ORCHESTRA_CONF_LINKADDR_HASH */ #define ORCHESTRA_LINKADDR_HASH(addr) ((addr != NULL) ? (addr)->u8[LINKADDR_SIZE - 1] : -1) -#endif /* ORCHESTRA_CONF_UNICAST_SENDER_BASED */ +#endif /* ORCHESTRA_CONF_LINKADDR_HASH */ /* The maximum hash */ #ifdef ORCHESTRA_CONF_MAX_HASH diff --git a/apps/orchestra/orchestra-rule-unicast-per-neighbor.c b/apps/orchestra/orchestra-rule-unicast-per-neighbor.c index 994a896ab..b70a907d0 100644 --- a/apps/orchestra/orchestra-rule-unicast-per-neighbor.c +++ b/apps/orchestra/orchestra-rule-unicast-per-neighbor.c @@ -45,7 +45,7 @@ #include "net/packetbuf.h" #if ORCHESTRA_UNICAST_SENDER_BASED && ORCHESTRA_COLLISION_FREE_HASH -#define UNICAST_SLOT_SHARED_FLAG ((ORCHESTRA_UNICAST_PERIOD < ORCHESTRA_MAX_HASH) ? LINK_OPTION_SHARED : 0) +#define UNICAST_SLOT_SHARED_FLAG ((ORCHESTRA_UNICAST_PERIOD < (ORCHESTRA_MAX_HASH + 1)) ? LINK_OPTION_SHARED : 0) #else #define UNICAST_SLOT_SHARED_FLAG LINK_OPTION_SHARED #endif diff --git a/core/net/mac/tsch/README.md b/core/net/mac/tsch/README.md index 8ffd639b2..ffd6dc789 100644 --- a/core/net/mac/tsch/README.md +++ b/core/net/mac/tsch/README.md @@ -43,7 +43,7 @@ four implementations it was tested against. We have designed this implementation with IPv6 and RPL in mind, but the code is fully independent from upper layers (with the exception of the optional `tsch-rpl.[ch]`), and has been -also tested with Rime (currently only with 64-bit link-later addresses). +also tested with Rime (currently only with 64-bit link-layer addresses). ## Code structure diff --git a/core/net/mac/tsch/tsch-queue.c b/core/net/mac/tsch/tsch-queue.c index affae7fb0..afe868030 100644 --- a/core/net/mac/tsch/tsch-queue.c +++ b/core/net/mac/tsch/tsch-queue.c @@ -45,6 +45,7 @@ #include "contiki.h" #include "lib/list.h" #include "lib/memb.h" +#include "lib/random.h" #include "net/queuebuf.h" #include "net/mac/rdc.h" #include "net/mac/tsch/tsch.h" @@ -76,24 +77,6 @@ LIST(neighbor_list); struct tsch_neighbor *n_broadcast; struct tsch_neighbor *n_eb; -/*---------------------------------------------------------------------------*/ -/** - * A pseudo-random generator with better properties than msp430-libc's default - **/ - -static uint32_t tsch_random_seed; - -static void -tsch_random_init(uint32_t x) -{ - tsch_random_seed = x; -} -static uint8_t -tsch_random_byte(uint8_t window) -{ - tsch_random_seed = tsch_random_seed * 1103515245 + 12345; - return (tsch_random_seed / 65536) & window; -} /*---------------------------------------------------------------------------*/ /* Add a TSCH neighbor */ struct tsch_neighbor * @@ -162,7 +145,15 @@ tsch_queue_update_time_source(const linkaddr_t *new_addr) if(!tsch_is_locked()) { if(!tsch_is_coordinator) { struct tsch_neighbor *old_time_src = tsch_queue_get_time_source(); - struct tsch_neighbor *new_time_src = new_addr ? tsch_queue_add_nbr(new_addr) : NULL; + struct tsch_neighbor *new_time_src = NULL; + + if(new_addr != NULL) { + /* Get/add neighbor, return 0 in case of failure */ + new_time_src = tsch_queue_add_nbr(new_addr); + if(new_time_src == NULL) { + return 0; + } + } if(new_time_src != old_time_src) { PRINTF("TSCH: update time source: %u -> %u\n", @@ -181,9 +172,9 @@ tsch_queue_update_time_source(const linkaddr_t *new_addr) #ifdef TSCH_CALLBACK_NEW_TIME_SOURCE TSCH_CALLBACK_NEW_TIME_SOURCE(old_time_src, new_time_src); #endif - - return 1; } + + return 1; } } return 0; @@ -434,8 +425,10 @@ tsch_queue_backoff_inc(struct tsch_neighbor *n) { /* Increment exponent */ n->backoff_exponent = MIN(n->backoff_exponent + 1, TSCH_MAC_MAX_BE); - /* Pick a window (number of shared slots to skip) */ - n->backoff_window = tsch_random_byte((1 << n->backoff_exponent) - 1); + /* Pick a window (number of shared slots to skip). Ignore least significant + * few bits, which, on some embedded implementations of rand (e.g. msp430-libc), + * are known to have poor pseudo-random properties. */ + n->backoff_window = (random_rand() >> 6) % (1 << n->backoff_exponent); /* Add one to the window as we will decrement it at the end of the current slot * through tsch_queue_update_all_backoff_windows */ n->backoff_window++; @@ -464,8 +457,6 @@ void tsch_queue_init(void) { list_init(neighbor_list); - tsch_random_init(*((uint32_t *)&linkaddr_node_addr) + - *((uint32_t *)&linkaddr_node_addr + 1)); memb_init(&neighbor_memb); memb_init(&packet_memb); /* Add virtual EB and the broadcast neighbors */ diff --git a/core/net/mac/tsch/tsch-queue.h b/core/net/mac/tsch/tsch-queue.h index 212129fb5..b4061be23 100644 --- a/core/net/mac/tsch/tsch-queue.h +++ b/core/net/mac/tsch/tsch-queue.h @@ -49,15 +49,31 @@ #ifdef TSCH_QUEUE_CONF_NUM_PER_NEIGHBOR #define TSCH_QUEUE_NUM_PER_NEIGHBOR TSCH_QUEUE_CONF_NUM_PER_NEIGHBOR #else +/* By default, round QUEUEBUF_CONF_NUM to next power of two + * (in the range [4;256]) */ +#if QUEUEBUF_CONF_NUM <= 4 +#define TSCH_QUEUE_NUM_PER_NEIGHBOR 4 +#elif QUEUEBUF_CONF_NUM <= 8 #define TSCH_QUEUE_NUM_PER_NEIGHBOR 8 +#elif QUEUEBUF_CONF_NUM <= 16 +#define TSCH_QUEUE_NUM_PER_NEIGHBOR 16 +#elif QUEUEBUF_CONF_NUM <= 32 +#define TSCH_QUEUE_NUM_PER_NEIGHBOR 32 +#elif QUEUEBUF_CONF_NUM <= 64 +#define TSCH_QUEUE_NUM_PER_NEIGHBOR 64 +#elif QUEUEBUF_CONF_NUM <= 128 +#define TSCH_QUEUE_NUM_PER_NEIGHBOR 128 +#else +#define TSCH_QUEUE_NUM_PER_NEIGHBOR 256 +#endif #endif -/* The number of neighbor queues. There two queues allocated for - * one EBs, one for broadcasts. Other queues are real neighbors */ +/* The number of neighbor queues. There are two queues allocated at all times: + * one for EBs, one for broadcasts. Other queues are for unicast to neighbors */ #ifdef TSCH_QUEUE_CONF_MAX_NEIGHBOR_QUEUES #define TSCH_QUEUE_MAX_NEIGHBOR_QUEUES TSCH_QUEUE_CONF_MAX_NEIGHBOR_QUEUES #else -#define TSCH_QUEUE_MAX_NEIGHBOR_QUEUES 8 +#define TSCH_QUEUE_MAX_NEIGHBOR_QUEUES ((NBR_TABLE_CONF_MAX_NEIGHBORS) + 2) #endif /* TSCH CSMA-CA parameters, see IEEE 802.15.4e-2012 */ diff --git a/core/net/mac/tsch/tsch-slot-operation.c b/core/net/mac/tsch/tsch-slot-operation.c index be6c96422..2ce84d50e 100644 --- a/core/net/mac/tsch/tsch-slot-operation.c +++ b/core/net/mac/tsch/tsch-slot-operation.c @@ -91,7 +91,7 @@ #error TSCH_DEQUEUED_ARRAY_SIZE must be greater or equal to QUEUEBUF_NUM #endif #if (TSCH_DEQUEUED_ARRAY_SIZE & (TSCH_DEQUEUED_ARRAY_SIZE - 1)) != 0 -#error TSCH_QUEUE_NUM_PER_NEIGHBOR must be power of two +#error TSCH_DEQUEUED_ARRAY_SIZE must be power of two #endif /* Truncate received drift correction information to maximum half @@ -190,7 +190,7 @@ tsch_get_lock(void) /* Issue a log whenever we had to busy wait until getting the lock */ TSCH_LOG_ADD(tsch_log_message, snprintf(log->message, sizeof(log->message), - "!get lock delay %u", busy_wait_time); + "!get lock delay %u", (unsigned)busy_wait_time); ); } return 1; @@ -248,28 +248,24 @@ check_timer_miss(rtimer_clock_t ref_time, rtimer_clock_t offset, rtimer_clock_t /*---------------------------------------------------------------------------*/ /* Schedule a wakeup at a specified offset from a reference time. * Provides basic protection against missed deadlines and timer overflows - * A non-zero return value signals to tsch_slot_operation a missed deadline. - * If conditional: schedule only if the deadline is not missed, else busy wait. - * If not conditional: schedule regardless of deadline miss. */ + * A return value of zero signals a missed deadline: no rtimer was scheduled. */ static uint8_t -tsch_schedule_slot_operation(struct rtimer *tm, rtimer_clock_t ref_time, rtimer_clock_t offset, int conditional, const char *str) +tsch_schedule_slot_operation(struct rtimer *tm, rtimer_clock_t ref_time, rtimer_clock_t offset, const char *str) { rtimer_clock_t now = RTIMER_NOW(); int r; + /* Subtract RTIMER_GUARD before checking for deadline miss + * because we can not schedule rtimer less than RTIMER_GUARD in the future */ int missed = check_timer_miss(ref_time, offset - RTIMER_GUARD, now); if(missed) { TSCH_LOG_ADD(tsch_log_message, snprintf(log->message, sizeof(log->message), - "!dl-miss-%d %s %d %d", - conditional, str, - (int)(now-ref_time), (int)offset); + "!dl-miss %s %d %d", + str, (int)(now-ref_time), (int)offset); ); - if(conditional) { - BUSYWAIT_UNTIL_ABS(0, ref_time, offset); - return 0; - } + return 0; } ref_time += offset; r = rtimer_set(tm, ref_time, 1, (void (*)(struct rtimer *, void *))tsch_slot_operation, NULL); @@ -279,14 +275,16 @@ tsch_schedule_slot_operation(struct rtimer *tm, rtimer_clock_t ref_time, rtimer_ return 1; } /*---------------------------------------------------------------------------*/ -/* Schedule slot operation conditionally, and YIELD if success only */ +/* Schedule slot operation conditionally, and YIELD if success only. + * Always attempt to schedule RTIMER_GUARD before the target to make sure to wake up + * ahead of time and then busy wait to exactly hit the target. */ #define TSCH_SCHEDULE_AND_YIELD(pt, tm, ref_time, offset, str) \ do { \ - if(tsch_schedule_slot_operation(tm, ref_time, offset, 1, str)) { \ + if(tsch_schedule_slot_operation(tm, ref_time, offset - RTIMER_GUARD, str)) { \ PT_YIELD(pt); \ } \ + BUSYWAIT_UNTIL_ABS(0, ref_time, offset); \ } while(0); - /*---------------------------------------------------------------------------*/ /* Get EB, broadcast or unicast packet to be sent, and target neighbor. */ static struct tsch_packet * @@ -396,8 +394,6 @@ PT_THREAD(tsch_tx_slot(struct pt *pt, struct rtimer *t)) * successful Tx or Drop) */ dequeued_index = ringbufindex_peek_put(&dequeued_ringbuf); if(dequeued_index != -1) { - /* is this a data packet? */ - static uint8_t is_data; if(current_packet == NULL || current_packet->qb == NULL) { mac_tx_status = MAC_TX_ERR_FATAL; } else { @@ -424,7 +420,6 @@ PT_THREAD(tsch_tx_slot(struct pt *pt, struct rtimer *t)) packet_len = queuebuf_datalen(current_packet->qb); /* is this a broadcast packet? (wait for ack?) */ is_broadcast = current_neighbor->is_broadcast; - is_data = ((((uint8_t *)(packet))[0]) & 7) == FRAME802154_DATAFRAME; /* read seqno from payload */ seqno = ((uint8_t *)(packet))[2]; /* if this is an EB, then update its Sync-IE */ @@ -601,7 +596,7 @@ PT_THREAD(tsch_tx_slot(struct pt *pt, struct rtimer *t)) log->tx.datalen = queuebuf_datalen(current_packet->qb); log->tx.drift = drift_correction; log->tx.drift_used = drift_neighbor != NULL; - log->tx.is_data = is_data; + log->tx.is_data = ((((uint8_t *)(queuebuf_dataptr(current_packet->qb)))[0]) & 7) == FRAME802154_DATAFRAME; log->tx.sec_level = queuebuf_attr(current_packet->qb, PACKETBUF_ATTR_SECURITY_LEVEL); log->tx.dest = TSCH_LOG_ID_FROM_LINKADDR(queuebuf_addr(current_packet->qb, PACKETBUF_ADDR_RECEIVER)); ); @@ -917,7 +912,7 @@ PT_THREAD(tsch_slot_operation(struct rtimer *t, void *ptr)) /* Update current slot start */ prev_slot_start = current_slot_start; current_slot_start += time_to_next_active_slot; - } while(!tsch_schedule_slot_operation(t, prev_slot_start, time_to_next_active_slot, 1, "main")); + } while(!tsch_schedule_slot_operation(t, prev_slot_start, time_to_next_active_slot, "main")); } tsch_in_slot_operation = 0; @@ -952,7 +947,7 @@ tsch_slot_operation_start(void) /* Update current slot start */ prev_slot_start = current_slot_start; current_slot_start += time_to_next_active_slot; - } while(!tsch_schedule_slot_operation(&slot_operation_timer, prev_slot_start, time_to_next_active_slot, 1, "association")); + } while(!tsch_schedule_slot_operation(&slot_operation_timer, prev_slot_start, time_to_next_active_slot, "association")); } /*---------------------------------------------------------------------------*/ /* Start actual slot operation */ diff --git a/core/net/mac/tsch/tsch-slot-operation.h b/core/net/mac/tsch/tsch-slot-operation.h index 64382fcc8..76d495848 100644 --- a/core/net/mac/tsch/tsch-slot-operation.h +++ b/core/net/mac/tsch/tsch-slot-operation.h @@ -47,7 +47,23 @@ #ifdef TSCH_CONF_DEQUEUED_ARRAY_SIZE #define TSCH_DEQUEUED_ARRAY_SIZE TSCH_CONF_DEQUEUED_ARRAY_SIZE #else +/* By default, round QUEUEBUF_CONF_NUM to next power of two + * (in the range [4;256]) */ +#if QUEUEBUF_CONF_NUM <= 4 +#define TSCH_DEQUEUED_ARRAY_SIZE 4 +#elif QUEUEBUF_CONF_NUM <= 8 +#define TSCH_DEQUEUED_ARRAY_SIZE 8 +#elif QUEUEBUF_CONF_NUM <= 16 #define TSCH_DEQUEUED_ARRAY_SIZE 16 +#elif QUEUEBUF_CONF_NUM <= 32 +#define TSCH_DEQUEUED_ARRAY_SIZE 32 +#elif QUEUEBUF_CONF_NUM <= 64 +#define TSCH_DEQUEUED_ARRAY_SIZE 64 +#elif QUEUEBUF_CONF_NUM <= 128 +#define TSCH_DEQUEUED_ARRAY_SIZE 128 +#else +#define TSCH_DEQUEUED_ARRAY_SIZE 256 +#endif #endif /* Size of the ring buffer storing incoming packets. diff --git a/core/net/mac/tsch/tsch.c b/core/net/mac/tsch/tsch.c index 1a943bbf0..5aadf09af 100644 --- a/core/net/mac/tsch/tsch.c +++ b/core/net/mac/tsch/tsch.c @@ -391,7 +391,7 @@ tsch_tx_process_pending() ringbufindex_get(&dequeued_ringbuf); } } - +/*---------------------------------------------------------------------------*/ /* Setup TSCH as a coordinator */ static void tsch_start_coordinator(void) @@ -407,15 +407,13 @@ tsch_start_coordinator(void) tsch_is_associated = 1; tsch_join_priority = 0; - PRINTF("TSCH: starting as coordinator, asn-%x.%lx\n", - current_asn.ms1b, current_asn.ls4b); + PRINTF("TSCH: starting as coordinator, PAN ID %x, asn-%x.%lx\n", + frame802154_get_pan_id(), current_asn.ms1b, current_asn.ls4b); - /* Start only after some initial delay */ - tsch_slot_operation_sync( - RTIMER_NOW() + TSCH_CLOCK_TO_TICKS(CLOCK_SECOND / 10), - ¤t_asn); + /* Start slot operation */ + tsch_slot_operation_sync(RTIMER_NOW(), ¤t_asn); } - +/*---------------------------------------------------------------------------*/ /* Leave the TSCH network */ void tsch_disassociate(void) @@ -426,7 +424,7 @@ tsch_disassociate(void) PRINTF("TSCH: leaving the network\n"); } } - +/*---------------------------------------------------------------------------*/ /* Attempt to associate to a network form an incoming EB */ static int tsch_associate(const struct input_packet *input_eb, rtimer_clock_t timestamp) diff --git a/examples/ipv6/rpl-tsch/project-conf.h b/examples/ipv6/rpl-tsch/project-conf.h index a5b2953cc..7ecfb74c1 100644 --- a/examples/ipv6/rpl-tsch/project-conf.h +++ b/examples/ipv6/rpl-tsch/project-conf.h @@ -133,11 +133,7 @@ #undef UIP_CONF_TCP #define UIP_CONF_TCP 0 #undef QUEUEBUF_CONF_NUM -#define QUEUEBUF_CONF_NUM 6 -#undef TSCH_QUEUE_CONF_NUM_PER_NEIGHBOR -#define TSCH_QUEUE_CONF_NUM_PER_NEIGHBOR 8 -#undef TSCH_QUEUE_CONF_MAX_NEIGHBOR_QUEUES -#define TSCH_QUEUE_CONF_MAX_NEIGHBOR_QUEUES 6 +#define QUEUEBUF_CONF_NUM 4 #undef UIP_CONF_MAX_ROUTES #define UIP_CONF_MAX_ROUTES 8 #undef NBR_TABLE_CONF_MAX_NEIGHBORS