48 #include "lib/random.h"
51 #include "net/mac/tsch/tsch.h"
53 #include "net/mac/tsch/tsch-queue.h"
54 #include "net/mac/tsch/tsch-schedule.h"
55 #include "net/mac/tsch/tsch-slot-operation.h"
56 #include "net/mac/tsch/tsch-log.h"
59 #if TSCH_LOG_LEVEL >= 1
60 #define DEBUG DEBUG_PRINT
62 #define DEBUG DEBUG_NONE
67 #if (TSCH_QUEUE_NUM_PER_NEIGHBOR & (TSCH_QUEUE_NUM_PER_NEIGHBOR - 1)) != 0
68 #error TSCH_QUEUE_NUM_PER_NEIGHBOR must be power of two
72 MEMB(packet_memb,
struct tsch_packet, QUEUEBUF_NUM);
73 MEMB(neighbor_memb,
struct tsch_neighbor, TSCH_QUEUE_MAX_NEIGHBOR_QUEUES);
77 struct tsch_neighbor *n_broadcast;
78 struct tsch_neighbor *n_eb;
82 struct tsch_neighbor *
83 tsch_queue_add_nbr(
const linkaddr_t *
addr)
85 struct tsch_neighbor *n =
NULL;
87 n = tsch_queue_get_nbr(addr);
94 memset(n, 0,
sizeof(
struct tsch_neighbor));
95 ringbufindex_init(&n->tx_ringbuf, TSCH_QUEUE_NUM_PER_NEIGHBOR);
99 tsch_queue_backoff_reset(n);
110 struct tsch_neighbor *
111 tsch_queue_get_nbr(
const linkaddr_t *addr)
113 if(!tsch_is_locked()) {
114 struct tsch_neighbor *n =
list_head(neighbor_list);
126 struct tsch_neighbor *
127 tsch_queue_get_time_source(
void)
129 if(!tsch_is_locked()) {
130 struct tsch_neighbor *curr_nbr =
list_head(neighbor_list);
131 while(curr_nbr !=
NULL) {
132 if(curr_nbr->is_time_source) {
143 tsch_queue_update_time_source(
const linkaddr_t *new_addr)
145 if(!tsch_is_locked()) {
146 if(!tsch_is_coordinator) {
147 struct tsch_neighbor *old_time_src = tsch_queue_get_time_source();
148 struct tsch_neighbor *new_time_src =
NULL;
150 if(new_addr !=
NULL) {
152 new_time_src = tsch_queue_add_nbr(new_addr);
153 if(new_time_src ==
NULL) {
158 if(new_time_src != old_time_src) {
159 PRINTF(
"TSCH: update time source: %u -> %u\n",
160 TSCH_LOG_ID_FROM_LINKADDR(old_time_src ? &old_time_src->addr :
NULL),
161 TSCH_LOG_ID_FROM_LINKADDR(new_time_src ? &new_time_src->addr : NULL));
164 if(new_time_src != NULL) {
165 new_time_src->is_time_source = 1;
168 if(old_time_src != NULL) {
169 old_time_src->is_time_source = 0;
172 #ifdef TSCH_CALLBACK_NEW_TIME_SOURCE
173 TSCH_CALLBACK_NEW_TIME_SOURCE(old_time_src, new_time_src);
185 tsch_queue_flush_nbr_queue(
struct tsch_neighbor *n)
187 while(!tsch_queue_is_empty(n)) {
188 struct tsch_packet *p = tsch_queue_remove_packet_from_queue(n);
192 PRINTF(
"TSCH-queue:! flushing packet\n");
194 mac_call_sent_callback(p->sent, p->ptr, p->ret, p->transmissions);
196 tsch_queue_free_packet(p);
203 tsch_queue_remove_nbr(
struct tsch_neighbor *n)
206 if(tsch_get_lock()) {
214 tsch_queue_flush_nbr_queue(n);
224 tsch_queue_add_packet(
const linkaddr_t *addr, mac_callback_t sent,
void *ptr)
226 struct tsch_neighbor *n =
NULL;
227 int16_t put_index = -1;
228 struct tsch_packet *p =
NULL;
229 if(!tsch_is_locked()) {
230 n = tsch_queue_add_nbr(addr);
232 put_index = ringbufindex_peek_put(&n->tx_ringbuf);
233 if(put_index != -1) {
237 #ifdef TSCH_CALLBACK_PACKET_READY
238 TSCH_CALLBACK_PACKET_READY();
240 p->qb = queuebuf_new_from_packetbuf();
245 p->transmissions = 0;
247 n->tx_array[put_index] = p;
248 ringbufindex_put(&n->tx_ringbuf);
257 PRINTF(
"TSCH-queue:! add packet failed: %u %p %d %p %p\n", tsch_is_locked(), n, put_index, p, p ? p->qb :
NULL);
263 tsch_queue_packet_count(
const linkaddr_t *addr)
265 struct tsch_neighbor *n =
NULL;
266 if(!tsch_is_locked()) {
267 n = tsch_queue_add_nbr(addr);
269 return ringbufindex_elements(&n->tx_ringbuf);
277 tsch_queue_remove_packet_from_queue(
struct tsch_neighbor *n)
279 if(!tsch_is_locked()) {
282 int16_t get_index = ringbufindex_get(&n->tx_ringbuf);
283 if(get_index != -1) {
284 return n->tx_array[get_index];
295 tsch_queue_free_packet(
struct tsch_packet *p)
298 queuebuf_free(p->qb);
305 tsch_queue_reset(
void)
308 if(!tsch_is_locked()) {
309 struct tsch_neighbor *n =
list_head(neighbor_list);
313 tsch_queue_flush_nbr_queue(n);
315 tsch_queue_backoff_reset(n);
323 tsch_queue_free_unused_neighbors(
void)
326 if(!tsch_is_locked()) {
327 struct tsch_neighbor *n =
list_head(neighbor_list);
332 if(!n->is_broadcast && !n->is_time_source && !n->tx_links_count
333 && tsch_queue_is_empty(n)) {
334 tsch_queue_remove_nbr(n);
343 tsch_queue_is_empty(
const struct tsch_neighbor *n)
345 return !tsch_is_locked() && n !=
NULL && ringbufindex_empty(&n->tx_ringbuf);
350 tsch_queue_get_packet_for_nbr(
const struct tsch_neighbor *n,
struct tsch_link *link)
352 if(!tsch_is_locked()) {
353 int is_shared_link = link !=
NULL && link->link_options & LINK_OPTION_SHARED;
355 int16_t get_index = ringbufindex_peek_get(&n->tx_ringbuf);
356 if(get_index != -1 &&
357 !(is_shared_link && !tsch_queue_backoff_expired(n))) {
359 #if TSCH_WITH_LINK_SELECTOR
360 int packet_attr_slotframe = queuebuf_attr(n->tx_array[get_index]->qb, PACKETBUF_ATTR_TSCH_SLOTFRAME);
361 int packet_attr_timeslot = queuebuf_attr(n->tx_array[get_index]->qb, PACKETBUF_ATTR_TSCH_TIMESLOT);
362 if(packet_attr_slotframe != 0xffff && packet_attr_slotframe != link->slotframe_handle) {
365 if(packet_attr_timeslot != 0xffff && packet_attr_timeslot != link->timeslot) {
369 return n->tx_array[get_index];
378 tsch_queue_get_packet_for_dest_addr(
const linkaddr_t *addr,
struct tsch_link *link)
380 if(!tsch_is_locked()) {
381 return tsch_queue_get_packet_for_nbr(tsch_queue_get_nbr(addr), link);
389 tsch_queue_get_unicast_packet_for_any(
struct tsch_neighbor **n,
struct tsch_link *link)
391 if(!tsch_is_locked()) {
392 struct tsch_neighbor *curr_nbr =
list_head(neighbor_list);
393 struct tsch_packet *p =
NULL;
394 while(curr_nbr !=
NULL) {
395 if(!curr_nbr->is_broadcast && curr_nbr->tx_links_count == 0) {
397 p = tsch_queue_get_packet_for_nbr(curr_nbr, link);
413 tsch_queue_backoff_expired(
const struct tsch_neighbor *n)
415 return n->backoff_window == 0;
420 tsch_queue_backoff_reset(
struct tsch_neighbor *n)
422 n->backoff_window = 0;
423 n->backoff_exponent = TSCH_MAC_MIN_BE;
428 tsch_queue_backoff_inc(
struct tsch_neighbor *n)
431 n->backoff_exponent = MIN(n->backoff_exponent + 1, TSCH_MAC_MAX_BE);
435 n->backoff_window = (
random_rand() >> 6) % (1 << n->backoff_exponent);
443 tsch_queue_update_all_backoff_windows(
const linkaddr_t *dest_addr)
445 if(!tsch_is_locked()) {
446 int is_broadcast =
linkaddr_cmp(dest_addr, &tsch_broadcast_address);
447 struct tsch_neighbor *n =
list_head(neighbor_list);
449 if(n->backoff_window != 0
450 && ((n->tx_links_count == 0 && is_broadcast)
451 || (n->tx_links_count > 0 &&
linkaddr_cmp(dest_addr, &n->addr)))) {
461 tsch_queue_init(
void)
467 n_eb = tsch_queue_add_nbr(&tsch_eb_address);
468 n_broadcast = tsch_queue_add_nbr(&tsch_broadcast_address);
void list_remove(list_t list, void *item)
Remove a specific element from a list.
#define LIST(name)
Declare a linked list.
static uip_ds6_addr_t * addr
Pointer to a router list entry.
#define MEMB(name, structure, num)
Declare a memory block.
void * list_item_next(void *item)
Get the next item following this item.
Private TSCH definitions (meant for use by TSCH implementation files only) ...
The MAC layer transmission could not be performed because of a fatal error.
void list_init(list_t list)
Initialize a list.
The MAC layer transmission could not be performed because of an error.
void memb_init(struct memb *m)
Initialize a memory block that was declared with MEMB().
void * list_head(list_t list)
Get a pointer to the first element of a list.
A set of debugging macros for the netstack
#define NULL
The null pointer.
unsigned short random_rand(void)
Generates a new random number using the cc2538 RNG.
void list_add(list_t list, void *item)
Add an item at the end of a list.
Linked list manipulation routines.
Memory block allocation routines.
Header file for the Rime queue buffer management
int linkaddr_cmp(const linkaddr_t *addr1, const linkaddr_t *addr2)
Compare two Rime addresses.
void linkaddr_copy(linkaddr_t *dest, const linkaddr_t *src)
Copy a Rime address.
void * memb_alloc(struct memb *m)
Allocate a memory block from a block of memory declared with MEMB().
char memb_free(struct memb *m, void *ptr)
Deallocate a memory block from a memory block previously declared with MEMB().