Contiki-NG
Loading...
Searching...
No Matches
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("Adding slotframe %u, size %u\n", handle, size);
96 return sf;
97 }
98 return NULL;
99}
100/*---------------------------------------------------------------------------*/
101/* Removes all slotframes, resulting in an empty schedule */
102int
104{
105 struct tsch_slotframe *sf;
106 while((sf = list_head(slotframe_list))) {
107 if(tsch_schedule_remove_slotframe(sf) == 0) {
108 return 0;
109 }
110 }
111 return 1;
112}
113/*---------------------------------------------------------------------------*/
114/* Removes a slotframe Return 1 if success, 0 if failure */
115int
117{
118 if(slotframe != NULL) {
119 /* Remove all links belonging to this slotframe */
120 struct tsch_link *l;
121 while((l = list_head(slotframe->links_list))) {
122 tsch_schedule_remove_link(slotframe, l);
123 }
124
125 /* Now that the slotframe has no links, remove it. */
126 if(tsch_get_lock()) {
127 LOG_INFO("Remove slotframe %u, size %u\n",
128 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 any link currently installed at this timeslot
232 * (needed to keep neighbor state in sync with link options etc.). We
233 * don't check for channel offset because only one link per timeslot
234 * is allowed in a given slotframe */
235 l = tsch_schedule_get_link_by_timeslot(slotframe, timeslot);
236 if(l != NULL) {
237 tsch_schedule_remove_link(slotframe, l);
238 l = NULL;
239 }
240 }
241 if(!tsch_get_lock()) {
242 LOG_ERR("! add_link memb_alloc couldn't take lock\n");
243 } else {
244 l = memb_alloc(&link_memb);
245 if(l == NULL) {
246 LOG_ERR("! add_link memb_alloc failed\n");
248 } else {
249 static int current_link_handle = 0;
250 struct tsch_neighbor *n;
251 /* Add the link to the slotframe */
252 list_add(slotframe->links_list, l);
253 /* Initialize link */
254 l->handle = current_link_handle++;
255 l->link_options = link_options;
256 l->link_type = link_type;
257 l->slotframe_handle = slotframe->handle;
258 l->timeslot = timeslot;
259 l->channel_offset = channel_offset;
260 l->data = NULL;
261 if(address == NULL) {
262 address = &linkaddr_null;
263 }
264 linkaddr_copy(&l->addr, address);
265
266 LOG_INFO("add_link sf=%u opt=%s type=%s ts=%u ch=%u addr=",
267 slotframe->handle,
268 print_link_options(link_options),
269 print_link_type(link_type), timeslot, channel_offset);
270 LOG_INFO_LLADDR(address);
271 LOG_INFO_("\n");
272 /* Release the lock before we update the neighbor (will take the lock) */
274
275 if(l->link_options & LINK_OPTION_TX) {
276 n = tsch_queue_add_nbr(&l->addr);
277 /* We have a tx link to this neighbor, update counters */
278 if(n != NULL) {
279 n->tx_links_count++;
280 if(!(l->link_options & LINK_OPTION_SHARED)) {
281 n->dedicated_tx_links_count++;
282 }
283 }
284 }
285 }
286 }
287 }
288 return l;
289}
290/*---------------------------------------------------------------------------*/
291/* Removes a link from slotframe. Return 1 if success, 0 if failure */
292int
294{
295 if(slotframe != NULL && l != NULL && l->slotframe_handle == slotframe->handle) {
296 if(tsch_get_lock()) {
297 uint8_t link_options;
298 linkaddr_t addr;
299
300 /* Save link option and addr in local variables as we need them
301 * after freeing the link */
302 link_options = l->link_options;
303 linkaddr_copy(&addr, &l->addr);
304
305 /* The link to be removed is scheduled as next, set it to NULL
306 * to abort the next link operation */
307 if(l == current_link) {
308 current_link = NULL;
309 }
310 LOG_INFO("remove_link sf=%u opt=%s type=%s ts=%u ch=%u addr=",
311 slotframe->handle,
312 print_link_options(l->link_options),
313 print_link_type(l->link_type), l->timeslot, l->channel_offset);
314 LOG_INFO_LLADDR(&l->addr);
315 LOG_INFO_("\n");
316
317 list_remove(slotframe->links_list, l);
318 memb_free(&link_memb, l);
319
320 /* Release the lock before we update the neighbor (will take the lock) */
322
323 /* This was a tx link to this neighbor, update counters */
324 if(link_options & LINK_OPTION_TX) {
326 if(n != NULL) {
327 n->tx_links_count--;
328 if(!(link_options & LINK_OPTION_SHARED)) {
329 n->dedicated_tx_links_count--;
330 }
331 }
332 }
333
334 return 1;
335 } else {
336 LOG_ERR("! remove_link memb_alloc couldn't take lock\n");
337 }
338 }
339 return 0;
340}
341/*---------------------------------------------------------------------------*/
342/* Removes a link from slotframe and timeslot + channel offset. Return a 1 if
343 * success, 0 if failure */
344int
346 uint16_t timeslot, uint16_t channel_offset)
347{
348 int ret = 0;
349 if(!tsch_is_locked()) {
350 if(slotframe != NULL) {
351 struct tsch_link *l = list_head(slotframe->links_list);
352 /* Loop over all items and remove all matching links */
353 while(l != NULL) {
354 struct tsch_link *next = list_item_next(l);
355 if(l->timeslot == timeslot && l->channel_offset == channel_offset) {
356 if(tsch_schedule_remove_link(slotframe, l)) {
357 ret = 1;
358 }
359 }
360 l = next;
361 }
362 }
363 }
364 return ret;
365}
366/*---------------------------------------------------------------------------*/
367/* Looks within a slotframe for a link with a given timeslot and channel
368 * offset */
369struct tsch_link *
371 uint16_t timeslot, uint16_t channel_offset)
372{
373 if(!tsch_is_locked()) {
374 if(slotframe != NULL) {
375 struct tsch_link *l = list_head(slotframe->links_list);
376 /* Loop over all items. Assume there is max one link per timeslot
377 and channel_offset */
378 while(l != NULL) {
379 if(l->timeslot == timeslot && l->channel_offset == channel_offset) {
380 return l;
381 }
382 l = list_item_next(l);
383 }
384 return l;
385 }
386 }
387 return NULL;
388}
389/*---------------------------------------------------------------------------*/
390/* Looks within a slotframe for a link with a given timeslot */
391struct tsch_link *
393 uint16_t timeslot)
394{
395 if(!tsch_is_locked()) {
396 if(slotframe != NULL) {
397 struct tsch_link *l = list_head(slotframe->links_list);
398 /* Loop over all items. Assume there is max one link per timeslot */
399 while(l != NULL) {
400 if(l->timeslot == timeslot) {
401 return l;
402 }
403 l = list_item_next(l);
404 }
405 return l;
406 }
407 }
408 return NULL;
409}
410/*---------------------------------------------------------------------------*/
411static struct tsch_link *
412default_tsch_link_comparator(struct tsch_link *a, struct tsch_link *b)
413{
414 if(!(a->link_options & LINK_OPTION_TX)) {
415 /* None of the links are Tx: simply return the first link */
416 return a;
417 }
418
419 /* Two Tx links at the same slotframe; return the one with most packets to send */
420 if(!linkaddr_cmp(&a->addr, &b->addr)) {
421 struct tsch_neighbor *an = tsch_queue_get_nbr(&a->addr);
422 struct tsch_neighbor *bn = tsch_queue_get_nbr(&b->addr);
423 int a_packet_count = an ? ringbufindex_elements(&an->tx_ringbuf) : 0;
424 int b_packet_count = bn ? ringbufindex_elements(&bn->tx_ringbuf) : 0;
425 /* Compare the number of packets in the queue */
426 return a_packet_count >= b_packet_count ? a : b;
427 }
428
429 /* Same neighbor address; simply return the first link */
430 return a;
431}
432
433/*---------------------------------------------------------------------------*/
434/* Returns the next active link after a given ASN, and a backup link (for the same ASN, with Rx flag) */
435struct tsch_link *
436tsch_schedule_get_next_active_link(struct tsch_asn_t *asn, uint16_t *time_offset,
437 struct tsch_link **backup_link)
438{
439 uint16_t time_to_curr_best = 0;
440 struct tsch_link *curr_best = NULL;
441 struct tsch_link *curr_backup = NULL; /* Keep a back link in case the current link
442 turns out useless when the time comes. For instance, for a Tx-only link, if there is
443 no outgoing packet in queue. In that case, run the backup link instead. The backup link
444 must have Rx flag set. */
445 if(!tsch_is_locked()) {
446 struct tsch_slotframe *sf = list_head(slotframe_list);
447 /* For each slotframe, look for the earliest occurring link */
448 while(sf != NULL) {
449 /* Get timeslot from ASN, given the slotframe length */
450 uint16_t timeslot = TSCH_ASN_MOD(*asn, sf->size);
451 struct tsch_link *l = list_head(sf->links_list);
452 while(l != NULL) {
453 uint16_t time_to_timeslot =
454 l->timeslot > timeslot ?
455 l->timeslot - timeslot :
456 sf->size.val + l->timeslot - timeslot;
457 if(curr_best == NULL || time_to_timeslot < time_to_curr_best) {
458 time_to_curr_best = time_to_timeslot;
459 curr_best = l;
460 curr_backup = NULL;
461 } else if(time_to_timeslot == time_to_curr_best) {
462 struct tsch_link *new_best = NULL;
463 /* Two links are overlapping, we need to select one of them.
464 * By standard: prioritize Tx links first, second by lowest handle */
465 if((curr_best->link_options & LINK_OPTION_TX) == (l->link_options & LINK_OPTION_TX)) {
466 /* Both or neither links have Tx, select the one with lowest handle */
467 if(l->slotframe_handle != curr_best->slotframe_handle) {
468 if(l->slotframe_handle < curr_best->slotframe_handle) {
469 new_best = l;
470 }
471 } else {
472 /* compare the link against the current best link and return the newly selected one */
473 new_best = TSCH_LINK_COMPARATOR(curr_best, l);
474 }
475 } else {
476 /* Select the link that has the Tx option */
477 if(l->link_options & LINK_OPTION_TX) {
478 new_best = l;
479 }
480 }
481
482 /* Maintain backup_link */
483 /* Check if 'l' best can be used as backup */
484 if(new_best != l && (l->link_options & LINK_OPTION_RX)) { /* Does 'l' have Rx flag? */
485 if(curr_backup == NULL || l->slotframe_handle < curr_backup->slotframe_handle) {
486 curr_backup = l;
487 }
488 }
489 /* Check if curr_best can be used as backup */
490 if(new_best != curr_best && (curr_best->link_options & LINK_OPTION_RX)) { /* Does curr_best have Rx flag? */
491 if(curr_backup == NULL || curr_best->slotframe_handle < curr_backup->slotframe_handle) {
492 curr_backup = curr_best;
493 }
494 }
495
496 /* Maintain curr_best */
497 if(new_best != NULL) {
498 curr_best = new_best;
499 }
500 }
501
502 l = list_item_next(l);
503 }
504 sf = list_item_next(sf);
505 }
506 if(time_offset != NULL) {
507 *time_offset = time_to_curr_best;
508 }
509 }
510 if(backup_link != NULL) {
511 *backup_link = curr_backup;
512 }
513 return curr_best;
514}
515/*---------------------------------------------------------------------------*/
516/* Module initialization, call only once at startup. Returns 1 is success, 0 if failure. */
517int
519{
520 if(tsch_get_lock()) {
521 memb_init(&link_memb);
522 memb_init(&slotframe_memb);
523 list_init(slotframe_list);
525 return 1;
526 } else {
527 return 0;
528 }
529}
530/*---------------------------------------------------------------------------*/
531/* Create a 6TiSCH minimal schedule */
532void
534{
535 struct tsch_slotframe *sf_min;
536 /* First, empty current schedule */
538 /* Build 6TiSCH minimal schedule.
539 * We pick a slotframe length of TSCH_SCHEDULE_DEFAULT_LENGTH */
540 sf_min = tsch_schedule_add_slotframe(0, TSCH_SCHEDULE_DEFAULT_LENGTH);
541 /* Add a single Tx|Rx|Shared slot using broadcast address (i.e. usable for unicast and broadcast).
542 * We set the link type to advertising, which is not compliant with 6TiSCH minimal schedule
543 * but is required according to 802.15.4e if also used for EB transmission.
544 * Timeslot: 0, channel offset: 0. */
546 (LINK_OPTION_RX | LINK_OPTION_TX | LINK_OPTION_SHARED | LINK_OPTION_TIME_KEEPING),
547 LINK_TYPE_ADVERTISING, &tsch_broadcast_address,
548 0, 0, 1);
549}
550/*---------------------------------------------------------------------------*/
551struct tsch_slotframe *
553{
554 return list_head(slotframe_list);
555}
556/*---------------------------------------------------------------------------*/
557struct tsch_slotframe *
559{
560 return list_item_next(sf);
561}
562/*---------------------------------------------------------------------------*/
563/* Prints out the current schedule (all slotframes and links) */
564void
566{
567 if(!tsch_is_locked()) {
568 struct tsch_slotframe *sf = list_head(slotframe_list);
569
570 LOG_PRINT("----- start slotframe list -----\n");
571
572 while(sf != NULL) {
573 struct tsch_link *l = list_head(sf->links_list);
574
575 LOG_PRINT("Slotframe Handle %u, size %u\n", sf->handle, sf->size.val);
576
577 while(l != NULL) {
578 LOG_PRINT("* Link Options %s, type %s, timeslot %u, " \
579 "channel offset %u, address ",
580 print_link_options(l->link_options),
581 print_link_type(l->link_type),
582 l->timeslot, l->channel_offset);
583 LOG_PRINT_LLADDR(&l->addr);
584 LOG_PRINT_("\n");
585 l = list_item_next(l);
586 }
587
588 sf = list_item_next(sf);
589 }
590
591 LOG_PRINT("----- end slotframe list -----\n");
592 }
593}
594/*---------------------------------------------------------------------------*/
595/** @} */
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
bool linkaddr_cmp(const linkaddr_t *addr1, const linkaddr_t *addr2)
Compare two link-layer addresses.
Definition linkaddr.c:69
const linkaddr_t linkaddr_null
The null link-layer address.
static void list_init(list_t list)
Initialize a list.
Definition list.h:152
#define LIST(name)
Declare a linked list.
Definition list.h:90
static void * list_item_next(const void *item)
Get the next item following this item.
Definition list.h:294
void list_add(list_t list, void *item)
Add an item at the end of a list.
Definition list.c:71
void list_remove(list_t list, const void *item)
Remove a specific element from a list.
Definition list.c:134
#define LIST_STRUCT_INIT(struct_ptr, name)
Initialize a linked list that is part of a structure.
Definition list.h:126
static void * list_head(const_list_t list)
Get a pointer to the first element of a list.
Definition list.h:169
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:91
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.
struct tsch_link * tsch_schedule_get_link_by_timeslot(struct tsch_slotframe *slotframe, uint16_t timeslot)
Looks within a slotframe for a link with a given timeslot.
int tsch_get_lock(void)
Takes the TSCH lock.
void tsch_release_lock(void)
Releases the TSCH lock.
int tsch_schedule_remove_link_by_offsets(struct tsch_slotframe *slotframe, uint16_t timeslot, uint16_t channel_offset)
Removes a link from a slotframe and timeslot + channel offset.
void tsch_schedule_print(void)
Prints out the current schedule (all slotframes and links)
struct tsch_link * tsch_schedule_get_link_by_offsets(struct tsch_slotframe *slotframe, uint16_t timeslot, uint16_t channel_offset)
Looks within a slotframe for a link with a given timeslot and channel offset.
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_slotframe * tsch_schedule_add_slotframe(uint16_t handle, uint16_t size)
Creates and adds a new slotframe.
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.
static int ringbufindex_elements(const struct ringbufindex *r)
Return the number of elements currently in the ring buffer.
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