Contiki-NG
tsch-schedule.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2014, SICS Swedish ICT.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the Institute nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * This file is part of the Contiki operating system.
30 *
31 */
32
33/**
34 * \file
35 * IEEE 802.15.4 TSCH MAC schedule manager.
36 * \author
37 * Simon Duquennoy <simonduq@sics.se>
38 * Beshr Al Nahas <beshr@sics.se>
39 * Atis Elsts <atis.elsts@edi.lv>
40 */
41
42/**
43 * \addtogroup tsch
44 * @{
45*/
46
47#include "contiki.h"
48#include "dev/leds.h"
49#include "lib/memb.h"
50#include "net/nbr-table.h"
51#include "net/packetbuf.h"
52#include "net/queuebuf.h"
53#include "net/mac/tsch/tsch.h"
55#include "sys/process.h"
56#include "sys/rtimer.h"
57#include <string.h>
58
59/* Log configuration */
60#include "sys/log.h"
61#define LOG_MODULE "TSCH Sched"
62#define LOG_LEVEL LOG_LEVEL_MAC
63
64/* Pre-allocated space for links */
65MEMB(link_memb, struct tsch_link, TSCH_SCHEDULE_MAX_LINKS);
66/* Pre-allocated space for slotframes */
67MEMB(slotframe_memb, struct tsch_slotframe, TSCH_SCHEDULE_MAX_SLOTFRAMES);
68/* List of slotframes (each slotframe holds its own list of links) */
69LIST(slotframe_list);
70
71/* Adds and returns a slotframe (NULL if failure) */
72struct tsch_slotframe *
73tsch_schedule_add_slotframe(uint16_t handle, uint16_t size)
74{
75 if(size == 0) {
76 return NULL;
77 }
78
80 /* A slotframe with this handle already exists */
81 return NULL;
82 }
83
84 if(tsch_get_lock()) {
85 struct tsch_slotframe *sf = memb_alloc(&slotframe_memb);
86 if(sf != NULL) {
87 /* Initialize the slotframe */
88 sf->handle = handle;
89 TSCH_ASN_DIVISOR_INIT(sf->size, size);
90 LIST_STRUCT_INIT(sf, links_list);
91 /* Add the slotframe to the global list */
92 list_add(slotframe_list, sf);
93 }
94 LOG_INFO("add_slotframe %u %u\n",
95 handle, size);
97 return sf;
98 }
99 return NULL;
100}
101/*---------------------------------------------------------------------------*/
102/* Removes all slotframes, resulting in an empty schedule */
103int
105{
106 struct tsch_slotframe *sf;
107 while((sf = list_head(slotframe_list))) {
108 if(tsch_schedule_remove_slotframe(sf) == 0) {
109 return 0;
110 }
111 }
112 return 1;
113}
114/*---------------------------------------------------------------------------*/
115/* Removes a slotframe Return 1 if success, 0 if failure */
116int
118{
119 if(slotframe != NULL) {
120 /* Remove all links belonging to this slotframe */
121 struct tsch_link *l;
122 while((l = list_head(slotframe->links_list))) {
123 tsch_schedule_remove_link(slotframe, l);
124 }
125
126 /* Now that the slotframe has no links, remove it. */
127 if(tsch_get_lock()) {
128 LOG_INFO("remove slotframe %u %u\n", slotframe->handle, slotframe->size.val);
129 memb_free(&slotframe_memb, slotframe);
130 list_remove(slotframe_list, slotframe);
132 return 1;
133 }
134 }
135 return 0;
136}
137/*---------------------------------------------------------------------------*/
138/* Looks for a slotframe from a handle */
139struct tsch_slotframe *
141{
142 if(!tsch_is_locked()) {
143 struct tsch_slotframe *sf = list_head(slotframe_list);
144 while(sf != NULL) {
145 if(sf->handle == handle) {
146 return sf;
147 }
148 sf = list_item_next(sf);
149 }
150 }
151 return NULL;
152}
153/*---------------------------------------------------------------------------*/
154/* Looks for a link from a handle */
155struct tsch_link *
157{
158 if(!tsch_is_locked()) {
159 struct tsch_slotframe *sf = list_head(slotframe_list);
160 while(sf != NULL) {
161 struct tsch_link *l = list_head(sf->links_list);
162 /* Loop over all items. Assume there is max one link per timeslot */
163 while(l != NULL) {
164 if(l->handle == handle) {
165 return l;
166 }
167 l = list_item_next(l);
168 }
169 sf = list_item_next(sf);
170 }
171 }
172 return NULL;
173}
174/*---------------------------------------------------------------------------*/
175static const char *
176print_link_options(uint16_t link_options)
177{
178 static char buffer[20];
179 unsigned length;
180
181 buffer[0] = '\0';
182 if(link_options & LINK_OPTION_TX) {
183 strcat(buffer, "Tx|");
184 }
185 if(link_options & LINK_OPTION_RX) {
186 strcat(buffer, "Rx|");
187 }
188 if(link_options & LINK_OPTION_SHARED) {
189 strcat(buffer, "Sh|");
190 }
191 length = strlen(buffer);
192 if(length > 0) {
193 buffer[length - 1] = '\0';
194 }
195
196 return buffer;
197}
198/*---------------------------------------------------------------------------*/
199static const char *
200print_link_type(uint16_t link_type)
201{
202 switch(link_type) {
203 case LINK_TYPE_NORMAL:
204 return "NORMAL";
205 case LINK_TYPE_ADVERTISING:
206 return "ADV";
207 case LINK_TYPE_ADVERTISING_ONLY:
208 return "ADV_ONLY";
209 default:
210 return "?";
211 }
212}
213/*---------------------------------------------------------------------------*/
214/* Adds a link to a slotframe, return a pointer to it (NULL if failure) */
215struct tsch_link *
217 uint8_t link_options, enum link_type link_type, const linkaddr_t *address,
218 uint16_t timeslot, uint16_t channel_offset, uint8_t do_remove)
219{
220 struct tsch_link *l = NULL;
221 if(slotframe != NULL) {
222 /* We currently support only one link per timeslot in a given slotframe. */
223
224 /* Validation of specified timeslot and channel_offset */
225 if(timeslot > (slotframe->size.val - 1)) {
226 LOG_ERR("! add_link invalid timeslot: %u\n", timeslot);
227 return NULL;
228 }
229
230 if(do_remove) {
231 /* Start with removing the link currently installed at this timeslot (needed
232 * to keep neighbor state in sync with link options etc.) */
233 tsch_schedule_remove_link_by_timeslot(slotframe, timeslot, channel_offset);
234 }
235 if(!tsch_get_lock()) {
236 LOG_ERR("! add_link memb_alloc couldn't take lock\n");
237 } else {
238 l = memb_alloc(&link_memb);
239 if(l == NULL) {
240 LOG_ERR("! add_link memb_alloc failed\n");
242 } else {
243 static int current_link_handle = 0;
244 struct tsch_neighbor *n;
245 /* Add the link to the slotframe */
246 list_add(slotframe->links_list, l);
247 /* Initialize link */
248 l->handle = current_link_handle++;
249 l->link_options = link_options;
250 l->link_type = link_type;
251 l->slotframe_handle = slotframe->handle;
252 l->timeslot = timeslot;
253 l->channel_offset = channel_offset;
254 l->data = NULL;
255 if(address == NULL) {
256 address = &linkaddr_null;
257 }
258 linkaddr_copy(&l->addr, address);
259
260 LOG_INFO("add_link sf=%u opt=%s type=%s ts=%u ch=%u addr=",
261 slotframe->handle,
262 print_link_options(link_options),
263 print_link_type(link_type), timeslot, channel_offset);
264 LOG_INFO_LLADDR(address);
265 LOG_INFO_("\n");
266 /* Release the lock before we update the neighbor (will take the lock) */
268
269 if(l->link_options & LINK_OPTION_TX) {
270 n = tsch_queue_add_nbr(&l->addr);
271 /* We have a tx link to this neighbor, update counters */
272 if(n != NULL) {
273 n->tx_links_count++;
274 if(!(l->link_options & LINK_OPTION_SHARED)) {
275 n->dedicated_tx_links_count++;
276 }
277 }
278 }
279 }
280 }
281 }
282 return l;
283}
284/*---------------------------------------------------------------------------*/
285/* Removes a link from slotframe. Return 1 if success, 0 if failure */
286int
288{
289 if(slotframe != NULL && l != NULL && l->slotframe_handle == slotframe->handle) {
290 if(tsch_get_lock()) {
291 uint8_t link_options;
292 linkaddr_t addr;
293
294 /* Save link option and addr in local variables as we need them
295 * after freeing the link */
296 link_options = l->link_options;
297 linkaddr_copy(&addr, &l->addr);
298
299 /* The link to be removed is scheduled as next, set it to NULL
300 * to abort the next link operation */
301 if(l == current_link) {
302 current_link = NULL;
303 }
304 LOG_INFO("remove_link sf=%u opt=%s type=%s ts=%u ch=%u addr=",
305 slotframe->handle,
306 print_link_options(l->link_options),
307 print_link_type(l->link_type), l->timeslot, l->channel_offset);
308 LOG_INFO_LLADDR(&l->addr);
309 LOG_INFO_("\n");
310
311 list_remove(slotframe->links_list, l);
312 memb_free(&link_memb, l);
313
314 /* Release the lock before we update the neighbor (will take the lock) */
316
317 /* This was a tx link to this neighbor, update counters */
318 if(link_options & LINK_OPTION_TX) {
320 if(n != NULL) {
321 n->tx_links_count--;
322 if(!(link_options & LINK_OPTION_SHARED)) {
323 n->dedicated_tx_links_count--;
324 }
325 }
326 }
327
328 return 1;
329 } else {
330 LOG_ERR("! remove_link memb_alloc couldn't take lock\n");
331 }
332 }
333 return 0;
334}
335/*---------------------------------------------------------------------------*/
336/* Removes a link from slotframe and timeslot. Return a 1 if success, 0 if failure */
337int
339 uint16_t timeslot, uint16_t channel_offset)
340{
341 int ret = 0;
342 if(!tsch_is_locked()) {
343 if(slotframe != NULL) {
344 struct tsch_link *l = list_head(slotframe->links_list);
345 /* Loop over all items and remove all matching links */
346 while(l != NULL) {
347 struct tsch_link *next = list_item_next(l);
348 if(l->timeslot == timeslot && l->channel_offset == channel_offset) {
349 if(tsch_schedule_remove_link(slotframe, l)) {
350 ret = 1;
351 }
352 }
353 l = next;
354 }
355 }
356 }
357 return ret;
358}
359/*---------------------------------------------------------------------------*/
360/* Looks within a slotframe for a link with a given timeslot */
361struct tsch_link *
363 uint16_t timeslot, uint16_t channel_offset)
364{
365 if(!tsch_is_locked()) {
366 if(slotframe != NULL) {
367 struct tsch_link *l = list_head(slotframe->links_list);
368 /* Loop over all items. Assume there is max one link per timeslot and channel_offset */
369 while(l != NULL) {
370 if(l->timeslot == timeslot && l->channel_offset == channel_offset) {
371 return l;
372 }
373 l = list_item_next(l);
374 }
375 return l;
376 }
377 }
378 return NULL;
379}
380/*---------------------------------------------------------------------------*/
381static struct tsch_link *
382default_tsch_link_comparator(struct tsch_link *a, struct tsch_link *b)
383{
384 if(!(a->link_options & LINK_OPTION_TX)) {
385 /* None of the links are Tx: simply return the first link */
386 return a;
387 }
388
389 /* Two Tx links at the same slotframe; return the one with most packets to send */
390 if(!linkaddr_cmp(&a->addr, &b->addr)) {
391 struct tsch_neighbor *an = tsch_queue_get_nbr(&a->addr);
392 struct tsch_neighbor *bn = tsch_queue_get_nbr(&b->addr);
393 int a_packet_count = an ? ringbufindex_elements(&an->tx_ringbuf) : 0;
394 int b_packet_count = bn ? ringbufindex_elements(&bn->tx_ringbuf) : 0;
395 /* Compare the number of packets in the queue */
396 return a_packet_count >= b_packet_count ? a : b;
397 }
398
399 /* Same neighbor address; simply return the first link */
400 return a;
401}
402
403/*---------------------------------------------------------------------------*/
404/* Returns the next active link after a given ASN, and a backup link (for the same ASN, with Rx flag) */
405struct tsch_link *
406tsch_schedule_get_next_active_link(struct tsch_asn_t *asn, uint16_t *time_offset,
407 struct tsch_link **backup_link)
408{
409 uint16_t time_to_curr_best = 0;
410 struct tsch_link *curr_best = NULL;
411 struct tsch_link *curr_backup = NULL; /* Keep a back link in case the current link
412 turns out useless when the time comes. For instance, for a Tx-only link, if there is
413 no outgoing packet in queue. In that case, run the backup link instead. The backup link
414 must have Rx flag set. */
415 if(!tsch_is_locked()) {
416 struct tsch_slotframe *sf = list_head(slotframe_list);
417 /* For each slotframe, look for the earliest occurring link */
418 while(sf != NULL) {
419 /* Get timeslot from ASN, given the slotframe length */
420 uint16_t timeslot = TSCH_ASN_MOD(*asn, sf->size);
421 struct tsch_link *l = list_head(sf->links_list);
422 while(l != NULL) {
423 uint16_t time_to_timeslot =
424 l->timeslot > timeslot ?
425 l->timeslot - timeslot :
426 sf->size.val + l->timeslot - timeslot;
427 if(curr_best == NULL || time_to_timeslot < time_to_curr_best) {
428 time_to_curr_best = time_to_timeslot;
429 curr_best = l;
430 curr_backup = NULL;
431 } else if(time_to_timeslot == time_to_curr_best) {
432 struct tsch_link *new_best = NULL;
433 /* Two links are overlapping, we need to select one of them.
434 * By standard: prioritize Tx links first, second by lowest handle */
435 if((curr_best->link_options & LINK_OPTION_TX) == (l->link_options & LINK_OPTION_TX)) {
436 /* Both or neither links have Tx, select the one with lowest handle */
437 if(l->slotframe_handle != curr_best->slotframe_handle) {
438 if(l->slotframe_handle < curr_best->slotframe_handle) {
439 new_best = l;
440 }
441 } else {
442 /* compare the link against the current best link and return the newly selected one */
443 new_best = TSCH_LINK_COMPARATOR(curr_best, l);
444 }
445 } else {
446 /* Select the link that has the Tx option */
447 if(l->link_options & LINK_OPTION_TX) {
448 new_best = l;
449 }
450 }
451
452 /* Maintain backup_link */
453 /* Check if 'l' best can be used as backup */
454 if(new_best != l && (l->link_options & LINK_OPTION_RX)) { /* Does 'l' have Rx flag? */
455 if(curr_backup == NULL || l->slotframe_handle < curr_backup->slotframe_handle) {
456 curr_backup = l;
457 }
458 }
459 /* Check if curr_best can be used as backup */
460 if(new_best != curr_best && (curr_best->link_options & LINK_OPTION_RX)) { /* Does curr_best have Rx flag? */
461 if(curr_backup == NULL || curr_best->slotframe_handle < curr_backup->slotframe_handle) {
462 curr_backup = curr_best;
463 }
464 }
465
466 /* Maintain curr_best */
467 if(new_best != NULL) {
468 curr_best = new_best;
469 }
470 }
471
472 l = list_item_next(l);
473 }
474 sf = list_item_next(sf);
475 }
476 if(time_offset != NULL) {
477 *time_offset = time_to_curr_best;
478 }
479 }
480 if(backup_link != NULL) {
481 *backup_link = curr_backup;
482 }
483 return curr_best;
484}
485/*---------------------------------------------------------------------------*/
486/* Module initialization, call only once at startup. Returns 1 is success, 0 if failure. */
487int
489{
490 if(tsch_get_lock()) {
491 memb_init(&link_memb);
492 memb_init(&slotframe_memb);
493 list_init(slotframe_list);
495 return 1;
496 } else {
497 return 0;
498 }
499}
500/*---------------------------------------------------------------------------*/
501/* Create a 6TiSCH minimal schedule */
502void
504{
505 struct tsch_slotframe *sf_min;
506 /* First, empty current schedule */
508 /* Build 6TiSCH minimal schedule.
509 * We pick a slotframe length of TSCH_SCHEDULE_DEFAULT_LENGTH */
510 sf_min = tsch_schedule_add_slotframe(0, TSCH_SCHEDULE_DEFAULT_LENGTH);
511 /* Add a single Tx|Rx|Shared slot using broadcast address (i.e. usable for unicast and broadcast).
512 * We set the link type to advertising, which is not compliant with 6TiSCH minimal schedule
513 * but is required according to 802.15.4e if also used for EB transmission.
514 * Timeslot: 0, channel offset: 0. */
516 (LINK_OPTION_RX | LINK_OPTION_TX | LINK_OPTION_SHARED | LINK_OPTION_TIME_KEEPING),
517 LINK_TYPE_ADVERTISING, &tsch_broadcast_address,
518 0, 0, 1);
519}
520/*---------------------------------------------------------------------------*/
521struct tsch_slotframe *
523{
524 return list_head(slotframe_list);
525}
526/*---------------------------------------------------------------------------*/
527struct tsch_slotframe *
529{
530 return list_item_next(sf);
531}
532/*---------------------------------------------------------------------------*/
533/* Prints out the current schedule (all slotframes and links) */
534void
536{
537 if(!tsch_is_locked()) {
538 struct tsch_slotframe *sf = list_head(slotframe_list);
539
540 LOG_PRINT("----- start slotframe list -----\n");
541
542 while(sf != NULL) {
543 struct tsch_link *l = list_head(sf->links_list);
544
545 LOG_PRINT("Slotframe Handle %u, size %u\n", sf->handle, sf->size.val);
546
547 while(l != NULL) {
548 LOG_PRINT("* Link Options %02x, type %u, timeslot %u, channel offset %u, address ",
549 l->link_options, l->link_type, l->timeslot, l->channel_offset);
550 LOG_PRINT_LLADDR(&l->addr);
551 LOG_PRINT_("\n");
552 l = list_item_next(l);
553 }
554
555 sf = list_item_next(sf);
556 }
557
558 LOG_PRINT("----- end slotframe list -----\n");
559 }
560}
561/*---------------------------------------------------------------------------*/
562/** @} */
802.15.4 frame creation and parsing functions
void linkaddr_copy(linkaddr_t *dest, const linkaddr_t *src)
Copy a link-layer address.
Definition: linkaddr.c:63
const linkaddr_t linkaddr_null
The null link-layer address.
int linkaddr_cmp(const linkaddr_t *addr1, const linkaddr_t *addr2)
Compare two link-layer addresses.
Definition: linkaddr.c:69
void list_init(list_t list)
Initialize a list.
Definition: list.c:65
void * list_head(const list_t list)
Get a pointer to the first element of a list.
Definition: list.c:82
#define LIST(name)
Declare a linked list.
Definition: list.h:89
void list_add(list_t list, void *item)
Add an item at the end of a list.
Definition: list.c:142
void list_remove(list_t list, const void *item)
Remove a specific element from a list.
Definition: list.c:237
void * list_item_next(const void *item)
Get the next item following this item.
Definition: list.c:322
#define LIST_STRUCT_INIT(struct_ptr, name)
Initialize a linked list that is part of a structure.
Definition: list.h:125
int memb_free(struct memb *m, void *ptr)
Deallocate a memory block from a memory block previously declared with MEMB().
Definition: memb.c:78
void * memb_alloc(struct memb *m)
Allocate a memory block from a block of memory declared with MEMB().
Definition: memb.c:59
void memb_init(struct memb *m)
Initialize a memory block that was declared with MEMB().
Definition: memb.c:52
#define MEMB(name, structure, num)
Declare a memory block.
Definition: memb.h:90
struct tsch_neighbor * tsch_queue_get_nbr(const linkaddr_t *addr)
Get a TSCH neighbor.
Definition: tsch-queue.c:110
int tsch_schedule_init(void)
Module initialization, call only once at init.
struct tsch_slotframe * tsch_schedule_get_slotframe_by_handle(uint16_t handle)
Looks up a slotframe by handle.
struct tsch_link * tsch_schedule_get_next_active_link(struct tsch_asn_t *asn, uint16_t *time_offset, struct tsch_link **backup_link)
Returns the next active link after a given ASN, and a backup link (for the same ASN,...
struct tsch_link * tsch_schedule_add_link(struct tsch_slotframe *slotframe, uint8_t link_options, enum link_type link_type, const linkaddr_t *address, uint16_t timeslot, uint16_t channel_offset, uint8_t do_remove)
Adds a link to a slotframe.
int tsch_schedule_remove_slotframe(struct tsch_slotframe *slotframe)
Removes a slotframe.
#define TSCH_ASN_DIVISOR_INIT(div, val_)
Initialize a struct asn_divisor_t.
Definition: tsch-asn.h:86
struct tsch_slotframe * tsch_schedule_slotframe_head(void)
Access the first item in the list of slotframes.
void tsch_schedule_create_minimal(void)
Create a 6tisch minimal schedule with length TSCH_SCHEDULE_DEFAULT_LENGTH.
struct tsch_link * tsch_schedule_get_link_by_handle(uint16_t handle)
Looks for a link from a handle.
int tsch_schedule_remove_all_slotframes(void)
Removes all slotframes, resulting in an empty schedule.
int tsch_get_lock(void)
Takes the TSCH lock.
void tsch_release_lock(void)
Releases the TSCH lock.
void tsch_schedule_print(void)
Prints out the current schedule (all slotframes and links)
struct tsch_neighbor * tsch_queue_add_nbr(const linkaddr_t *addr)
Add a TSCH neighbor queue.
Definition: tsch-queue.c:81
#define TSCH_ASN_MOD(asn, div)
Returns the result (16 bits) of a modulo operation on ASN, with divisor being a struct asn_divisor_t.
Definition: tsch-asn.h:93
link_type
802.15.4e link types.
Definition: tsch-types.h:54
int tsch_is_locked(void)
Checks if the TSCH lock is set.
struct tsch_link * tsch_schedule_get_link_by_timeslot(struct tsch_slotframe *slotframe, uint16_t timeslot, uint16_t channel_offset)
Looks within a slotframe for a link with a given timeslot.
struct tsch_slotframe * tsch_schedule_add_slotframe(uint16_t handle, uint16_t size)
Creates and adds a new slotframe.
Definition: tsch-schedule.c:73
int tsch_schedule_remove_link_by_timeslot(struct tsch_slotframe *slotframe, uint16_t timeslot, uint16_t channel_offset)
Removes a link from a slotframe and timeslot.
int tsch_schedule_remove_link(struct tsch_slotframe *slotframe, struct tsch_link *l)
Removes a link.
struct tsch_slotframe * tsch_schedule_slotframe_next(struct tsch_slotframe *sf)
Access the next item in the list of slotframes.
Header file for the LED HAL.
Header file for the logging system.
Memory block allocation routines.
Header file for the Packet buffer (packetbuf) management.
Header file for the Contiki process interface.
Header file for the Packet queue buffer management.
int ringbufindex_elements(const struct ringbufindex *r)
Return the number of elements currently in the ring buffer.
Definition: ringbufindex.c:134
Header file for the real-time timer module.
The ASN is an absolute slot number over 5 bytes.
Definition: tsch-asn.h:48
TSCH neighbor information.
Definition: tsch-types.h:109
802.15.4e slotframe (contains links)
Definition: tsch-types.h:84
Main API declarations for TSCH.
static uip_ds6_addr_t * addr
Pointer to a nbr cache entry.
Definition: uip-nd6.c:107