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 */
65 MEMB(link_memb, struct tsch_link, TSCH_SCHEDULE_MAX_LINKS);
66 /* Pre-allocated space for slotframes */
67 MEMB(slotframe_memb, struct tsch_slotframe, TSCH_SCHEDULE_MAX_SLOTFRAMES);
68 /* List of slotframes (each slotframe holds its own list of links) */
69 LIST(slotframe_list);
70 
71 /* Adds and returns a slotframe (NULL if failure) */
72 struct tsch_slotframe *
73 tsch_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 */
103 int
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 */
116 int
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 */
139 struct 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 */
155 struct 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 /*---------------------------------------------------------------------------*/
175 static const char *
176 print_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 /*---------------------------------------------------------------------------*/
199 static const char *
200 print_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) */
215 struct 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 */
286 int
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) {
319  struct tsch_neighbor *n = tsch_queue_get_nbr(&addr);
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 */
337 int
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 */
361 struct 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 /*---------------------------------------------------------------------------*/
381 static struct tsch_link *
382 default_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) */
405 struct tsch_link *
406 tsch_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. */
487 int
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 */
502 void
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. */
515  tsch_schedule_add_link(sf_min,
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 /*---------------------------------------------------------------------------*/
521 struct tsch_slotframe *
523 {
524  return list_head(slotframe_list);
525 }
526 /*---------------------------------------------------------------------------*/
527 struct tsch_slotframe *
529 {
530  return list_item_next(sf);
531 }
532 /*---------------------------------------------------------------------------*/
533 /* Prints out the current schedule (all slotframes and links) */
534 void
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 %u\n",
549  l->link_options, l->link_type, l->timeslot, l->channel_offset, l->addr.u8[7]);
550  l = list_item_next(l);
551  }
552 
553  sf = list_item_next(sf);
554  }
555 
556  LOG_PRINT("----- end slotframe list -----\n");
557  }
558 }
559 /*---------------------------------------------------------------------------*/
560 /** @} */
#define TSCH_ASN_DIVISOR_INIT(div, val_)
Initialize a struct asn_divisor_t.
Definition: tsch-asn.h:86
#define LIST_STRUCT_INIT(struct_ptr, name)
Initialize a linked list that is part of a structure.
Definition: list.h:125
struct tsch_neighbor * tsch_queue_get_nbr(const linkaddr_t *addr)
Get a TSCH neighbor.
Definition: tsch-queue.c:110
struct tsch_slotframe * tsch_schedule_slotframe_next(struct tsch_slotframe *sf)
Access the next item in the list of slotframes.
int memb_free(struct memb *m, void *ptr)
Deallocate a memory block from a memory block previously declared with MEMB().
Definition: memb.c:78
static uip_ds6_addr_t * addr
Pointer to a nbr cache entry.
Definition: uip-nd6.c:107
int tsch_schedule_init(void)
Module initialization, call only once at init.
int tsch_get_lock(void)
Takes the TSCH lock.
void tsch_release_lock(void)
Releases the TSCH lock.
TSCH neighbor information.
Definition: tsch-types.h:109
802.15.4e slotframe (contains links)
Definition: tsch-types.h:84
struct tsch_slotframe * tsch_schedule_add_slotframe(uint16_t handle, uint16_t size)
Creates and adds a new slotframe.
Definition: tsch-schedule.c:73
const linkaddr_t linkaddr_null
The null link-layer address.
struct tsch_slotframe * tsch_schedule_get_slotframe_by_handle(uint16_t handle)
Looks up a slotframe by handle.
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.
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.
struct tsch_neighbor * tsch_queue_add_nbr(const linkaddr_t *addr)
Add a TSCH neighbor queue.
Definition: tsch-queue.c:81
Header file for the Packet queue buffer management
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, with Rx flag)
void tsch_schedule_print(void)
Prints out the current schedule (all slotframes and links)
void * list_head(list_t list)
Get a pointer to the first element of a list.
Definition: list.c:82
Header file for the real-time timer module.
#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
Header file for the Contiki process interface.
Main API declarations for TSCH.
int tsch_schedule_remove_link(struct tsch_slotframe *slotframe, struct tsch_link *l)
Removes a link.
802.15.4 frame creation and parsing functions
int ringbufindex_elements(const struct ringbufindex *r)
Return the number of elements currently in the ring buffer.
Definition: ringbufindex.c:134
Memory block allocation routines.
int tsch_is_locked(void)
Checks if the TSCH lock is set.
struct tsch_slotframe * tsch_schedule_slotframe_head(void)
Access the first item in the list of slotframes.
link_type
802.15.4e link types.
Definition: tsch-types.h:54
void linkaddr_copy(linkaddr_t *dest, const linkaddr_t *src)
Copy a link-layer address.
Definition: linkaddr.c:63
int tsch_schedule_remove_slotframe(struct tsch_slotframe *slotframe)
Removes a slotframe.
void list_add(list_t list, void *item)
Add an item at the end of a list.
Definition: list.c:142
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
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.
#define LIST(name)
Declare a linked list.
Definition: list.h:89
int tsch_schedule_remove_all_slotframes(void)
Removes all slotframes, resulting in an empty schedule.
void * memb_alloc(struct memb *m)
Allocate a memory block from a block of memory declared with MEMB().
Definition: memb.c:59
struct tsch_link * tsch_schedule_get_link_by_handle(uint16_t handle)
Looks for a link from a handle.
Header file for the Packet buffer (packetbuf) management
void memb_init(struct memb *m)
Initialize a memory block that was declared with MEMB().
Definition: memb.c:52
Header file for the logging system
Header file for the LED HAL.
The ASN is an absolute slot number over 5 bytes.
Definition: tsch-asn.h:48
void list_remove(list_t list, void *item)
Remove a specific element from a list.
Definition: list.c:237
void tsch_schedule_create_minimal(void)
Create a 6tisch minimal schedule with length TSCH_SCHEDULE_DEFAULT_LENGTH.
void * list_item_next(void *item)
Get the next item following this item.
Definition: list.c:322
#define MEMB(name, structure, num)
Declare a memory block.
Definition: memb.h:90