This commit is contained in:
Simon Duquennoy 2015-11-21 00:08:00 +01:00
parent 27da5b8ab5
commit 7eabf8d391
9 changed files with 85 additions and 73 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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 */

View file

@ -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 */

View file

@ -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 */

View file

@ -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.

View file

@ -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),
&current_asn);
/* Start slot operation */
tsch_slot_operation_sync(RTIMER_NOW(), &current_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)

View file

@ -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